http://git-wip-us.apache.org/repos/asf/cayenne/blob/26d8434d/cayenne-tools/src/main/java/org/apache/cayenne/gen/ClassGenerationAction.java ---------------------------------------------------------------------- diff --git a/cayenne-tools/src/main/java/org/apache/cayenne/gen/ClassGenerationAction.java b/cayenne-tools/src/main/java/org/apache/cayenne/gen/ClassGenerationAction.java index ce0c1c9..6f2f881 100644 --- a/cayenne-tools/src/main/java/org/apache/cayenne/gen/ClassGenerationAction.java +++ b/cayenne-tools/src/main/java/org/apache/cayenne/gen/ClassGenerationAction.java @@ -18,6 +18,16 @@ ****************************************************************/ package org.apache.cayenne.gen; +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + import org.apache.cayenne.CayenneRuntimeException; import org.apache.cayenne.access.loader.NamePatternMatcher; import org.apache.cayenne.map.DataMap; @@ -31,567 +41,544 @@ import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.runtime.RuntimeConstants; import org.apache.velocity.runtime.log.NullLogSystem; -import java.io.File; -import java.io.FileOutputStream; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; - public class ClassGenerationAction { - static final String TEMPLATES_DIR_NAME = "templates/v1_2/"; - - public static final String SINGLE_CLASS_TEMPLATE = TEMPLATES_DIR_NAME + "singleclass.vm"; - public static final String SUBCLASS_TEMPLATE = TEMPLATES_DIR_NAME + "subclass.vm"; - public static final String SUPERCLASS_TEMPLATE = TEMPLATES_DIR_NAME + "superclass.vm"; - - public static final String EMBEDDABLE_SINGLE_CLASS_TEMPLATE = TEMPLATES_DIR_NAME + "embeddable-singleclass.vm"; - public static final String EMBEDDABLE_SUBCLASS_TEMPLATE = TEMPLATES_DIR_NAME + "embeddable-subclass.vm"; - public static final String EMBEDDABLE_SUPERCLASS_TEMPLATE = TEMPLATES_DIR_NAME + "embeddable-superclass.vm"; - - public static final String DATAMAP_SINGLE_CLASS_TEMPLATE = TEMPLATES_DIR_NAME + "datamap-singleclass.vm"; - public static final String DATAMAP_SUBCLASS_TEMPLATE = TEMPLATES_DIR_NAME + "datamap-subclass.vm"; - public static final String DATAMAP_SUPERCLASS_TEMPLATE = TEMPLATES_DIR_NAME + "datamap-superclass.vm"; - - public static final String SUPERCLASS_PREFIX = "_"; - private static final String WILDCARD = "*"; - - protected Collection<Artifact> artifacts; - - protected String superPkg; - protected DataMap dataMap; - - protected ArtifactsGenerationMode artifactsGenerationMode; - protected boolean makePairs; - - protected Log logger; - protected File destDir; - protected boolean overwrite; - protected boolean usePkgPath; - - protected String template; - protected String superTemplate; - protected String embeddableTemplate; - protected String embeddableSuperTemplate; - protected String queryTemplate; - protected String querySuperTemplate; - protected long timestamp; - protected String outputPattern; - protected String encoding; - protected boolean createPropertyNames; - - // runtime ivars - protected VelocityContext context; - protected Map<String, Template> templateCache; - - public ClassGenerationAction() { - this.outputPattern = "*.java"; - this.timestamp = System.currentTimeMillis(); - this.usePkgPath = true; - this.makePairs = true; - this.context = new VelocityContext(); - this.templateCache = new HashMap<String, Template>(5); - - this.artifacts = new ArrayList<Artifact>(); - } - - protected String defaultTemplateName(TemplateType type) { - switch (type) { - case ENTITY_SINGLE_CLASS: - return ClassGenerationAction.SINGLE_CLASS_TEMPLATE; - case ENTITY_SUBCLASS: - return ClassGenerationAction.SUBCLASS_TEMPLATE; - case ENTITY_SUPERCLASS: - return ClassGenerationAction.SUPERCLASS_TEMPLATE; - case EMBEDDABLE_SUBCLASS: - return ClassGenerationAction.EMBEDDABLE_SUBCLASS_TEMPLATE; - case EMBEDDABLE_SUPERCLASS: - return ClassGenerationAction.EMBEDDABLE_SUPERCLASS_TEMPLATE; - case EMBEDDABLE_SINGLE_CLASS: - return ClassGenerationAction.EMBEDDABLE_SINGLE_CLASS_TEMPLATE; - case DATAMAP_SINGLE_CLASS: - return ClassGenerationAction.DATAMAP_SINGLE_CLASS_TEMPLATE; - case DATAMAP_SUPERCLASS: - return ClassGenerationAction.DATAMAP_SUPERCLASS_TEMPLATE; - case DATAMAP_SUBCLASS: - return ClassGenerationAction.DATAMAP_SUBCLASS_TEMPLATE; - default: - throw new IllegalArgumentException("Invalid template type: " + type); - } - } - - protected String customTemplateName(TemplateType type) { - switch (type) { - case ENTITY_SINGLE_CLASS: - return template; - case ENTITY_SUBCLASS: - return template; - case ENTITY_SUPERCLASS: - return superTemplate; - case EMBEDDABLE_SUBCLASS: - return embeddableTemplate; - case EMBEDDABLE_SUPERCLASS: - return embeddableSuperTemplate; - case DATAMAP_SINGLE_CLASS: - return queryTemplate; - case DATAMAP_SUPERCLASS: - return querySuperTemplate; - case DATAMAP_SUBCLASS: - return queryTemplate; - default: - throw new IllegalArgumentException("Invalid template type: " + type); - } - } - - /** - * Returns a String used to prefix class name to create a generated superclass. - * Default value is "_". - */ - protected String getSuperclassPrefix() { - return ClassGenerationAction.SUPERCLASS_PREFIX; - } - - /** - * VelocityContext initialization method called once per artifact. - */ - protected void resetContextForArtifact(Artifact artifact) { - StringUtils stringUtils = StringUtils.getInstance(); - - String qualifiedClassName = artifact.getQualifiedClassName(); - String packageName = stringUtils.stripClass(qualifiedClassName); - String className = stringUtils.stripPackageName(qualifiedClassName); - - String qualifiedBaseClassName = artifact.getQualifiedBaseClassName(); - String basePackageName = stringUtils.stripClass(qualifiedBaseClassName); - String baseClassName = stringUtils.stripPackageName(qualifiedBaseClassName); - - String superClassName = getSuperclassPrefix() - + stringUtils.stripPackageName(qualifiedClassName); - - String superPackageName = this.superPkg; - if (superPackageName == null) { - superPackageName = packageName + ".auto"; - } - - context.put(Artifact.BASE_CLASS_KEY, baseClassName); - context.put(Artifact.BASE_PACKAGE_KEY, basePackageName); - - context.put(Artifact.SUB_CLASS_KEY, className); - context.put(Artifact.SUB_PACKAGE_KEY, packageName); - - context.put(Artifact.SUPER_CLASS_KEY, superClassName); - context.put(Artifact.SUPER_PACKAGE_KEY, superPackageName); - - context.put(Artifact.OBJECT_KEY, artifact.getObject()); - context.put(Artifact.STRING_UTILS_KEY, stringUtils); - - context.put(Artifact.CREATE_PROPERTY_NAMES, createPropertyNames); - } - - /** - * VelocityContext initialization method called once per each artifact and template - * type combination. - */ - protected void resetContextForArtifactTemplate( - Artifact artifact, - TemplateType templateType) { - context.put(Artifact.IMPORT_UTILS_KEY, new ImportUtils()); - artifact.postInitContext(context); - } - - /** - * Executes class generation once per each artifact. - */ - public void execute() throws Exception { - - validateAttributes(); - - try { - for (Artifact artifact : artifacts) { - execute(artifact); - } - } - finally { - // must reset engine at the end of class generator run to avoid memory - // leaks and stale templates - this.templateCache.clear(); - } - } - - /** - * Executes class generation for a single artifact. - */ - protected void execute(Artifact artifact) throws Exception { - - resetContextForArtifact(artifact); - - ArtifactGenerationMode artifactMode = makePairs - ? ArtifactGenerationMode.GENERATION_GAP - : ArtifactGenerationMode.SINGLE_CLASS; - - TemplateType[] templateTypes = artifact.getTemplateTypes(artifactMode); - for (TemplateType type : templateTypes) { - - Writer out = openWriter(type); - if (out != null) { - - resetContextForArtifactTemplate(artifact, type); - getTemplate(type).merge(context, out); - out.close(); - } - } - } - - protected Template getTemplate(TemplateType type) throws Exception { - - String templateName = customTemplateName(type); - if (templateName == null) { - templateName = defaultTemplateName(type); - } - - // Velocity < 1.5 has some memory problems, so we will create a VelocityEngine - // every time, and store templates in an internal cache, to avoid uncontrolled - // memory leaks... Presumably 1.5 fixes it. - - Template template = templateCache.get(templateName); - - if (template == null) { - - Properties props = new Properties(); - - // null logger that will prevent velocity.log from being generated - props.put(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, NullLogSystem.class - .getName()); - props.put("resource.loader", "cayenne"); - props.put("cayenne.resource.loader.class", ClassGeneratorResourceLoader.class - .getName()); - props.put("cayenne.resource.loader.cache", "false"); - - VelocityEngine velocityEngine = new VelocityEngine(); - velocityEngine.init(props); - - template = velocityEngine.getTemplate(templateName); - templateCache.put(templateName, template); - } - - return template; - } - - /** - * Validates the state of this class generator. Throws CayenneRuntimeException if it - * is in an inconsistent state. Called internally from "execute". - */ - protected void validateAttributes() { - if (destDir == null) { - throw new CayenneRuntimeException("'destDir' attribute is missing."); - } - - if (!destDir.isDirectory()) { - throw new CayenneRuntimeException("'destDir' is not a directory."); - } - - if (!destDir.canWrite()) { - throw new CayenneRuntimeException("Do not have write permissions for " - + destDir); - } - } - - /** - * Sets the destDir. - */ - public void setDestDir(File destDir) { - this.destDir = destDir; - } - - /** - * Sets <code>overwrite</code> property. - */ - public void setOverwrite(boolean overwrite) { - this.overwrite = overwrite; - } - - /** - * Sets <code>makepairs</code> property. - */ - public void setMakePairs(boolean makePairs) { - this.makePairs = makePairs; - } - - /** - * Sets <code>template</code> property. - */ - public void setTemplate(String template) { - this.template = template; - } - - /** - * Sets <code>superTemplate</code> property. - */ - public void setSuperTemplate(String superTemplate) { - this.superTemplate = superTemplate; - } - - public void setQueryTemplate(String queryTemplate) { - this.queryTemplate = queryTemplate; - } - - public void setQuerySuperTemplate(String querySuperTemplate) { - this.querySuperTemplate = querySuperTemplate; - } - - /** - * Sets <code>usepkgpath</code> property. - */ - public void setUsePkgPath(boolean usePkgPath) { - this.usePkgPath = usePkgPath; - } - - /** - * Sets <code>outputPattern</code> property. - */ - public void setOutputPattern(String outputPattern) { - this.outputPattern = outputPattern; - } - - /** - * Sets <code>createPropertyNames</code> property. - */ - public void setCreatePropertyNames(boolean createPropertyNames) { - this.createPropertyNames = createPropertyNames; - } - - /** - * Opens a Writer to write generated output. Returned Writer is mapped to a filesystem - * file (although subclasses may override that). File location is determined from the - * current state of VelocityContext and the TemplateType passed as a parameter. Writer - * encoding is determined from the value of the "encoding" property. - */ - protected Writer openWriter(TemplateType templateType) throws Exception { - - File outFile = (templateType.isSuperclass()) - ? fileForSuperclass() - : fileForClass(); - if (outFile == null) { - return null; - } - - if (logger != null) { - String label = templateType.isSuperclass() ? "superclass" : "class"; - logger.info("Generating " + label + " file: " + outFile.getCanonicalPath()); - } - - // return writer with specified encoding - FileOutputStream out = new FileOutputStream(outFile); - - return (encoding != null) - ? new OutputStreamWriter(out, encoding) - : new OutputStreamWriter(out); - } - - /** - * Returns a target file where a generated superclass must be saved. If null is - * returned, class shouldn't be generated. - */ - protected File fileForSuperclass() throws Exception { - - String packageName = (String) context.get(Artifact.SUPER_PACKAGE_KEY); - String className = (String) context.get(Artifact.SUPER_CLASS_KEY); - - String filename = NamePatternMatcher.replaceWildcardInStringWithString( - WILDCARD, - outputPattern, - className); - File dest = new File(mkpath(destDir, packageName), filename); - - // Ignore if the destination is newer than the map - // (internal timestamp), i.e. has been generated after the map was - // last saved AND the template is older than the destination file - if (dest.exists() && !isOld(dest)) { - - if (superTemplate == null) { - return null; - } - - File superTemplateFile = new File(superTemplate); - if (superTemplateFile.lastModified() < dest.lastModified()) { - return null; - } - } - - return dest; - } - - /** - * Returns a target file where a generated class must be saved. If null is returned, - * class shouldn't be generated. - */ - protected File fileForClass() throws Exception { - - String packageName = (String) context.get(Artifact.SUB_PACKAGE_KEY); - String className = (String) context.get(Artifact.SUB_CLASS_KEY); - - String filename = NamePatternMatcher.replaceWildcardInStringWithString( - WILDCARD, - outputPattern, - className); - File dest = new File(mkpath(destDir, packageName), filename); - - if (dest.exists()) { - // no overwrite of subclasses - if (makePairs) { - return null; - } - - // skip if said so - if (!overwrite) { - return null; - } - - // Ignore if the destination is newer than the map - // (internal timestamp), i.e. has been generated after the map was - // last saved AND the template is older than the destination file - if (!isOld(dest)) { - - if (template == null) { - return null; - } - - File templateFile = new File(template); - if (templateFile.lastModified() < dest.lastModified()) { - return null; - } - } - } - - return dest; - } - - /** - * Returns true if <code>file</code> parameter is older than internal timestamp of - * this class generator. - */ - protected boolean isOld(File file) { - return file.lastModified() <= timestamp; - } - - /** - * Returns a File object corresponding to a directory where files that belong to - * <code>pkgName</code> package should reside. Creates any missing diectories below - * <code>dest</code>. - */ - protected File mkpath(File dest, String pkgName) throws Exception { - - if (!usePkgPath || pkgName == null) { - return dest; - } - - String path = pkgName.replace('.', File.separatorChar); - File fullPath = new File(dest, path); - if (!fullPath.isDirectory() && !fullPath.mkdirs()) { - throw new Exception("Error making path: " + fullPath); - } - - return fullPath; - } - - public void setTimestamp(long timestamp) { - this.timestamp = timestamp; - } - - /** - * Sets file encoding. If set to null, default system encoding will be used. - */ - public void setEncoding(String encoding) { - this.encoding = encoding; - } - - /** - * Sets "superPkg" property value. - */ - public void setSuperPkg(String superPkg) { - this.superPkg = superPkg; - } - - /** - * @param dataMap The dataMap to set. - */ - public void setDataMap(DataMap dataMap) { - this.dataMap = dataMap; - } - - /** - * Adds entities to the internal entity list. - */ - public void addEntities(Collection<ObjEntity> entities) { - if (artifactsGenerationMode == ArtifactsGenerationMode.ENTITY || - artifactsGenerationMode == ArtifactsGenerationMode.ALL ) { - if (entities != null) { - for (ObjEntity entity : entities) { - artifacts.add(new EntityArtifact(entity)); - } - } - } - } - - public void addEmbeddables(Collection<Embeddable> embeddables) { - if (artifactsGenerationMode == ArtifactsGenerationMode.ENTITY || - artifactsGenerationMode == ArtifactsGenerationMode.ALL ) { - if (embeddables != null) { - for (Embeddable embeddable : embeddables) { - artifacts.add(new EmbeddableArtifact(embeddable)); - } - } - } - } - - public void addQueries(Collection<Query> queries) { - if (artifactsGenerationMode == ArtifactsGenerationMode.DATAMAP - || artifactsGenerationMode == ArtifactsGenerationMode.ALL) { - - // TODO: andrus 10.12.2010 - why not also check for empty query list?? Or - // create a better API for enabling DataMapArtifact - if (queries != null) { - artifacts.add(new DataMapArtifact(dataMap, queries)); - } - } - } - - /** - * Sets an optional shared VelocityContext. Useful with tools like VPP that can set - * custom values in the context, not known to Cayenne. - */ - public void setContext(VelocityContext context) { - this.context = context; - } - - /** - * Injects an optional logger that will be used to trace generated files at the info - * level. - */ - public void setLogger(Log logger) { - this.logger = logger; - } - - public void setEmbeddableTemplate(String embeddableTemplate) { - this.embeddableTemplate = embeddableTemplate; - } - - public void setEmbeddableSuperTemplate(String embeddableSuperTemplate) { - this.embeddableSuperTemplate = embeddableSuperTemplate; - } - - public void setArtifactsGenerationMode(String mode) { - if (ArtifactsGenerationMode.ENTITY.getLabel().equalsIgnoreCase(mode)) { - this.artifactsGenerationMode = ArtifactsGenerationMode.ENTITY; - } - else if (ArtifactsGenerationMode.DATAMAP.getLabel().equalsIgnoreCase(mode)) { - this.artifactsGenerationMode = ArtifactsGenerationMode.DATAMAP; - } - else { - this.artifactsGenerationMode = ArtifactsGenerationMode.ALL; - } - } + static final String TEMPLATES_DIR_NAME = "templates/v1_2/"; + + public static final String SINGLE_CLASS_TEMPLATE = TEMPLATES_DIR_NAME + "singleclass.vm"; + public static final String SUBCLASS_TEMPLATE = TEMPLATES_DIR_NAME + "subclass.vm"; + public static final String SUPERCLASS_TEMPLATE = TEMPLATES_DIR_NAME + "superclass.vm"; + + public static final String EMBEDDABLE_SINGLE_CLASS_TEMPLATE = TEMPLATES_DIR_NAME + "embeddable-singleclass.vm"; + public static final String EMBEDDABLE_SUBCLASS_TEMPLATE = TEMPLATES_DIR_NAME + "embeddable-subclass.vm"; + public static final String EMBEDDABLE_SUPERCLASS_TEMPLATE = TEMPLATES_DIR_NAME + "embeddable-superclass.vm"; + + public static final String DATAMAP_SINGLE_CLASS_TEMPLATE = TEMPLATES_DIR_NAME + "datamap-singleclass.vm"; + public static final String DATAMAP_SUBCLASS_TEMPLATE = TEMPLATES_DIR_NAME + "datamap-subclass.vm"; + public static final String DATAMAP_SUPERCLASS_TEMPLATE = TEMPLATES_DIR_NAME + "datamap-superclass.vm"; + + public static final String SUPERCLASS_PREFIX = "_"; + private static final String WILDCARD = "*"; + + protected Collection<Artifact> artifacts; + + protected String superPkg; + protected DataMap dataMap; + + protected ArtifactsGenerationMode artifactsGenerationMode; + protected boolean makePairs; + + protected Log logger; + protected File destDir; + protected boolean overwrite; + protected boolean usePkgPath; + + protected String template; + protected String superTemplate; + protected String embeddableTemplate; + protected String embeddableSuperTemplate; + protected String queryTemplate; + protected String querySuperTemplate; + protected long timestamp; + protected String outputPattern; + protected String encoding; + protected boolean createPropertyNames; + + // runtime ivars + protected VelocityContext context; + protected Map<String, Template> templateCache; + + public ClassGenerationAction() { + this.outputPattern = "*.java"; + this.timestamp = System.currentTimeMillis(); + this.usePkgPath = true; + this.makePairs = true; + this.context = new VelocityContext(); + this.templateCache = new HashMap<String, Template>(5); + + this.artifacts = new ArrayList<Artifact>(); + } + + protected String defaultTemplateName(TemplateType type) { + switch (type) { + case ENTITY_SINGLE_CLASS: + return ClassGenerationAction.SINGLE_CLASS_TEMPLATE; + case ENTITY_SUBCLASS: + return ClassGenerationAction.SUBCLASS_TEMPLATE; + case ENTITY_SUPERCLASS: + return ClassGenerationAction.SUPERCLASS_TEMPLATE; + case EMBEDDABLE_SUBCLASS: + return ClassGenerationAction.EMBEDDABLE_SUBCLASS_TEMPLATE; + case EMBEDDABLE_SUPERCLASS: + return ClassGenerationAction.EMBEDDABLE_SUPERCLASS_TEMPLATE; + case EMBEDDABLE_SINGLE_CLASS: + return ClassGenerationAction.EMBEDDABLE_SINGLE_CLASS_TEMPLATE; + case DATAMAP_SINGLE_CLASS: + return ClassGenerationAction.DATAMAP_SINGLE_CLASS_TEMPLATE; + case DATAMAP_SUPERCLASS: + return ClassGenerationAction.DATAMAP_SUPERCLASS_TEMPLATE; + case DATAMAP_SUBCLASS: + return ClassGenerationAction.DATAMAP_SUBCLASS_TEMPLATE; + default: + throw new IllegalArgumentException("Invalid template type: " + type); + } + } + + protected String customTemplateName(TemplateType type) { + switch (type) { + case ENTITY_SINGLE_CLASS: + return template; + case ENTITY_SUBCLASS: + return template; + case ENTITY_SUPERCLASS: + return superTemplate; + case EMBEDDABLE_SUBCLASS: + return embeddableTemplate; + case EMBEDDABLE_SUPERCLASS: + return embeddableSuperTemplate; + case DATAMAP_SINGLE_CLASS: + return queryTemplate; + case DATAMAP_SUPERCLASS: + return querySuperTemplate; + case DATAMAP_SUBCLASS: + return queryTemplate; + default: + throw new IllegalArgumentException("Invalid template type: " + type); + } + } + + /** + * Returns a String used to prefix class name to create a generated + * superclass. Default value is "_". + */ + protected String getSuperclassPrefix() { + return ClassGenerationAction.SUPERCLASS_PREFIX; + } + + /** + * VelocityContext initialization method called once per artifact. + */ + protected void resetContextForArtifact(Artifact artifact) { + StringUtils stringUtils = StringUtils.getInstance(); + + String qualifiedClassName = artifact.getQualifiedClassName(); + String packageName = stringUtils.stripClass(qualifiedClassName); + String className = stringUtils.stripPackageName(qualifiedClassName); + + String qualifiedBaseClassName = artifact.getQualifiedBaseClassName(); + String basePackageName = stringUtils.stripClass(qualifiedBaseClassName); + String baseClassName = stringUtils.stripPackageName(qualifiedBaseClassName); + + String superClassName = getSuperclassPrefix() + stringUtils.stripPackageName(qualifiedClassName); + + String superPackageName = this.superPkg; + if (superPackageName == null) { + superPackageName = packageName + ".auto"; + } + + context.put(Artifact.BASE_CLASS_KEY, baseClassName); + context.put(Artifact.BASE_PACKAGE_KEY, basePackageName); + + context.put(Artifact.SUB_CLASS_KEY, className); + context.put(Artifact.SUB_PACKAGE_KEY, packageName); + + context.put(Artifact.SUPER_CLASS_KEY, superClassName); + context.put(Artifact.SUPER_PACKAGE_KEY, superPackageName); + + context.put(Artifact.OBJECT_KEY, artifact.getObject()); + context.put(Artifact.STRING_UTILS_KEY, stringUtils); + + context.put(Artifact.CREATE_PROPERTY_NAMES, createPropertyNames); + } + + /** + * VelocityContext initialization method called once per each artifact and + * template type combination. + */ + protected void resetContextForArtifactTemplate(Artifact artifact, TemplateType templateType) { + context.put(Artifact.IMPORT_UTILS_KEY, new ImportUtils()); + artifact.postInitContext(context); + } + + /** + * Executes class generation once per each artifact. + */ + public void execute() throws Exception { + + validateAttributes(); + + try { + for (Artifact artifact : artifacts) { + execute(artifact); + } + } finally { + // must reset engine at the end of class generator run to avoid + // memory + // leaks and stale templates + this.templateCache.clear(); + } + } + + /** + * Executes class generation for a single artifact. + */ + protected void execute(Artifact artifact) throws Exception { + + resetContextForArtifact(artifact); + + ArtifactGenerationMode artifactMode = makePairs ? ArtifactGenerationMode.GENERATION_GAP + : ArtifactGenerationMode.SINGLE_CLASS; + + TemplateType[] templateTypes = artifact.getTemplateTypes(artifactMode); + for (TemplateType type : templateTypes) { + + try (Writer out = openWriter(type);) { + if (out != null) { + + resetContextForArtifactTemplate(artifact, type); + getTemplate(type).merge(context, out); + } + } + } + } + + protected Template getTemplate(TemplateType type) throws Exception { + + String templateName = customTemplateName(type); + if (templateName == null) { + templateName = defaultTemplateName(type); + } + + // Velocity < 1.5 has some memory problems, so we will create a + // VelocityEngine + // every time, and store templates in an internal cache, to avoid + // uncontrolled + // memory leaks... Presumably 1.5 fixes it. + + Template template = templateCache.get(templateName); + + if (template == null) { + + Properties props = new Properties(); + + // null logger that will prevent velocity.log from being generated + props.put(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, NullLogSystem.class.getName()); + props.put("resource.loader", "cayenne"); + props.put("cayenne.resource.loader.class", ClassGeneratorResourceLoader.class.getName()); + props.put("cayenne.resource.loader.cache", "false"); + + VelocityEngine velocityEngine = new VelocityEngine(); + velocityEngine.init(props); + + template = velocityEngine.getTemplate(templateName); + templateCache.put(templateName, template); + } + + return template; + } + + /** + * Validates the state of this class generator. Throws + * CayenneRuntimeException if it is in an inconsistent state. Called + * internally from "execute". + */ + protected void validateAttributes() { + if (destDir == null) { + throw new CayenneRuntimeException("'destDir' attribute is missing."); + } + + if (!destDir.isDirectory()) { + throw new CayenneRuntimeException("'destDir' is not a directory."); + } + + if (!destDir.canWrite()) { + throw new CayenneRuntimeException("Do not have write permissions for " + destDir); + } + } + + /** + * Sets the destDir. + */ + public void setDestDir(File destDir) { + this.destDir = destDir; + } + + /** + * Sets <code>overwrite</code> property. + */ + public void setOverwrite(boolean overwrite) { + this.overwrite = overwrite; + } + + /** + * Sets <code>makepairs</code> property. + */ + public void setMakePairs(boolean makePairs) { + this.makePairs = makePairs; + } + + /** + * Sets <code>template</code> property. + */ + public void setTemplate(String template) { + this.template = template; + } + + /** + * Sets <code>superTemplate</code> property. + */ + public void setSuperTemplate(String superTemplate) { + this.superTemplate = superTemplate; + } + + public void setQueryTemplate(String queryTemplate) { + this.queryTemplate = queryTemplate; + } + + public void setQuerySuperTemplate(String querySuperTemplate) { + this.querySuperTemplate = querySuperTemplate; + } + + /** + * Sets <code>usepkgpath</code> property. + */ + public void setUsePkgPath(boolean usePkgPath) { + this.usePkgPath = usePkgPath; + } + + /** + * Sets <code>outputPattern</code> property. + */ + public void setOutputPattern(String outputPattern) { + this.outputPattern = outputPattern; + } + + /** + * Sets <code>createPropertyNames</code> property. + */ + public void setCreatePropertyNames(boolean createPropertyNames) { + this.createPropertyNames = createPropertyNames; + } + + /** + * Opens a Writer to write generated output. Returned Writer is mapped to a + * filesystem file (although subclasses may override that). File location is + * determined from the current state of VelocityContext and the TemplateType + * passed as a parameter. Writer encoding is determined from the value of + * the "encoding" property. + */ + protected Writer openWriter(TemplateType templateType) throws Exception { + + File outFile = (templateType.isSuperclass()) ? fileForSuperclass() : fileForClass(); + if (outFile == null) { + return null; + } + + if (logger != null) { + String label = templateType.isSuperclass() ? "superclass" : "class"; + logger.info("Generating " + label + " file: " + outFile.getCanonicalPath()); + } + + // return writer with specified encoding + FileOutputStream out = new FileOutputStream(outFile); + + return (encoding != null) ? new OutputStreamWriter(out, encoding) : new OutputStreamWriter(out); + } + + /** + * Returns a target file where a generated superclass must be saved. If null + * is returned, class shouldn't be generated. + */ + protected File fileForSuperclass() throws Exception { + + String packageName = (String) context.get(Artifact.SUPER_PACKAGE_KEY); + String className = (String) context.get(Artifact.SUPER_CLASS_KEY); + + String filename = NamePatternMatcher.replaceWildcardInStringWithString(WILDCARD, outputPattern, className); + File dest = new File(mkpath(destDir, packageName), filename); + + // Ignore if the destination is newer than the map + // (internal timestamp), i.e. has been generated after the map was + // last saved AND the template is older than the destination file + if (dest.exists() && !isOld(dest)) { + + if (superTemplate == null) { + return null; + } + + File superTemplateFile = new File(superTemplate); + if (superTemplateFile.lastModified() < dest.lastModified()) { + return null; + } + } + + return dest; + } + + /** + * Returns a target file where a generated class must be saved. If null is + * returned, class shouldn't be generated. + */ + protected File fileForClass() throws Exception { + + String packageName = (String) context.get(Artifact.SUB_PACKAGE_KEY); + String className = (String) context.get(Artifact.SUB_CLASS_KEY); + + String filename = NamePatternMatcher.replaceWildcardInStringWithString(WILDCARD, outputPattern, className); + File dest = new File(mkpath(destDir, packageName), filename); + + if (dest.exists()) { + // no overwrite of subclasses + if (makePairs) { + return null; + } + + // skip if said so + if (!overwrite) { + return null; + } + + // Ignore if the destination is newer than the map + // (internal timestamp), i.e. has been generated after the map was + // last saved AND the template is older than the destination file + if (!isOld(dest)) { + + if (template == null) { + return null; + } + + File templateFile = new File(template); + if (templateFile.lastModified() < dest.lastModified()) { + return null; + } + } + } + + return dest; + } + + /** + * Returns true if <code>file</code> parameter is older than internal + * timestamp of this class generator. + */ + protected boolean isOld(File file) { + return file.lastModified() <= timestamp; + } + + /** + * Returns a File object corresponding to a directory where files that + * belong to <code>pkgName</code> package should reside. Creates any missing + * diectories below <code>dest</code>. + */ + protected File mkpath(File dest, String pkgName) throws Exception { + + if (!usePkgPath || pkgName == null) { + return dest; + } + + String path = pkgName.replace('.', File.separatorChar); + File fullPath = new File(dest, path); + if (!fullPath.isDirectory() && !fullPath.mkdirs()) { + throw new Exception("Error making path: " + fullPath); + } + + return fullPath; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + /** + * Sets file encoding. If set to null, default system encoding will be used. + */ + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + /** + * Sets "superPkg" property value. + */ + public void setSuperPkg(String superPkg) { + this.superPkg = superPkg; + } + + /** + * @param dataMap + * The dataMap to set. + */ + public void setDataMap(DataMap dataMap) { + this.dataMap = dataMap; + } + + /** + * Adds entities to the internal entity list. + */ + public void addEntities(Collection<ObjEntity> entities) { + if (artifactsGenerationMode == ArtifactsGenerationMode.ENTITY + || artifactsGenerationMode == ArtifactsGenerationMode.ALL) { + if (entities != null) { + for (ObjEntity entity : entities) { + artifacts.add(new EntityArtifact(entity)); + } + } + } + } + + public void addEmbeddables(Collection<Embeddable> embeddables) { + if (artifactsGenerationMode == ArtifactsGenerationMode.ENTITY + || artifactsGenerationMode == ArtifactsGenerationMode.ALL) { + if (embeddables != null) { + for (Embeddable embeddable : embeddables) { + artifacts.add(new EmbeddableArtifact(embeddable)); + } + } + } + } + + public void addQueries(Collection<Query> queries) { + if (artifactsGenerationMode == ArtifactsGenerationMode.DATAMAP + || artifactsGenerationMode == ArtifactsGenerationMode.ALL) { + + // TODO: andrus 10.12.2010 - why not also check for empty query + // list?? Or + // create a better API for enabling DataMapArtifact + if (queries != null) { + artifacts.add(new DataMapArtifact(dataMap, queries)); + } + } + } + + /** + * Sets an optional shared VelocityContext. Useful with tools like VPP that + * can set custom values in the context, not known to Cayenne. + */ + public void setContext(VelocityContext context) { + this.context = context; + } + + /** + * Injects an optional logger that will be used to trace generated files at + * the info level. + */ + public void setLogger(Log logger) { + this.logger = logger; + } + + public void setEmbeddableTemplate(String embeddableTemplate) { + this.embeddableTemplate = embeddableTemplate; + } + + public void setEmbeddableSuperTemplate(String embeddableSuperTemplate) { + this.embeddableSuperTemplate = embeddableSuperTemplate; + } + + public void setArtifactsGenerationMode(String mode) { + if (ArtifactsGenerationMode.ENTITY.getLabel().equalsIgnoreCase(mode)) { + this.artifactsGenerationMode = ArtifactsGenerationMode.ENTITY; + } else if (ArtifactsGenerationMode.DATAMAP.getLabel().equalsIgnoreCase(mode)) { + this.artifactsGenerationMode = ArtifactsGenerationMode.DATAMAP; + } else { + this.artifactsGenerationMode = ArtifactsGenerationMode.ALL; + } + } }
http://git-wip-us.apache.org/repos/asf/cayenne/blob/26d8434d/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportAction.java ---------------------------------------------------------------------- diff --git a/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportAction.java b/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportAction.java index d604c45..2683d97 100644 --- a/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportAction.java +++ b/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportAction.java @@ -18,6 +18,20 @@ */ package org.apache.cayenne.tools.dbimport; +import static org.apache.commons.lang.StringUtils.isBlank; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.sql.Connection; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; + +import javax.sql.DataSource; + import org.apache.cayenne.access.DbLoader; import org.apache.cayenne.configuration.ConfigurationTree; import org.apache.cayenne.configuration.DataNodeDescriptor; @@ -25,8 +39,20 @@ import org.apache.cayenne.configuration.server.DataSourceFactory; import org.apache.cayenne.configuration.server.DbAdapterFactory; import org.apache.cayenne.dba.DbAdapter; import org.apache.cayenne.di.Inject; -import org.apache.cayenne.map.*; -import org.apache.cayenne.merge.*; +import org.apache.cayenne.map.DataMap; +import org.apache.cayenne.map.EntityResolver; +import org.apache.cayenne.map.MapLoader; +import org.apache.cayenne.map.ObjEntity; +import org.apache.cayenne.map.ObjRelationship; +import org.apache.cayenne.merge.AbstractToModelToken; +import org.apache.cayenne.merge.AddRelationshipToDb; +import org.apache.cayenne.merge.DbMerger; +import org.apache.cayenne.merge.ExecutingMergerContext; +import org.apache.cayenne.merge.MergerContext; +import org.apache.cayenne.merge.MergerFactory; +import org.apache.cayenne.merge.MergerToken; +import org.apache.cayenne.merge.ModelMergeDelegate; +import org.apache.cayenne.merge.ProxyModelMergeDelegate; import org.apache.cayenne.project.Project; import org.apache.cayenne.project.ProjectSaver; import org.apache.cayenne.resource.URLResource; @@ -36,15 +62,6 @@ import org.apache.cayenne.validation.ValidationResult; import org.apache.commons.logging.Log; import org.xml.sax.InputSource; -import javax.sql.DataSource; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.sql.Connection; -import java.util.*; - -import static org.apache.commons.lang.StringUtils.isBlank; - /** * A thin wrapper around {@link DbLoader} that encapsulates DB import logic for * the benefit of Ant and Maven db importers. @@ -53,214 +70,205 @@ import static org.apache.commons.lang.StringUtils.isBlank; */ public class DbImportAction { - private final ProjectSaver projectSaver; - private final Log logger; - private final DataSourceFactory dataSourceFactory; - private final DbAdapterFactory adapterFactory; - private final MapLoader mapLoader; - - public DbImportAction(@Inject Log logger, - @Inject ProjectSaver projectSaver, - @Inject DataSourceFactory dataSourceFactory, - @Inject DbAdapterFactory adapterFactory, - @Inject MapLoader mapLoader) { - this.logger = logger; - this.projectSaver = projectSaver; - this.dataSourceFactory = dataSourceFactory; - this.adapterFactory = adapterFactory; - this.mapLoader = mapLoader; - } - - public void execute(DbImportConfiguration config) throws Exception { - - if (logger.isDebugEnabled()) { - logger.debug("DB connection: " + config.getDataSourceInfo()); - } - - if (logger.isDebugEnabled()) { - logger.debug(config); - } - - DataNodeDescriptor dataNodeDescriptor = config.createDataNodeDescriptor(); - DataSource dataSource = dataSourceFactory.getDataSource(dataNodeDescriptor); - DbAdapter adapter = adapterFactory.createAdapter(dataNodeDescriptor, dataSource); - - DataMap loadedFomDb = load(config, adapter, dataSource.getConnection()); - if (loadedFomDb == null) { - logger.info("Nothing was loaded from db."); - return; - } - - DataMap existing = loadExistingDataMap(config.getDataMapFile()); - if (existing == null) { - logger.info(""); - File file = config.getDataMapFile(); - logger.info("Map file does not exist. Loaded db model will be saved into '" - + (file == null ? "null" : file.getAbsolutePath() + "'")); - - saveLoaded(config.initializeDataMap(loadedFomDb)); - } else { - MergerFactory mergerFactory = adapter.mergerFactory(); - - List<MergerToken> mergeTokens = new DbMerger(mergerFactory) - .createMergeTokens(existing, loadedFomDb, config.getDbLoaderConfig()); - if (mergeTokens.isEmpty()) { - logger.info(""); - logger.info("Detected changes: No changes to import."); - return; - } - - if (!isBlank(config.getDefaultPackage())) { - existing.setDefaultPackage(config.getDefaultPackage()); - } - - final Collection<ObjEntity> loadedObjEntities = new LinkedList<ObjEntity>(); - DataMap executed = execute(new ProxyModelMergeDelegate(config.createMergeDelegate()) { - @Override - public void objEntityAdded(ObjEntity ent) { - loadedObjEntities.add(ent); - - super.objEntityAdded(ent); - } - - }, existing, log(sort(reverse(mergerFactory, mergeTokens)))); - - DbLoader.flattenManyToManyRelationships(executed, loadedObjEntities, config.getNameGenerator()); - - relationshipsSanity(executed); - - - saveLoaded(executed); - } - } - - private void relationshipsSanity(DataMap executed) { - for (ObjEntity objEntity : executed.getObjEntities()) { - - List<ObjRelationship> rels = new LinkedList<ObjRelationship>(objEntity.getRelationships()); - for (ObjRelationship rel : rels) { - if (rel.getSourceEntity() == null || rel.getTargetEntity() == null) { - logger.error("Incorrect obj relationship source or target entity is null: " + rel); - - objEntity.removeRelationship(rel.getName()); - } - } - } - } - - protected static List<MergerToken> sort(List<MergerToken> reverse) { - Collections.sort(reverse, new Comparator<MergerToken>() { - @Override - public int compare(MergerToken o1, MergerToken o2) { - if (o1 instanceof AddRelationshipToDb && o2 instanceof AddRelationshipToDb) { - return 0; - } - - if (!(o1 instanceof AddRelationshipToDb || o2 instanceof AddRelationshipToDb)) { - return o1.getClass().getSimpleName().compareTo(o2.getClass().getSimpleName()); - } - - return o1 instanceof AddRelationshipToDb ? 1 : -1; - } - }); - - return reverse; - } - - private Collection<MergerToken> log(List<MergerToken> tokens) { - logger.info(""); - if (tokens.isEmpty()) { - logger.info("Detected changes: No changes to import."); - return tokens; - } - - logger.info("Detected changes: "); - for (MergerToken token : tokens) { - logger.info(String.format(" %-20s %s", token.getTokenName(), token.getTokenValue())); - } - logger.info(""); - - return tokens; - } - - private DataMap loadExistingDataMap(File dataMapFile) throws IOException { - if (dataMapFile != null && dataMapFile.exists() && dataMapFile.canRead()) { - DataMap dataMap = mapLoader.loadDataMap(new InputSource(dataMapFile.getCanonicalPath())); - dataMap.setNamespace(new EntityResolver(Collections.singleton(dataMap))); - dataMap.setConfigurationSource(new URLResource(dataMapFile.toURI().toURL())); - - return dataMap; - } - - return null; - } - - private List<MergerToken> reverse(MergerFactory mergerFactory, Iterable<MergerToken> mergeTokens) throws IOException { - List<MergerToken> tokens = new LinkedList<MergerToken>(); - for (MergerToken token : mergeTokens) { - if (token instanceof AbstractToModelToken) { - continue; - } - tokens.add(token.createReverse(mergerFactory)); - } - return tokens; - } - - /** - * Performs configured schema operations via DbGenerator. - */ - private DataMap execute(ModelMergeDelegate mergeDelegate, DataMap dataMap, Collection<MergerToken> tokens) { - MergerContext mergerContext = new ExecutingMergerContext( - dataMap, null, null, mergeDelegate); - - for (MergerToken tok : tokens) { - try { - tok.execute(mergerContext); - } catch (Throwable th) { - String message = "Migration Error. Can't apply changes from token: " + tok.getTokenName() - + " (" + tok.getTokenValue() + ")"; - - logger.error(message, th); - mergerContext.getValidationResult().addFailure(new SimpleValidationFailure(th, message)); - } - } - - ValidationResult failures = mergerContext.getValidationResult(); - if (failures == null || !failures.hasFailures()) { - logger.info("Migration Complete Successfully."); - } else { - logger.info("Migration Complete."); - logger.warn("Migration finished. The following problem(s) were ignored."); - for (ValidationFailure failure : failures.getFailures()) { - logger.warn(failure.toString()); - } - } - - return dataMap; - } - - private DbLoader getLoader(DbImportConfiguration config, DbAdapter adapter, Connection connection) throws InstantiationException, IllegalAccessException, ClassNotFoundException { - return config.createLoader(adapter, connection, config.createLoaderDelegate()); - } - - void saveLoaded(DataMap dataMap) throws FileNotFoundException { - ConfigurationTree<DataMap> projectRoot = new ConfigurationTree<DataMap>(dataMap); - Project project = new Project(projectRoot); - projectSaver.save(project); - } - - private DataMap load(DbImportConfiguration config, DbAdapter adapter, Connection connection) throws Exception { - DataMap dataMap = config.createDataMap(); - - try { - DbLoader loader = config.createLoader(adapter, connection, config.createLoaderDelegate()); - loader.load(dataMap, config.getDbLoaderConfig()); - } finally { - if (connection != null) { - connection.close(); - } - } - - return dataMap; - } + private final ProjectSaver projectSaver; + private final Log logger; + private final DataSourceFactory dataSourceFactory; + private final DbAdapterFactory adapterFactory; + private final MapLoader mapLoader; + + public DbImportAction(@Inject Log logger, @Inject ProjectSaver projectSaver, + @Inject DataSourceFactory dataSourceFactory, @Inject DbAdapterFactory adapterFactory, + @Inject MapLoader mapLoader) { + this.logger = logger; + this.projectSaver = projectSaver; + this.dataSourceFactory = dataSourceFactory; + this.adapterFactory = adapterFactory; + this.mapLoader = mapLoader; + } + + public void execute(DbImportConfiguration config) throws Exception { + + if (logger.isDebugEnabled()) { + logger.debug("DB connection: " + config.getDataSourceInfo()); + } + + if (logger.isDebugEnabled()) { + logger.debug(config); + } + + DataNodeDescriptor dataNodeDescriptor = config.createDataNodeDescriptor(); + DataSource dataSource = dataSourceFactory.getDataSource(dataNodeDescriptor); + DbAdapter adapter = adapterFactory.createAdapter(dataNodeDescriptor, dataSource); + + DataMap loadedFomDb; + try (Connection c = dataSource.getConnection()) { + loadedFomDb = load(config, adapter, c); + } + + if (loadedFomDb == null) { + logger.info("Nothing was loaded from db."); + return; + } + + DataMap existing = loadExistingDataMap(config.getDataMapFile()); + if (existing == null) { + logger.info(""); + File file = config.getDataMapFile(); + logger.info("Map file does not exist. Loaded db model will be saved into '" + + (file == null ? "null" : file.getAbsolutePath() + "'")); + + saveLoaded(config.initializeDataMap(loadedFomDb)); + } else { + MergerFactory mergerFactory = adapter.mergerFactory(); + + List<MergerToken> mergeTokens = new DbMerger(mergerFactory).createMergeTokens(existing, loadedFomDb, + config.getDbLoaderConfig()); + if (mergeTokens.isEmpty()) { + logger.info(""); + logger.info("Detected changes: No changes to import."); + return; + } + + if (!isBlank(config.getDefaultPackage())) { + existing.setDefaultPackage(config.getDefaultPackage()); + } + + final Collection<ObjEntity> loadedObjEntities = new LinkedList<ObjEntity>(); + DataMap executed = execute(new ProxyModelMergeDelegate(config.createMergeDelegate()) { + @Override + public void objEntityAdded(ObjEntity ent) { + loadedObjEntities.add(ent); + + super.objEntityAdded(ent); + } + + }, existing, log(sort(reverse(mergerFactory, mergeTokens)))); + + DbLoader.flattenManyToManyRelationships(executed, loadedObjEntities, config.getNameGenerator()); + + relationshipsSanity(executed); + + saveLoaded(executed); + } + } + + private void relationshipsSanity(DataMap executed) { + for (ObjEntity objEntity : executed.getObjEntities()) { + + List<ObjRelationship> rels = new LinkedList<ObjRelationship>(objEntity.getRelationships()); + for (ObjRelationship rel : rels) { + if (rel.getSourceEntity() == null || rel.getTargetEntity() == null) { + logger.error("Incorrect obj relationship source or target entity is null: " + rel); + + objEntity.removeRelationship(rel.getName()); + } + } + } + } + + protected static List<MergerToken> sort(List<MergerToken> reverse) { + Collections.sort(reverse, new Comparator<MergerToken>() { + @Override + public int compare(MergerToken o1, MergerToken o2) { + if (o1 instanceof AddRelationshipToDb && o2 instanceof AddRelationshipToDb) { + return 0; + } + + if (!(o1 instanceof AddRelationshipToDb || o2 instanceof AddRelationshipToDb)) { + return o1.getClass().getSimpleName().compareTo(o2.getClass().getSimpleName()); + } + + return o1 instanceof AddRelationshipToDb ? 1 : -1; + } + }); + + return reverse; + } + + private Collection<MergerToken> log(List<MergerToken> tokens) { + logger.info(""); + if (tokens.isEmpty()) { + logger.info("Detected changes: No changes to import."); + return tokens; + } + + logger.info("Detected changes: "); + for (MergerToken token : tokens) { + logger.info(String.format(" %-20s %s", token.getTokenName(), token.getTokenValue())); + } + logger.info(""); + + return tokens; + } + + private DataMap loadExistingDataMap(File dataMapFile) throws IOException { + if (dataMapFile != null && dataMapFile.exists() && dataMapFile.canRead()) { + DataMap dataMap = mapLoader.loadDataMap(new InputSource(dataMapFile.getCanonicalPath())); + dataMap.setNamespace(new EntityResolver(Collections.singleton(dataMap))); + dataMap.setConfigurationSource(new URLResource(dataMapFile.toURI().toURL())); + + return dataMap; + } + + return null; + } + + private List<MergerToken> reverse(MergerFactory mergerFactory, Iterable<MergerToken> mergeTokens) + throws IOException { + List<MergerToken> tokens = new LinkedList<MergerToken>(); + for (MergerToken token : mergeTokens) { + if (token instanceof AbstractToModelToken) { + continue; + } + tokens.add(token.createReverse(mergerFactory)); + } + return tokens; + } + + /** + * Performs configured schema operations via DbGenerator. + */ + private DataMap execute(ModelMergeDelegate mergeDelegate, DataMap dataMap, Collection<MergerToken> tokens) { + MergerContext mergerContext = new ExecutingMergerContext(dataMap, null, null, mergeDelegate); + + for (MergerToken tok : tokens) { + try { + tok.execute(mergerContext); + } catch (Throwable th) { + String message = "Migration Error. Can't apply changes from token: " + tok.getTokenName() + " (" + + tok.getTokenValue() + ")"; + + logger.error(message, th); + mergerContext.getValidationResult().addFailure(new SimpleValidationFailure(th, message)); + } + } + + ValidationResult failures = mergerContext.getValidationResult(); + if (failures == null || !failures.hasFailures()) { + logger.info("Migration Complete Successfully."); + } else { + logger.info("Migration Complete."); + logger.warn("Migration finished. The following problem(s) were ignored."); + for (ValidationFailure failure : failures.getFailures()) { + logger.warn(failure.toString()); + } + } + + return dataMap; + } + + void saveLoaded(DataMap dataMap) throws FileNotFoundException { + ConfigurationTree<DataMap> projectRoot = new ConfigurationTree<DataMap>(dataMap); + Project project = new Project(projectRoot); + projectSaver.save(project); + } + + private DataMap load(DbImportConfiguration config, DbAdapter adapter, Connection connection) throws Exception { + DataMap dataMap = config.createDataMap(); + + DbLoader loader = config.createLoader(adapter, connection, config.createLoaderDelegate()); + loader.load(dataMap, config.getDbLoaderConfig()); + + return dataMap; + } } http://git-wip-us.apache.org/repos/asf/cayenne/blob/26d8434d/cayenne-tools/src/test/java/org/apache/cayenne/tools/CayenneGeneratorTaskCrossMapRelationshipsTest.java ---------------------------------------------------------------------- diff --git a/cayenne-tools/src/test/java/org/apache/cayenne/tools/CayenneGeneratorTaskCrossMapRelationshipsTest.java b/cayenne-tools/src/test/java/org/apache/cayenne/tools/CayenneGeneratorTaskCrossMapRelationshipsTest.java index df24bdb..40877b8 100644 --- a/cayenne-tools/src/test/java/org/apache/cayenne/tools/CayenneGeneratorTaskCrossMapRelationshipsTest.java +++ b/cayenne-tools/src/test/java/org/apache/cayenne/tools/CayenneGeneratorTaskCrossMapRelationshipsTest.java @@ -38,142 +38,120 @@ import static org.junit.Assert.fail; public class CayenneGeneratorTaskCrossMapRelationshipsTest { - /** - * Tests pairs generation with a cross-DataMap relationship. - */ - @Test - public void testCrossDataMapRelationships() throws Exception { - - CayenneGeneratorTask task = new CayenneGeneratorTask(); - task.setProject(new Project()); - task.setTaskName("Test"); - task.setLocation(Location.UNKNOWN_LOCATION); - - // prepare destination directory - - File destDir = new File(FileUtil.baseTestDirectory(), "cgen12"); - // prepare destination directory - if (!destDir.exists()) { - assertTrue(destDir.mkdirs()); - } - - File map = new File(destDir, "cgen-dependent.map.xml"); - ResourceUtil.copyResourceToFile( - "org/apache/cayenne/tools/cgen-dependent.map.xml", - map); - - File additionalMaps[] = new File[1]; - additionalMaps[0] = new File(destDir, "cgen.map.xml"); - ResourceUtil.copyResourceToFile( - "org/apache/cayenne/tools/cgen.map.xml", - additionalMaps[0]); - - FileList additionalMapsFilelist = new FileList(); - additionalMapsFilelist.setDir(additionalMaps[0].getParentFile()); - additionalMapsFilelist.setFiles(additionalMaps[0].getName()); - - Path additionalMapsPath = new Path(task.getProject()); - additionalMapsPath.addFilelist(additionalMapsFilelist); - - // setup task - task.setMap(map); - task.setAdditionalMaps(additionalMapsPath); - task.setMakepairs(true); - task.setOverwrite(false); - task.setMode("entity"); - task.setIncludeEntities("MyArtGroup"); - task.setDestDir(destDir); - task.setSuperpkg("org.apache.cayenne.testdo.cgen2.auto"); - task.setUsepkgpath(true); - - // run task - task.execute(); - - // check results - File a = new File(destDir, convertPath("org/apache/cayenne/testdo/cgen2/MyArtGroup.java")); - assertTrue(a.isFile()); - assertContents(a, "MyArtGroup", "org.apache.cayenne.testdo.cgen2", "_MyArtGroup"); - - File _a = new File(destDir, convertPath("org/apache/cayenne/testdo/cgen2/auto/_MyArtGroup.java")); - assertTrue(_a.exists()); - assertContents(_a, "_MyArtGroup", "org.apache.cayenne.testdo.cgen2.auto", "CayenneDataObject"); - assertContents(_a, "import org.apache.cayenne.testdo.testmap.ArtGroup;"); - assertContents(_a, " ArtGroup getToParentGroup()"); - assertContents(_a, "setToParentGroup(ArtGroup toParentGroup)"); - } - - private String convertPath(String unixPath) { - return unixPath.replace('/', File.separatorChar); - } - - private void assertContents(File f, String content) throws Exception { - - BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream( - f))); - - try { - String s = null; - while ((s = in.readLine()) != null) { - if (s.contains(content)) - return; - } - - fail("<" + content + "> not found in " + f.getAbsolutePath() + "."); - } - finally { - in.close(); - } - - } - - private void assertContents( - File f, - String className, - String packageName, - String extendsName) throws Exception { - - BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream( - f))); - - try { - assertPackage(in, packageName); - assertClass(in, className, extendsName); - } - finally { - in.close(); - } - - } - - private void assertPackage(BufferedReader in, String packageName) throws Exception { - - String s = null; - while ((s = in.readLine()) != null) { - - if (Pattern.matches("^package\\s+([^\\s;]+);", s)) { - assertTrue(s.contains(packageName)); - return; - } - } - - fail("No package declaration found."); - } - - private void assertClass(BufferedReader in, String className, String extendsName) - throws Exception { - - Pattern classPattern = Pattern.compile("^public\\s+"); - - String s = null; - while ((s = in.readLine()) != null) { - if (classPattern.matcher(s).find()) { - assertTrue(s.contains(className)); - assertTrue(s.contains(extendsName)); - assertTrue(s.indexOf(className) < s.indexOf(extendsName)); - return; - } - } - - fail("No class declaration found."); - } + /** + * Tests pairs generation with a cross-DataMap relationship. + */ + @Test + public void testCrossDataMapRelationships() throws Exception { + + CayenneGeneratorTask task = new CayenneGeneratorTask(); + task.setProject(new Project()); + task.setTaskName("Test"); + task.setLocation(Location.UNKNOWN_LOCATION); + + // prepare destination directory + + File destDir = new File(FileUtil.baseTestDirectory(), "cgen12"); + // prepare destination directory + if (!destDir.exists()) { + assertTrue(destDir.mkdirs()); + } + + File map = new File(destDir, "cgen-dependent.map.xml"); + ResourceUtil.copyResourceToFile("org/apache/cayenne/tools/cgen-dependent.map.xml", map); + + File additionalMaps[] = new File[1]; + additionalMaps[0] = new File(destDir, "cgen.map.xml"); + ResourceUtil.copyResourceToFile("org/apache/cayenne/tools/cgen.map.xml", additionalMaps[0]); + + FileList additionalMapsFilelist = new FileList(); + additionalMapsFilelist.setDir(additionalMaps[0].getParentFile()); + additionalMapsFilelist.setFiles(additionalMaps[0].getName()); + + Path additionalMapsPath = new Path(task.getProject()); + additionalMapsPath.addFilelist(additionalMapsFilelist); + + // setup task + task.setMap(map); + task.setAdditionalMaps(additionalMapsPath); + task.setMakepairs(true); + task.setOverwrite(false); + task.setMode("entity"); + task.setIncludeEntities("MyArtGroup"); + task.setDestDir(destDir); + task.setSuperpkg("org.apache.cayenne.testdo.cgen2.auto"); + task.setUsepkgpath(true); + + // run task + task.execute(); + + // check results + File a = new File(destDir, convertPath("org/apache/cayenne/testdo/cgen2/MyArtGroup.java")); + assertTrue(a.isFile()); + assertContents(a, "MyArtGroup", "org.apache.cayenne.testdo.cgen2", "_MyArtGroup"); + + File _a = new File(destDir, convertPath("org/apache/cayenne/testdo/cgen2/auto/_MyArtGroup.java")); + assertTrue(_a.exists()); + assertContents(_a, "_MyArtGroup", "org.apache.cayenne.testdo.cgen2.auto", "CayenneDataObject"); + assertContents(_a, "import org.apache.cayenne.testdo.testmap.ArtGroup;"); + assertContents(_a, " ArtGroup getToParentGroup()"); + assertContents(_a, "setToParentGroup(ArtGroup toParentGroup)"); + } + + private String convertPath(String unixPath) { + return unixPath.replace('/', File.separatorChar); + } + + private void assertContents(File f, String content) throws Exception { + + try (BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(f)));) { + String s = null; + while ((s = in.readLine()) != null) { + if (s.contains(content)) + return; + } + + fail("<" + content + "> not found in " + f.getAbsolutePath() + "."); + } + + } + + private void assertContents(File f, String className, String packageName, String extendsName) throws Exception { + + try (BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(f)));) { + assertPackage(in, packageName); + assertClass(in, className, extendsName); + } + } + + private void assertPackage(BufferedReader in, String packageName) throws Exception { + + String s = null; + while ((s = in.readLine()) != null) { + + if (Pattern.matches("^package\\s+([^\\s;]+);", s)) { + assertTrue(s.contains(packageName)); + return; + } + } + + fail("No package declaration found."); + } + + private void assertClass(BufferedReader in, String className, String extendsName) throws Exception { + + Pattern classPattern = Pattern.compile("^public\\s+"); + + String s = null; + while ((s = in.readLine()) != null) { + if (classPattern.matcher(s).find()) { + assertTrue(s.contains(className)); + assertTrue(s.contains(extendsName)); + assertTrue(s.indexOf(className) < s.indexOf(extendsName)); + return; + } + } + + fail("No class declaration found."); + } } http://git-wip-us.apache.org/repos/asf/cayenne/blob/26d8434d/cayenne-tools/src/test/java/org/apache/cayenne/tools/CayenneGeneratorTaskTest.java ---------------------------------------------------------------------- diff --git a/cayenne-tools/src/test/java/org/apache/cayenne/tools/CayenneGeneratorTaskTest.java b/cayenne-tools/src/test/java/org/apache/cayenne/tools/CayenneGeneratorTaskTest.java index 09c954d..f6f616b 100644 --- a/cayenne-tools/src/test/java/org/apache/cayenne/tools/CayenneGeneratorTaskTest.java +++ b/cayenne-tools/src/test/java/org/apache/cayenne/tools/CayenneGeneratorTaskTest.java @@ -38,359 +38,280 @@ import static org.junit.Assert.fail; public class CayenneGeneratorTaskTest { - private static final File baseDir; - private static final File map; - private static final File mapEmbeddables; - private static final File template; - - static { - - baseDir = FileUtil.baseTestDirectory(); - map = new File(baseDir, "antmap.xml"); - mapEmbeddables = new File(baseDir, "antmap-embeddables.xml"); - template = new File(baseDir, "velotemplate.vm"); - - ResourceUtil.copyResourceToFile("testmap.map.xml", map); - ResourceUtil.copyResourceToFile("embeddable.map.xml", mapEmbeddables); - ResourceUtil.copyResourceToFile( - "org/apache/cayenne/tools/velotemplate.vm", - template); - } - - protected CayenneGeneratorTask task; - - @Before - public void setUp() { - - Project project = new Project(); - project.setBaseDir(baseDir); - - task = new CayenneGeneratorTask(); - task.setProject(project); - task.setTaskName("Test"); - task.setLocation(Location.UNKNOWN_LOCATION); - } - - /** - * Test single classes with a non-standard template. - */ - @Test - public void testSingleClassesCustTemplate() throws Exception { - // prepare destination directory - File mapDir = new File(baseDir, "single-classes-custtempl"); - assertTrue(mapDir.mkdirs()); - - // setup task - task.setDestDir(mapDir); - task.setMap(map); - task.setMakepairs(false); - task.setUsepkgpath(true); - task.setTemplate(template.getPath()); - - // run task - task.execute(); - - // check results - File a = new File( - mapDir, - convertPath("org/apache/cayenne/testdo/testmap/Artist.java")); - assertTrue(a.isFile()); - assertContents( - a, - "Artist", - "org.apache.cayenne.testdo.testmap", - "CayenneDataObject"); - - File _a = new File( - mapDir, - convertPath("org/apache/cayenne/testdo/testmap/_Artist.java")); - assertFalse(_a.exists()); - } - - /** Test single classes generation including full package path. */ - @Test - public void testSingleClasses1() throws Exception { - // prepare destination directory - File mapDir = new File(baseDir, "single-classes-tree"); - assertTrue(mapDir.mkdirs()); - - // setup task - task.setDestDir(mapDir); - task.setMap(map); - task.setMakepairs(false); - task.setUsepkgpath(true); - - // run task - task.execute(); - - // check results - File a = new File( - mapDir, - convertPath("org/apache/cayenne/testdo/testmap/Artist.java")); - assertTrue(a.isFile()); - assertContents( - a, - "Artist", - "org.apache.cayenne.testdo.testmap", - "CayenneDataObject"); - - File _a = new File( - mapDir, - convertPath("org/apache/cayenne/testdo/testmap/_Artist.java")); - assertFalse(_a.exists()); - } - - /** Test single classes generation ignoring package path. */ - @Test - public void testSingleClasses2() throws Exception { - // prepare destination directory - File mapDir = new File(baseDir, "single-classes-flat"); - assertTrue(mapDir.mkdirs()); - - // setup task - task.setDestDir(mapDir); - task.setMap(map); - task.setMakepairs(false); - task.setUsepkgpath(false); - - // run task - task.execute(); - - // check results - File a = new File(mapDir, convertPath("Artist.java")); - assertTrue(a.exists()); - assertContents( - a, - "Artist", - "org.apache.cayenne.testdo.testmap", - "CayenneDataObject"); - - File _a = new File(mapDir, convertPath("_Artist.java")); - assertFalse(_a.exists()); - - File pkga = new File( - mapDir, - convertPath("org/apache/cayenne/testdo/testmap/Artist.java")); - assertFalse(pkga.exists()); - } - - /** Test pairs generation including full package path, default superclass package. */ - @Test - public void testPairs1() throws Exception { - // prepare destination directory - File mapDir = new File(baseDir, "pairs-tree"); - assertTrue(mapDir.mkdirs()); - - // setup task - task.setDestDir(mapDir); - task.setMap(map); - task.setMakepairs(true); - task.setUsepkgpath(true); - - // run task - task.execute(); - - // check results - File a = new File( - mapDir, - convertPath("org/apache/cayenne/testdo/testmap/Artist.java")); - assertTrue(a.isFile()); - assertContents(a, "Artist", "org.apache.cayenne.testdo.testmap", "_Artist"); - - File _a = new File( - mapDir, - convertPath("org/apache/cayenne/testdo/testmap/auto/_Artist.java")); - assertTrue(_a.exists()); - assertContents( - _a, - "_Artist", - "org.apache.cayenne.testdo.testmap", - "CayenneDataObject"); - } - - /** Test pairs generation in the same directory. */ - @Test - public void testPairs2() throws Exception { - // prepare destination directory - File mapDir = new File(baseDir, "pairs-flat"); - assertTrue(mapDir.mkdirs()); - - // setup task - task.setDestDir(mapDir); - task.setMap(map); - task.setMakepairs(true); - task.setUsepkgpath(false); - - // run task - task.execute(); - - // check results - File a = new File(mapDir, convertPath("Artist.java")); - assertTrue(a.isFile()); - assertContents(a, "Artist", "org.apache.cayenne.testdo.testmap", "_Artist"); - - File _a = new File(mapDir, convertPath("_Artist.java")); - assertTrue(_a.exists()); - assertContents( - _a, - "_Artist", - "org.apache.cayenne.testdo.testmap", - "CayenneDataObject"); - - File pkga = new File( - mapDir, - convertPath("org/apache/cayenne/testdo/testmap/Artist.java")); - assertFalse(pkga.exists()); - } - - /** - * Test pairs generation including full package path with superclass and subclass in - * different packages. - */ - @Test - public void testPairs3() throws Exception { - // prepare destination directory - File mapDir = new File(baseDir, "pairs-tree-split"); - assertTrue(mapDir.mkdirs()); - - // setup task - task.setDestDir(mapDir); - task.setMap(map); - task.setMakepairs(true); - task.setUsepkgpath(true); - task.setSuperpkg("org.apache.cayenne.testdo.testmap.superart"); - - // run task - task.execute(); - - // check results - File a = new File( - mapDir, - convertPath("org/apache/cayenne/testdo/testmap/Artist.java")); - assertTrue(a.isFile()); - assertContents(a, "Artist", "org.apache.cayenne.testdo.testmap", "_Artist"); - - File _a = new File( - mapDir, - convertPath("org/apache/cayenne/testdo/testmap/superart/_Artist.java")); - assertTrue(_a.exists()); - assertContents( - _a, - "_Artist", - "org.apache.cayenne.testdo.testmap.superart", - "CayenneDataObject"); - } - - @Test - public void testPairsEmbeddable3() throws Exception { - // prepare destination directory - File mapDir = new File(baseDir, "pairs-embeddables3-split"); - assertTrue(mapDir.mkdirs()); - - // setup task - task.setDestDir(mapDir); - task.setMap(mapEmbeddables); - task.setMakepairs(true); - task.setUsepkgpath(true); - task.setSuperpkg("org.apache.cayenne.testdo.embeddable.auto"); - - // run task - task.execute(); - - // check entity results - File a = new File( - mapDir, - convertPath("org/apache/cayenne/testdo/embeddable/EmbedEntity1.java")); - assertTrue(a.isFile()); - assertContents( - a, - "EmbedEntity1", - "org.apache.cayenne.testdo.embeddable", - "_EmbedEntity1"); - - File _a = new File( - mapDir, - convertPath("org/apache/cayenne/testdo/embeddable/auto/_EmbedEntity1.java")); - assertTrue(_a.exists()); - assertContents( - _a, - "_EmbedEntity1", - "org.apache.cayenne.testdo.embeddable.auto", - "CayenneDataObject"); - - // check embeddable results - File e = new File( - mapDir, - convertPath("org/apache/cayenne/testdo/embeddable/Embeddable1.java")); - assertTrue(e.isFile()); - assertContents( - e, - "Embeddable1", - "org.apache.cayenne.testdo.embeddable", - "_Embeddable1"); - - File _e = new File( - mapDir, - convertPath("org/apache/cayenne/testdo/embeddable/auto/_Embeddable1.java")); - assertTrue(_e.exists()); - assertContents( - _e, - "_Embeddable1", - "org.apache.cayenne.testdo.embeddable.auto", - "Object"); - } - - private String convertPath(String unixPath) { - return unixPath.replace('/', File.separatorChar); - } - - private void assertContents( - File f, - String className, - String packageName, - String extendsName) throws Exception { - - BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream( - f))); - - try { - assertPackage(in, packageName); - assertClass(in, className, extendsName); - } - finally { - in.close(); - } - - } - - private void assertPackage(BufferedReader in, String packageName) throws Exception { - - String s = null; - while ((s = in.readLine()) != null) { - if (Pattern.matches("^package\\s+([^\\s;]+);", s)) { - assertTrue(s.indexOf(packageName) > 0); - return; - } - } - - fail("No package declaration found."); - } - - private void assertClass(BufferedReader in, String className, String extendsName) - throws Exception { - - Pattern classPattern = Pattern.compile("^public\\s+"); - - String s = null; - while ((s = in.readLine()) != null) { - if (classPattern.matcher(s).find()) { - assertTrue(s.indexOf(className) > 0); - assertTrue(s.indexOf(extendsName) > 0); - assertTrue(s.indexOf(className) < s.indexOf(extendsName)); - return; - } - } - - fail("No class declaration found."); - } + private static final File baseDir; + private static final File map; + private static final File mapEmbeddables; + private static final File template; + + static { + + baseDir = FileUtil.baseTestDirectory(); + map = new File(baseDir, "antmap.xml"); + mapEmbeddables = new File(baseDir, "antmap-embeddables.xml"); + template = new File(baseDir, "velotemplate.vm"); + + ResourceUtil.copyResourceToFile("testmap.map.xml", map); + ResourceUtil.copyResourceToFile("embeddable.map.xml", mapEmbeddables); + ResourceUtil.copyResourceToFile("org/apache/cayenne/tools/velotemplate.vm", template); + } + + protected CayenneGeneratorTask task; + + @Before + public void setUp() { + + Project project = new Project(); + project.setBaseDir(baseDir); + + task = new CayenneGeneratorTask(); + task.setProject(project); + task.setTaskName("Test"); + task.setLocation(Location.UNKNOWN_LOCATION); + } + + /** + * Test single classes with a non-standard template. + */ + @Test + public void testSingleClassesCustTemplate() throws Exception { + // prepare destination directory + File mapDir = new File(baseDir, "single-classes-custtempl"); + assertTrue(mapDir.mkdirs()); + + // setup task + task.setDestDir(mapDir); + task.setMap(map); + task.setMakepairs(false); + task.setUsepkgpath(true); + task.setTemplate(template.getPath()); + + // run task + task.execute(); + + // check results + File a = new File(mapDir, convertPath("org/apache/cayenne/testdo/testmap/Artist.java")); + assertTrue(a.isFile()); + assertContents(a, "Artist", "org.apache.cayenne.testdo.testmap", "CayenneDataObject"); + + File _a = new File(mapDir, convertPath("org/apache/cayenne/testdo/testmap/_Artist.java")); + assertFalse(_a.exists()); + } + + /** Test single classes generation including full package path. */ + @Test + public void testSingleClasses1() throws Exception { + // prepare destination directory + File mapDir = new File(baseDir, "single-classes-tree"); + assertTrue(mapDir.mkdirs()); + + // setup task + task.setDestDir(mapDir); + task.setMap(map); + task.setMakepairs(false); + task.setUsepkgpath(true); + + // run task + task.execute(); + + // check results + File a = new File(mapDir, convertPath("org/apache/cayenne/testdo/testmap/Artist.java")); + assertTrue(a.isFile()); + assertContents(a, "Artist", "org.apache.cayenne.testdo.testmap", "CayenneDataObject"); + + File _a = new File(mapDir, convertPath("org/apache/cayenne/testdo/testmap/_Artist.java")); + assertFalse(_a.exists()); + } + + /** Test single classes generation ignoring package path. */ + @Test + public void testSingleClasses2() throws Exception { + // prepare destination directory + File mapDir = new File(baseDir, "single-classes-flat"); + assertTrue(mapDir.mkdirs()); + + // setup task + task.setDestDir(mapDir); + task.setMap(map); + task.setMakepairs(false); + task.setUsepkgpath(false); + + // run task + task.execute(); + + // check results + File a = new File(mapDir, convertPath("Artist.java")); + assertTrue(a.exists()); + assertContents(a, "Artist", "org.apache.cayenne.testdo.testmap", "CayenneDataObject"); + + File _a = new File(mapDir, convertPath("_Artist.java")); + assertFalse(_a.exists()); + + File pkga = new File(mapDir, convertPath("org/apache/cayenne/testdo/testmap/Artist.java")); + assertFalse(pkga.exists()); + } + + /** + * Test pairs generation including full package path, default superclass + * package. + */ + @Test + public void testPairs1() throws Exception { + // prepare destination directory + File mapDir = new File(baseDir, "pairs-tree"); + assertTrue(mapDir.mkdirs()); + + // setup task + task.setDestDir(mapDir); + task.setMap(map); + task.setMakepairs(true); + task.setUsepkgpath(true); + + // run task + task.execute(); + + // check results + File a = new File(mapDir, convertPath("org/apache/cayenne/testdo/testmap/Artist.java")); + assertTrue(a.isFile()); + assertContents(a, "Artist", "org.apache.cayenne.testdo.testmap", "_Artist"); + + File _a = new File(mapDir, convertPath("org/apache/cayenne/testdo/testmap/auto/_Artist.java")); + assertTrue(_a.exists()); + assertContents(_a, "_Artist", "org.apache.cayenne.testdo.testmap", "CayenneDataObject"); + } + + /** Test pairs generation in the same directory. */ + @Test + public void testPairs2() throws Exception { + // prepare destination directory + File mapDir = new File(baseDir, "pairs-flat"); + assertTrue(mapDir.mkdirs()); + + // setup task + task.setDestDir(mapDir); + task.setMap(map); + task.setMakepairs(true); + task.setUsepkgpath(false); + + // run task + task.execute(); + + // check results + File a = new File(mapDir, convertPath("Artist.java")); + assertTrue(a.isFile()); + assertContents(a, "Artist", "org.apache.cayenne.testdo.testmap", "_Artist"); + + File _a = new File(mapDir, convertPath("_Artist.java")); + assertTrue(_a.exists()); + assertContents(_a, "_Artist", "org.apache.cayenne.testdo.testmap", "CayenneDataObject"); + + File pkga = new File(mapDir, convertPath("org/apache/cayenne/testdo/testmap/Artist.java")); + assertFalse(pkga.exists()); + } + + /** + * Test pairs generation including full package path with superclass and + * subclass in different packages. + */ + @Test + public void testPairs3() throws Exception { + // prepare destination directory + File mapDir = new File(baseDir, "pairs-tree-split"); + assertTrue(mapDir.mkdirs()); + + // setup task + task.setDestDir(mapDir); + task.setMap(map); + task.setMakepairs(true); + task.setUsepkgpath(true); + task.setSuperpkg("org.apache.cayenne.testdo.testmap.superart"); + + // run task + task.execute(); + + // check results + File a = new File(mapDir, convertPath("org/apache/cayenne/testdo/testmap/Artist.java")); + assertTrue(a.isFile()); + assertContents(a, "Artist", "org.apache.cayenne.testdo.testmap", "_Artist"); + + File _a = new File(mapDir, convertPath("org/apache/cayenne/testdo/testmap/superart/_Artist.java")); + assertTrue(_a.exists()); + assertContents(_a, "_Artist", "org.apache.cayenne.testdo.testmap.superart", "CayenneDataObject"); + } + + @Test + public void testPairsEmbeddable3() throws Exception { + // prepare destination directory + File mapDir = new File(baseDir, "pairs-embeddables3-split"); + assertTrue(mapDir.mkdirs()); + + // setup task + task.setDestDir(mapDir); + task.setMap(mapEmbeddables); + task.setMakepairs(true); + task.setUsepkgpath(true); + task.setSuperpkg("org.apache.cayenne.testdo.embeddable.auto"); + + // run task + task.execute(); + + // check entity results + File a = new File(mapDir, convertPath("org/apache/cayenne/testdo/embeddable/EmbedEntity1.java")); + assertTrue(a.isFile()); + assertContents(a, "EmbedEntity1", "org.apache.cayenne.testdo.embeddable", "_EmbedEntity1"); + + File _a = new File(mapDir, convertPath("org/apache/cayenne/testdo/embeddable/auto/_EmbedEntity1.java")); + assertTrue(_a.exists()); + assertContents(_a, "_EmbedEntity1", "org.apache.cayenne.testdo.embeddable.auto", "CayenneDataObject"); + + // check embeddable results + File e = new File(mapDir, convertPath("org/apache/cayenne/testdo/embeddable/Embeddable1.java")); + assertTrue(e.isFile()); + assertContents(e, "Embeddable1", "org.apache.cayenne.testdo.embeddable", "_Embeddable1"); + + File _e = new File(mapDir, convertPath("org/apache/cayenne/testdo/embeddable/auto/_Embeddable1.java")); + assertTrue(_e.exists()); + assertContents(_e, "_Embeddable1", "org.apache.cayenne.testdo.embeddable.auto", "Object"); + } + + private String convertPath(String unixPath) { + return unixPath.replace('/', File.separatorChar); + } + + private void assertContents(File f, String className, String packageName, String extendsName) throws Exception { + + try (BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(f)));) { + assertPackage(in, packageName); + assertClass(in, className, extendsName); + } + } + + private void assertPackage(BufferedReader in, String packageName) throws Exception { + + String s = null; + while ((s = in.readLine()) != null) { + if (Pattern.matches("^package\\s+([^\\s;]+);", s)) { + assertTrue(s.indexOf(packageName) > 0); + return; + } + } + + fail("No package declaration found."); + } + + private void assertClass(BufferedReader in, String className, String extendsName) throws Exception { + + Pattern classPattern = Pattern.compile("^public\\s+"); + + String s = null; + while ((s = in.readLine()) != null) { + if (classPattern.matcher(s).find()) { + assertTrue(s.indexOf(className) > 0); + assertTrue(s.indexOf(extendsName) > 0); + assertTrue(s.indexOf(className) < s.indexOf(extendsName)); + return; + } + } + + fail("No class declaration found."); + } } http://git-wip-us.apache.org/repos/asf/cayenne/blob/26d8434d/cayenne-tools/src/test/java/org/apache/cayenne/tools/DbImporterTaskTest.java ---------------------------------------------------------------------- diff --git a/cayenne-tools/src/test/java/org/apache/cayenne/tools/DbImporterTaskTest.java b/cayenne-tools/src/test/java/org/apache/cayenne/tools/DbImporterTaskTest.java index ce44aa7..075d88d 100644 --- a/cayenne-tools/src/test/java/org/apache/cayenne/tools/DbImporterTaskTest.java +++ b/cayenne-tools/src/test/java/org/apache/cayenne/tools/DbImporterTaskTest.java @@ -88,10 +88,10 @@ public class DbImporterTaskTest { assertSkipRelationshipsLoading(getCdbImport("build-skip-relationships-loading.xml").getReverseEngineering()); } - @Test - public void testTableTypes() throws Exception { - assertTableTypes(getCdbImport("build-table-types.xml").getReverseEngineering()); - } + @Test + public void testTableTypes() throws Exception { + assertTableTypes(getCdbImport("build-table-types.xml").getReverseEngineering()); + } @Test public void testIncludeTable() throws Exception { @@ -190,14 +190,13 @@ public class DbImporterTaskTest { DetailedDiff diff = new DetailedDiff(new Diff(control, test)); if (!diff.similar()) { - for (Difference d : ((List<Difference>) diff.getAllDifferences())) { + for (Difference d : ((List<Difference>) diff.getAllDifferences())) { - - System.out.println("-------------------------------------------"); - System.out.println(d.getTestNodeDetail().getNode()); - System.out.println(d.getControlNodeDetail().getValue()); - } - fail(diff.toString()); + System.out.println("-------------------------------------------"); + System.out.println(d.getTestNodeDetail().getNode()); + System.out.println(d.getControlNodeDetail().getValue()); + } + fail(diff.toString()); } } catch (SAXException e) { @@ -216,16 +215,13 @@ public class DbImporterTaskTest { Class.forName(dbImportConfiguration.getDriver()).newInstance(); - Connection c = DriverManager.getConnection(dbImportConfiguration.getUrl()); - try { - - Statement stmt = c.createStatement(); + try (Connection c = DriverManager.getConnection(dbImportConfiguration.getUrl());) { // TODO: move parsing SQL files to a common utility (DBHelper?) . // ALso see UnitDbApater.executeDDL - this should use the same // utility - try { + try (Statement stmt = c.createStatement();) { for (String sql : SQLReader.statements(sqlUrl, ";")) { // skip comments @@ -235,11 +231,7 @@ public class DbImporterTaskTest { stmt.execute(sql); } - } finally { - stmt.close(); } - } finally { - c.close(); } }
