diff --git a/hapi-tinder-plugin/pom.xml b/hapi-tinder-plugin/pom.xml index 6ca54b53533..49da9e1bfd1 100644 --- a/hapi-tinder-plugin/pom.xml +++ b/hapi-tinder-plugin/pom.xml @@ -117,6 +117,13 @@ 3.2 provided + + + + org.apache.ant + ant + 1.7.0 + diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/ant/TinderGeneratorTask.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/ant/TinderGeneratorTask.java new file mode 100644 index 00000000000..437a5ccfb8b --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/ant/TinderGeneratorTask.java @@ -0,0 +1,356 @@ +/** + * SOA Software, Inc. Copyright (C) 2000-2012, All rights reserved + * + * This software is the confidential and proprietary information of SOA Software, Inc. + * and is subject to copyright protection under laws of the United States of America and + * other countries. The use of this software should be in accordance with the license + * agreement terms you entered into with SOA Software, Inc. + * + * $Id$ + */ + +package ca.uhn.fhir.tinder.ant; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.StringTokenizer; +import java.util.TreeSet; +import java.util.Map.Entry; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; +import javax.xml.namespace.QName; + +import org.apache.commons.lang.WordUtils; +import org.apache.maven.model.Resource; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.DefaultLogger; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.EnumeratedAttribute; +import org.apache.tools.ant.util.FileUtils; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.tools.generic.EscapeTool; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.tinder.parser.ResourceGeneratorUsingSpreadsheet; + +/** + * + * @author Copyright (c) 2012, SOA Software, Inc. All rights reserved. + * @since 6.0 + */ +public class TinderGeneratorTask extends Task { + + // Parameter(required = true) + private String version; + + // Parameter(required = true) + private String template; + private String templateFile; + private File templateFileFile; + + // Parameter(required = true, defaultValue = "${project.build.directory}/..") + private String projectHome; + + // Parameter(required = true, defaultValue = "${project.build.directory}/generated-sources/tinder") + private String targetDir; + private File targetDirectoryFile; + + private String targetPackage; + + // Parameter(required = true, defaultValue = "${project.build.directory}/generated-resources/tinder") + private String targetFile; + + // Parameter(required = true) + private String packageBase; + + private String targetClassSuffix; + + // Parameter(required = false) + private List baseResourceNames; + + // Parameter(required = false) + private List excludeResourceNames; + + private boolean verbose; + + private FhirContext fhirContext; // set from version in validateAttributes + + /** + * + */ + public TinderGeneratorTask () { + super(); + } + + @Override + public void execute () throws BuildException { + validateAttributes(); + + try { + + if (baseResourceNames == null || baseResourceNames.isEmpty()) { + baseResourceNames = new ArrayList(); + + log("No resource names supplied, going to use all resources from version: "+fhirContext.getVersion().getVersion()); + + Properties p = new Properties(); + try { + p.load(fhirContext.getVersion().getFhirVersionPropertiesFile()); + } catch (IOException e) { + throw new BuildException("Failed to load version property file", e); + } + + if (verbose) { + log("Property file contains: "+p); + } + + for(Object next : p.keySet()) { + if (((String)next).startsWith("resource.")) { + baseResourceNames.add(((String)next).substring("resource.".length()).toLowerCase()); + } + } + } else { + for (int i = 0; i < baseResourceNames.size(); i++) { + baseResourceNames.set(i, baseResourceNames.get(i).toLowerCase()); + } + } + + if (excludeResourceNames != null) { + for (int i = 0; i < excludeResourceNames.size(); i++) { + baseResourceNames.remove(excludeResourceNames.get(i).toLowerCase()); + } + } + + log("Including the following resources: "+baseResourceNames); + + ResourceGeneratorUsingSpreadsheet gen = new ResourceGeneratorUsingSpreadsheet(version, projectHome); + gen.setBaseResourceNames(baseResourceNames); + + try { + gen.parse(); + +// gen.setFilenameSuffix("ResourceProvider"); +// gen.setTemplate("/vm/jpa_daos.vm"); +// gen.writeAll(packageDirectoryBase, null,packageBase); + + // gen.setFilenameSuffix("ResourceTable"); + // gen.setTemplate("/vm/jpa_resource_table.vm"); + // gen.writeAll(directoryBase, packageBase); + + } catch (Exception e) { + throw new BuildException("Failed to parse FHIR metadata", e); + } + + try { + VelocityContext ctx = new VelocityContext(); + ctx.put("resources", gen.getResources()); + ctx.put("packageBase", packageBase); + ctx.put("targetPackage", targetPackage); + ctx.put("version", version); + ctx.put("esc", new EscapeTool()); + + String capitalize = WordUtils.capitalize(version); + if ("Dstu".equals(capitalize)) { + capitalize="Dstu1"; + } + ctx.put("versionCapitalized", capitalize); + + VelocityEngine v = new VelocityEngine(); + v.setProperty("resource.loader", "cp"); + v.setProperty("cp.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); + v.setProperty("runtime.references.strict", Boolean.TRUE); + + targetDirectoryFile.mkdirs(); + + if (targetFile != null) { + InputStream templateIs = null; + if (templateFileFile != null) { + templateIs = new FileInputStream(templateFileFile); + } else { + templateIs = ResourceGeneratorUsingSpreadsheet.class.getResourceAsStream(template); + } + InputStreamReader templateReader = new InputStreamReader(templateIs); + + File target = null; + if (targetPackage != null) { + target = new File(targetDir, targetPackage.replace('.', File.separatorChar)); + } else { + target = new File(targetDir); + } + target.mkdirs(); + File f = new File(target, targetFile); + OutputStreamWriter w = new OutputStreamWriter(new FileOutputStream(f, false), "UTF-8"); + + v.evaluate(ctx, w, "", templateReader); + w.close(); + + } else { + File packageDirectoryBase = new File(targetDir, packageBase.replace(".", File.separatorChar + "")); + packageDirectoryBase.mkdirs(); + + gen.setFilenameSuffix(targetClassSuffix); + gen.setTemplate(template); + gen.setTemplateFile(templateFileFile); + gen.writeAll(packageDirectoryBase, null,packageBase); + + } + + } catch (Exception e) { + log("Caught exception: "+e.getClass().getName()+" ["+e.getMessage()+"]", 1); + e.printStackTrace(); + throw new BuildException("Failed to generate file(s)", e); + } + + cleanup(); + + } catch (Exception e) { + if (e instanceof BuildException) { + throw (BuildException)e; + } + log("Caught exception: "+e.getClass().getName()+" ["+e.getMessage()+"]", 1); + e.printStackTrace(); + throw new BuildException("Error processing "+getTaskName()+" task.", e); + } + } + + protected void validateAttributes () throws BuildException { + if (null == version) { + throw new BuildException("The "+this.getTaskName()+" task requires \"version\" attribute."); + } + if ("dstu".equals(version)) { + fhirContext = FhirContext.forDstu1(); + } else if ("dstu2".equals(version)) { + fhirContext = FhirContext.forDstu2(); + } else if ("dstu3".equals(version)) { + fhirContext = FhirContext.forDstu3(); + } else { + throw new BuildException("Unknown version configured: " + version); + } + + if (null == template) { + if (null == templateFile) { + throw new BuildException("The "+this.getTaskName()+" task requires \"template\" or \"templateFile\" attribute."); + } + templateFileFile = new File(templateFile); + if (!templateFileFile.exists()) { + throw new BuildException("The Velocity template file ["+templateFileFile.getAbsolutePath()+"] does not exist."); + } + if (!templateFileFile.canRead()) { + throw new BuildException("The Velocity template file ["+templateFileFile.getAbsolutePath()+"] cannot be read."); + } + if (!templateFileFile.isFile()) { + throw new BuildException("The Velocity template file ["+templateFileFile.getAbsolutePath()+"] is not a file."); + } + } + + if (null == projectHome) { + throw new BuildException("The "+this.getTaskName()+" task requires \"projectHome\" attribute."); + } + + if (null == targetDir) { + throw new BuildException("The "+this.getTaskName()+" task requires \"targetDirectory\" attribute."); + } + targetDirectoryFile = new File(targetDir); + + if (targetFile != null || (packageBase != null && targetClassSuffix != null)) { + // this is good + } else { + throw new BuildException("The "+this.getTaskName()+" task requires either the \"targetFile\" attribute or both the \"packageBase\" and \"targetClassSuffix\" attributes."); + + } + } + + protected void cleanup () { + } + + + public void setBaseResourceNames(String names) { + if (null == this.baseResourceNames) { + this.baseResourceNames = new ArrayList(); + } + if (names != null) { + List work = new ArrayList(); + String[] tokens = names.split(","); + for (String token : tokens) { + work.add(token.trim()); + } + this.baseResourceNames.addAll(work); + } + } + public void setExcludeResourceNames(String names) { + if (null == this.excludeResourceNames) { + this.excludeResourceNames = new ArrayList(); + } + if (names != null) { + List work = new ArrayList(); + String[] tokens = names.split(","); + for (String token : tokens) { + work.add(token.trim()); + } + this.excludeResourceNames.addAll(work); + } + } + public void setTemplate(String template) { + this.template = template; + } + public void setTemplateFile(String template) { + this.templateFile = template; + } + public void setProjectHome(String projectHome) { + this.projectHome = projectHome; + } + public void setTargetDir(String targetDirectory) { + this.targetDir = targetDirectory; + } + public void setTargetFile(String targetFile) { + this.targetFile = targetFile; + } + public void setTargetPackage(String targetPackage) { + this.targetPackage = targetPackage; + } + public void setPackageBase(String packageBase) { + this.packageBase = packageBase; + } + public void setTargetClassSuffix(String targetClassSuffix) { + this.targetClassSuffix = targetClassSuffix; + } + public static class Version extends EnumeratedAttribute { + public String[] getValues() { + return new String[] {"dstu", "dstu2", "dstu3"}; + } + } + public void setVersion(Version version) { + this.version = version.getValue(); + } + + public void setVerbose(boolean verbose) { + this.verbose = verbose; + } +} diff --git a/hapi-tinder-test/pom.xml b/hapi-tinder-test/pom.xml index 865c3f9fcc8..6d25430a0c4 100644 --- a/hapi-tinder-test/pom.xml +++ b/hapi-tinder-test/pom.xml @@ -143,6 +143,101 @@ + + maven-antrun-plugin + + + testTinderTask + generate-sources + + run + + + + + + + + + + + + + + + + ca.uhn.hapi.fhir + hapi-fhir-base + 1.5-SNAPSHOT + + + ca.uhn.hapi.fhir + hapi-tinder-plugin + 1.5-SNAPSHOT + + + ca.uhn.hapi.fhir + hapi-fhir-structures-dstu2 + 1.5-SNAPSHOT + + + + org.apache.maven.plugins maven-deploy-plugin diff --git a/hapi-tinder-test/src/test/java/test/TestAntTask.java b/hapi-tinder-test/src/test/java/test/TestAntTask.java new file mode 100644 index 00000000000..fd81a49dda7 --- /dev/null +++ b/hapi-tinder-test/src/test/java/test/TestAntTask.java @@ -0,0 +1,23 @@ +package test; + +import java.util.List; + +import org.junit.Test; + +import ca.uhn.test.ant.single.TestConfigDstu2; +import ca.uhn.test.ant.multi.*; +import test.ResourceTest; + +public class TestAntTask { + + @Test + public void testGeneratedListReferencingGenerics() { + // This won't compile if tinder didn't generate the right names... + TestConfigDstu2 config = new TestConfigDstu2(); + List generics = config.testProvidersDstu2(); + for (ResourceTest generic : generics) { + String name = generic.getResourceName(); + } + } + +}