diff options
Diffstat (limited to 'jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/jpa2/GenericPersistentTypeMetamodelSynchronizer.java')
-rw-r--r-- | jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/jpa2/GenericPersistentTypeMetamodelSynchronizer.java | 604 |
1 files changed, 0 insertions, 604 deletions
diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/jpa2/GenericPersistentTypeMetamodelSynchronizer.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/jpa2/GenericPersistentTypeMetamodelSynchronizer.java deleted file mode 100644 index 6e6108c88a..0000000000 --- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/jpa2/GenericPersistentTypeMetamodelSynchronizer.java +++ /dev/null @@ -1,604 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2010 Oracle. All rights reserved. - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0, which accompanies this distribution - * and is available at http://www.eclipse.org/legal/epl-v10.html. - * - * Contributors: - * Oracle - initial API and implementation - ******************************************************************************/ -package org.eclipse.jpt.core.internal.jpa2; - -import java.io.PrintWriter; -import java.io.Serializable; -import java.io.StringWriter; -import java.util.Comparator; -import java.util.Date; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.TreeSet; -import java.util.Map.Entry; - -import org.eclipse.core.resources.IFile; -import org.eclipse.jdt.core.ICompilationUnit; -import org.eclipse.jdt.core.IPackageFragment; -import org.eclipse.jdt.core.IPackageFragmentRoot; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jpt.core.JptCorePlugin; -import org.eclipse.jpt.core.context.AttributeMapping; -import org.eclipse.jpt.core.context.PersistentAttribute; -import org.eclipse.jpt.core.context.PersistentType; -import org.eclipse.jpt.core.jpa2.JpaProject2_0; -import org.eclipse.jpt.core.jpa2.context.AttributeMapping2_0; -import org.eclipse.jpt.core.jpa2.context.MetamodelField; -import org.eclipse.jpt.core.jpa2.context.PersistentType2_0; -import org.eclipse.jpt.core.jpa2.resource.java.JPA2_0; -import org.eclipse.jpt.core.jpa2.resource.java.JavaResourcePersistentType2_0; -import org.eclipse.jpt.utility.Filter; -import org.eclipse.jpt.utility.internal.ClassName; -import org.eclipse.jpt.utility.internal.CollectionTools; -import org.eclipse.jpt.utility.internal.IndentingPrintWriter; -import org.eclipse.jpt.utility.internal.StringTools; -import org.eclipse.jpt.utility.internal.Transformer; -import org.eclipse.jpt.utility.internal.iterables.FilteringIterable; -import org.eclipse.jpt.utility.internal.iterables.TransformationIterable; - -import com.ibm.icu.text.Collator; -import com.ibm.icu.text.DateFormat; -import com.ibm.icu.text.SimpleDateFormat; - -/** - * For now, the "synchronization" is simple brute-force: we generate the source - * code and then compare it with what is already present in the file. - * If the new source is different, we replace the file contents; otherwise, we - * leave the file unchanged. - */ -@SuppressWarnings("nls") -public class GenericPersistentTypeMetamodelSynchronizer - implements PersistentType2_0.MetamodelSynchronizer -{ - protected final PersistentType2_0 persistentType; - - - public GenericPersistentTypeMetamodelSynchronizer(PersistentType2_0 persistentType) { - super(); - this.persistentType = persistentType; - } - - public IFile getFile() { - return (IFile) this.getPackageFragment().getCompilationUnit(this.getFileName()).getResource(); - } - - - // ********** synchronize ********** - - public void synchronize() { - try { - this.synchronize_(); - } catch (JavaModelException ex) { - JptCorePlugin.log(ex); - } - } - - protected void synchronize_() throws JavaModelException { - IPackageFragment pkg = this.getPackageFragment(); - String fileName = this.getFileName(); - - ICompilationUnit compilationUnit = pkg.getCompilationUnit(fileName); - if (compilationUnit.exists()) { - // overwrite existing file if it has changed (ignoring the timestamp) - String newSource = this.buildSource(compilationUnit); - if (newSource != null) { - pkg.createCompilationUnit(fileName, newSource, true, null); // true=force - } - } else { - // write a new file, creating the package folders if necessary - if ( ! pkg.exists()) { - this.getSourceFolder().createPackageFragment(pkg.getElementName(), true, null); // true=force - } - pkg.createCompilationUnit(fileName, this.buildSource(), false, null); // false=no force - } - } - - /** - * pre-condition: the compilation unit exists - * - * return null if the old source is not to be replaced - */ - protected String buildSource(ICompilationUnit compilationUnit) throws JavaModelException { - IFile file = (IFile) compilationUnit.getResource(); - JavaResourcePersistentType2_0 genType = this.getJpaProject().getGeneratedMetamodelType(file); - if (genType == null) { - return null; // the file exists, but its source is not a generated metamodel class - } - - String oldSource = compilationUnit.getSource(); - int oldLength = oldSource.length(); - - String newSource = this.buildSource(); - int newLength = newSource.length(); - if (newLength != oldLength) { - return newSource; - } - - String date = genType.getGeneratedAnnotation().getDate(); // if we get here, this will be non-empty - int dateBegin = oldSource.indexOf(date); - if (dateBegin == -1) { - return null; // hmmm... - } - int dateEnd = dateBegin + date.length(); - if (dateEnd > oldLength) { - return null; // hmmm... - } - - if (newSource.regionMatches(0, oldSource, 0, dateBegin) && - newSource.regionMatches(dateEnd, oldSource, dateEnd, oldLength - dateEnd)) { - return null; - } - return newSource; - } - - - // ********** package/file ********** - - protected IPackageFragment getPackageFragment() { - return this.getSourceFolder().getPackageFragment(this.getPackageName()); - } - - protected IPackageFragmentRoot getSourceFolder() { - return this.getJpaProject().getMetamodelPackageFragmentRoot(); - } - - protected JpaProject2_0 getJpaProject() { - return (JpaProject2_0) this.persistentType.getJpaProject(); - } - - // TODO - protected String getPackageName() { - // the default is to store the metamodel in the same package as the model - return ClassName.getPackageName(this.getMetamodelClassName()); - } - - protected String getFileName() { - return ClassName.getSimpleName(this.getMetamodelClassName()) + ".java"; - } - - protected String getMetamodelClassName() { - return this.buildMetamodelClassName(this.persistentType.getName()); - } - - // TODO - protected String buildMetamodelClassName(String className) { - // the default is to simply append an underscore to the model class name - return className + '_'; - } - - - // ********** source code ********** - - /** - * build the "body" source first; then build the "package" and "imports" source - * and concatenate the "body" source to it - */ - protected String buildSource() { - // build the body source first so we can gather up the import statements - BodySourceWriter bodySourceWriter = this.buildBodySourceWriter(); - - StringWriter sw = new StringWriter(bodySourceWriter.getLength() + 2000); - PrintWriter pw = new PrintWriter(sw); - this.printPackageAndImportsOn(pw, bodySourceWriter); - pw.print(bodySourceWriter.getSource()); - return sw.toString(); - } - - protected BodySourceWriter buildBodySourceWriter() { - BodySourceWriter pw = new BodySourceWriter(this.getPackageName(), this.getMetamodelClassName()); - this.printBodySourceOn(pw); - return pw; - } - - protected void printBodySourceOn(BodySourceWriter pw) { - this.printClassDeclarationOn(pw); - pw.print(" {"); - pw.println(); - - pw.indent(); - this.printAttributesOn(pw); - pw.undent(); - - pw.print('}'); - pw.println(); // EOF - } - - - // ********** class declaration ********** - - protected void printClassDeclarationOn(BodySourceWriter pw) { - this.printGeneratedAnnotationOn(pw); - this.printStaticMetamodelAnnotationOn(pw); - - pw.print("public class "); - pw.printTypeDeclaration(this.getMetamodelClassName()); - PersistentType superPersistentType = this.persistentType.getSuperPersistentType(); - if (superPersistentType != null) { - pw.print(" extends "); - pw.printTypeDeclaration(this.buildMetamodelClassName(superPersistentType.getName())); - } - } - - protected void printStaticMetamodelAnnotationOn(BodySourceWriter pw) { - pw.printAnnotation(JPA2_0.STATIC_METAMODEL); - pw.print('('); - pw.printTypeDeclaration(this.persistentType.getName()); - pw.print(".class"); - pw.print(')'); - pw.println(); - } - - protected void printGeneratedAnnotationOn(BodySourceWriter pw) { - pw.printAnnotation("javax.annotation.Generated"); - pw.print('('); - pw.print("value="); - pw.printStringLiteral(JavaResourcePersistentType2_0.METAMODEL_GENERATED_ANNOTATION_VALUE); - pw.print(", "); - pw.print("date="); - pw.printStringLiteral(format(new Date())); - pw.print(')'); - pw.println(); - } - - /** - * {@link SimpleDateFormat} is not thread-safe. - */ - protected static synchronized String format(Date date) { - return DATE_FORMAT.format(date); - } - /** - * Recommended date format is ISO 8601. - * @see javax.annotation.Generated - */ - private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); - - - // ********** attributes ********** - - protected void printAttributesOn(BodySourceWriter pw) { - for (Iterator<PersistentAttribute> stream = this.persistentType.attributes(); stream.hasNext(); ) { - this.printAttributeOn(stream.next(), pw); - } - } - - protected void printAttributeOn(PersistentAttribute persistentAttribute, BodySourceWriter pw) { - AttributeMapping attributeMapping = persistentAttribute.getMapping(); - if (attributeMapping != null) { // probably shouldn't be null? - this.printAttributeMappingOn(attributeMapping, pw); - } - } - - protected void printAttributeMappingOn(AttributeMapping attributeMapping, BodySourceWriter pw) { - MetamodelField field = ((AttributeMapping2_0) attributeMapping).getMetamodelField(); - if (field != null) { - this.printFieldOn(field, pw); - } - } - - protected void printFieldOn(MetamodelField field, BodySourceWriter pw) { - for (String modifier : field.getModifiers()) { - pw.print(modifier); - pw.print(' '); - } - pw.printTypeDeclaration(field.getTypeName()); - pw.print('<'); - for (Iterator<String> stream = field.getTypeArgumentNames().iterator(); stream.hasNext(); ) { - pw.printTypeDeclaration(stream.next()); - if (stream.hasNext()) { - pw.print(", "); - } - } - pw.print('>'); - pw.print(' '); - pw.print(field.getName()); - pw.print(';'); - pw.println(); - } - - - // ********** package and imports ********** - - protected void printPackageAndImportsOn(PrintWriter pw, BodySourceWriter bodySourceWriter) { - if (this.getPackageName().length() != 0) { - pw.print("package "); - pw.print(this.getPackageName()); - pw.print(';'); - pw.println(); - pw.println(); - } - - for (String import_ : bodySourceWriter.getImports()) { - pw.print("import "); - pw.print(import_); - pw.print(';'); - pw.println(); - } - pw.println(); - } - - - // ********** source writer ********** - - /** - * Extend IndentingPrintWriter with some methods that facilitate building - * class source code. - */ - protected static class BodySourceWriter - extends IndentingPrintWriter - { - protected final String packageName; - protected final String className; - // key = short class name; value = import package - protected final HashMap<String, ImportPackage> imports = new HashMap<String, ImportPackage>(); - - protected BodySourceWriter(String packageName, String className) { - super(new StringWriter(2000)); - this.packageName = packageName; - this.className = className; - } - - protected String getSource() { - return this.out.toString(); - } - - protected int getLength() { - return ((StringWriter) this.out).getBuffer().length(); - } - - protected void printVisibility(String visibilityModifier) { - if (visibilityModifier.length() != 0) { - this.print(visibilityModifier); - this.print(' '); - } - } - - protected void printAnnotation(String annotationName) { - this.print('@'); - this.printTypeDeclaration(annotationName); - } - - protected void printTypeDeclaration(String typeDeclaration) { - this.print(this.buildImportedTypeDeclaration(typeDeclaration)); - } - - protected void printField(String fieldName, String typeDeclaration, String visibility) { - this.printVisibility(visibility); - this.printTypeDeclaration(typeDeclaration); - this.print(' '); - this.print(fieldName); - this.print(';'); - this.println(); - this.println(); - } - - protected void printParameterizedField(String fieldName, String typeDeclaration, String parameterTypeDeclaration, String visibility) { - this.printVisibility(visibility); - this.printTypeDeclaration(typeDeclaration); - this.print('<'); - this.printTypeDeclaration(parameterTypeDeclaration); - this.print('>'); - this.print(' '); - this.print(fieldName); - this.print(';'); - this.println(); - this.println(); - } - - /** - * Convert the specified string to a String Literal and print it, - * adding the surrounding double-quotes and escaping characters - * as necessary. - */ - void printStringLiteral(String string) { - StringTools.convertToJavaStringLiteralOn(string, this); - } - - - // ********** imports ********** - - // ***** writing - /** - * Return the specified class's "imported" name. - * The class declaration must be of the form: - * "int" - * "int[]" (not "[I") - * "java.lang.Object" - * "java.lang.Object[]" (not "[Ljava.lang.Object;") - * "java.util.Map.Entry" (not "java.util.Map$Entry") - * "java.util.Map.Entry[][]" (not "[[Ljava.util.Map$Entry;") - * - * To really do this right, we would need to gather all the types from - * the "unamed" (default) package that were referenced in the - * compilation unit beforehand. *Any* collisions with one of these - * types would have to be fully qualified (whether it was from - * 'java.lang' or the same package as the current compilation unit). - * In other words, if we have any types from the "unnamed" package, - * results are unpredictable.... - */ - protected String buildImportedTypeDeclaration(String typeDeclaration) { - if (this.typeDeclarationIsMemberClass(typeDeclaration)) { - // no need for an import, just return the partially-qualified name - return this.buildMemberClassTypeDeclaration(typeDeclaration); - } - int last = typeDeclaration.lastIndexOf('.'); - String currentPackageName = (last == -1) ? "" : typeDeclaration.substring(0, last); - String shortTypeDeclaration = typeDeclaration.substring(last + 1); - String shortElementTypeName = shortTypeDeclaration; - while (shortElementTypeName.endsWith("[]")) { - shortElementTypeName = shortElementTypeName.substring(0, shortElementTypeName.length() - 2); - } - ImportPackage prev = this.imports.get(shortElementTypeName); - if (prev == null) { - // this is the first class with this short element type name - this.imports.put(shortElementTypeName, new ImportPackage(currentPackageName)); - return shortTypeDeclaration; - } - if (prev.packageName.equals(currentPackageName)) { - // this element type has already been imported - return shortTypeDeclaration; - } - if (currentPackageName.equals(this.packageName) && - prev.packageName.equals("java.lang")) { - // we force the 'java.lang' class to be explicitly imported - prev.collision = true; - } - // another class with the same short element type name has been - // previously imported, so this one must be used fully-qualified - return typeDeclaration; - } - - /** - * e.g. "foo.bar.Employee.PK" will return true - */ - protected boolean typeDeclarationIsMemberClass(String typeDeclaration) { - return (typeDeclaration.length() > this.className.length()) - && typeDeclaration.startsWith(this.className) - && (typeDeclaration.charAt(this.className.length()) == '.'); - } - - /** - * e.g. "foo.bar.Employee.PK" will return "Employee.PK" - * this prevents collisions with other imported classes (e.g. "joo.jar.PK") - */ - protected String buildMemberClassTypeDeclaration(String typeDeclaration) { - int index = this.packageName.length(); - if (index != 0) { - index++; // bump past the '.' - } - return typeDeclaration.substring(index); - } - - // ***** reading - protected Iterable<String> getImports() { - return this.getSortedRequiredImports(); - } - - /** - * transform our map entries to class names - */ - protected Iterable<String> getSortedRequiredImports() { - return new TransformationIterable<Map.Entry<String, ImportPackage>, String>(this.getSortedRequiredImportEntries(), this.buildImportEntriesTransformer()); - } - - protected Transformer<Map.Entry<String, ImportPackage>, String> buildImportEntriesTransformer() { - return IMPORT_ENTRIES_TRANSFORMER; - } - - protected static final Transformer<Map.Entry<String, ImportPackage>, String> IMPORT_ENTRIES_TRANSFORMER = new ImportEntriesTransformer(); - - protected static class ImportEntriesTransformer - implements Transformer<Map.Entry<String, ImportPackage>, String> - { - public String transform(Entry<String, ImportPackage> importEntry) { - String pkg = importEntry.getValue().packageName; - String type = importEntry.getKey(); - StringBuilder sb = new StringBuilder(pkg.length() + 1 + type.length()); - sb.append(pkg); - sb.append('.'); - sb.append(type); - return sb.toString(); - } - } - - /** - * sort by package first, then class (*not* by fully-qualified class name) - */ - protected Iterable<Map.Entry<String, ImportPackage>> getSortedRequiredImportEntries() { - TreeSet<Map.Entry<String, ImportPackage>> sortedEntries = new TreeSet<Map.Entry<String, ImportPackage>>(this.buildImportEntriesComparator()); - CollectionTools.addAll(sortedEntries, this.getRequiredImportEntries()); - return sortedEntries; - } - - protected Comparator<Map.Entry<String, ImportPackage>> buildImportEntriesComparator() { - return IMPORT_ENTRIES_COMPARATOR; - } - - protected static final Comparator<Map.Entry<String, ImportPackage>> IMPORT_ENTRIES_COMPARATOR = new ImportEntriesComparator(); - - protected static class ImportEntriesComparator - implements Comparator<Map.Entry<String, ImportPackage>>, Serializable - { - public int compare(Map.Entry<String, ImportPackage> e1, Map.Entry<String, ImportPackage> e2) { - Collator collator = Collator.getInstance(); - int pkg = collator.compare(e1.getValue().packageName, e2.getValue().packageName); - return (pkg == 0) ? collator.compare(e1.getKey(), e2.getKey()) : pkg; - } - } - - /** - * strip off any non-required imports (e.g. "java.lang.Object') - */ - protected Iterable<Map.Entry<String, ImportPackage>> getRequiredImportEntries() { - return new FilteringIterable<Map.Entry<String, ImportPackage>>(this.imports.entrySet(), this.buildRequiredImportEntriesFilter()); - } - - protected Filter<Map.Entry<String, ImportPackage>> buildRequiredImportEntriesFilter() { - return new RequiredImportEntriesFilter(); - } - - protected class RequiredImportEntriesFilter - implements Filter<Map.Entry<String, ImportPackage>> - { - public boolean accept(Map.Entry<String, ImportPackage> importEntry) { - return this.packageMustBeImported(importEntry.getValue()); - } - - protected boolean packageMustBeImported(ImportPackage importPackage) { - String pkg = importPackage.packageName; - if (pkg.equals("")) { - // cannot import a type from the "unnamed" package - return false; - } - if (pkg.equals("java.lang")) { - // we must import from 'java.lang' if we also have a class in the same package - return importPackage.collision; - } - if (pkg.equals(BodySourceWriter.this.packageName)) { - // we never need to import a class from the same package - return false; - } - return true; - } - } - - /** - * We need a 'collision' flag for when we encounter a class from - * 'java.lang' followed by a class from the current compilation unit's - * package. We will need to include the explicit import of the - * 'java.lang' class and all the references to the other class will - * have to be fully-qualified. - * - * If the classes are encountered in the opposite order (i.e. the class - * from the current compilation unit's package followed by the class - * from 'java.lang'), we do *not* need to import the first class while - * all the references to the 'java.lang' class will be fully-qualified. - * - * Unfortunately, we still have a problem: if we reference a class from - * 'java.lang' and there is a conflicting class from the current - * compilation unit's package (but that class is *not* revealed to us - * here), the simple name will be resolved to the non-'java.lang' class. - * Unless we simply force an import of *all* 'java.lang' classes.... :-( - * - * This shouldn't happen very often. :-) - */ - protected static class ImportPackage { - protected final String packageName; - protected boolean collision = false; - - protected ImportPackage(String packageName) { - super(); - this.packageName = packageName; - } - } - - } - -} |