You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jdo-commits@db.apache.org by mb...@apache.org on 2005/05/22 19:55:54 UTC

svn commit: r171351 [14/16] - in /incubator/jdo/trunk/enhancer20: ./ src/ src/conf/ src/java/ src/java/org/ src/java/org/apache/ src/java/org/apache/jdo/ src/java/org/apache/jdo/enhancer/ src/java/org/apache/jdo/impl/ src/java/org/apache/jdo/impl/enhancer/ src/java/org/apache/jdo/impl/enhancer/classfile/ src/java/org/apache/jdo/impl/enhancer/core/ src/java/org/apache/jdo/impl/enhancer/generator/ src/java/org/apache/jdo/impl/enhancer/meta/ src/java/org/apache/jdo/impl/enhancer/meta/model/ src/java/org/apache/jdo/impl/enhancer/meta/prop/ src/java/org/apache/jdo/impl/enhancer/meta/util/ src/java/org/apache/jdo/impl/enhancer/util/ test/ test/sempdept/ test/sempdept/src/ test/sempdept/src/empdept/

Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/prop/JDOField.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/prop/JDOField.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/prop/JDOField.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/prop/JDOField.java Sun May 22 10:55:51 2005
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.jdo.impl.enhancer.meta.prop;
+
+import java.lang.reflect.Modifier;
+
+
+/**
+ * A class to hold the properties of a field.
+ */
+final class JDOField
+{
+    /**
+     * The name of the field.
+     */
+    final private String name;
+    
+    /**
+     * The type of the field.
+     */
+    private String type = null;
+    
+    /**
+     * The access modifier of the field.
+     */
+    private int modifiers = Modifier.PRIVATE;
+    
+    /**
+     * The JDO modifier of the field.
+     */
+    private String jdoModifier = null;
+    
+    /**
+     * The annotation type.
+     */
+    private String annotationType = null;
+    
+    /**
+     * Creates a new object with the given name.
+     *
+     * @param  name  The name of the field.
+     */
+    JDOField(String name)
+    {
+        this.name = name;
+    }
+    
+    /**
+     * Returns the name of the field.
+     *
+     * @return  The name of the field.
+     */
+    public String getName()
+    {
+        return name;
+    }
+    
+    /**
+     * Sets the type of the field. The given classname should have a
+     * natural form(with dots) and is converted to a VM-similar
+     * notation(with slashes).
+     *
+     * @param  type  The natural classname.
+     */
+    public void setType(String type)
+    {
+        this.type = NameHelper.fromCanonicalClassName(type);
+    }
+    
+    /**
+     * Returns the type of the field.
+     *
+     * @return  The type of the field.
+     */
+    public String getType()
+    {
+        return type;
+    }
+    
+    /**
+     * Returns the modifiers of the field.
+     *
+     * @param modifiers  The modifiers of the field.
+     */
+    public void setModifiers(int modifiers)
+    {
+        this.modifiers = modifiers;
+    }
+    
+    /**
+     * Returns the modifiers of the field.
+     *
+     * @return  The modifiers of the field.
+     */
+    public int getModifiers()
+    {
+        return modifiers;
+    }
+    
+    /**
+     * Sets the annotation type of the field.
+     *
+     * @param  annotationType annotation type
+     */
+    public void setAnnotationType(String annotationType)
+    {
+        this.annotationType = annotationType;
+    }
+    
+    /**
+     * Returns whether the field is annotated.
+     *
+     * @return  true if annotated field
+     */
+    public boolean isAnnotated()
+    {
+        return annotationType != null;
+    }
+    
+    /**
+     * Returns whether the field is a key primary.
+     *
+     * @return  true if primary key.
+     */
+    public boolean isKey()
+    {
+        return (annotationType != null
+                && annotationType.equals(
+                    MetaDataProperties.ANNOTATION_TYPE_KEY));
+    }
+    
+    /**
+     * Is the field in the default fetch group?
+     *
+     * @return  Is the field in the default fetch group?
+     */
+    public boolean isInDefaultFetchGroup()
+    {
+        return (annotationType != null
+                && annotationType.equals(
+                    MetaDataProperties.ANNOTATION_TYPE_DFG));
+    }
+    
+    /**
+     * Sets the modifiers of the field.
+     *
+     * @param jdoModifier  the persistence modifier of the field
+     */
+    public void setJdoModifier(String jdoModifier)
+    {
+        this.jdoModifier = jdoModifier;
+    }
+    
+    /**
+     * Returns whether the field is declared transient.
+     *
+     * @return  true if declared transient field.
+     * @see  #setJdoModifier
+     */
+    public boolean isKnownTransient()
+    {
+        return (jdoModifier != null
+                && jdoModifier.equals(MetaDataProperties.JDO_TRANSIENT));
+    }
+    
+    /**
+     * Returns whether the field is persistent.
+     *
+     * @return  true if persistent field.
+     * @see  #setJdoModifier
+     */
+    public boolean isPersistent()
+    {
+        return (jdoModifier != null
+                && jdoModifier.equals(MetaDataProperties.JDO_PERSISTENT));
+    }
+    
+    /**
+     * Returns whether the field is transactional.
+     *
+     * @return  true if transactional field
+     * @see  #setJdoModifier
+     */
+    public boolean isTransactional()
+    {
+        return (jdoModifier != null
+                && jdoModifier.equals(MetaDataProperties.JDO_TRANSACTIONAL));
+    }
+    
+    /**
+     * Returns whether the field is managed.
+     *
+     * @return  true if managed field
+     */
+    public boolean isManaged()
+    {
+        return (isPersistent() || isTransactional());
+    }
+    
+    /**
+     * Creates a string-representation of the object.
+     *
+     * @return  The string-representation of the object.
+     */
+    public String toString()
+    {
+        return ('<' + "name:" + name
+                + ',' + MetaDataProperties.PROPERTY_TYPE
+                + ':' + type
+                + ',' + MetaDataProperties.PROPERTY_ACCESS_MODIFIER
+                + ':' + Modifier.toString(modifiers)
+                + ',' + MetaDataProperties.PROPERTY_JDO_MODIFIER
+                + ':' + jdoModifier
+                + ',' + MetaDataProperties.PROPERTY_ANNOTATION_TYPE
+                + ':' + annotationType + '>');
+    }
+}

Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/prop/MetaDataProperties.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/prop/MetaDataProperties.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/prop/MetaDataProperties.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/prop/MetaDataProperties.java Sun May 22 10:55:51 2005
@@ -0,0 +1,859 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.jdo.impl.enhancer.meta.prop;
+
+import java.lang.reflect.Modifier;
+
+import java.util.Iterator;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.List;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.HashMap;
+import java.util.ArrayList;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+import java.text.MessageFormat;
+
+import org.apache.jdo.impl.enhancer.meta.EnhancerMetaDataFatalError;
+import org.apache.jdo.impl.enhancer.meta.EnhancerMetaDataUserException;
+
+
+
+/**
+ * This class parses properties containing meta data information
+ * about classes. The syntax of the properties is the following:
+ * <ul>
+ *   <li> the keys in the properties file are fully qualified classnames or
+ *        fully qualified fieldnames </li>
+ *   <li> a fields is separated by a classname with a hash mark ('#')
+ *        (e.g. "test.Test#test1") </li>
+ *   <li> all classnames are given in a natural form (e.g.
+ *        "java.lang.Integer", "java.lang.Integer[][]", "int",
+ *        "test.Test$Test1") </li>
+ *   <li> property keys are classnames and fieldnames
+ *        (e.g. "test.Test=...", "test.Test#field1=...") <br> </li>
+ *   <li> Classnames can have the following attributes:
+ *     <ul>
+ *       <li> jdo:{persistent|transactional} </li>
+ *       <li> super: &#60;classname&#62; </li>
+ *       <li> oid: &#60;classname&#62; </li>
+ *       <li> access: {public|protected|package|private} </li>
+ *     </ul> </li>
+ *   <li> Fieldnames can have the following attributes:
+ *     <ul>
+ *       <li> type:&#60;type&#62; </li>
+ *       <li> access: {public|protected|package|private} </li>
+ *       <li> jdo:{persistent|transactional|transient} </li>
+ *       <li> annotation:{key|dfg|mediated} </li>
+ *     </ul> </li>
+ *   <li> the names of the attributes can be ommitted: you can say <br>
+ *        test.Test1#field1=jdo:persistent,type:java.lang.String,key,... <br>
+ *        or <br>
+ *        test.Test1#field1=persistent,java.lang.String,key,... <br>
+ *        or <br>
+ *        test.Test1#field1=jdo:persistent,java.lang.String,key,... <br> </li>
+ *   <li> in order to find fields of a class, a line for the class has to be
+ *        specified in the properties: To find the field
+ *        <code>test.Test1#field</code>, the keys <code>test.Test1</code> and
+ *        <code>test.Test1#Field</code> have to be present. </li>
+ * </ul>
+ * This class is not thread safe.
+ */
+final class MetaDataProperties
+{
+    /**
+     *  The delimiter of a property key between the class- and fieldname.
+     */
+    static final char FIELD_DELIMITER = '#';
+
+    /**
+     *  A string of delimiter characters between attributes.
+     */
+    static final String PROPERTY_DELIMITERS = " \t,;";
+
+    /**
+     *  A delimiter character between attribute name and attribute value
+     */
+    static final char PROPERTY_ASSIGNER = ':';
+
+    // attribute names for classes and fields
+    static final String PROPERTY_ACCESS_MODIFIER = "access";
+    static final String PROPERTY_JDO_MODIFIER    = "jdo";
+    static final String PROPERTY_SUPER_CLASSNAME = "super";
+    static final String PROPERTY_OID_CLASSNAME   = "oid";
+    static final String PROPERTY_TYPE            = "type";
+    static final String PROPERTY_ANNOTATION_TYPE = "annotation";
+
+    // values of the access attribute of classes and fields.
+    static final String ACCESS_PRIVATE       = "private";
+    static final String ACCESS_PACKAGE_LOCAL = "package";
+    static final String ACCESS_PROTECTED     = "protected";
+    static final String ACCESS_PUBLIC        = "public";
+
+    // values of the jdo attribute of classes and fields.
+    static final String JDO_TRANSIENT     = "transient";
+    static final String JDO_PERSISTENT    = "persistent";
+    static final String JDO_TRANSACTIONAL = "transactional";
+
+    // values of the annotation type attribute of fields.
+    static final String ANNOTATION_TYPE_KEY      = "key";
+    static final String ANNOTATION_TYPE_DFG      = "dfg";
+    static final String ANNOTATION_TYPE_MEDIATED = "mediated";
+
+    /**
+     *  The properties to parse.
+     */
+    private Properties properties;
+
+    /**
+     *  A map of already read class properties. The keys are the
+     *  classnames, the values are the appropriate
+     *  <code>JDOClass</code>-object.
+     */
+    private final Map cachedJDOClasses = new HashMap();
+
+    /**
+     *  A constant for the cache indicating that a given classname
+     *  if not specified in the properties.
+     */
+    static private final JDOClass NULL = new JDOClass(null);
+
+    /**
+     *  A temporary vector (this is the reason why the implementation is not
+     *  thread safe).
+     */
+    private final List tmpTokens = new ArrayList();
+
+    /**
+     *  Creates a new object with the given properties.
+     *
+     *  @param  props  The properties.
+     */
+    public MetaDataProperties(Properties props)
+    {
+        this.properties = props;
+    }
+
+    /**
+     *  Get the information about the class with the given name.
+     *
+     *  @param  classname  The classname.
+     *  @return  The information about the class or <code>null</code> if no
+     *           information is given.
+     *  @throws  EnhancerMetaDataUserException  If something went wrong parsing
+     *                                     the properties.
+     */
+    public final JDOClass getJDOClass(String classname)
+        throws EnhancerMetaDataUserException
+    {
+        classname = NameHelper.toCanonicalClassName(classname);
+        JDOClass clazz = (JDOClass)cachedJDOClasses.get(classname);
+        if (clazz == NULL) { //already searched but not found
+            return null;
+        }
+        if (clazz != null) {
+            return clazz;
+        }
+
+        //load it from the properties file
+        String s = properties.getProperty(classname);
+        if (s == null) { //class not defined
+            cachedJDOClasses.put(classname, NULL);
+            return null;
+        }
+
+        //the class could be found in the properties
+        clazz = parseJDOClass(classname, s);  //parse the class attributes
+        parseJDOFields(clazz);  //parse all fields
+        validateDependencies(clazz);  //check dependencies
+        cachedJDOClasses.put(clazz.getName(), clazz);
+
+        return clazz;
+    }
+
+    /**
+     *  Gets the information about the specified field.
+     *
+     *  @param  classname  The name of the class.
+     *  @param  fieldname  The name of the field of the class.
+     *  @return  The information about the field or <code>null</code> if
+     *           no information could be found.
+     *  @throws  EnhancerMetaDataUserException  If something went wrong parsing
+     *                                     the properties.
+     */
+    public final JDOField getJDOField(String fieldname,
+                                      String classname)
+        throws EnhancerMetaDataUserException
+    {
+        JDOClass clazz = getJDOClass(classname);
+        return (clazz != null ? clazz.getField(fieldname) : null);
+    }
+
+    /**
+     *  Gets all classnames in the properties.
+     *
+     *  @return  All classnames in the properties.
+     */
+    public final String[] getKnownClassNames()
+    {
+        Collection classnames = new HashSet();
+        for (Enumeration names = properties.propertyNames();
+             names.hasMoreElements();) {
+            String name = (String)names.nextElement();
+            if (name.indexOf(FIELD_DELIMITER) < 0) {
+                classnames.add(NameHelper.fromCanonicalClassName(name));
+            }
+        }
+
+        return (String[])classnames.toArray(new String[classnames.size()]);
+    }
+
+    /**
+     *  Parses the attributes-string of a class and puts them into a
+     *  <code>JDOClass</code>-object.
+     *
+     *  @param  classname  The name of the class.
+     *  @param  attributes  The attribute-string as specified in the properties.
+     *  @return  The create <code>JDOClass</code>-object.
+     *  @throws  EnhancerMetaDataUserException  If something went wrong parsing
+     *                                     the attributes.
+     */
+    private final JDOClass parseJDOClass(String classname,
+                                         String attributes)
+        throws EnhancerMetaDataUserException
+    {
+        List props = parseProperties(attributes);
+
+        // check each property
+        for (int i = 0; i < props.size(); i++) {
+            final Property prop = (Property)props.get(i);
+            validateClassProperty(prop, classname);
+        }
+
+        // check dependencies of all properties
+        checkForDuplicateProperties(props, classname);
+
+        // properties are OK - assign them to the JDOClass object
+        JDOClass clazz = new JDOClass(classname);
+        for (int i = 0; i < props.size(); i++) {
+            Property prop = (Property)props.get(i);
+            if (prop.name.equals(PROPERTY_ACCESS_MODIFIER)) {
+                clazz.setModifiers(getModifiers(prop.value));
+            } else if (prop.name.equals(PROPERTY_JDO_MODIFIER)) {
+                clazz.setPersistent(prop.value.equals(JDO_PERSISTENT));
+            } else if (prop.name.equals(PROPERTY_SUPER_CLASSNAME)) {
+                clazz.setSuperClassName(prop.value);
+            } else if (prop.name.equals(PROPERTY_OID_CLASSNAME)) {
+                clazz.setOidClassName(prop.value);
+            }
+        }
+
+        return clazz;
+    }
+
+    /**
+     *  Checks if the given attribute-property of a class is valid.
+     *
+     *  @param  prop       The attribute-property.
+     *  @param  classname  The classname.
+     *  @throws  EnhancerMetaDataUserException  If the validation failed.
+     */
+    static private void validateClassProperty(Property prop,
+                                              String classname)
+        throws EnhancerMetaDataUserException
+    {
+        String value = prop.value;
+        if (prop.name == null) {
+            // try to guess the property name
+            if (value.equals(ACCESS_PUBLIC)
+                || value.equals(ACCESS_PROTECTED)
+                || value.equals(ACCESS_PACKAGE_LOCAL)
+                || value.equals(ACCESS_PRIVATE)) {
+                // assume access modifier
+                prop.name = PROPERTY_ACCESS_MODIFIER;
+            } else if (value.equals(JDO_PERSISTENT)
+                       || value.equals(JDO_TRANSIENT)) {
+                // assume persistence modifier
+                prop.name = PROPERTY_JDO_MODIFIER;
+            }
+            //@olsen: not unique anymore, could also be oid class name
+            // else {
+            //     //assume the the given value is the superclassname
+            //     prop.name = PROPERTY_SUPER_CLASSNAME;
+            // }
+        } else {
+            // do we have a valid property name?
+            String name = prop.name;
+            checkPropertyName(prop.name,
+                              new String[]{
+                                  PROPERTY_ACCESS_MODIFIER,
+                                  PROPERTY_JDO_MODIFIER,
+                                  PROPERTY_SUPER_CLASSNAME,
+                                  PROPERTY_OID_CLASSNAME
+                              },
+                              classname);
+
+            // do we have a valid property value?
+            checkPropertyValue(prop,
+                               new String[]{
+                                   ACCESS_PUBLIC,
+                                   ACCESS_PROTECTED,
+                                   ACCESS_PACKAGE_LOCAL,
+                                   ACCESS_PRIVATE
+                               },
+                               PROPERTY_ACCESS_MODIFIER,
+                               classname);
+            checkPropertyValue(prop,
+                               new String[]{
+                                   JDO_TRANSIENT,
+                                   JDO_PERSISTENT
+                               },
+                               PROPERTY_JDO_MODIFIER,
+                               classname);
+        }
+    }
+
+    /**
+     *  Parses all fields of a given class.
+     *
+     *  @param  clazz  the representation of the class
+     *  @throws EnhancerMetaDataUserException on parse errors
+     */
+    private final void parseJDOFields(JDOClass clazz)
+        throws EnhancerMetaDataUserException
+    {
+        //search for fields of the class
+        for (Enumeration names = properties.propertyNames();
+             names.hasMoreElements();) {
+            String name = (String)names.nextElement();
+            if (name.startsWith(clazz.getName() + FIELD_DELIMITER)) {
+                //field found
+                String fieldname
+                    = name.substring(name.indexOf(FIELD_DELIMITER) + 1,
+                                     name.length());
+                validateFieldName(fieldname, clazz.getName());
+                clazz.addField(parseJDOField(properties.getProperty(name),
+                                             fieldname, clazz));
+            }
+        }
+        clazz.sortFields();
+    }
+
+    /**
+     *  Parses the attribute-string of a field.
+     *
+     *  @param  attributes  The attribute-string.
+     *  @param  fieldname   The fieldname.
+     *  @param  clazz       The class to field belongs to.
+     *  @throws  EnhancerMetaDataUserException  on parse errors
+     */
+    private final JDOField parseJDOField(String attributes,
+                                         String fieldname,
+                                         JDOClass clazz)
+        throws EnhancerMetaDataUserException
+    {
+        List props = parseProperties(attributes);
+
+        //check each property
+        for (int i = 0; i < props.size(); i++) {
+            Property prop = (Property)props.get(i);
+            validateFieldProperty(prop, fieldname, clazz.getName());
+        }
+
+        //check dependencies of all properties
+        checkForDuplicateProperties(props,
+                                    clazz.getName() + FIELD_DELIMITER
+                                    + fieldname);
+
+        //properties are OK - assign them to the JDOField object
+        JDOField field = new JDOField(fieldname);
+        for (int i = 0; i < props.size(); i++) {
+            Property prop = (Property)props.get(i);
+            if (prop.name.equals(PROPERTY_ACCESS_MODIFIER)) {
+                field.setModifiers(getModifiers(prop.value));
+            } else if (prop.name.equals(PROPERTY_JDO_MODIFIER)) {
+                field.setJdoModifier(prop.value);
+            } else if (prop.name.equals(PROPERTY_TYPE)) {
+                field.setType(prop.value);
+            } else if (prop.name.equals(PROPERTY_ANNOTATION_TYPE)) {
+                field.setAnnotationType(prop.value);
+            }
+        }
+
+        return field;
+    }
+
+    /**
+     *  Checks if the given attribute-property if valid for a field.
+     *
+     *  @param  prop       The attribute-property.
+     *  @param  fieldname  The fieldname.
+     *  @param  classname  The classname.
+     *  @throws  EnhancerMetaDataUserException  If the check fails.
+     */
+    private final void validateFieldProperty(Property prop,
+                                             String fieldname,
+                                             String classname)
+        throws EnhancerMetaDataUserException
+    {
+        //try to guess the property name
+        String value = prop.value;
+        if (prop.name == null) {
+            if (value.equals(ACCESS_PUBLIC)  ||
+                value.equals(ACCESS_PROTECTED)  ||
+                value.equals(ACCESS_PACKAGE_LOCAL)  ||
+                value.equals(ACCESS_PRIVATE)) {
+                // access modifier
+                prop.name = PROPERTY_ACCESS_MODIFIER;
+            } else if (value.equals(JDO_PERSISTENT)  ||
+                     value.equals(JDO_TRANSIENT)  ||
+                     value.equals(JDO_TRANSACTIONAL)) {
+                // persistence modifier
+                prop.name = PROPERTY_JDO_MODIFIER;
+            } else if (value.equals(ANNOTATION_TYPE_KEY)  ||
+                     value.equals(ANNOTATION_TYPE_DFG)  ||
+                     value.equals(ANNOTATION_TYPE_MEDIATED)) {
+                // annotation type
+                prop.name = PROPERTY_ANNOTATION_TYPE;
+            } else {
+                //assume the the given value is the type
+                prop.name = PROPERTY_TYPE;
+            }
+        } else {
+            String entry = classname + FIELD_DELIMITER + fieldname;
+
+            //do we have a valid property name?
+            checkPropertyName(prop.name,
+                              new String[]{
+                                  PROPERTY_ACCESS_MODIFIER,
+                                  PROPERTY_JDO_MODIFIER,
+                                  PROPERTY_TYPE,
+                                  PROPERTY_ANNOTATION_TYPE
+                              },
+                              entry);
+
+            //do we have a valid property value
+            checkPropertyValue(prop,
+                               new String[]{
+                                   ACCESS_PUBLIC,
+                                   ACCESS_PROTECTED,
+                                   ACCESS_PACKAGE_LOCAL,
+                                   ACCESS_PRIVATE
+                               },
+                               PROPERTY_ACCESS_MODIFIER,
+                               entry);
+            checkPropertyValue(prop,
+                               new String[]{
+                                   JDO_PERSISTENT,
+                                   JDO_TRANSIENT,
+                                   JDO_TRANSACTIONAL
+                               },
+                               PROPERTY_JDO_MODIFIER,
+                               entry);
+            checkPropertyValue(prop,
+                               new String[]{
+                                   ANNOTATION_TYPE_KEY,
+                                   ANNOTATION_TYPE_DFG,
+                                   ANNOTATION_TYPE_MEDIATED
+                               },
+                               PROPERTY_ANNOTATION_TYPE,
+                               entry);
+        }
+    }
+
+    /**
+     *  Validates dependencies between a class and its fields and between.
+     *
+     *  @param clazz the class
+     *  @throws  EnhancerMetaDataUserException  if the validation fails
+     */
+    private final void validateDependencies(JDOClass clazz)
+        throws EnhancerMetaDataUserException
+    {
+        final List fields = clazz.getFields();
+        for (Iterator i = fields.iterator(); i.hasNext();) {
+            JDOField field = (JDOField)i.next();
+
+            // check the jdo field modifier
+            if (field.isPersistent() && clazz.isTransient()) {
+                // non-persistent classes cannot have persistent fields
+                final String msg
+                    = getMsg(Msg.ERR_TRANSIENT_CLASS_WITH_PERSISTENT_FIELD,
+                             new String[]{
+                                 clazz.getName(),
+                                 field.getName() });
+                throw new EnhancerMetaDataUserException(msg);
+            }
+            if (field.isTransactional() && clazz.isTransient()) {
+                // non-persistent classes cannot have transactional fields
+                final String msg
+                    = getMsg(Msg.ERR_TRANSIENT_CLASS_WITH_TRANSACTIONAL_FIELD,
+                             new String[]{
+                                 clazz.getName(),
+                                 field.getName() });
+                throw new EnhancerMetaDataUserException(msg);
+            }
+            if (!field.isKnownTransient() && !field.isManaged()) {
+                // unspecified persistence modifier
+                final String msg
+                    = getMsg(Msg.ERR_UNSPECIFIED_FIELD_PERSISTENCE_MODIFIER,
+                             new String[]{
+                                 clazz.getName(),
+                                 field.getName() });
+                throw new EnhancerMetaDataUserException(msg);
+            }
+
+            // check annotation type
+            if (!field.isAnnotated() && field.isManaged()) {
+                // unspecified annotation type
+                final String msg
+                    = getMsg(Msg.ERR_UNSPECIFIED_FIELD_ANNOTATION_TYPE,
+                             new String[]{
+                                 clazz.getName(),
+                                 field.getName() });
+                throw new EnhancerMetaDataUserException(msg);
+            }
+            if (field.isAnnotated() && !field.isManaged()) {
+                // non managed field with annotation type
+                final String msg
+                    = getMsg(Msg.ERR_NON_MANAGED_ANNOTATED_FIELD,
+                             new String[]{
+                                 clazz.getName(),
+                                 field.getName() });
+                throw new EnhancerMetaDataUserException(msg);
+            }
+            if (field.isAnnotated() && clazz.isTransient()) {
+                // a non-persistent class cannot have an annotated field
+                final String msg
+                    = getMsg(Msg.ERR_TRANSIENT_CLASS_WITH_ANNOTATED_FIELD,
+                             new String[]{
+                                 clazz.getName(),
+                                 field.getName() });
+                throw new EnhancerMetaDataUserException(msg);
+            }
+        }
+    }
+
+    /**
+     *  Checks if a given fieldname is a valid Java identifier.
+     *
+     *  @param  fieldname  The fieldname.
+     *  @param  classname  The corresponding classname.
+     *  @throws  EnhancerMetaDataUserException  If the check fails.
+     */
+    static private void validateFieldName(String fieldname,
+                                          String classname)
+        throws EnhancerMetaDataUserException
+    {
+        if (fieldname.length() == 0) {
+            final String msg
+                = getMsg(Msg.ERR_EMPTY_FIELDNAME,
+                         new String[]{ classname });
+            throw new EnhancerMetaDataUserException(msg);
+        }
+
+        if (!Character.isJavaIdentifierStart(fieldname.charAt(0))) {
+            final String msg
+                = getMsg(Msg.ERR_INVALID_FIELDNAME,
+                         new String[]{ classname, fieldname });
+            throw new EnhancerMetaDataUserException(msg);
+        }
+
+        for (int i = fieldname.length() - 1; i >= 0; i--) {
+            final char c = fieldname.charAt(i);
+            if (!Character.isJavaIdentifierPart(c)) {
+                final String msg
+                    = getMsg(Msg.ERR_INVALID_FIELDNAME,
+                             new String[]{ classname, fieldname });
+                throw new EnhancerMetaDataUserException(msg);
+            }
+        }
+    }
+
+    /**
+     *  Checks if an attribute-property was entered twice for a class or field.
+     *
+     *  @param  props  The properties.
+     *  @param  entry  The class- or fieldname.
+     *  @throws  EnhancerMetaDataUserException  If the check fails.
+     */
+    static private void checkForDuplicateProperties(List props,
+                                                    String entry)
+        throws EnhancerMetaDataUserException
+    {
+        for (int i = 0; i < props.size(); i++) {
+            for (int j = i + 1; j < props.size(); j++) {
+                Property p1 = (Property)props.get(i);
+                Property p2 = (Property)props.get(j);
+                if (p1.name.equals(p2.name) && !p1.value.equals(p2.value)) {
+                    final String msg
+                        = getMsg(Msg.ERR_DUPLICATE_PROPERTY_NAME,
+                                 new String[]{
+                                     entry,
+                                     p1.name,
+                                     p1.value,
+                                     p2.value });
+                    throw new EnhancerMetaDataUserException(msg);
+                }
+            }
+        }
+    }
+
+    /**
+     *  Checks if an attribute name is recognized by the parser.
+     *
+     *  @param  name        The name of the attribute.
+     *  @param  validnames  A list of valid names(the attribute name has to
+     *                      be in this list).
+     *  @param  entry       The class- or fieldname.
+     *  @throws  EnhancerMetaDataUserException  If the check fails.
+     */
+    static private void checkPropertyName(String name,
+                                          String[] validnames,
+                                          String entry)
+        throws EnhancerMetaDataUserException
+    {
+        for (int i = 0; i < validnames.length; i++) {
+            if (name.equals(validnames[i])) {
+                return;
+            }
+        }
+
+        final String msg
+            = getMsg(Msg.ERR_INVALID_PROPERTY_NAME,
+                     new String[]{ entry, name });
+        throw new EnhancerMetaDataUserException(msg);
+    }
+
+    /**
+     *  Checks if the given value of an attribute-property is recognized by
+     *  by the parser if that value belongs to a given attribute name.
+     *
+     *  @param  prop         The attribute-property(with name and value).
+     *  @param  validvalues  A list of valid values.
+     *  @param  name         The name of the attribute-property to check.
+     *  @param  entry        The class- or fieldname.
+     *  @throws  EnhancerMetaDataUserException  If the check fails.
+     */
+    static private void checkPropertyValue(Property  prop,
+                                           String[] validvalues,
+                                                 String    name,
+                                                 String    entry)
+        throws EnhancerMetaDataUserException
+    {
+        if ( !prop.name.equals(name)) {
+            return;
+        }
+
+        for (int i = 0; i < validvalues.length; i++) {
+            if (prop.value.equals(validvalues[i])) {
+                return;
+            }
+        }
+
+        final String msg
+            = getMsg(Msg.ERR_INVALID_PROPERTY_VALUE,
+                     new String[]{ entry, name, prop.value });
+        throw new EnhancerMetaDataUserException(msg);
+    }
+
+    /**
+     *  Formats an error message with the given parameters.
+     *
+     *  @param  msg     The message with format strings.
+     *  @param  params  The params to format the message with.
+     *  @return  The formatted error message.
+     */
+    static final String getMsg(String   msg,
+                               String[] params)
+    {
+        return MessageFormat.format(msg, params);
+    }
+
+    /**
+     *  Parses the attribute-string of a class- or fieldname.
+     *
+     *  @param  attributes  The attribute-string.
+     *  @return  A list of <code>Propert<</code>-objects for the attributes.
+     *  @exception  EnhancerMetaDataUserException  If the parsing fails.
+     */
+    final List parseProperties(String attributes)
+        throws EnhancerMetaDataUserException
+    {
+        tmpTokens.clear();
+        for (StringTokenizer t
+                 = new StringTokenizer(attributes, PROPERTY_DELIMITERS);
+             t.hasMoreTokens();) {
+            tmpTokens.add(parseProperty(t.nextToken()));
+        }
+
+        return tmpTokens;
+    }
+
+    /**
+     *  Parses the given attribute and splits it into name and value.
+     *
+     *  @param  attribute  The attribute-string.
+     *  @return  The <code>Propert</code>-object.
+     *  @exception  EnhancerMetaDataUserException  If the parsing fails.
+     */
+    private final Property parseProperty(String attribute)
+        throws EnhancerMetaDataUserException
+    {
+        Property prop = new Property();
+        int idx = attribute.indexOf(PROPERTY_ASSIGNER);
+        if (idx < 0) {
+            prop.value = attribute;
+        } else {
+            prop.name = attribute.substring(0, idx);
+            prop.value = attribute.substring(idx + 1, attribute.length());
+            if (prop.name.length() == 0 || prop.value.length() == 0) {
+                final String msg
+                    = getMsg(Msg.ERR_EMPTY_PROPERTY_NAME_OR_VALUE,
+                             new String[]{ attribute });
+                throw new EnhancerMetaDataUserException(msg);
+            }
+        }
+
+        return prop;
+    }
+
+    /**
+     * Returns the modifier value for a Java modifier name.
+     */
+    static private int getModifiers(String modifier)
+    {
+        if (modifier.equals(ACCESS_PUBLIC)) {
+            return Modifier.PUBLIC;
+        }
+        if (modifier.equals(ACCESS_PRIVATE)) {
+            return Modifier.PRIVATE;
+        }
+        if (modifier.equals(ACCESS_PROTECTED)) {
+            return Modifier.PROTECTED;
+        }
+        return 0;
+    }
+
+    /**
+     *  A simple test to run from the command line.
+     *
+     *  @param  argv  The command line arguments.
+     */
+    public static void main(String[] argv)
+    {
+        if (argv.length != 1) {
+            System.err.println("Error: no property filename specified");
+            return;
+        }
+        final Properties p = new Properties();
+        try {
+            java.io.InputStream in
+                = new java.io.FileInputStream(new java.io.File(argv[0]));
+            p.load(in);
+            in.close();
+            System.out.println("PROPERTIES: " + p);
+            System.out.println("############");
+            final MetaDataProperties props = new MetaDataProperties(p);
+            String[] classnames = props.getKnownClassNames();
+            for (int i = 0; i < classnames.length; i++) {
+                String classname = classnames[i];
+                System.out.println(classname + ": "
+                                   + props.getJDOClass(classname));
+            }
+        } catch(Throwable ex) {
+            ex.printStackTrace(System.err);
+        }
+    }
+
+    /**
+     *  The holder-class for the name and the value of a property.
+     */
+    static private final class Property
+    {
+        /**
+         *  The name of the property.
+         */
+        String name = null;
+
+        /**
+         *  The value of the property.
+         */
+        String value = null;
+
+        /**
+         *  Creates a string-representation of this object.
+         *
+         *  @return  The string-representation of this object.
+         */
+        public final String toString()
+        {
+            return '<' + name + ':' + value + '>';
+        }
+    }
+
+    //^olsen: -> Bundle.properties
+
+    /**
+     *  Holds all unformatted error messages.
+     */
+    static private interface Msg
+    {
+        // the unformatted error messages
+        static final String PREFIX = "Error Parsing meta data properties: ";
+
+        static final String ERR_EMPTY_FIELDNAME =
+        PREFIX + "The class ''{0}'' may not have an empty fieldname.";
+
+        static final String ERR_INVALID_FIELDNAME =
+        PREFIX + "The field name ''{1}'' of class ''{0}'' is not valid.";
+
+        static final String ERR_EMPTY_PROPERTY_NAME_OR_VALUE  =
+        PREFIX + "The property name and value may not be empty if a ''" + 
+        PROPERTY_ASSIGNER + "'' is specified: ''{0}''.";
+
+        static final String ERR_INVALID_PROPERTY_NAME =
+        PREFIX + "Invalid property name for entry ''{0}'': ''{1}''.";
+
+        static final String ERR_INVALID_PROPERTY_VALUE =
+        PREFIX + "Invalid value for property ''{1}'' of entry ''{0}'': ''{2}''.";
+
+        static final String ERR_DUPLICATE_PROPERTY_NAME =
+        PREFIX + "The property ''{1}'' for the entry ''{0}'' entered twice with values: ''{2}'' and ''{3}''.";
+
+        static final String ERR_UNSPECIFIED_FIELD_PERSISTENCE_MODIFIER =
+        PREFIX + "No persistence modifier specified for field: ''{0}.{1}''.";
+
+        static final String ERR_TRANSIENT_CLASS_WITH_PERSISTENT_FIELD =
+        PREFIX + "A non-persistent class cannot have a persistent field(class ''{0}'' with field ''{1})''.";
+
+        static final String ERR_TRANSIENT_CLASS_WITH_TRANSACTIONAL_FIELD =
+        PREFIX + "A non-persistent class cannot have a transactional field(class ''{0}'' with field ''{1})''.";
+
+        static final String ERR_UNSPECIFIED_FIELD_ANNOTATION_TYPE =
+        PREFIX + "No annotation type specified for field: ''{0}.{1}''.";
+
+        static final String ERR_TRANSIENT_CLASS_WITH_ANNOTATED_FIELD =
+        PREFIX + "A non-persistent class cannot have an annotated field(''{1}'' of class ''{0}'') can''t have a fetch group.";
+
+        static final String ERR_NON_MANAGED_ANNOTATED_FIELD =
+        PREFIX + "A non-managed field(''{1}'' of class ''{0}'') can''t be a annotated.";
+    }
+}

Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/prop/NameHelper.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/prop/NameHelper.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/prop/NameHelper.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/prop/NameHelper.java Sun May 22 10:55:51 2005
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.jdo.impl.enhancer.meta.prop;
+
+
+/**
+ * Some utility methods for classname conversion.
+ */
+final class NameHelper
+{
+    /**
+     *  Converts a classname given in a given VM-similar notation(with slashes)
+     *  into a canonical notation (with dots).
+     *
+     *  @param  classname The VM-similar notation of the classname.
+     *  @return  The canonical classname.
+     *  @see  #fromCanonicalClassName
+     */
+    static String toCanonicalClassName(String classname)
+    {
+        return classname.replace('/', '.');
+    }
+
+    /**
+     *  Converts a classname given in a canonical form(with dots) into
+     *  a VM-similar notation (with slashes)
+     *
+     *  @param  classname  The canonical classname.
+     *  @return  The VM-similar classname notation.
+     *  @see  #toCanonicalClassName
+     */
+    static String fromCanonicalClassName(String classname)
+    {
+        return classname.replace('.', '/');
+    }
+}

Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/util/EnhancerMetaDataBaseModel.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/util/EnhancerMetaDataBaseModel.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/util/EnhancerMetaDataBaseModel.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/util/EnhancerMetaDataBaseModel.java Sun May 22 10:55:51 2005
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.jdo.impl.enhancer.meta.util;
+
+import java.io.PrintWriter;
+
+import java.util.Iterator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ArrayList;
+
+import org.apache.jdo.impl.enhancer.meta.EnhancerMetaData;
+import org.apache.jdo.impl.enhancer.meta.EnhancerMetaDataFatalError;
+import org.apache.jdo.impl.enhancer.meta.EnhancerMetaDataUserException;
+import org.apache.jdo.impl.enhancer.util.Support;
+
+
+
+/**
+ * Provides the JDO meta information based on a JDO meta model.
+ */
+public abstract class EnhancerMetaDataBaseModel
+    extends Support
+    implements EnhancerMetaData
+{
+    // misc
+    protected boolean verbose = true;
+    protected final PrintWriter out;
+
+    // default settings
+    static protected final HashSet unenhancableTypePrefixes = new HashSet();
+    static
+    {
+        unenhancableTypePrefixes.add("java/");
+        unenhancableTypePrefixes.add("javax/");
+    }
+
+    /**
+     * Creates an instance.
+     */
+    public EnhancerMetaDataBaseModel(PrintWriter out,
+                                     boolean verbose)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        affirm(out != null);
+        this.out = out;
+    }
+
+    /**
+     *  Prints out a warning message.
+     *
+     *  @param msg the message
+     */
+    public void printWarning(String msg)
+    {
+        out.println(getI18N("enhancer.metadata.warning", msg));
+    }
+
+    /**
+     *  Prints out a verbose message.
+     *
+     *  @param msg the message
+     */
+    public void printMessage(String msg)
+    {
+        if (verbose) {
+            out.println(getI18N("enhancer.metadata.message", msg));
+        }
+    }
+
+    /**
+     * Returns whether a class is not to be modified by the enhancer.
+     *
+     * @see EnhancerMetaData#isKnownUnenhancableClass(String)
+     */
+    public boolean isKnownUnenhancableClass(String classPath)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        //check the transient prefixes
+        for (Iterator i = unenhancableTypePrefixes.iterator(); i.hasNext();) {
+            final String typePrefix = (String)i.next();
+            if (classPath.startsWith(typePrefix))
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns whether a class is persistence-capable root class.
+     *
+     * @see EnhancerMetaData#isPersistenceCapableRootClass(String)
+     */
+    public boolean isPersistenceCapableRootClass(String classPath)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        return (isPersistenceCapableClass(classPath)
+                && (getPersistenceCapableSuperClass(classPath) == null));
+    }
+
+    /**
+     * Returns the name of the persistence-capable root class of a class.
+     *
+     * @see EnhancerMetaData#getPersistenceCapableRootClass(String)
+     */
+    public String getPersistenceCapableRootClass(String classPath)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        if (!isPersistenceCapableClass(classPath)) {
+            return null;
+        }
+
+        String pcRootClass;
+        String clazz = classPath;
+        do {
+            pcRootClass = clazz;
+            clazz = getPersistenceCapableSuperClass(clazz);
+        } while (clazz != null);
+        return pcRootClass;
+    }
+
+    /**
+     * Returns the name of the key class of the next persistence-capable
+     * superclass that defines one.
+     *
+     * @see EnhancerMetaData#getSuperKeyClass(String)
+     */
+    public String getSuperKeyClass(String classPath)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        for (String superClass = getPersistenceCapableSuperClass(classPath);
+             superClass != null;
+             superClass = getPersistenceCapableSuperClass(superClass)) {
+            final String superKeyClass = getKeyClass(superClass);
+            if (superKeyClass != null) {
+                return superKeyClass;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns whether a field of a class is known to be either transient
+     * transactional or persistent.
+     *
+     * @see EnhancerMetaData#isManagedField(String, String)
+     */
+    public boolean isManagedField(String classPath, String fieldName)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        return (isPersistentField(classPath, fieldName)
+                || isTransactionalField(classPath, fieldName));
+    }
+
+    /**
+     * Returns the field flags of a declared, managed field of a class.
+     *
+     * @see EnhancerMetaData#getFieldFlags(String, String)
+     */
+    public int getFieldFlags(String classPath, String fieldName)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        if (!isManagedField(classPath, fieldName)) {
+            affirm(!isTransactionalField(classPath, fieldName));
+            affirm(!isPersistentField(classPath, fieldName));
+            affirm(!isKeyField(classPath, fieldName));
+            affirm(!isDefaultFetchGroupField(classPath, fieldName));
+            return 0;
+        }
+        //affirm(isManagedField(classPath, fieldName));
+
+        if (isTransactionalField(classPath, fieldName)) {
+            affirm(!isPersistentField(classPath, fieldName));
+            affirm(!isKeyField(classPath, fieldName));
+            // ignore any dfg membership of transactional fields
+            //affirm(!isDefaultFetchGroupField(classPath, fieldName));
+            return CHECK_WRITE;
+        }
+        //affirm(!isTransactionalField(classPath, fieldName));
+        affirm(isPersistentField(classPath, fieldName));
+
+        if (isKeyField(classPath, fieldName)) {
+            // ignore any dfg membership of key fields
+            //affirm(!isDefaultFetchGroupField(classPath, fieldName));
+            return MEDIATE_WRITE;
+        }
+        //affirm(!isKeyField(classPath, fieldName));
+            
+        if (isDefaultFetchGroupField(classPath, fieldName)) {
+            return CHECK_READ | CHECK_WRITE;
+        }
+        //affirm(!isDefaultFetchGroupField(classPath, fieldName));
+
+        return MEDIATE_READ | MEDIATE_WRITE;
+    }
+
+    /**
+     * Returns an array of field names of all key fields of a class.
+     *
+     * @see EnhancerMetaData#getKeyFields(String)
+     */
+    public String[] getKeyFields(String classPath)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        final List keys = new ArrayList();
+        final String[] fieldNames = getManagedFields(classPath);
+        final int n = fieldNames.length;
+        for (int i = 0; i < n; i++) {
+            if (isKeyField(classPath, fieldNames[i])) {
+                keys.add(fieldNames[i]);
+            }
+        }
+        return (String[])keys.toArray(new String[keys.size()]);
+    }
+
+    /**
+     * Returns the field flags for some declared, managed fields of a class.
+     *
+     * @see EnhancerMetaData#getFieldFlags(String, String[])
+     */
+    public int[] getFieldFlags(String classPath, String[] fieldNames)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        final int n = (fieldNames != null ? fieldNames.length : 0);
+        final int[] flags = new int[n];
+        for (int i = 0; i < n; i++) {
+            flags[i] = getFieldFlags(classPath, fieldNames[i]);
+        }
+        return flags;
+    }
+
+    /**
+     * Returns the unique field index of some declared, managed fields of a
+     * class.
+     *
+     * @see EnhancerMetaData#getFieldNumber(String, String[])
+     */
+    public int[] getFieldNumber(String classPath, String[] fieldNames)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        final int n = (fieldNames != null ? fieldNames.length : 0);
+        final int[] flags = new int[n];
+        for (int i = 0; i < n; i++) {
+            flags[i] = getFieldNumber(classPath, fieldNames[i]);
+        }
+        return flags;
+    }
+}

Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/util/EnhancerMetaDataTimer.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/util/EnhancerMetaDataTimer.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/util/EnhancerMetaDataTimer.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/meta/util/EnhancerMetaDataTimer.java Sun May 22 10:55:51 2005
@@ -0,0 +1,325 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.jdo.impl.enhancer.meta.util;
+
+import org.apache.jdo.impl.enhancer.meta.EnhancerMetaData;
+import org.apache.jdo.impl.enhancer.meta.EnhancerMetaDataFatalError;
+import org.apache.jdo.impl.enhancer.meta.EnhancerMetaDataUserException;
+import org.apache.jdo.impl.enhancer.util.Support;
+
+
+
+
+public final class EnhancerMetaDataTimer
+    extends Support
+    implements EnhancerMetaData
+{
+    // delegate
+    final protected EnhancerMetaData delegate;
+
+    /**
+     * Creates an instance.
+     */
+    public EnhancerMetaDataTimer(EnhancerMetaData delegate)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        affirm(delegate);
+        this.delegate = delegate;
+    }
+
+    public String getDeclaringClass(String classPath, String fieldName)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        try {
+            timer.push("EnhancerMetaData.getDeclaringClass(String,String)",
+                       "EnhancerMetaData.getDeclaringClass(" + classPath 
+                       + ", " + fieldName + ")");
+            return delegate.getDeclaringClass(classPath, fieldName);
+        } finally {
+            timer.pop();
+        }
+    }
+
+    public void declareField(String classPath,
+                             String fieldName,
+                             String signature)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        try {
+            timer.push("EnhancerMetaData.declareField(String,String,String)",
+                       "EnhancerMetaData.declareField(" + classPath
+                       + ", " + fieldName + ", " + signature + ")");
+            delegate.declareField(classPath, fieldName, signature);
+        } finally {
+            timer.pop();
+        }
+    }
+    
+    public boolean isPersistenceCapableClass(String classPath)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        try {
+            timer.push("EnhancerMetaData.isPersistenceCapableClass(String)",
+                       "EnhancerMetaData.isPersistenceCapableClass(" + classPath + ")");
+            return delegate.isPersistenceCapableClass(classPath);
+        } finally {
+            timer.pop();
+        }
+    }
+
+    public boolean isSerializableClass(String classPath)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        try {
+            timer.push("EnhancerMetaData.isSerializableClass(String)",
+                       "EnhancerMetaData.isSerializableClass(" + classPath + ")");
+            return delegate.isSerializableClass(classPath);
+        } finally {
+            timer.pop();
+        }
+    }
+
+    public boolean isKnownUnenhancableClass(String classPath)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        try {
+            timer.push("EnhancerMetaData.isKnownUnenhancableClass(String)",
+                       "EnhancerMetaData.isKnownUnenhancableClass(" + classPath + ")");
+            return delegate.isKnownUnenhancableClass(classPath);
+        } finally {
+            timer.pop();
+        }
+    }
+
+    public boolean isPersistenceCapableRootClass(String classPath)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        try {
+            timer.push("EnhancerMetaData.isPersistenceCapableRootClass(String)",
+                       "EnhancerMetaData.isPersistenceCapableRootClass(" + classPath + ")");
+            return delegate.isPersistenceCapableRootClass(classPath);
+        } finally {
+            timer.pop();
+        }
+    }
+
+    public String getPersistenceCapableRootClass(String classPath)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        try {
+            timer.push("EnhancerMetaData.getPersistenceCapableRootClass(String)",
+                       "EnhancerMetaData.getPersistenceCapableRootClass(" + classPath + ")");
+            return delegate.getPersistenceCapableRootClass(classPath);
+        } finally {
+            timer.pop();
+        }
+    }
+
+    public String getPersistenceCapableSuperClass(String classPath)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        try {
+            timer.push("EnhancerMetaData.getPersistenceCapableSuperClass(String)",
+                       "EnhancerMetaData.getPersistenceCapableSuperClass(" + classPath + ")");
+            return delegate.getPersistenceCapableSuperClass(classPath);
+        } finally {
+            timer.pop();
+        }
+    }
+
+    public String getKeyClass(String classPath)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        try {
+            timer.push("EnhancerMetaData.getKeyClass(String)",
+                       "EnhancerMetaData.getKeyClass(" + classPath + ")");
+            return delegate.getKeyClass(classPath);
+        } finally {
+            timer.pop();
+        }
+    }
+
+    public String getSuperKeyClass(String classPath)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        try {
+            timer.push("EnhancerMetaData.getSuperKeyClass(String)",
+                       "EnhancerMetaData.getSuperKeyClass(" + classPath + ")");
+            return delegate.getSuperKeyClass(classPath);
+        } finally {
+            timer.pop();
+        }
+    }
+
+    public boolean isKnownNonManagedField(String classPath,
+                                          String fieldName,
+                                          String fieldSig)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        try {
+            timer.push("EnhancerMetaData.isKnownNonManagedField(String,String,String)",
+                       "EnhancerMetaData.isKnownNonManagedField(" + classPath
+                       + ", " + fieldName + ", " + fieldSig + ")");
+            return delegate.isKnownNonManagedField(classPath,
+                                                   fieldName, fieldSig);
+        } finally {
+            timer.pop();
+        }
+    }
+
+    public boolean isManagedField(String classPath, String fieldName)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        try {
+            timer.push("EnhancerMetaData.isManagedField(String,String)",
+                       "EnhancerMetaData.isManagedField(" + classPath
+                       + ", " + fieldName + ")");
+            return delegate.isManagedField(classPath, fieldName);
+        } finally {
+            timer.pop();
+        }
+    }
+
+    public boolean isPersistentField(String classPath, String fieldName)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        try {
+            timer.push("EnhancerMetaData.isPersistentField(String,String)",
+                       "EnhancerMetaData.isPersistentField(" + classPath
+                       + ", " + fieldName + ")");
+            return delegate.isPersistentField(classPath, fieldName);
+        } finally {
+            timer.pop();
+        }
+    }
+
+    public boolean isTransactionalField(String classPath, String fieldName)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        try {
+            timer.push("EnhancerMetaData.isTransactionalField(String,String)",
+                       "EnhancerMetaData.isTransactionalField(" + classPath
+                       + ", " + fieldName + ")");
+            return delegate.isTransactionalField(classPath, fieldName);
+        } finally {
+            timer.pop();
+        }
+    }
+
+    public boolean isKeyField(String classPath, String fieldName)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        try {
+            timer.push("EnhancerMetaData.isKeyField(String,String)",
+                       "EnhancerMetaData.isKeyField(" + classPath
+                       + ", " + fieldName + ")");
+            return delegate.isKeyField(classPath, fieldName);
+        } finally {
+            timer.pop();
+        }
+    }
+
+    public boolean isDefaultFetchGroupField(String classPath, String fieldName)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        try {
+            timer.push("EnhancerMetaData.isDefaultFetchGroupField(String,fieldName)",
+                       "EnhancerMetaData.isDefaultFetchGroupField(" + classPath
+                       + ", " + fieldName + ")");
+            return delegate.isDefaultFetchGroupField(classPath, fieldName);
+        } finally {
+            timer.pop();
+        }
+    }
+
+    public int getFieldFlags(String classPath, String fieldName)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        try {
+            timer.push("EnhancerMetaData.getFieldFlags(String, String)",
+                       "EnhancerMetaData.getFieldFlags(" + classPath
+                       + ", " + fieldName + ")");
+            return delegate.getFieldFlags(classPath, fieldName);
+        } finally {
+            timer.pop();
+        }
+    }
+
+    public int getFieldNumber(String classPath, String fieldName)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        try {
+            timer.push("EnhancerMetaData.getFieldNumber(String, String)",
+                       "EnhancerMetaData.getFieldNumber(" + classPath
+                       + ", " + fieldName + ")");
+            return delegate.getFieldNumber(classPath, fieldName);
+        } finally {
+            timer.pop();
+        }
+    }
+
+    public String[] getManagedFields(String classPath)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        try {
+            timer.push("EnhancerMetaData.getManagedFields(String)",
+                       "EnhancerMetaData.getmanagedFields(" + classPath + ")");
+            return delegate.getManagedFields(classPath);
+        } finally {
+            timer.pop();
+        }
+    }
+
+    public String[] getKeyFields(String classPath)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        try {
+            timer.push("EnhancerMetaData.getKeyFields(String)",
+                       "EnhancerMetaData.getKeyFields(" + classPath + ")");
+            return delegate.getKeyFields(classPath);
+        } finally {
+            timer.pop();
+        }
+    }
+
+
+    public int[] getFieldFlags(String classPath, String[] fieldNames)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        try {
+            timer.push("EnhancerMetaData.getFieldFlags(String, String[])",
+                       "EnhancerMetaData.getFieldFlags(" + classPath + ")");
+            return delegate.getFieldFlags(classPath, fieldNames);
+        } finally {
+            timer.pop();
+        }
+    }
+
+
+    public int[] getFieldNumber(String classPath, String[] fieldNames)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        try {
+            timer.push("EnhancerMetaData.getFieldNumber(String, String[])",
+                       "EnhancerMetaData.getFieldNumber(" + classPath + ")");
+            return delegate.getFieldNumber(classPath, fieldNames);
+        } finally {
+            timer.pop();
+        }
+    }
+}

Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/AnnotationTest.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/AnnotationTest.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/AnnotationTest.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/AnnotationTest.java Sun May 22 10:55:51 2005
@@ -0,0 +1,418 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.jdo.impl.enhancer.util;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Enumeration;
+import java.util.List;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.IOException;
+import java.io.DataInputStream;
+
+import org.apache.jdo.impl.enhancer.EnhancerFatalError;
+import org.apache.jdo.impl.enhancer.JdoMetaMain;
+import org.apache.jdo.impl.enhancer.classfile.ClassFile;
+import org.apache.jdo.impl.enhancer.classfile.ClassMethod;
+import org.apache.jdo.impl.enhancer.classfile.CodeAttribute;
+import org.apache.jdo.impl.enhancer.classfile.ConstClass;
+import org.apache.jdo.impl.enhancer.classfile.ConstFieldRef;
+import org.apache.jdo.impl.enhancer.classfile.ConstMethodRef;
+import org.apache.jdo.impl.enhancer.classfile.ConstNameAndType;
+import org.apache.jdo.impl.enhancer.classfile.Descriptor;
+import org.apache.jdo.impl.enhancer.classfile.Insn;
+import org.apache.jdo.impl.enhancer.classfile.InsnConstOp;
+import org.apache.jdo.impl.enhancer.classfile.VMConstants;
+import org.apache.jdo.impl.enhancer.meta.EnhancerMetaData;
+import org.apache.jdo.impl.enhancer.meta.EnhancerMetaDataFatalError;
+import org.apache.jdo.impl.enhancer.meta.EnhancerMetaDataUserException;
+
+
+
+
+
+/**
+ * Utility class for testing a class file for correct annotation.
+ *
+ * @author Martin Zaun
+ */
+public class AnnotationTest
+    extends JdoMetaMain
+{
+    // return values of internal test methods
+    static public final int AFFIRMATIVE = 1;
+    static public final int NEGATIVE = 0;
+    static public final int ERROR = -1;
+
+    // ----------------------------------------------------------------------
+
+    private boolean verbose;
+    private String className;
+    private String classFileName;
+    private ClassFile classFile;
+
+    public AnnotationTest(PrintWriter out,
+                          PrintWriter err)
+    {
+        super(out, err);
+    }
+
+    private int checkGetPutField(PrintWriter out,
+                                 Insn insn,
+                                 boolean jdoMethod) 
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        // get the instruction arguments
+        final InsnConstOp fieldInsn = (InsnConstOp)insn;
+        final ConstFieldRef fieldRef = (ConstFieldRef)fieldInsn.value();
+        final ConstClass declClass = fieldRef.className();
+        final String declClassName = declClass.asString();
+        final ConstNameAndType fieldNameAndType = fieldRef.nameAndType();
+        final String fieldName = fieldNameAndType.name().asString();
+        final String fieldType = fieldNameAndType.signature().asString();
+
+        // check if field is known to be non-managed or not annotatable
+        final int res;
+        if (jdoMeta.isKnownNonManagedField(declClassName,
+                                           fieldName, fieldType)) {
+            if (false) { // verbose
+                out.println("        --- unannotated field access: "
+                            + declClassName + "." + fieldName);
+            }
+            res = NEGATIVE;
+        } else if (jdoMethod) {
+            if (false) { // verbose
+                out.println("        --- unannotated field access: "
+                            + declClassName + "." + fieldName);
+            } 
+            res = NEGATIVE;
+        } else if (jdoMeta.isPersistenceCapableClass(declClassName)
+                   && (fieldName.equals("jdoStateManager")
+                       || fieldName.equals("jdoFlags"))) {
+            if (false) { // verbose
+                out.println("        --- unannotated field access: "
+                            + declClassName + "." + fieldName);
+            } 
+            res = NEGATIVE;
+        } else {
+            out.println("        !!! ERROR: missing annotation of field access: "
+                        + declClassName + "." + fieldName);
+            res = ERROR;
+        }
+        return res;
+    }
+    
+    private int checkInvokeStatic(PrintWriter out,
+                                  Insn insn,
+                                  boolean jdoMethod) 
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        // get the instruction arguments
+        final InsnConstOp methodInsn = (InsnConstOp)insn;
+        final ConstMethodRef methodRef = (ConstMethodRef)methodInsn.value();
+        final ConstClass declClass = methodRef.className();
+        final String declClassName = declClass.asString();
+        final ConstNameAndType methodNameAndType = methodRef.nameAndType();
+        final String methodName = methodNameAndType.name().asString();
+        final String methodType = methodNameAndType.signature().asString();
+
+        if (!methodName.startsWith("jdoSet")
+            && (!methodName.startsWith("jdoGet")
+                || methodName.equals("jdoGetManagedFieldCount"))) {
+            return NEGATIVE;
+        }
+        final String fieldName = methodName.substring(6);
+
+        final int res;
+        final String fieldType;
+        if (methodName.startsWith("jdoGet")) {
+            fieldType = Descriptor.extractResultSig(methodType);
+        } else {
+            final String argSig = Descriptor.extractArgSig(methodType);
+            final int idx = Descriptor.nextSigElement(argSig, 0);
+            fieldType = argSig.substring(idx);
+        }
+        affirm(fieldType != null);
+        
+        // check if field is known to be non-managed or non-annotable
+        if (jdoMeta.isKnownNonManagedField(declClassName,
+                                           fieldName, fieldType)) {
+            out.println("        !!! ERROR: annotated access to non-managed field: "
+                        + declClassName + "." + fieldName);
+            res = ERROR;
+        } else if (jdoMethod) {
+            out.println("        !!! ERROR: annotated field access in JDO method: "
+                        + declClassName + "." + fieldName);
+            res = ERROR;
+        } else {
+            if (verbose) {
+                out.println("        +++ annotated field access: "
+                            + declClassName + "." + fieldName);
+            }
+            res = AFFIRMATIVE;
+        }
+
+        return res;
+    }
+    
+    private int hasAnnotation(PrintWriter out,
+                              ClassMethod method,
+                              String methodName) 
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        final CodeAttribute codeAttr = method.codeAttribute();
+
+        // return if method is abstract or native
+        if (codeAttr == null)
+            return NEGATIVE;
+
+        int res = NEGATIVE;
+        // don't annotate readObject(ObjectInputStream) or any jdo* methods
+        // except for jdoPreStore() and jdoPreDelete().
+        final boolean jdoMethod
+            = ((methodName.startsWith("jdo") 
+                && !(methodName.equals("jdoPreStore()")
+                     || methodName.equals("jdoPreDelete()")))
+               || methodName.equals("readObject(java.io.ObjectInputStream)"));
+
+        // first instruction is a target
+        final Insn firstInsn = codeAttr.theCode();
+        Insn insn = firstInsn.next();
+        while (insn != null) {
+            switch(insn.opcode()) {
+            case VMConstants.opc_getfield:
+            case VMConstants.opc_putfield: {
+                final int r = checkGetPutField(out, insn, jdoMethod);
+                if (r < NEGATIVE) {
+                    res = ERROR;
+                }
+                break;
+            }
+            case VMConstants.opc_invokestatic: {
+                final int r = checkInvokeStatic(out, insn, jdoMethod);
+                if (r < NEGATIVE) {
+                    res = ERROR;
+                } else if (r > NEGATIVE) {
+                    if (res == NEGATIVE) {
+                        res = AFFIRMATIVE;
+                    }
+                }
+                break;
+            }
+            default:
+            }
+
+            insn = insn.next();
+        }
+
+        return res;
+    }
+
+    private int testAnnotation(PrintWriter out)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        affirm(ERROR < NEGATIVE && NEGATIVE < AFFIRMATIVE);
+        affirm(classFile);
+
+        int res = NEGATIVE;
+        
+        Enumeration e = classFile.methods().elements();
+        while (e.hasMoreElements()) {
+            final ClassMethod method = (ClassMethod)e.nextElement();
+            final String methodSig = method.signature().asString();
+            final String methodArgs = Descriptor.userMethodArgs(methodSig);
+            final String methodName = method.name().asString() + methodArgs;
+            
+            // check class-specific enhancement
+            final StringWriter s = new StringWriter();
+            int r = hasAnnotation(new PrintWriter(s), method, methodName);
+            if (r < NEGATIVE) {
+                out.println("    !!! ERROR: incorrect annotation in: "
+                            + methodName);
+                out.println(s.toString());
+                res = ERROR;
+            } else if (r == NEGATIVE) {
+                if (verbose) {
+                    out.println("    --- not annotated: "
+                                + methodName);
+                    out.println(s.toString());
+                }
+            } else {
+                affirm(r > NEGATIVE);
+                if (verbose) {
+                    out.println("    +++ has correct annotation: "
+                                + methodName);
+                    out.println(s.toString());
+                }
+                if (res == NEGATIVE) {
+                    res = AFFIRMATIVE;
+                }
+            }
+        }
+        
+        return res;
+    }
+
+    private int parseClass(PrintWriter out)
+    {
+        DataInputStream dis = null;
+        try {
+            affirm(className == null ^ classFileName == null);
+            if (className != null) {
+                dis = new DataInputStream(openClassInputStream(className));
+            } else {
+                dis = new DataInputStream(openFileInputStream(classFileName));
+            }
+            final boolean allowJDK12ClassFiles = true;
+            classFile = new ClassFile(dis, allowJDK12ClassFiles);
+
+            // check user class name from ClassFile
+            final String userClassName
+                = classFile.className().asString().replace('/', '.');
+            //^olsen: better throw user exception or error
+            affirm(className == null || className.equals(userClassName));
+            out.println("    +++ parsed classfile");
+        } catch (ClassFormatError ex) {
+            out.println("    !!! ERROR: format error when parsing class: "
+                        + className);
+            out.println("        error: " + err);
+            return ERROR;
+        } catch (IOException ex) {
+            out.println("    !!! ERROR: exception while reading class: "
+                        + className);
+            out.println("        exception: " + ex);
+            return ERROR;
+        } finally {
+            closeInputStream(dis);
+        }
+
+        affirm(classFile);
+        return AFFIRMATIVE;
+    }
+
+    private int test(PrintWriter out,
+                     String className,
+                     String classFileName)
+        throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
+    {
+        this.className = className;
+        this.classFileName = classFileName;
+        affirm(className == null ^ classFileName == null);
+        final String name = (className != null ? className : classFileName);
+
+        if (verbose) {
+            out.println("-------------------------------------------------------------------------------");
+            out.println();
+            out.println("Test class for correct annotation: "
+                        + name + " ...");
+        }
+        
+        // check parsing class
+        StringWriter s = new StringWriter();
+        if (parseClass(new PrintWriter(s)) <= NEGATIVE) {
+            out.println();
+            out.println("!!! ERROR: failed parsing class: " + name);
+            out.println(s.toString());
+            return ERROR;
+        }
+
+        if (verbose) {
+            out.println();
+            out.println("+++ parsed class: " + name);
+            out.println(s.toString());
+        }
+        
+        // check annotation
+        s = new StringWriter();
+        final int r = testAnnotation(new PrintWriter(s));
+        if (r < NEGATIVE) {
+            out.println();
+            out.println("!!! ERROR: incorrect annotation: " + name);
+            out.println(s.toString());
+            return ERROR;
+        }
+        
+        if (r == NEGATIVE) {
+            out.println();
+            out.println("--- class not annotated: " + name);
+        } else {
+            out.println();
+            out.println("+++ class annotated: " + name);
+        }
+        if (verbose) {
+            out.println(s.toString());
+        }
+
+        return r;
+    }
+
+    protected int test(PrintWriter out,
+                       boolean verbose,
+                       List classNames,
+                       List classFileNames)
+    {
+        affirm(classNames);
+        this.verbose = verbose;
+
+        out.println();
+        out.println("AnnotationTest: Testing Classes for JDO Persistence-Capability Enhancement");
+
+        int nofFailed = 0;
+        final int all = classNames.size() + classFileNames.size();
+        for (int i = 0; i < classNames.size(); i++) {
+            if (test(out, (String)classNames.get(i), null) < NEGATIVE) {
+                nofFailed++;
+            }
+        }
+        for (int i = 0; i < classFileNames.size(); i++) {
+            if (test(out, null, (String)classFileNames.get(i)) < NEGATIVE) {
+                nofFailed++;
+            }
+        }
+        final int nofPassed = all - nofFailed;
+
+        out.println();
+        out.println("AnnotationTest: Summary:  TESTED: " + all
+                    + "  PASSED: " + nofPassed
+                    + "  FAILED: " + nofFailed);
+        return nofFailed;
+    }
+    
+    // ----------------------------------------------------------------------
+
+    /**
+     * Run the annotation test.
+     */
+    protected int process()
+    {
+        //^olsen: to be extended for zip/jar file arguments
+        return test(out, options.verbose.value,
+                    options.classNames, options.classFileNames);
+    }
+
+    static public void main(String[] args)
+    {
+        final PrintWriter out = new PrintWriter(System.out, true);
+        out.println("--> AnnotationTest.main()");
+        final AnnotationTest main = new AnnotationTest(out, out);
+        int res = main.run(args);
+        out.println("<-- AnnotationTest.main(): exit = " + res);
+        System.exit(res);
+    }
+}

Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/Assertion.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/Assertion.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/Assertion.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/util/Assertion.java Sun May 22 10:55:51 2005
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.jdo.impl.enhancer.util;
+
+
+/**
+ * Support for signalling internal implementation errors.
+ */
+public class Assertion {
+
+    static protected final void affirm(boolean condition) {
+        if (!condition)
+            throw new InternalError("assertion failed.");
+    }
+
+    static protected final void affirm(boolean condition, String msg) {
+        if (!condition)
+            throw new InternalError("assertion failed: " + msg);
+    }
+
+    static protected final void affirm(Object object) {
+        if (object == null)
+            throw new InternalError("assertion failed.");
+    }
+
+    static protected final void affirm(Object object, String msg) {
+        if (object == null)
+            throw new InternalError("assertion failed: " + msg);
+    }
+}