com.sun.jdo.api.persistence.enhancer.meta.JDOMetaDataProperties Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of payara-micro Show documentation
Show all versions of payara-micro Show documentation
Micro Distribution of the Payara Project
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
//JDOMetaDataProperties - Java Source
//***************** package ***********************************************
package com.sun.jdo.api.persistence.enhancer.meta;
//***************** import ************************************************
import java.lang.reflect.Modifier;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Enumeration;
import java.util.Map;
import java.util.List;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Properties;
import java.util.StringTokenizer;
import java.text.MessageFormat;
//#########################################################################
/**
* 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.
*/
//#########################################################################
public final class JDOMetaDataProperties
{
/**
* The delimiter of a property key between the class- and fieldname.
*/
private static final char FIELD_DELIMITER = '#';
/**
* A string of delimiter characters between attributes.
*/
private static final String PROPERTY_DELIMITERS = " \t,;";
/**
* A delimiter character between attribute name and attribute value
*/
private static final char PROPERTY_ASSIGNER = ':';
//attribute names for classes and fields
private static final String PROPERTY_ACCESS_MODIFIER = "access";
private static final String PROPERTY_JDO_MODIFIER = "jdo";
private static final String PROPERTY_SUPER_CLASSNAME = "super";
private static final String PROPERTY_OID_CLASSNAME = "oid";
private static final String PROPERTY_TYPE = "type";
private static final String PROPERTY_ANNOTATION_TYPE = "annotation";
//values of the access attribute of classes and fields.
private static final String ACCESS_PRIVATE = "private";
private static final String ACCESS_PACKAGE_LOCAL = "package";
private static final String ACCESS_PROTECTED = "protected";
private static final String ACCESS_PUBLIC = "public";
//values of the jdo attribute of classes and fields.
private static final String JDO_TRANSIENT = "transient";
private static final String JDO_PERSISTENT = "persistent";
private static final String JDO_TRANSACTIONAL = "transactional";
//values of the annotation type attribute of fields.
private static final String ANNOTATION_TYPE_PK = "pk";
private static final String ANNOTATION_TYPE_DFG = "dfg";
private 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
* JDOClass
-object.
*/
private final Map cachedJDOClasses = new HashMap ();
/**
* A constant for the cache indicating that a given classname
* if not specified in the properties.
*/
private static 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.
*
* @see #properties
*********************************************************************/
public JDOMetaDataProperties (Properties props)
{
this.properties = props;
} //JDOMetaDataProperties.
/**********************************************************************
* 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.
*********************************************************************/
public final JDOClass getJDOClass (String classname)
throws JDOMetaDataUserException
{
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;
} //JDOMetaDataProperties.getJDOClass()
/**********************************************************************
* 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.
*********************************************************************/
public final JDOField getJDOField (String fieldname,
String classname)
throws JDOMetaDataUserException
{
JDOClass clazz = getJDOClass (classname);
return (clazz != null ? clazz.getField (fieldname) : null);
} //JDOMetaDataProperties.getJDOField()
/**********************************************************************
* Gets all classnames in the properties.
*
* @return All classnames in the properties.
*********************************************************************/
public final String [] getKnownClassNames ()
{
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 ()]);
} //JDOMetaDataProperties.getKnownClassNames()
/**********************************************************************
* 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
*********************************************************************/
private static final String toCanonicalClassName (String classname)
{
return classname.replace ('/', '.');
} //JDOMetaDataProperties.toCanonicalClassName()
/**********************************************************************
* 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
*********************************************************************/
private static final String fromCanonicalClassName (String classname)
{
return classname.replace ('.', '/');
} //JDOMetaDataProperties.fromCanonicalClassName()
/**********************************************************************
* 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.
*********************************************************************/
private final JDOClass parseJDOClass (String classname,
String attributes)
throws JDOMetaDataUserException
{
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;
} //JDOMetaDataProperties.parseJDOClass()
/**********************************************************************
* 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.
*********************************************************************/
private static final void validateClassProperty (Property prop,
String classname)
throws JDOMetaDataUserException
{
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);
}
} //JDOMetaDataProperties.validateClassProperty()
/**********************************************************************
* Parses all fields of a given class.
*
* @param clazz The representation of the class.
*
* @throws JDOMetaDataUserException If something went wrong parsing
* the properties.
*********************************************************************/
private final void parseJDOFields (JDOClass clazz)
throws JDOMetaDataUserException
{
//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 ();
} //JDOMetaDataProperties.parseJDOField()
/**********************************************************************
* 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.
*********************************************************************/
private final JDOField parseJDOField (String attributes,
String fieldname,
JDOClass clazz)
throws JDOMetaDataUserException
{
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;
} //JDOMetaDataProperties.parseJDOField()
/**********************************************************************
* 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.
*********************************************************************/
private final void validateFieldProperty (Property prop,
String fieldname,
String classname)
throws JDOMetaDataUserException
{
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);
}
} //JDOMetaDataProperties.validateFieldProperty()
/**********************************************************************
* Validates dependencies between a class and its fields and between.
*
* @param clazz The class.
*
* @throws JDOMetaDataUserException If the validation fails.
*********************************************************************/
private final void validateDependencies (JDOClass clazz)
throws JDOMetaDataUserException
{
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;
}
}
} //JDOMetaDataProperties.validateDependencies()
/**********************************************************************
* 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.
*********************************************************************/
private static final void validateFieldName (String fieldname,
String classname)
throws JDOMetaDataUserException
{
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 }));
}
}
} //JDOMetaDataProperties.checkFieldName()
/**********************************************************************
* 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.
*********************************************************************/
private static final void checkForDuplicateProperties (List props,
String entry)
throws JDOMetaDataUserException
{
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 }));
}
}
}
} //JDOMetaDataProperties.checkForDuplicateEntries()
/**********************************************************************
* 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.
*********************************************************************/
private static final void checkPropertyName (String name,
String [] validnames,
String entry)
throws JDOMetaDataUserException
{
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 }));
} //JDOMetaDataProperties.checkPropertyName()
/**********************************************************************
* 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.
*********************************************************************/
private static final void checkPropertyValue (Property prop,
String [] validvalues,
String name,
String entry)
throws JDOMetaDataUserException
{
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 }));
} //JDOMetaDataProperties.checkPropertyValue()
/**********************************************************************
* 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 getErrorMsg (String msg,
String [] params)
{
return MessageFormat.format (msg, (Object []) params);
} //JDOMetaDataProperties.getErrorMsg()
/**********************************************************************
* 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.
*********************************************************************/
final List parseProperties (String attributes)
throws JDOMetaDataUserException
{
this.tmpTokens.clear ();
StringTokenizer t = new StringTokenizer (attributes, PROPERTY_DELIMITERS);
while (t.hasMoreTokens ())
{
this.tmpTokens.add (parseProperty (t.nextToken ()));
}
return this.tmpTokens;
} //JDOMetaDataProperties.getTokens()
/**********************************************************************
* 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.
*********************************************************************/
private final Property parseProperty (String attribute)
throws JDOMetaDataUserException
{
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;
} //JDOMetaDataProperties.parseProperty()
/**********************************************************************
*
*********************************************************************/
private static final 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;
} //JDOMetaDataProperties.getModifiers()
/**********************************************************************
* 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;
}
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 ("############");
JDOMetaDataProperties props = new JDOMetaDataProperties (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);
}
} //JDOMetaDataProperties.main()
*/
//#####################################################################
/**
* The holder-class for the name and the value of a property.
*/
//#####################################################################
private static 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 + '>';
} //Property.toString()
} //Property
//#####################################################################
/**
* Holds all unformatted error messages.
*/
//#####################################################################
private static interface IErrorMessages
{
//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_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_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_PERSISTENT_ANNOTATED_FIELD =
PREFIX + "A non-persistent field (''{1}'' of class ''{0}'') can''t be a annotated.";
} //IErrorMessages
//#####################################################################
/**
* A class to hold all parsed attributes of a class.
*/
//#####################################################################
static final class JDOClass
{
/**
* The name of the class.
*/
private String name;
/**
* The name of the superclass.
*/
private String superClassName = null;
/**
* The name of the oid class.
*/
private String oidClassName = null;
/**
* The access modifier.
*/
private int modifiers = Modifier.PUBLIC;
/**
* Do we have a persistent class?
*/
private boolean isPersistent = true;
/**
* A list of all parsed fields.
*/
private final List fields = new ArrayList ();
/**
*
*/
private String [] managedFieldNames = null;
/**
*
*/
private String [] fieldNames = null;
/******************************************************************
* Constructs a new object with the given name.
*
* @param name The name of the class.
*
* @see #name
*****************************************************************/
JDOClass (String name)
{
this.name = name;
} //JDOClass.
/******************************************************************
* Gets the name of the class.
*
* @return The name of the class.
*
* @see #name
*****************************************************************/
public final String getName ()
{
return this.name;
} //JDOClass.getName()
/******************************************************************
*
*****************************************************************/
public final int getModifiers ()
{
return this.modifiers;
} //JDOClass.getModifiers()
/******************************************************************
* Sets the superclassname. The given classname should have a canonical
* form (with dots). It is converted to the CM-similar notation
* (with slashes).
*
* @param classname The superclassname.
*
* @see #superClassName
*****************************************************************/
private final void setSuperClassName (String classname)
{
this.superClassName = fromCanonicalClassName (classname);
} //JDOClass.setSuperClassName()
/******************************************************************
* Gets the superclassname.
*
* @return The superclassname.
*
* @see #superClassName
*****************************************************************/
public final String getSuperClassName ()
{
return this.superClassName;
} //JDOClass.getSuperClassName()
/******************************************************************
* Sets the superclassname. The given classname should have a canonical
* form (with dots). It is converted to the CM-similar notation
* (with slashes).
*
* @param classname The superclassname.
*
* @see #superClassName
*****************************************************************/
public void setOidClassName(String classname)
{
this.oidClassName = fromCanonicalClassName(classname);
}
/******************************************************************
* Gets the oidClassName.
*
* @return The oidClassName.
*
* @see #oidClassName
*****************************************************************/
public String getOidClassName()
{
return oidClassName;
}
/******************************************************************
* Do we have a persistent class.
*
* @return Do we have a persistent class?
*
* @see #isPersistent
*****************************************************************/
public final boolean isPersistent ()
{
return this.isPersistent;
} //JDOMetaClass.isPersistent()
/******************************************************************
* Do we have a transient class.
*
* @return Do we have a transient class?
*
* @see #isPersistent
*****************************************************************/
public final boolean isTransient ()
{
return ! isPersistent ();
} //JDOMetaClass.isTransient()
/******************************************************************
* Adds a new field.
*
* @param field The new field.
*
* @see #fields
*****************************************************************/
private final void addField (JDOField field)
{
this.fields.add (field);
} //JDOClass.addField()
/******************************************************************
* Gets the field with the given name.
*
* @param name The name of the requested field.
*
* @return The field or null
if not found.
*
* @see #fields
*****************************************************************/
public final JDOField getField (String name)
{
int idx = getIndexOfField (name);
return (idx > -1 ? (JDOField) this.fields.get (idx) : null);
} //JDOField.getField()
/******************************************************************
* Gets the index of the field with the given name.
*
* @param name The name of the field.
*
* @return The index or -1
if the field was not found.
*
* @see #fields
*****************************************************************/
public final int getIndexOfField (String name)
{
for (int i = 0; i < this.fields.size (); i++)
{
JDOField field = (JDOField) this.fields.get (i);
if (field.getName ().equals (name))
{
return i;
}
}
return -1;
} //JDOClass.getIndexOfField()
/******************************************************************
* Gets all fields of this class.
*
* @return The fields.
*
* @see #fields
*****************************************************************/
public final String [] getFields ()
{
if (this.fieldNames == null)
{
final int n = this.fields.size ();
String [] fields = new String [n];
for (int i = 0; i < n; i++)
{
fields [i] = ((JDOField) this.fields.get (i)).getName ();
}
this.fieldNames = fields;
}
return this.fieldNames;
} //JDOClass.getFields()
/******************************************************************
* Sorts the fields of this class according to the names. This method
* should be called if all fields are added. It is necessary to
* establish an order on the fields.
*
* @see #fields
*****************************************************************/
private final void sortFields ()
{
Collections.sort (this.fields,
new Comparator ()
{
public final int compare (Object f1, Object f2)
{
JDOField field1 = (JDOField) f1;
JDOField field2 = (JDOField) f2;
//if we dont have managed fields we dont care
if ( ! (field1.isManaged () && field2.isManaged ()))
{
return (field1.isManaged () ? -1 : 1);
}
return (field1).getName ().compareTo (field2.getName ());
}
});
} //JDOClass.sortFields()
/******************************************************************
* Gets a list of persistent field names of this class.
*
* @return The persistent fieldnames.
*
* @see #fields
*****************************************************************/
public final String [] getManagedFieldNames ()
{
if (this.managedFieldNames == null)
{
final int n = this.fields.size ();
List tmp = new ArrayList (n);
for (int i = 0; i < n; i++)
{
JDOField field = (JDOField) this.fields.get (i);
if (field.isManaged ())
{
tmp.add (field.getName ());
}
}
this.managedFieldNames = (String []) tmp.toArray (new String [tmp.size ()]);
}
return this.managedFieldNames;
} //JDOClass.getManagedFieldNames()
/******************************************************************
* Creates a string-representation for this object.
*
* @return The string-representation of this object.
*****************************************************************/
public final String toString ()
{
return '<' + PROPERTY_SUPER_CLASSNAME + ':' + this.superClassName + ',' +
PROPERTY_ACCESS_MODIFIER + ':' + Modifier.toString (this.modifiers) + ',' +
PROPERTY_JDO_MODIFIER + ':' + this.isPersistent + ',' +
"fields:" + this.fields + '>';
} //JDOClass.toString()
} //JDOClass
//#####################################################################
/**
* A class to hold the properties of a field.
*/
//#####################################################################
static final class JDOField
{
/**
* The name of the field.
*/
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.
*
* @see #name
*****************************************************************/
JDOField (String name)
{
this.name = name;
} //JDOField.
/******************************************************************
* Gets the name of the field.
*
* @return The name of the field.
*
* @see #name
*****************************************************************/
public final String getName ()
{
return this.name;
} //JDOField.getName()
/******************************************************************
* 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.
*
* @see #type
*****************************************************************/
public final void setType (String type)
{
this.type = fromCanonicalClassName (type);
} //JDOField.setType()
/******************************************************************
* Gets the type of the field.
*
* @return The type of the field.
*
* @see #type
*****************************************************************/
public final String getType ()
{
return this.type;
} //JDOField.getType()
/******************************************************************
*
*****************************************************************/
public final int getModifiers ()
{
return this.modifiers;
} //JDOField.getModifiers()
/******************************************************************
* Do we have an annotated field?
*
* @return Do we have an annotated field?
*
* @see #annotationType
*****************************************************************/
public final boolean isAnnotated ()
{
return this.annotationType != null;
} //JDOField.isAnnotated()
/******************************************************************
* Do we have a primary key?
*
* @return Do we have a primary key?
*
* @see #annotationType
*****************************************************************/
public final boolean isPk ()
{
return (this.annotationType != null && this.annotationType.equals (ANNOTATION_TYPE_PK));
} //JDOField.isPk()
/******************************************************************
* Is the field in the default fetch group?
*
* @return Is the field in the default fetch group?
*
* @see #annotationType
*****************************************************************/
public final boolean isInDefaultFetchGroup ()
{
return (this.annotationType != null && this.annotationType.equals (ANNOTATION_TYPE_DFG));
} //JDOField.isInDefaultFetchGroup()
/******************************************************************
* Returns whether the field is declared transient.
*
* @return true if declared transient field.
* @see #jdoModifier
*/
public boolean isKnownTransient()
{
return (jdoModifier != null
&& jdoModifier.equals(JDO_TRANSIENT));
}
/******************************************************************
* Do we have a persistent field.
*
* @return Do we have a persistent field.
*
* @see #jdoModifier
*****************************************************************/
public final boolean isPersistent ()
{
return (this.jdoModifier != null && this.jdoModifier.equals (JDO_PERSISTENT));
} //JDOField.isPersistent()
/******************************************************************
* Do we have a transactional field.
*
* @return So we have a transactional field?
*
* @see #jdoModifier
*****************************************************************/
public final boolean isTransactional ()
{
return (this.jdoModifier != null && this.jdoModifier.equals (JDO_TRANSACTIONAL));
} //JDOField.isTransactional()
/******************************************************************
* Do we have a managed field?
*
* @return Do we have a managed field?
*****************************************************************/
public final boolean isManaged ()
{
return (isPersistent () || isTransactional ());
} //JDOField.isManaged()
/******************************************************************
* Creates a string-representation of the object.
*
* @return The string-representation of the object.
*****************************************************************/
public final String toString ()
{
return '<' + "name:" + this.name + ',' +
PROPERTY_TYPE + ':' + this.type + ',' +
PROPERTY_ACCESS_MODIFIER + ':' + Modifier.toString (this.modifiers) + ',' +
PROPERTY_JDO_MODIFIER + ':' + this.jdoModifier + ',' +
PROPERTY_ANNOTATION_TYPE + ':' + this.annotationType +
'>';
} //JDOField.toString()
} //JDOField
} //JDOMetaDataProperties