FileDocCategorySizeDatePackage
JDOMetaDataProperties.javaAPI DocGlassfish v2 API57944Fri May 04 22:34:38 BST 2007com.sun.jdo.api.persistence.enhancer.meta

JDOMetaDataProperties

public final class JDOMetaDataProperties extends Object
This class parses properties containing meta data information about classes. The syntax of the properties is the following:
  • the keys in the properties file are fully qualified classnames or fully qualified fieldnames
  • a fields is separated by a classname with a hash mark ('#') (e.g. "test.Test#test1")
  • all classnames are given in a natural form (e.g. "java.lang.Integer", "java.lang.Integer[][]", "int", "test.Test$Test1")
  • property keys are classnames and fieldnames (e.g. "test.Test=...", "test.Test#field1=...")
  • Classnames can have the following attributes:
    • jdo:{persistent|transactional}
    • super: <classname>
    • access: {public|protected|package|private}
  • Fieldnames can have the following attributes:
    • type:<type>
    • access: {public|protected|package|private}
    • jdo:{persistent|transactional|transient}
    • annotation:{pk|dfg|mediated}
  • the names of the attributes can be ommitted: you can say
    test.Test1#field1=jdo:persistent,type:java.lang.String,pk,...
    or
    test.Test1#field1=persistent,java.lang.String,pk,...
    or
    test.Test1#field1=jdo:persistent,java.lang.String,pk,...
  • in order to find fields of a class, a line for the class has to be specified in the properties: To find the field test.Test1#field, the keys test.Test1 and test.Test1#Field have to be present.
This class is not thread safe.

Fields Summary
private static final char
FIELD_DELIMITER
The delimiter of a property key between the class- and fieldname.
private static final String
PROPERTY_DELIMITERS
A string of delimiter characters between attributes.
private static final char
PROPERTY_ASSIGNER
A delimiter character between attribute name and attribute value
private static final String
PROPERTY_ACCESS_MODIFIER
private static final String
PROPERTY_JDO_MODIFIER
private static final String
PROPERTY_SUPER_CLASSNAME
private static final String
PROPERTY_OID_CLASSNAME
private static final String
PROPERTY_TYPE
private static final String
PROPERTY_ANNOTATION_TYPE
private static final String
ACCESS_PRIVATE
private static final String
ACCESS_PACKAGE_LOCAL
private static final String
ACCESS_PROTECTED
private static final String
ACCESS_PUBLIC
private static final String
JDO_TRANSIENT
private static final String
JDO_PERSISTENT
private static final String
JDO_TRANSACTIONAL
private static final String
ANNOTATION_TYPE_PK
private static final String
ANNOTATION_TYPE_DFG
private static final String
ANNOTATION_TYPE_MEDIATED
private Properties
properties
The properties to parse.
private final Map
cachedJDOClasses
A map of already read class properties. The keys are the classnames, the values are the appropriate JDOClass-object.
private static final JDOClass
NULL
A constant for the cache indicating that a given classname if not specified in the properties.
private final List
tmpTokens
A temporary vector (this is the reason why the implementation is not thread safe).
Constructors Summary
public JDOMetaDataProperties(Properties props)
Creates a new object with the given properties.

param
props The properties.
see
#properties



                             

       
    

        this.properties = props;

    
Methods Summary
private static final voidcheckForDuplicateProperties(java.util.List props, java.lang.String entry)
Checks if an attribute-property was entered twice for a class or field.

param
props The properties.
param
entry The class- or fieldname.
throws
JDOMetaDataUserException If the check fails.


        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))
                {
                    throw new JDOMetaDataUserException (getErrorMsg (IErrorMessages.ERR_DUPLICATE_PROPERTY_NAME,
                                                                     new String [] { entry, p1.name, p1.value, p2.value }));
                }
            }
        }

    
private static final voidcheckPropertyName(java.lang.String name, java.lang.String[] validnames, java.lang.String entry)
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
JDOMetaDataUserException If the check fails.


        for  (int i = 0; i < validnames.length; i++)
        {
            if  (name.equals (validnames [i]))
            {
                return;
            }
        }

        throw new JDOMetaDataUserException (getErrorMsg (IErrorMessages.ERR_INVALID_PROPERTY_NAME,
                                                         new String [] { entry, name }));

    
