openjpa-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ppod...@apache.org
Subject svn commit: r762968 - in /openjpa/trunk: openjpa-all/ openjpa-persistence/src/main/java/org/apache/openjpa/persistence/meta/ openjpa-persistence/src/main/java/org/apache/openjpa/persistence/util/ openjpa-persistence/src/main/resources/META-INF/services...
Date Tue, 07 Apr 2009 21:14:41 GMT
Author: ppoddar
Date: Tue Apr  7 21:14:40 2009
New Revision: 762968

URL: http://svn.apache.org/viewvc?rev=762968&view=rev
Log:
OPENJPA-1010: Canonical Metamodel Generator from annotated source code that hooks into JDK6 Annotation Processing facility.

Added:
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/meta/
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/meta/AnnotationProcessor6.java   (with props)
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/util/
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/util/SourceCode.java   (with props)
    openjpa/trunk/openjpa-persistence/src/main/resources/META-INF/services/javax.annotation.processing.Processor.hidden
    openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/meta/
    openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/meta/localizer.properties   (with props)
Modified:
    openjpa/trunk/openjpa-all/pom.xml

Modified: openjpa/trunk/openjpa-all/pom.xml
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-all/pom.xml?rev=762968&r1=762967&r2=762968&view=diff
==============================================================================
--- openjpa/trunk/openjpa-all/pom.xml (original)
+++ openjpa/trunk/openjpa-all/pom.xml Tue Apr  7 21:14:40 2009
@@ -76,6 +76,13 @@
                                 <aggregate-file servicename="org.apache.openjpa.lib.conf.ProductDerivation" />
                                 <aggregate-file servicename="javax.persistence.spi.PersistenceProvider" />
                                 <aggregate-file servicename="org.apache.openjpa.kernel.exps.ExpressionParser" />
