
com.sun.jdo.api.persistence.enhancer.meta.JDOMetaDataProperties Maven / Gradle / Ivy
/*
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
//JDOMetaDataProperties - Java Source
//***************** package ***********************************************
package com.sun.jdo.api.persistence.enhancer.meta;
//***************** import ************************************************
import java.lang.reflect.Modifier;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
//#########################################################################
/**
* 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 final 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 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 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 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 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 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 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 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 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 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 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 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);
} else if (clazz.isTransient()) {
// if we have a non-persistent class
// 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 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 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 void checkPropertyName(String name, String[] validnames, String entry)
throws JDOMetaDataUserException {
for (String validname : validnames) {
if (name.equals(validname)) {
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 void checkPropertyValue(Property prop, String[] validvalues, String name, String entry)
throws JDOMetaDataUserException {
if (!prop.name.equals(name)) {
return;
}
for (String validvalue : validvalues) {
if (prop.value.equals(validvalue)) {
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 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.
*********************************************************************/
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 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 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.
*****************************************************************/
@Override
public String toString() {
return '<' + name + ':' + value + '>';
} // Property.toString()
} //Property
//#####################################################################
/**
* Holds all unformatted error messages.
*/
//#####################################################################
private interface IErrorMessages
{
//the unformatted error messages
String PREFIX = "Error Parsing meta data properties: ";
String ERR_EMPTY_FIELDNAME =
PREFIX + "The class ''{0}'' may not have an empty fieldname.";
String ERR_INVALID_FIELDNAME =
PREFIX + "The field name ''{1}'' of class ''{0}'' is not valid.";
String ERR_EMPTY_PROPERTY_NAME_OR_VALUE =
PREFIX + "The property name and value may not be empty if a ''" + PROPERTY_ASSIGNER + "'' is specified: ''{0}''.";
String ERR_INVALID_PROPERTY_NAME =
PREFIX + "Invalid property name for entry ''{0}'': ''{1}''.";
String ERR_INVALID_PROPERTY_VALUE =
PREFIX + "Invalid value for property ''{1}'' of entry ''{0}'': ''{2}''.";
String ERR_DUPLICATE_PROPERTY_NAME =
PREFIX + "The property ''{1}'' for the entry ''{0}'' entered twice with values: ''{2}'' and ''{3}''.";
String ERR_TRANSIENT_CLASS_WITH_PERSISTENT_FIELD =
PREFIX + "A non-persistent class cannot have a persistent field (class ''{0}'' with field ''{1})''.";
String ERR_TRANSIENT_CLASS_WITH_TRANSACTIONAL_FIELD =
PREFIX + "A non-persistent class cannot have a transactional field (class ''{0}'' with field ''{1})''.";
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.";
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 String getName() {
return this.name;
} // JDOClass.getName()
/******************************************************************
*
*****************************************************************/
public 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 void setSuperClassName(String classname) {
this.superClassName = fromCanonicalClassName(classname);
} // JDOClass.setSuperClassName()
/******************************************************************
* Gets the superclassname.
*
* @return The superclassname.
* @see #superClassName
*****************************************************************/
public 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 boolean isPersistent() {
return this.isPersistent;
} // JDOMetaClass.isPersistent()
/******************************************************************
* Do we have a transient class.
*
* @return Do we have a transient class?
* @see #isPersistent
*****************************************************************/
public boolean isTransient() {
return !isPersistent();
} // JDOMetaClass.isTransient()
/******************************************************************
* Adds a new field.
*
* @param field The new field.
* @see #fields
*****************************************************************/
private 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 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 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 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 void sortFields() {
Collections.sort(this.fields, new Comparator() {
@Override
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 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.
*****************************************************************/
@Override
public 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 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 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 String getType() {
return this.type;
} // JDOField.getType()
/******************************************************************
*
*****************************************************************/
public int getModifiers() {
return this.modifiers;
} // JDOField.getModifiers()
/******************************************************************
* Do we have an annotated field?
*
* @return Do we have an annotated field?
* @see #annotationType
*****************************************************************/
public boolean isAnnotated() {
return this.annotationType != null;
} // JDOField.isAnnotated()
/******************************************************************
* Do we have a primary key?
*
* @return Do we have a primary key?
* @see #annotationType
*****************************************************************/
public 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 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 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 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 boolean isManaged() {
return (isPersistent() || isTransactional());
} // JDOField.isManaged()
/******************************************************************
* Creates a string-representation of the object.
*
* @return The string-representation of the object.
*****************************************************************/
@Override
public 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
© 2015 - 2025 Weber Informatics LLC | Privacy Policy