private static final voidcheckPropertyValue(com.sun.jdo.api.persistence.enhancer.meta.JDOMetaDataProperties$Property prop, java.lang.String[] validvalues, java.lang.String name, java.lang.String entry)
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
JDOMetaDataUserException If the check fails.


        if  ( ! prop.name.equals (name))
        {
            return;
        }

        for  (int i = 0; i < validvalues.length; i++)
        {
            if  (prop.value.equals (validvalues [i]))
            {
                return;
            }
        }

        throw new JDOMetaDataUserException (getErrorMsg (IErrorMessages.ERR_INVALID_PROPERTY_VALUE,
                                                         new String [] { entry, name, prop.value }));

    
private static final java.lang.StringfromCanonicalClassName(java.lang.String classname)
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


        return classname.replace ('.", '/");

    
static final java.lang.StringgetErrorMsg(java.lang.String msg, java.lang.String[] params)
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.


        return MessageFormat.format (msg, (Object []) params);

    
public final com.sun.jdo.api.persistence.enhancer.meta.JDOMetaDataProperties$JDOClassgetJDOClass(java.lang.String classname)
Get the information about the class with the given name.

param
classname The classname.
return
The information about the class or null if no information is given.
throws
JDOMetaDataUserException If something went wrong parsing the properties.


        classname = toCanonicalClassName (classname);
        JDOClass clazz = (JDOClass) this.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 = this.properties.getProperty (classname);
        if  (s == null)  //class not defined
        {
            this.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
        this.cachedJDOClasses.put (clazz.getName (), clazz);

        return clazz;

    
public final com.sun.jdo.api.persistence.enhancer.meta.JDOMetaDataProperties$JDOFieldgetJDOField(java.lang.String fieldname, java.lang.String classname)
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 null if no information could be found.
throws
JDOMetaDataUserException If something went wrong parsing the properties.


        JDOClass clazz = getJDOClass (classname);
        return (clazz != null  ?  clazz.getField (fieldname)  :  null);

    
public final java.lang.String[]getKnownClassNames()
Gets all classnames in the properties.

return
All classnames in the properties.


        Collection classnames = new HashSet ();
        for  (Enumeration names = this.properties.propertyNames (); names.hasMoreElements ();)
        {
            String name = (String) names.nextElement ();
            if  (name.indexOf (FIELD_DELIMITER) < 0)
            {
                classnames.add (fromCanonicalClassName (name));
            }
        }

        return (String []) classnames.toArray (new String [classnames.size ()]);

    
private static final intgetModifiers(java.lang.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;

    
private final com.sun.jdo.api.persistence.enhancer.meta.JDOMetaDataProperties$JDOClassparseJDOClass(java.lang.String classname, java.lang.String attributes)
Parses the attributes-string of a class and puts them into a JDOClass-object.

param
classname The name of the class.
param
atributes The attribute-string as specified in the properties.
return
@return The create JDOClass-object.
throws
JDOMetaDataUserException If something went wrong parsing the attributes.


        List props = parseProperties (attributes);

        //check each property
        for  (int i = 0; i < props.size (); i++)
        {
            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.modifiers = getModifiers (prop.value);
            }
            else if  (prop.name.equals (PROPERTY_JDO_MODIFIER))
            {
                clazz.isPersistent = 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;

    
private final com.sun.jdo.api.persistence.enhancer.meta.JDOMetaDataProperties$JDOFieldparseJDOField(java.lang.String attributes, java.lang.String fieldname, com.sun.jdo.api.persistence.enhancer.meta.JDOMetaDataProperties$JDOClass clazz)
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
JDOMetaDataUserException If something went wrong parsing the attributes.


        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.modifiers = getModifiers (prop.value);
            }
            else if  (prop.name.equals (PROPERTY_JDO_MODIFIER))
            {
                field.jdoModifier = prop.value;
            }
            else if  (prop.name.equals (PROPERTY_TYPE))
            {
                field.setType (prop.value);
            }
            else if  (prop.name.equals (PROPERTY_ANNOTATION_TYPE))
            {
                field.annotationType = prop.value;
            }
        }

        return field;

    
private final voidparseJDOFields(com.sun.jdo.api.persistence.enhancer.meta.JDOMetaDataProperties$JDOClass clazz)
Parses all fields of a given class.

param
clazz The representation of the class.
throws
JDOMetaDataUserException If something went wrong parsing the properties.


        //search for fields of the class
        for  (Enumeration names = this.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 (this.properties.getProperty (name), fieldname, clazz));
            }
        }
        clazz.sortFields ();

    