+                                
+                                <!-- this services file is hidden because otherwise source compilation -->
+                                <!-- sees it and tries to invoke our AnnotationProcessor which itself  -->
+                                <!-- is yet to be compiled!                                            -->
+                                <copy file="${basedir}/../openjpa-persistence/src/main/resources/META-INF/services/javax.annotation.processing.Processor.hidden" 
+                                      tofile="${basedir}/target/classes/META-INF/services/javax.annotation.processing.Processor"/>
+                                
                             </tasks>
                         </configuration>
                         <goals>

Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/meta/AnnotationProcessor6.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/meta/AnnotationProcessor6.java?rev=762968&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/meta/AnnotationProcessor6.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/meta/AnnotationProcessor6.java Tue Apr  7 21:14:40 2009
@@ -0,0 +1,794 @@
+package org.apache.openjpa.persistence.meta;
+
+import static javax.lang.model.SourceVersion.RELEASE_6;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Generated;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.Filer;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.annotation.processing.SupportedOptions;
+import javax.annotation.processing.SupportedSourceVersion;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.PrimitiveType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+import javax.persistence.Access;
+import javax.persistence.AccessType;
+import javax.persistence.Transient;
+import javax.persistence.metamodel.TypesafeMetamodel;
+import javax.tools.Diagnostic;
+import javax.tools.JavaFileObject;
+
+import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.persistence.util.SourceCode;
+import org.apache.openjpa.util.UserException;
+
+/**
+ * Annotation processing tool to generate/instantiate a meta-model given the
+ * annotated source code of persistent domain model.
+ * <p>
+ * This tool is invoked as part of compilation phase for JDK6 compiler provided
+ * OpenJPA and JPA class libraries are specified in the compiler 
+ * <code>-processorpath</code> option. <br>
+ * For example<br>
+ * <code>$ javac -processorpath path/to/openjpa.jar;/path/to/jpa.jar 
+ * src/mypackage/MyClass.java</code>
+ * <br> 
+ * will generate source code for canonical meta-model for 
+ * <code>mypackage.MyClass</code> (if it is annotated with persistence 
+ * annotation <code>Entity or Embedded or MappedSuperclass</code>) to produce a 
+ * file <code>mypackage/MyClass_.java</code>.
+ * <p>
+ * The generated source code is written relative to the source path root which
+ * is, by default, the current directory or as specified by -s option to 
+ * <code>javac</code> compiler. 
+ * 
+ * @author Pinaki Poddar
+ * 
+ * @since 2.0.0
+ * 
+ */
+@SupportedAnnotationTypes({ 
+    "javax.persistence.Entity",
+    "javax.persistence.Embeddable", 
+    "javax.persistence.MappedSuperclass" })
+@SupportedOptions( { "log" })
+@SupportedSourceVersion(RELEASE_6)
+
+public class AnnotationProcessor6 extends AbstractProcessor {
+    private static final String UNDERSCORE = "_";
+
+
+    /**
+     * Set of Inclusion Filters based on member type, access type or transient
+     * annotations. Used to determine the subset of available field/method that 
+     * are persistent.   
+     */
+    static InclusiveFilter propertyAccessFilter =
+        new AccessFilter(AccessType.PROPERTY);
+    static InclusiveFilter fieldAccessFilter = 
+        new AccessFilter(AccessType.FIELD);
+    
+    static InclusiveFilter fieldFilter = new KindFilter(ElementKind.FIELD);
+    static InclusiveFilter methodFilter = new KindFilter(ElementKind.METHOD);
+    
+    static InclusiveFilter getterFilter = new GetterFilter();
+    static InclusiveFilter setterFilter = new SetterFilter();
+    
+    static InclusiveFilter nonTransientFilter = new NonTransientMemberFilter();
+
+    private static Localizer _loc =
+        Localizer.forPackage(AnnotationProcessor6.class);
+
+    /**
+     * Category of members as per JPA 2.0 type system.
+     * 
+     */
+    private static enum TypeCategory {
+        ATTRIBUTE("javax.persistence.metamodel.Attribute"), 
+        COLLECTION("javax.persistence.metamodel.Collection"), 
+        SET("javax.persistence.metamodel.Set"), 
+        LIST("javax.persistence.metamodel.List"), 
+        MAP("javax.persistence.metamodel.Map");
+
+        private String type;
+
+        private TypeCategory(String type) {
+            this.type = type;
+        }
+
+        public String getMetaModelType() {
+            return type;
+        }
+        
+    }
+    
+    /**
+     * Enumerates available java.util.* collection classes to categorize them
+     * into corresponding JPA meta-model member type.
+     */
+    private static List<String> CLASSNAMES_LIST = Arrays.asList(
+        new String[]{
+        "java.util.List", "java.util.AbstractList", 
+        "java.util.AbstractSequentialList", "java.util.ArrayList", 
+        "java.util.Stack", "java.util.Vector"});
+    private static List<String> CLASSNAMES_SET = Arrays.asList(
+        new String[]{
+        "java.util.Set", "java.util.AbstractSet", "java.util.EnumSet", 
+        "java.util.HashSet", "java.util.LinkedList", "java.util.LinkedHashSet", 
+        "java.util.SortedSet", "java.util.TreeSet"});
+    private static List<String> CLASSNAMES_MAP = Arrays.asList(
+        new String[]{
+        "java.util.Map", "java.util.AbstractMap", "java.util.EnumMap", 
+        "java.util.HashMap",  "java.util.Hashtable", 
+        "java.util.IdentityHashMap",  "java.util.LinkedHashMap", 
+        "java.util.Properties", "java.util.SortedMap", 
+        "java.util.TreeMap"});
+    private static List<String> CLASSNAMES_COLLECTION = Arrays.asList(
+        new String[]{
+        "java.util.Collection", "java.util.AbstractCollection", 
+        "java.util.AbstractQueue", "java.util.Queue", 
+        "java.util.PriorityQueue"});
+    
+    /**
+     * Gets the fully-qualified name of member class in JPA 2.0 type system,
+     * given the fully-qualified name of a Java class.
+     *  
+     */
+    private TypeCategory toMetaModelTypeCategory(String name) {
+        if (CLASSNAMES_COLLECTION.contains(name))
+            return TypeCategory.COLLECTION;
+        if (CLASSNAMES_LIST.contains(name))
+            return TypeCategory.LIST;
+        if (CLASSNAMES_SET.contains(name))
+            return TypeCategory.SET;
+        if (CLASSNAMES_MAP.contains(name))
+            return TypeCategory.MAP;
+        return TypeCategory.ATTRIBUTE;
+    }
+    
+    /**
+     * Initialization.
+     */
+    @Override
+    public synchronized void init(ProcessingEnvironment processingEnv) {
+        super.init(processingEnv);
+        processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, 
+            _loc.get("mmg-tool-banner").getMessage());
+        System.err.println(processingEnv.getOptions());
+    }
+    
+    /**
+     * The entry point for javac compiler.
+     */
+    @Override
+    public boolean process(Set<? extends TypeElement> annos,
+        RoundEnvironment roundEnv) {
+        if (!roundEnv.processingOver()) {
+            Set<? extends Element> elements = roundEnv.getRootElements();
+            for (Element e : elements) {
+                process((TypeElement) e);
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Generate meta-model source code for the given type.
+     * 
+     * @return true if code is generated for the given element. false otherwise.
+     */
+    private boolean process(TypeElement e) {
+        if (!isAnnotatedAsEntity(e)) {
+            return false;
+        }
+
+        Elements eUtils = processingEnv.getElementUtils();
+        String originalClass = eUtils.getBinaryName((TypeElement) e).toString();
+        String originalSimpleClass = e.getSimpleName().toString();
+        String metaClass = originalClass + UNDERSCORE;
+
+        log(_loc.get("mmg-process", originalClass).getMessage());
+
+        SourceCode source = new SourceCode(metaClass);
+        comment(source);
+        annotate(source, originalClass);
+        TypeElement supCls = getPCSuperclass(e);
+        if (supCls != null)
+            source.getTopLevelClass().setSuper(supCls.toString() + UNDERSCORE);
+        try {
+            PrintWriter writer = createSourceFile(metaClass, e);
+            SourceCode.Class modelClass = source.getTopLevelClass();
+            List<? extends Element> members = getPersistentMembers(e);
+            
+            for (Element m : members) {
+                DeclaredType decl = getDeclaredType(m);
+                String fieldName = m.getSimpleName().toString();
+                String fieldType = getDeclaredTypeName(decl);
+                TypeCategory typeCategory = toMetaModelTypeCategory(fieldType);
+                String metaModelType = typeCategory.getMetaModelType();
+                SourceCode.Field modelField = null;
+                switch (typeCategory) {
+                case ATTRIBUTE:
+                    modelField = modelClass.addField(fieldName, metaModelType);
+                    modelField.addParameter(originalSimpleClass)
+                              .addParameter(fieldType);
+                    break;
+                case COLLECTION:
+                case LIST:
+                case SET:
+                    TypeMirror param = getTypeParameter(decl, 0);
+                    String elementType = getDeclaredTypeName(param);
+                    modelField = modelClass.addField(fieldName, metaModelType);
+                    modelField.addParameter(originalSimpleClass)
+                              .addParameter(elementType);
+                    break;
+                case MAP:
+                    TypeMirror key = getTypeParameter(decl, 0);
+                    TypeMirror value = getTypeParameter(decl, 1);
+                    String keyType = getDeclaredTypeName(key);
+                    String valueType = getDeclaredTypeName(value);
+                    modelField = modelClass.addField(fieldName, metaModelType);
+                    modelField.addParameter(originalSimpleClass)
+                              .addParameter(keyType)
+                              .addParameter(valueType);
+                    break;
+                }
+                modelField.makePublic().makeStatic().makeVolatile();
+            }
+            source.write(writer);
+            writer.flush();
+            writer.close();
+            return true;
+        } catch (IOException e1) {
+            throw new RuntimeException(e1);
+        } finally {
+
+        }
+    }
+    
+    private void annotate(SourceCode source, String originalClass) {
+        SourceCode.Class cls = source.getTopLevelClass();
+        cls.addAnnotation(TypesafeMetamodel.class.getName())
+            .addArgument("value", originalClass + ".class", false);
+        cls.addAnnotation(Generated.class.getName())
+           .addArgument("value", this.getClass().getName())
+           .addArgument("date", new Date().toString());
+    }
+    
+    private void comment(SourceCode source) {
+        source.addComment(false, _loc.get("mmg-tool-sign").getMessage());
+    }
+    
+    private PrintWriter createSourceFile(String metaClass, TypeElement e) 
+        throws IOException {
+        Filer filer = processingEnv.getFiler();
+        JavaFileObject javaFile = filer.createSourceFile(metaClass, e);
+        OutputStream out = javaFile.openOutputStream();
+        PrintWriter writer = new PrintWriter(out);
+        return writer;
+    }
+    
+    /**
+     * Get  access type of the given class, if specified explicitly. 
+     * null otherwise.
+     * 
+     * @param type
+     * @return FIELD or PROPERTY 
+     */
+    AccessType getExplicitAccessType(TypeElement type) {
+        Object access = getAnnotationValue(type, Access.class);
+        if (equalsByValue(AccessType.FIELD, access))
+            return AccessType.FIELD;
+        if (equalsByValue(AccessType.PROPERTY, access))
+            return AccessType.PROPERTY;
+        return null;
+    }
+    
+    /**
+     * Gets the list of persistent fields and/or methods for the given type.
+     * 
+     * Scans relevant @AccessType annotation and field/method as per JPA
+     * specification to determine the candidate set of field/methods.
+     */
+    private List<Element> getPersistentMembers(TypeElement type) {
+        AccessType access = getExplicitAccessType(type);
+        boolean isExplicit = access != null;
+        
+        List<Element> result = new ArrayList<Element>();
+        List<? extends Element> allMembers = type.getEnclosedElements();
+        Set<VariableElement> allFields =
+            (Set<VariableElement>) filter(allMembers, fieldFilter,
+                nonTransientFilter);
+        Set<ExecutableElement> allMethods =
+            (Set<ExecutableElement>) filter(allMembers, methodFilter,
+                nonTransientFilter);
+        Set<VariableElement> propertyAnnotatedFields =
+            filter(allFields, propertyAccessFilter);
+
+        Set<ExecutableElement> fieldAnnotatedMethods =
+            filter(allMethods, fieldAccessFilter);
+
+        if (!propertyAnnotatedFields.isEmpty())
+            throw new UserException(_loc.get("access-prop-on-field", type,
+                toString(propertyAnnotatedFields)));
+        if (!fieldAnnotatedMethods.isEmpty())
+            throw new UserException(_loc.get("access-field-on-prop", type,
+                toString(fieldAnnotatedMethods)));
+
+        Set<ExecutableElement> getters = filter(allMethods, getterFilter);
+        Set<ExecutableElement> setters = filter(allMethods, setterFilter);
+        getters = matchGetterAndSetter(getters, setters);
+        
+        boolean isFieldAccess = isExplicit 
+            ? AccessType.FIELD.equals(access) : !allFields.isEmpty();
+        boolean isPropertyAccess = isExplicit 
+            ? AccessType.PROPERTY.equals(access) : !getters.isEmpty();
+
+        if (isExplicit) {
+            if (isFieldAccess) {
+                result.addAll(allFields);
+                result.addAll(filter(getters, propertyAccessFilter));
+            } else {
+                result.addAll(getters);
+                result.addAll(filter(allFields, fieldAccessFilter));
+            }
+        } else { // implicit access type
+            if (isFieldAccess && isPropertyAccess)
+                throw new UserException(_loc.get("access-mixed", type,
+                    toString(allFields), toString(getters)));
+            if (isFieldAccess) {
+                result.addAll(allFields);
+            } else if (isPropertyAccess) {
+                result.addAll(getters);
+            } else {
+                warn(_loc.get("access-none", type).toString());
+            }
+        }
+        return result;
+    }
+
+    // =========================================================================
+    // Annotation processing utilities
+    // =========================================================================
+    
+    /**
+     * Affirms if the given element is annotated with any of the given 
+     * annotations.
+     * 
+     * @param annos null checks for any annotation that starts with 
+     *            'javax.persistence.' or 'openjpa.*'.
+     * 
+     */
+    private boolean isAnnotatedWith(Element e, Set<String> annos) {
+        if (e == null)
+            return false;
+        List<? extends AnnotationMirror> mirrors = e.getAnnotationMirrors();
+        if (annos == null) {
+            for (AnnotationMirror mirror : mirrors) {
+                String name = mirror.getAnnotationType().toString();
+                if (startsWith(name, "javax.persistence.")
+                 || startsWith(name, "openjpa."))
+                    return true;
+            }
+            return false;
+        } else {
+            for (AnnotationMirror mirror : mirrors) {
+                String name = mirror.getAnnotationType().toString();
+                if (annos.contains(name))
+                    return true;
+            }
+            return false;
+        }
+    }
+    
+    /**
+     * Affirms if the given list contains one of the registered annotation that
+     * designates an entity type.
+     */
+    private boolean isAnnotatedAsEntity(TypeElement e) {
+        return isAnnotatedWith(e, getSupportedAnnotationTypes());
+    }
+    
+     /**
+     * Get the element name of the class the given mirror represents. If the
+     * mirror is primitive then returns the corresponding boxed class name.
+     * If the mirror is parameterized returns only the generic type i.e.
+     * if the given declared type is 
+     * <code>java.util.Set&lt;java.lang.String&gt;</code> this method will 
+     * return <code>java.util.Set</code>.
+     */
+    private String getDeclaredTypeName(TypeMirror mirror) {
+        return processingEnv.getTypeUtils().asElement(box(mirror)).toString();
+    }
+
+    /**
+     * Gets the declared type of the given member. For fields, returns the 
+     * declared type while for method returns the return type. 
+     * 
+     * @param e a field or method.
+     * @exception if given member is neither a field nor a method.
+     */
+    private DeclaredType getDeclaredType(Element e) {
+        TypeMirror result = null;
+        switch (e.getKind()) {
+        case FIELD:
+            result = e.asType();
+            break;
+        case METHOD:
+            result = ((ExecutableElement) e).getReturnType();
+            break;
+        default:
+            throw new IllegalArgumentException(toDetails(e));
+        }
+        result = box(result);
+        if (result.getKind() == TypeKind.DECLARED)
+            return (DeclaredType)result;
+        throw new IllegalArgumentException(toDetails(e));
+    }
+    
+    /**
+     * Affirms if the given type mirrors a primitive.
+     */
+    private boolean isPrimitive(TypeMirror mirror) {
+        TypeKind kind = mirror.getKind();
+        return kind == TypeKind.BOOLEAN 
+            || kind == TypeKind.BYTE
+            || kind == TypeKind.CHAR
+            || kind == TypeKind.DOUBLE
+            || kind == TypeKind.FLOAT
+            || kind == TypeKind.INT
+            || kind == TypeKind.LONG
+            || kind == TypeKind.SHORT;
+    }
+    
+    TypeMirror box(TypeMirror t) {
+        if (isPrimitive(t))
+            return processingEnv.getTypeUtils()
+            .boxedClass((PrimitiveType)t).asType();
+        return t;
+    }
+
+    /**
+     * Gets the parameter type argument at the given index of the given type.
+     * 
+     * @return if the given type represents a parameterized type, then the
+     *         indexed parameter type argument. Otherwise null.
+     */
+    private TypeMirror getTypeParameter(DeclaredType mirror, int index) {
+        List<? extends TypeMirror> params = mirror.getTypeArguments();
+        return (params == null || params.size() < index+1) 
+            ? null : params.get(index);
+    }
+
+    /**
+     * Gets the nearest super class of the given class which is persistent.
+     * 
+     * @return null if no such super class exists.
+     */
+    private TypeElement getPCSuperclass(TypeElement cls) {
+        TypeMirror sup = cls.getSuperclass();
+        if (sup == null || isRootObject(sup))
+            return null;
+        TypeElement supe =
+            (TypeElement) processingEnv.getTypeUtils().asElement(sup);
+        if (isAnnotatedAsEntity(supe)) 
+            return supe;
+        return getPCSuperclass(supe);
+    }
+
+
+    /**
+     * Affirms if the given declaration has the given annotation.
+     */
+    private static boolean hasAnnotation(Element e,
+        Class<? extends Annotation> anno) {
+        return e != null && e.getAnnotation(anno) != null;
+    }
+    
+    /**
+     * Gets the value of the given annotation, if present, in the given
+     * declaration. Otherwise, null.
+     */
+    private static Object getAnnotationValue(Element decl,
+        Class<? extends Annotation> anno) {
+        return getAnnotationValue(decl, anno, "value");
+    }
+
+    /**
+     * Gets the value of the given attribute of the given annotation, if
+     * present, in the given declaration. Otherwise, null.
+     */
+    private static Object getAnnotationValue(Element e,
+        Class<? extends Annotation> anno, String attr) {
+        if (e == null || e.getAnnotation(anno) == null)
+            return null;
+        List<? extends AnnotationMirror> annos = e.getAnnotationMirrors();
+        for (AnnotationMirror mirror : annos) {
+            if (mirror.getAnnotationType().toString().equals(anno.getName())) {
+                Map<? extends ExecutableElement, ? extends AnnotationValue> 
+                values = mirror.getElementValues();
+                for (ExecutableElement ex : values.keySet()) {
+                    if (ex.getSimpleName().equals(attr))
+                        return values.get(ex).getValue();
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Matches the given getters with the given setters. Removes the getters
+     * that do not have a corresponding setter.
+     */
+    private Set<ExecutableElement> matchGetterAndSetter(
+        Set<ExecutableElement> getters,  Set<ExecutableElement> setters) {
+        Collection<ExecutableElement> unmatched =
+            new ArrayList<ExecutableElement>();
+        for (ExecutableElement getter : getters) {
+            String name = getter.getSimpleName().toString();
+            TypeMirror returns = getter.getReturnType();
+            String setterName = "set" + name.substring("get".length());
+            boolean matched = false;
+            for (ExecutableElement setter : setters) {
+                TypeMirror argType =
+                    setter.getParameters().iterator().next().asType();
+                matched =
+                    setter.getSimpleName().equals(setterName)
+                        && argType.equals(returns);
+                if (matched)
+                    break;
+            }
+            if (!matched && isBoolean(returns)) {
+                setterName = "set" + name.substring("is".length());
+                for (ExecutableElement setter : setters) {
+                    TypeMirror argType =
+                        setter.getParameters().iterator().next().asType();
+                    matched =
+                        setter.getSimpleName().equals(setterName)
+                            && isBoolean(argType);
+                    if (matched)
+                        break;
+                }
+            }
+            if (!matched) {
+                warn(_loc.get("getter-unmatched", getter, 
+                    getter.getEnclosingElement()).toString());
+                unmatched.add(getter);
+            }
+
+        }
+        getters.removeAll(unmatched);
+        return getters;
+    }
+
+    // ========================================================================
+    //  Selection Filters select specific elements from a collection.
+    // ========================================================================
+    
+    /**
+     * Inclusive element filtering predicate.
+     *
+     */
+    private static interface InclusiveFilter {
+        /**
+         * Return true to include the given element.
+         */
+        boolean includes(Element e);
+    }
+
+    /**
+     * Filter the given collection with the conjunction of filters. The given
+     * collection itself is not modified.
+     */
+    private <T extends Element> Set<T> filter(Collection<T> coll, 
+        InclusiveFilter... filters) {
+        Set<T> result = new HashSet<T>();
+        for (T e : coll) {
+            boolean include = true;
+            for (InclusiveFilter f : filters) {
+                if (!f.includes(e)) {
+                    include = false;
+                    break;
+                }
+            }
+            if (include)
+                result.add(e);
+        }
+        return result;
+    }
+
+    /**
+     * Selects getter method. A getter method name starts with 'get', returns a
+     * non-void type and has no argument. Or starts with 'is', returns a boolean
+     * and has no argument.
+     * 
+     */
+    static class GetterFilter implements InclusiveFilter {
+        public boolean includes(Element obj) {
+            if (!isMethod(obj))
+                return false;
+
+            ExecutableElement m = (ExecutableElement) obj;
+            String name = m.getSimpleName().toString();
+            TypeMirror returnType = m.getReturnType();
+            return m.getParameters().isEmpty()
+                 && ((startsWith(name, "get") && !isVoid(returnType))
+                 || (startsWith(name, "is") && isBoolean(returnType)));
+        }
+    }
+
+    /**
+     * Selects setter method. A setter method name starts with 'set', returns a
+     * void and has single argument.
+     * 
+     */
+    static class SetterFilter implements InclusiveFilter {
+        public boolean includes(Element obj) {
+            if (!isMethod(obj))
+                return false;
+
+            ExecutableElement m = (ExecutableElement) obj;
+            String name = m.getSimpleName().toString();
+            TypeMirror returnType = m.getReturnType();
+            return startsWith(name, "set") && isVoid(returnType) 
+                && m.getParameters().size() == 1;
+        }
+    }
+
+    /**
+     * Selects elements which is annotated with @Access annotation and that 
+     * annotation has the given AccessType value.
+     * 
+     */
+    static class AccessFilter implements InclusiveFilter {
+        final AccessType target;
+
+        public AccessFilter(AccessType target) {
+            this.target = target;
+        }
+
+        public boolean includes(Element obj) {
+            Object value = getAnnotationValue(obj, Access.class);
+            return equalsByValue(target, value);
+        }
+    }
+
+    /**
+     * Selects elements of given kind.
+     * 
+     */
+    static class KindFilter implements InclusiveFilter {
+        final ElementKind target;
+
+        public KindFilter(ElementKind target) {
+            this.target = target;
+        }
+
+        public boolean includes(Element obj) {
+            return obj.getKind() == target;
+        }
+    }
+
+    /**
+     * Selects all non-transient element.
+     * 
+     */
+    static class NonTransientMemberFilter implements InclusiveFilter {
+        public boolean includes(Element obj) {
+            boolean isTransient = hasAnnotation(obj, Transient.class)
+                            || obj.getModifiers().contains(Modifier.TRANSIENT);
+            return !isTransient;
+        }
+    }
+    
+    
+    // ========================================================================
+    //  Utilities
+    // ========================================================================
+
+    /**
+     * Affirms if the given mirror represents a primitive or non-primitive
+     * boolean.
+     */
+    private static boolean isBoolean(TypeMirror type) {
+        return (type != null && (type.getKind() == TypeKind.BOOLEAN 
+            || "java.lang.Boolean".equals(type.toString())));
+    }
+
+    /**
+     * Affirms if the given mirror represents a void.
+     */
+    private static boolean isVoid(TypeMirror type) {
+        return (type != null && type.getKind() == TypeKind.VOID);
+    }
+
+    /**
+     * Affirms if the given element represents a method.
+     */
+    private static boolean isMethod(Element e) {
+        return e != null && ExecutableElement.class.isInstance(e)
+            && ((Element) e).getKind() == ElementKind.METHOD;
+    }
+
+    /**
+     * Affirms if the given mirror represents root java.lang.Object.
+     */
+    private static boolean isRootObject(TypeMirror type) {
+        return type != null && "java.lang.Object".equals(type.toString());
+    }
+    
+    /**
+     * Affirms if the given full string starts with the given head.
+     */
+    private static boolean startsWith(String full, String head) {
+        return full != null && full.startsWith(head) 
+            && full.length() > head.length();
+    }
+
+    /**
+     * Affirms if the given enum equals the given value.
+     */
+    private static boolean equalsByValue(Enum<?> e, Object v) {
+        if (v == null)
+            return false;
+        return e.toString().equals(v.toString());
+    }
+    
+    
+    // =========================================================================
+    // Logging
+    // =========================================================================
+
+    private void log(String msg) {
+        if (!processingEnv.getOptions().containsKey("log"))
+            return;
+        processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, msg);
+    }
+
+    private void warn(String msg) {
+        processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, msg);
+    }
+    
+    private static String toString(Collection<? extends Element> elements) {
+        StringBuilder tmp = new StringBuilder();
+        int i = 0;
+        for (Element e : elements) {
+            tmp.append(e.getSimpleName() + (++i == elements.size() ? "" : ","));
+        }
+        return tmp.toString();
+    }
+    
+    String toDetails(Element e) {
+        TypeMirror mirror = e.asType();
+        return new StringBuffer(e.getKind().toString()).append(" ")
+                           .append(e.toString())
+                           .append("Mirror ")
+                           .append(mirror.getKind().toString())
+                           .append(mirror.toString()).toString();
+    }
+}

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/meta/AnnotationProcessor6.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/util/SourceCode.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/util/SourceCode.java?rev=762968&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/util/SourceCode.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/util/SourceCode.java Tue Apr  7 21:14:40 2009
@@ -0,0 +1,823 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+
+package org.apache.openjpa.persistence.util;
+
+import java.io.PrintWriter;
+import java.util.*;
+
+import org.apache.openjpa.lib.util.Localizer;
+
+/**
+ * A utility to help writing Java Source code dynamically.
+ * 
+ * Provides basic elements of Java Source Code e.g. Package, Class, Field, 
+ * Method, Import, Annotation, Argument.
+ * 
+ * Mutator methods return the operating element for easy chaining. 
+ * 
+ * @author Pinaki Poddar
+ * 
+ * @since 2.0.0
+ *
+ */
+public class SourceCode {
+	private static Localizer _loc = Localizer.forPackage(SourceCode.class);
+	
+	/**
+	 * List of Java Keywords and primitive types. Populated statically.
+	 */
+    private static final ArrayList<String> reserved = new ArrayList<String>();
+    private static final ArrayList<String> knownTypes = new ArrayList<String>();
+	
+	private static int TABSIZE                = 4;
+	private static final String SPACE         = " ";
+	private static final String BLANK         = "";
+	private static final String SEMICOLON     = ";";
+    public static final String  COMMA         = ",";
+    public static final String  DOT           = ".";
+    public static final String  EQUAL         = "=";
+    public static final String  QUOTE         = "\"";
+	private static final String[] BRACKET_BLOCK  = {"{", "}"};
+	private static final String[] BRACKET_ARGS   = {"(", ")"};
+    private static final String[] BRACKET_PARAMS = {"<", ">"};
+	
+	private Comment comment;
+	private final Package pkg;
+	private final Class   cls;
+    private final Set<Import> imports = new TreeSet<Import>();
+	
+	
+	/**
+	 * Create source code for a top-level class with given fully-qualified 
+	 * class name. 
+	 */
+	public SourceCode(String c) {
+	    ClassName name = new ClassName(c);
+	    this.cls = new Class(c);
+        this.pkg = new Package(name.getPackageName());
+	}
+	
+	/**
+	 * Gets the top level class represented by this receiver.
+	 */
+	public Class getTopLevelClass() {
+		return cls;
+	}
+	
+	public Package getPackage() {
+	    return pkg;
+	}
+	
+    /**
+     * Sets the tab size. Tabs are always written as spaces.
+     */
+    public SourceCode setTabSize(int t) {
+        if (t>0) TABSIZE = Math.max(t, 8);
+        return this;
+    }
+
+	boolean addImport(ClassName name) {
+		String pkgName = name.getPackageName();
+		if ("java.lang".equals(pkgName))
+			return false;
+		return imports.add(new Import(name));
+	}
+	
+	
+	public SourceCode addComment(boolean inline, String... lines) {
+		if (comment == null) comment = new Comment();
+		comment.makeInline(inline);
+		for (String line:lines) comment.append(line);
+		return this;
+	}
+	
+	/**
+	 * Prints the class to the given Writer.
+	 * @param out
+	 */
+	public void write(PrintWriter out) {
+		if (comment != null) {
+		    comment.write(out, 0);
+		      out.println();
+		}
+		if (pkg != null) {
+		    pkg.write(out,0);
+		    out.println();
+		}
+		for (Import imp:imports) {
+			imp.write(out, 0);
+		}
+		out.println();
+		cls.write(out, 0);
+		out.flush();
+	}
+	
+	/**
+	 * Outputs <code>tab</code> number of spaces.
+	 */
+	static void tab(PrintWriter out, int tab) {
+		for (int i=0; i<tab*TABSIZE; i++) {
+			out.print(SPACE);
+		}
+	}
+	
+    static void writeList(PrintWriter out, String header, List<?> list) { 
+        writeList(out, header, list, new String[]{BLANK, BLANK}, false);
+    }
+	
+	static void writeList(PrintWriter out, String header, List<?> list, 
+			String[] bracket, boolean writeEmpty) {
+		if (list == null || list.isEmpty()) {
+		    if (writeEmpty)
+		        out.append(bracket[0]+bracket[1]);
+			return;
+		}
+		out.append(header);
+		out.append(bracket[0]);
+		for (int i=0; i<list.size(); i++) {
+			out.append(list.get(i).toString());
+			if (i!=list.size()-1) out.append(COMMA);
+		}
+		out.append(bracket[1]);
+	}
+	
+	static String capitalize(String s) {
+		return Character.toUpperCase(s.charAt(0))+s.substring(1);
+	}
+	
+	static boolean isValidToken(String s) {
+		return s != null && s.length() > 0 && 
+		      !reserved.contains(s) && isJavaIdentifier(s);
+	}
+	
+	public static boolean isKnownType(String s) {
+		return knownTypes.contains(s);
+	}
+	
+	static boolean isEmpty(String s) {
+		return s == null || s.length()==0;
+	}
+	
+	static LinkedList<String> tokenize(String s, String delim) {
+	    StringTokenizer tokenizer = new StringTokenizer(s, delim, false);
+		LinkedList<String> tokens = new LinkedList<String>();
+		while (tokenizer.hasMoreTokens())
+			tokens.add(tokenizer.nextToken());
+		return tokens;
+	}
+	
+	public static boolean isJavaIdentifier(String s) {
+        if (s == null || s.length() == 0 || 
+        	!Character.isJavaIdentifierStart(s.charAt(0))) {
+            return false;
+        }
+        for (int i=1; i<s.length(); i++) {
+            if (!Character.isJavaIdentifierPart(s.charAt(i))) {
+                return false;
+            }
+        }
+        return true;
+    }
+	
+	
+    public enum ACCESS {PUBLIC, PROTECTED, PRIVATE}
+		
+	/**
+	 * Abstract element has a name, optional list of modifiers, annotations
+	 * and arguments. 
+	 */
+	public abstract class Element<T> implements Comparable<Element<T>> {
+		protected String name;
+		protected ClassName type;
+		protected ACCESS access;
+		protected boolean isStatic;
+		protected boolean isFinal;
+		protected Comment comment;
+		protected List<ClassName> params = new ArrayList<ClassName>();
+		protected List<Annotation> annos = new ArrayList<Annotation>();
+		
+        protected Element(String name, ClassName type) {
+            this.name = name;
+            this.type = type;
+        }
+
+        public ClassName getType() {
+			return type;
+		}
+				
+		public Annotation addAnnotation(String a) {
+			Annotation an = new Annotation(a);
+			annos.add(an);
+			return an;
+		}
+		
+		public Element<T> addParameter(String param) {
+		    params.add(new ClassName(param));
+		    return this;
+		}
+		
+		public int compareTo(Element<T> other) {
+			return name.compareTo(other.name);
+		}
+		
+		public T addComment(boolean inline, String... lines) {
+			if (comment == null) comment = new Comment();
+			comment.makeInline(inline);
+			for (String line:lines) comment.append(line);
+			return (T)this;
+		}
+		
+		public T makePublic() {
+			access = ACCESS.PUBLIC;
+			return (T)this;
+		}
+		
+		public T makeProtected() {
+			access = ACCESS.PROTECTED;
+			return (T)this;
+		}
+		
+		public T makePrivate() {
+			access = ACCESS.PRIVATE;
+			return (T)this;
+		}
+		
+		public T makeStatic() {
+			isStatic = true;
+			return (T)this;
+		}
+		
+		public T makeFinal() {
+			isFinal = true;
+			return (T)this;
+		}
+		
+		public void write(PrintWriter out, int tab) {
+			if (comment != null) comment.write(out, tab);
+			for (Annotation a:annos)
+				a.write(out, tab);
+			tab(out, tab);
+			if (access != null) 
+			    out.append(access.toString().toLowerCase() + SPACE);
+			if (isStatic) 
+			    out.append("static" + SPACE);
+			if (isFinal) 
+			    out.append("final" + SPACE);
+		}
+	}
+
+	/**
+	 * Represent <code>class</code> declaration.
+	 *
+	 */
+	public class Class extends Element<Class> {
+		private boolean isAbstract;
+		private ClassName superCls;
+		private List<ClassName> interfaces = new ArrayList<ClassName>();
+	    private Set<Field> fields   = new TreeSet<Field>();
+	    private Set<Method> methods = new TreeSet<Method>();
+		
+		public Class(String name) {
+			super(name, new ClassName(name));
+			makePublic();
+		}
+		
+		public Class setSuper(String s) {
+			superCls = new ClassName(s);
+			return this;
+		}
+		
+		public Class addInterface(String s) {
+			interfaces.add(new ClassName(s));
+			return this;
+		}
+		
+		public Class makeAbstract() {
+			isAbstract = true;
+			return this;
+		}
+		
+	    /**
+	     * Adds getters and setters to every non-public field.
+	     */
+	    public Class markAsBean() {
+	        for (Field f:fields)
+	            f.markAsBean();
+	        return this;
+	    }
+
+        public String getName() {
+            return getType().getSimpleName();
+        }
+        
+        public String getPackageName() {
+            return getType().getPackageName();
+        }
+        
+        public Field addField(String name, String type) {
+            return addField(name, new ClassName(type));
+        }
+
+        public Field addField(String f, ClassName type) {
+	        if (!isValidToken(f)) {
+	            throw new IllegalArgumentException(
+	                _loc.get("invalid-field-name",f).toString());
+	        }
+	        Field field = new Field(this, f, type);
+	        
+	        if (!fields.add(field))
+	            throw new IllegalArgumentException(_loc.get(
+	                "duplicate-field", field, this).toString());
+	        return field;
+	    }
+
+        public Method addMethod(String m, String retType) {
+            return addMethod(m, new ClassName(retType));
+        }
+        
+	    protected Method addMethod(String m, ClassName retType) {
+	        if (isEmpty(m) || !isValidToken(m)) {
+	            throw new IllegalArgumentException(_loc.get(
+	                "invalid-method",m).toString());
+	        }
+	        Method method = new Method(this, m, retType);
+	        if (!methods.add(method)) 
+	            throw new IllegalArgumentException(_loc.get(
+	                "duplicate-method", method, this).toString());
+	        return method;
+	    }
+
+	    public void write(PrintWriter out, int tab) {
+			super.write(out, tab);
+			if (isAbstract) 
+			    out.append("abstract ");
+			out.print("class ");
+			out.print(type.simpleName);
+			writeList(out, BLANK, params, BRACKET_PARAMS, false);
+			if (superCls != null)
+				out.print(" extends " + superCls + SPACE);
+			writeList(out, "implements ", interfaces);
+			out.println(SPACE + BRACKET_BLOCK[0]);
+	        for (Field field:fields) 
+	            field.write(out, 1);
+	        for (Method method:methods) 
+	            method.write(out, 1);
+	        out.println(BRACKET_BLOCK[1]);
+		}
+	}
+
+	/**
+	 * Represents field declaration.
+	 *
+	 */
+	public class Field extends Element<Field> {
+	    private final Class owner;
+		protected boolean isTransient;
+		protected boolean isVolatile;
+		
+		Field(Class owner, String name, ClassName type) {
+			super(name, type);
+			this.owner = owner;
+			makePrivate();
+		}
+		
+		/**
+		 * Adds bean-style getter setter method.
+		 */
+		public Field markAsBean() {
+			addGetter();
+			addSetter();
+			return this;
+		}
+		
+		public Field addGetter() {
+			owner.addMethod("get"+ capitalize(name), type)
+			     .makePublic()
+			     .addCodeLine("return "+ name);
+			return this;
+		}
+		
+		public Field addSetter() {
+			owner.addMethod("set"+ capitalize(name), "void")
+			     .makePublic()
+                 .addArgument(new Argument<ClassName,String>(type, name,SPACE))
+			     .addCodeLine("this."+ name + " = " + name);
+			return this;
+		}
+		
+        public void makeVolatile() {
+            isVolatile = true; 
+        }
+        
+        public void makeTransient() {
+            isTransient = true; 
+        }
+		
+		public String toString() {
+			return type + SPACE + name;
+		}
+		
+		public void write(PrintWriter out, int tab) {
+			super.write(out, tab);
+			if (isVolatile) out.print("volatile ");
+			if (isTransient) out.print("transient ");
+			out.print(type);
+			writeList(out, BLANK, params, BRACKET_PARAMS, false);
+			out.println(SPACE + name + SEMICOLON);
+		}
+		
+		public boolean equals(Object other) {
+			if (other instanceof Field) {
+				Field that = (Field)other;
+				return name.equals(that.name);
+			}
+			return false;
+		}
+	}
+	
+	/**
+	 * Represents Method declaration.
+	 * 
+	 *
+	 */
+	class Method  extends Element<Method> {
+	    private final Class owner;
+		private boolean isAbstract;
+		private List<Argument<ClassName,String>> args = 
+		    new ArrayList<Argument<ClassName,String>>();
+		private List<String> codeLines = new ArrayList<String>();
+		
+        Method(Class owner, String n, String t) {
+            this(owner, n, new ClassName(t));
+        }
+        
+        public Method(Class owner, String name, ClassName returnType) {
+            super(name, returnType);
+            this.owner = owner;
+            makePublic();
+        }
+		
+		public Method addArgument(Argument<ClassName,String> arg) {
+			args.add(arg);
+			return this;
+		}
+		
+		public Method addCodeLine(String line) {
+			if (isAbstract)
+                throw new IllegalStateException("abstract method " + name 
+				    + " can not have body");
+			if (!line.endsWith(SEMICOLON))
+			    line = line + SEMICOLON;
+			codeLines.add(line);
+			return this;
+		}
+		
+		public Method makeAbstract() {
+			if (codeLines.isEmpty())
+				isAbstract = true;
+			else
+                throw new IllegalStateException("method " + name + 
+				    " can not be abstract. It has a body");
+			return this;
+		}
+		
+		
+		public String toString() {
+			return type + SPACE + name;
+		}
+		
+		public void write(PrintWriter out, int tab) {
+			out.println(BLANK);
+			super.write(out, tab);
+			if (isAbstract) out.append("abstract ");
+			out.print(type + SPACE + name);
+			writeList(out, BLANK, args, BRACKET_ARGS, true);
+			if (isAbstract) {
+				out.println(SEMICOLON);
+				return;
+			}
+			out.println(SPACE + BRACKET_BLOCK[0]);
+			for (String line : codeLines) {
+				tab(out, tab+1);
+				out.println(line);
+			}
+			tab(out, tab);
+			out.println(BRACKET_BLOCK[1]);
+		}
+		
+		public boolean equals(Object other) {
+			if (other instanceof Method) {
+				Method that = (Method)other;
+                return name.equals(that.name) && args.equals(that.args);
+			}
+			return false;
+		}
+	}
+	
+	/**
+	 * Represents <code>import</code> statement.
+	 *
+	 */
+	class Import implements Comparable<Import> {
+		private final ClassName name;
+		
+		public Import(ClassName name) {
+			this.name = name;
+		}
+		
+		public int compareTo(Import other) {
+			return name.compareTo(other.name);
+		}
+		
+		public void write(PrintWriter out, int tab) {
+		    String pkg = name.getPackageName();
+		    if (pkg.length() == 0 || pkg.equals(getPackage().name))
+		        return;
+		    out.println("import "+ name.getName() + SEMICOLON);
+		}
+		
+		public boolean equals(Object other) {
+			if (other instanceof Import) {
+				Import that = (Import)other;
+				return name.equals(that.name);
+			}
+			return false;
+		}
+	}
+	
+	/**
+	 * Represents method argument.
+	 *
+	 */
+	public class Argument<K,V> {
+		final private K key;
+		final private V value;
+		final private String connector;
+		
+		Argument(K key, V value, String connector) {
+			this.key = key;
+			this.value = value;
+			this.connector = connector;
+		}
+		
+        public String toString() {
+			return key + connector + value;
+		}
+	}
+	
+	/**
+	 * Represents annotation.
+	 *
+	 */
+	public class Annotation {
+		private String name;
+        private List<Argument<?,?>> args = new ArrayList<Argument<?,?>>();
+		
+		Annotation(String n) {
+			name = n;
+		}
+		
+        public Annotation addArgument(String key, String v, boolean quote) {
+            return addArgument(new Argument<String,String>(key, 
+                quote ? quote(v) : v, EQUAL));
+        }
+        
+        public Annotation addArgument(String key, String v) {
+            return addArgument(key, v, true);
+        }
+        
+        public Annotation addArgument(String key, String[] vs) {
+            StringBuffer tmp = new StringBuffer(BRACKET_BLOCK[0]);
+            for (int i=0; i < vs.length; i++) {
+                tmp.append(quote(vs[i]));
+                tmp.append(i != vs.length-1 ? COMMA : BLANK);
+            }
+            tmp.append(BRACKET_BLOCK[1]);
+            return addArgument(key, tmp.toString(), false);
+        }
+        
+        public <K,V> Annotation addArgument(Argument<K,V> arg) {
+            args.add(arg);
+            return this;
+        }
+		
+		public void write(PrintWriter out, int tab) {
+			tab(out, tab);
+			out.print("@"+name);
+			writeList(out, BLANK, args, BRACKET_ARGS, false);
+			out.println();
+		}
+		
+		String quote(String s) {
+		    return QUOTE + s + QUOTE;
+		}
+	}
+	
+	static class Package {
+		private String name;
+		
+		Package(String p) {
+			name = p;
+		}
+		
+		public void write(PrintWriter out, int tab) {
+			out.println("package " + name + SEMICOLON);
+		}
+	}
+	
+	class Comment {
+		List<String> lines = new ArrayList<String>();
+		private boolean inline = false;
+		
+		public void append(String line) {
+			lines.add(line);
+		}
+		
+		boolean isEmpty() {
+			return lines.isEmpty();
+		}
+		
+		void makeInline(boolean flag) {
+			inline = flag;
+		}
+		public void write(PrintWriter out, int tab) {
+			if (inline) {
+				for (String l:lines) {
+					tab(out, tab);
+					out.println("// " + l);
+				}
+			} else {
+				int i = 0;
+				for (String l:lines) {
+					tab(out, tab);
+					if (i == 0) {
+						out.println("/** ");
+						tab(out, tab);
+					} 
+					out.println(" *  " + l);
+					i++;
+				}
+				tab(out, tab);
+				out.println("**/");
+			}
+		}
+	}
+	
+	/**
+	 * Represents fully-qualified name of a Java type.
+	 * 
+	 * Constructing a name adds it to the list of imports for the enclosing
+	 * SourceCode.
+	 *
+	 */
+	class ClassName implements Comparable<ClassName> {
+        public final String fullName;
+        public final String simpleName;
+        public final String pkgName;
+        
+	    ClassName(String name) {
+	        this.fullName = name;
+	        int dot = fullName.lastIndexOf(DOT);
+	        simpleName = (dot == -1) ? fullName : fullName.substring(dot+1);
+	        pkgName = (dot == -1) ? BLANK : fullName.substring(0,dot);
+            if (!isValidTypeName(name)) {
+                throw new IllegalArgumentException("invalid-type [" 
+                    + name + "]");
+            }
+            addImport(this);
+	    }
+	    
+	    /**
+	     * Gets fully qualified name of this receiver.
+	     */
+	    public String getName() {
+	        return fullName;
+	    }
+	    
+        /**
+         * Gets simple name of this receiver.
+         */
+	    public String getSimpleName() {
+	        return simpleName;
+	    }
+	    
+	    /**
+	     * Gets the package name of this receiver. Default package name is 
+	     * represented as empty string.
+	     */
+	    public String getPackageName() {
+	        return pkgName;
+	    }
+	    
+	    /**
+	     * Gets the simple name of this receiver.
+	     */
+	    public String toString() {
+	        return simpleName;
+	    }
+	    
+	    /**
+	     * Compares by fully-qualified name.
+	     */
+	    public int compareTo(ClassName other) {
+	        return fullName.compareTo(other.fullName);
+	    }
+	    
+	    public boolean isValidTypeName(String s) {
+	        return isValidPackageName(pkgName) 
+	            && (isValidToken(simpleName));
+	    }
+	    
+	    boolean isValidPackageName(String s) {
+	        if (isEmpty(s)) return true;
+	        LinkedList<String> tokens = tokenize(s, DOT);
+	        for (String token : tokens) {
+	            if (!isValidToken(token))
+	                return false;
+	        }
+	        return !s.endsWith(DOT);
+	    }
+	    
+	}
+	
+	static {
+		reserved.add("abstract");
+		reserved.add("continue");
+		reserved.add("for");
+		reserved.add("new");
+		reserved.add("switch");
+		reserved.add("assert");
+		reserved.add("default"); 	
+		reserved.add("goto");
+		reserved.add("package");
+		reserved.add("synchronized");
+		reserved.add("boolean");
+		reserved.add("do");
+		reserved.add("if");
+		reserved.add("private");
+		reserved.add("this");
+		reserved.add("break");
+		reserved.add("double");
+		reserved.add("implements");
+		reserved.add("protected");
+		reserved.add("throw");
+		reserved.add("byte");
+		reserved.add("else");
+		reserved.add("import");
+		reserved.add("public");
+		reserved.add("throws");
+		reserved.add("case");
+		reserved.add("enum");
+		reserved.add("instanceof");
+		reserved.add("return");
+		reserved.add("transient");
+		reserved.add("catch");
+		reserved.add("extends");
+		reserved.add("int");
+		reserved.add("short");
+		reserved.add("try");
+		reserved.add("char");
+		reserved.add("final");
+		reserved.add("interface");
+		reserved.add("static");
+		reserved.add("void");
+		reserved.add("class");
+		reserved.add("finally");
+		reserved.add("long");
+		reserved.add("strictfp");
+		reserved.add("volatile");
+		reserved.add("const");
+		reserved.add("float");
+		reserved.add("native");
+		reserved.add("super");
+		reserved.add("while");
+		
+		knownTypes.add("boolean");
+		knownTypes.add("byte");
+		knownTypes.add("char");
+		knownTypes.add("double");
+		knownTypes.add("float");
+		knownTypes.add("int");
+		knownTypes.add("long");
+		knownTypes.add("short");
+		knownTypes.add("void");
+		knownTypes.add("String");
+	}
+}

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/util/SourceCode.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openjpa/trunk/openjpa-persistence/src/main/resources/META-INF/services/javax.annotation.processing.Processor.hidden
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/resources/META-INF/services/javax.annotation.processing.Processor.hidden?rev=762968&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/resources/META-INF/services/javax.annotation.processing.Processor.hidden (added)
+++ openjpa/trunk/openjpa-persistence/src/main/resources/META-INF/services/javax.annotation.processing.Processor.hidden Tue Apr  7 21:14:40 2009
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+org.apache.openjpa.persistence.meta.AnnotationProcessor6

Added: openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/meta/localizer.properties
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/meta/localizer.properties?rev=762968&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/meta/localizer.properties (added)
+++ openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/meta/localizer.properties Tue Apr  7 21:14:40 2009
@@ -0,0 +1,39 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+access-prop-on-field: Class "{0}" annotated field(s) "{1}" with PROPERTY \
+	access annotation. PROPERTY access is not permitted on fields
+access-field-on-prop: Class "{0}" annotated method(s) "{1}" with FIELD access \
+	annotation. FIELD access is not permitted on methods
+access-mixed: Class "{0}" annotated fields "{1}" with FIELD access and \
+	methods "{2}" with PROPERTY access. As class "{0}" is not using an explicit \
+	access, it is not permitted to mix PROPERTY and FIELD access annotations
+access-none: Class "{0}" has not explicitly annotated any access type and \
+	no field or method is annotated either. It is not possible to determine \
+	its access type
+field-missing: "{0}" is not a managed field in "{1}"
+field-not-decl: "{0}" is not declared in "{1}" itself but one of its \
+	persistent super class
+field-type-mismatch: Actual type of field "{0}" "{1}" does not match with the \
+	expected type "{2}"
+field-element-type-mismatch: Actual element type of field "{0}" "{1}" does not \
+	match with the expected element type "{2}"
+field-key-type-mismatch: Actual key type of map field "{0}" "{1}" does not \
+	match with the expected key type "{2}"	
+getter-unmatched: Getter method "{0}" in "{1}" has no matching setter method.
+mmg-tool-banner: Starting OpenJPA Annotation Processor for Metamodel Generation 
+mmg-process: Processing source code "{0}" to generate metamodel source code
+mmg-too-sign: Generated by OpenJPA MetaModel Generator Tool.
\ No newline at end of file

Propchange: openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/meta/localizer.properties
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message