final java.util.ListparseProperties(java.lang.String attributes)
Parses the attribute-string of a class- or fieldname.

param
attributes The attribute-string.
return
A list of Propert<-objects for the attributes.
exception
JDOMetaDataUserException If the parsing fails.


        this.tmpTokens.clear ();
        StringTokenizer t = new StringTokenizer (attributes, PROPERTY_DELIMITERS);
        while (t.hasMoreTokens ())
        {
            this.tmpTokens.add (parseProperty (t.nextToken ()));
        }

        return this.tmpTokens;

    
private final com.sun.jdo.api.persistence.enhancer.meta.JDOMetaDataProperties$PropertyparseProperty(java.lang.String attribute)
Parses the given attribute and splits it into name and value.

param
attribute The attribute-string.
return
The Propert-object.
exception
JDOMetaDataUserException If the parsing fails.


        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)
            {
                throw new JDOMetaDataUserException (getErrorMsg (IErrorMessages.ERR_EMPTY_PROPERTY_NAME_OR_VALUE,
                                                                 new String [] { attribute }));
            }
        }

        return prop;

    
private static final java.lang.StringtoCanonicalClassName(java.lang.String classname)
Converts a classname given in a given VM-similar notation (with slashes) into a canonical notation (with dots).

param
The VM-similar notation of the classname.
return
The canonical classname.
see
#fromCanonicalClassName


        return classname.replace ('/", '.");

    
private static final voidvalidateClassProperty(com.sun.jdo.api.persistence.enhancer.meta.JDOMetaDataProperties$Property prop, java.lang.String classname)
Checks if the given attribute-property of a class is valid.

param
prop The attribute-property.
param
classname The classname.
throws
JDOMetaDataUserException If the validation failed.


        String value = prop.value;
        if  (prop.name == null)  //try to guess the property name
        {
            //check access modifier
            if  (value.equals (ACCESS_PUBLIC)  ||
                 value.equals (ACCESS_PROTECTED)  ||
                 value.equals (ACCESS_PACKAGE_LOCAL)  ||
                 value.equals (ACCESS_PRIVATE))
            {
                prop.name = PROPERTY_ACCESS_MODIFIER;
            }

            //check persistence
            else if  (value.equals (JDO_PERSISTENT)  ||
                      value.equals (JDO_TRANSIENT))
            {
                prop.name = PROPERTY_JDO_MODIFIER;
            }

            //assume the the given value is the superclassname
            else
            {
                prop.name = PROPERTY_SUPER_CLASSNAME;
            }
        }
        else
        {
            //do we have a valid property name?
            String name = prop.name;
            checkPropertyName (prop.name, new String []
                                              {
                                                PROPERTY_OID_CLASSNAME,
                                                PROPERTY_ACCESS_MODIFIER,
                                                PROPERTY_JDO_MODIFIER,
                                                PROPERTY_SUPER_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);
        }

    
private final voidvalidateDependencies(com.sun.jdo.api.persistence.enhancer.meta.JDOMetaDataProperties$JDOClass clazz)
Validates dependencies between a class and its fields and between.

param
clazz The class.
throws
JDOMetaDataUserException If the validation fails.


        for  (int i = clazz.fields.size () - 1; i >= 0; i--)
        {
            JDOField field = (JDOField) clazz.fields.get (i);

            //set the jdo field modifier according to the jdo class modifier (if jdo field not set yet)
            if  (field.jdoModifier == null)
            {
                field.jdoModifier = (clazz.isPersistent ()  ?  JDO_PERSISTENT  :  JDO_TRANSIENT);
            }
            //if we have a non-persistent class
            else if  (clazz.isTransient ())
            {
                //non-persistent classes cannot have persistent fields
                if  (field.isPersistent ())
                {
                    throw new JDOMetaDataUserException (getErrorMsg (IErrorMessages.ERR_TRANSIENT_CLASS_WITH_PERSISTENT_FIELD,
                                                                     new String [] { clazz.getName (), field.getName () }));
                }
                //non-persistent classes cannot have transactional fields
                if  (field.isTransactional ())
                {
                    throw new JDOMetaDataUserException (getErrorMsg (IErrorMessages.ERR_TRANSIENT_CLASS_WITH_TRANSACTIONAL_FIELD,
                                                                     new String [] { clazz.getName (), field.getName () }));
                }
            }

            //a non-persistent class cannot have an annotated field
            if  (field.isAnnotated ()  &&  clazz.isTransient ())
            {
                throw new JDOMetaDataUserException (getErrorMsg (IErrorMessages.ERR_TRANSIENT_CLASS_WITH_ANNOTATED_FIELD,
                                                                 new String [] { clazz.getName (), field.getName () }));
            }

            //a non-persistent field cannot have an annotation type
            if  ( ! field.isPersistent ()  &&  field.isAnnotated ())
            {
                field.annotationType = ANNOTATION_TYPE_MEDIATED;
            }

            //set the annotation type if not done yet
            if  ( ! field.isAnnotated ()  &&  clazz.isPersistent ())
            {
                field.annotationType = ANNOTATION_TYPE_MEDIATED;
            }
        }

    
private static final voidvalidateFieldName(java.lang.String fieldname, java.lang.String classname)
Checks if a given fieldname is a valid Java identifier.

param
fieldname The fieldname.
param
classname The corresponding classname.
throws
JDOMetaDataUserException If the check fails.


        if  (fieldname.length () == 0)
        {
            throw new JDOMetaDataUserException (getErrorMsg (IErrorMessages.ERR_EMPTY_FIELDNAME,
                                                             new String [] { classname }));
        }
        if  ( ! Character.isJavaIdentifierStart (fieldname.charAt (0)))
        {
            throw new JDOMetaDataUserException (getErrorMsg (IErrorMessages.ERR_INVALID_FIELDNAME,
                                                             new String [] { classname, fieldname }));
        }
        for  (int i = fieldname.length () - 1; i >= 0; i--)
        {
            final char c = fieldname.charAt (i);
            if  ( ! Character.isJavaIdentifierPart (c))
            {
                throw new JDOMetaDataUserException (getErrorMsg (IErrorMessages.ERR_INVALID_FIELDNAME,
                                                                 new String [] { classname, fieldname }));
            }
        }

    
private final voidvalidateFieldProperty(com.sun.jdo.api.persistence.enhancer.meta.JDOMetaDataProperties$Property prop, java.lang.String fieldname, java.lang.String classname)
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
JDOMetaDataUserException If the check fails.


        String value = prop.value;
        if  (prop.name == null)  //try to guess the property name
        {
            //check access modifier
            if  (value.equals (ACCESS_PUBLIC)  ||
                 value.equals (ACCESS_PROTECTED)  ||
                 value.equals (ACCESS_PACKAGE_LOCAL)  ||
                 value.equals (ACCESS_PRIVATE))
            {
                prop.name = PROPERTY_ACCESS_MODIFIER;
            }

            //check persistence
            else if  (value.equals (JDO_PERSISTENT)  ||
                      value.equals (JDO_TRANSIENT)  ||
                      value.equals (JDO_TRANSACTIONAL))
            {
                prop.name = PROPERTY_JDO_MODIFIER;
            }

            //annotation type?
            else if  (value.equals (ANNOTATION_TYPE_PK)  ||
                      value.equals (ANNOTATION_TYPE_DFG)  ||
                      value.equals (ANNOTATION_TYPE_MEDIATED))
            {
                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_PK,
                                        ANNOTATION_TYPE_DFG,
                                        ANNOTATION_TYPE_MEDIATED
                                    },
                                PROPERTY_ANNOTATION_TYPE,
                                entry);
        }