Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOFieldImplDynamic.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOFieldImplDynamic.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOFieldImplDynamic.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOFieldImplDynamic.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,558 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jdo.impl.model.jdo; + +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.List; + +import org.apache.jdo.impl.model.jdo.util.TypeSupport; +import org.apache.jdo.model.ModelException; +import org.apache.jdo.model.java.JavaField; +import org.apache.jdo.model.java.JavaType; +import org.apache.jdo.model.jdo.JDOArray; +import org.apache.jdo.model.jdo.JDOCollection; +import org.apache.jdo.model.jdo.JDOField; +import org.apache.jdo.model.jdo.JDOMap; +import org.apache.jdo.model.jdo.JDOReference; +import org.apache.jdo.model.jdo.JDORelationship; +import org.apache.jdo.model.jdo.NullValueTreatment; +import org.apache.jdo.model.jdo.PersistenceModifier; +import org.apache.jdo.util.I18NHelper; + +/** + * An instance of this class represents the JDO metadata of a managed field + * of a persistence capable class. This dynamic implementation only + * stores property values explicitly set by setter method. + * <p> + * Please note, you cannot rely on the Java identity of the + * JDORelationship instance returned by [EMAIL PROTECTED] #getRelationship}. + * The getter will always return a new Java Instance, unless the + * relationship is explicitly set by the setter + * [EMAIL PROTECTED] #setRelationship(JDORelationship relationship)}. + * <p> + * TBD: + * <ul> + * <li> Change usage of POSSIBLY_PERSISTENT persistence-modifier as soon as + * the enhancer fully supports it. + * <li> Property change support + * </ul> + * + * @author Michael Bouschen + * @since 1.1 + * @version 1.1 + */ +public class JDOFieldImplDynamic + extends JDOMemberImpl + implements JDOField +{ + /** + * Property persistenceModifier. + * Default see [EMAIL PROTECTED] #getPersistenceModifier}. + */ + protected int persistenceModifier = PersistenceModifier.UNSPECIFIED; + + /** Property primaryKey. Defaults to <code>false</code>. */ + private boolean primaryKey = false; + + /** Property nullValueTreatment. Defaults to none. */ + private int nullValueTreatment = NullValueTreatment.NONE; + + /** Property defaultFetchGroup. Default see [EMAIL PROTECTED] #isDefaultFetchGroup}. */ + protected Boolean defaultFetchGroup; + + /** Property embedded. Default see [EMAIL PROTECTED] #isEmbedded}. */ + protected Boolean embedded; + + /** Property javaField. No default. */ + private transient JavaField javaField; + + /** Property serializable. Defaults to <code>false</code>. */ + private boolean serializable = false; + + /** Relationship JDOField<->JDORelationship. */ + protected JDORelationship relationship; + + /** I18N support */ + protected final static I18NHelper msg = + I18NHelper.getInstance(JDOFieldImplDynamic.class); + + /** + * Get the persistence modifier of this JDOField. + * @return the persistence modifier, one of + * [EMAIL PROTECTED] PersistenceModifier#NONE}, + * [EMAIL PROTECTED] PersistenceModifier#PERSISTENT}, + * [EMAIL PROTECTED] PersistenceModifier#TRANSACTIONAL}, or + * [EMAIL PROTECTED] PersistenceModifier#POSSIBLY_PERSISTENT}. + */ + public int getPersistenceModifier() { + if (persistenceModifier != PersistenceModifier.UNSPECIFIED) { + // return persistenceModifier, if explicitly set by the setter + return persistenceModifier; + } + + // not set => calculate + int result = PersistenceModifier.UNSPECIFIED; + JavaType type = getType(); + if (nameHasJDOPrefix()) { + result = PersistenceModifier.NONE; + } + else if (type != null) { + result = TypeSupport.isPersistenceFieldType(type) ? + PersistenceModifier.POSSIBLY_PERSISTENT : + PersistenceModifier.NONE; + } + + return result; + } + + /** + * Set the persistence modifier for this JDOField. + * @param persistenceModifier an integer indicating the persistence + * modifier, one of: [EMAIL PROTECTED] PersistenceModifier#UNSPECIFIED}, + * [EMAIL PROTECTED] PersistenceModifier#NONE}, + * [EMAIL PROTECTED] PersistenceModifier#PERSISTENT}, + * [EMAIL PROTECTED] PersistenceModifier#TRANSACTIONAL}, or + * [EMAIL PROTECTED] PersistenceModifier#POSSIBLY_PERSISTENT}. + */ + public void setPersistenceModifier (int persistenceModifier) + throws ModelException { + if (nameHasJDOPrefix() && + (persistenceModifier == PersistenceModifier.PERSISTENT || + persistenceModifier == PersistenceModifier.TRANSACTIONAL)) { + throw new ModelException( + msg.msg("EXC_IllegalJDOPrefix", getName())); //NOI18N + } + this.persistenceModifier = persistenceModifier; + } + + /** + * Determines whether this JDOField is a key field or not. + * @return <code>true</code> if the field is a key field, + * <code>false</code> otherwise + */ + public boolean isPrimaryKey() { + return primaryKey; + } + + /** + * Set whether this JDOField is a key field or not. + * @param primaryKey if <code>true</code>, the JDOField is marked + * as a key field; otherwise, it is not + */ + public void setPrimaryKey(boolean primaryKey) { + this.primaryKey = primaryKey; + } + + /** + * Gets the null value treatment indicator of this JDOField. + * @return the null value treatment of this JDOField, one of + * [EMAIL PROTECTED] NullValueTreatment#NONE}, [EMAIL PROTECTED] NullValueTreatment#EXCEPTION} or + * [EMAIL PROTECTED] NullValueTreatment#DEFAULT} + */ + public int getNullValueTreatment() { + return nullValueTreatment; + } + + /** + * Sets the null value treatment indicator for this JDOField. + * @param nullValueTreatment an integer indicating the null + * value treatment, one of: [EMAIL PROTECTED] NullValueTreatment#NONE}, + * [EMAIL PROTECTED] NullValueTreatment#EXCEPTION} or + * [EMAIL PROTECTED] NullValueTreatment#DEFAULT} + */ + public void setNullValueTreatment(int nullValueTreatment) { + this.nullValueTreatment = nullValueTreatment; + } + + /** + * Determines whether this JDOField is part of the default fetch group or + * not. + * @return <code>true</code> if the field is part of the default fetch + * group, <code>false</code> otherwise + */ + public boolean isDefaultFetchGroup() { + if (defaultFetchGroup != null) { + // return dfg, if explicitly set by the setter + return defaultFetchGroup.booleanValue(); + } + + // not set => calculate + boolean dfg = false; + if (isPrimaryKey()) { + dfg = false; + } + else { + JavaType type = getType(); + if ((type != null) && type.isValue()) { + dfg = true; + } + } + + return dfg; + } + + /** + * Set whether this JDOField is part of the default fetch group or not. + * @param defaultFetchGroup if <code>true</code>, the JDOField is marked + * as beeing part of the default fetch group; otherwise, it is not + */ + public void setDefaultFetchGroup(boolean defaultFetchGroup) { + this.defaultFetchGroup = + defaultFetchGroup ? Boolean.TRUE : Boolean.FALSE; + } + + /** + * Determines whether the field should be stored if possible as part of + * the instance instead of as its own instance in the datastore. + * @return <code>true</code> if the field is stored as part of the instance; + * <code>false</code> otherwise + */ + public boolean isEmbedded() { + if (embedded != null) { + // return embedded, if explicitly set by the setter + return embedded.booleanValue(); + } + + // not set => calculate + boolean result = false; + JavaType type = getType(); + if (type != null) { + result = TypeSupport.isEmbeddedFieldType(type); + } + return result; + } + + /** + * Set whether the field should be stored if possible as part of + * the instance instead of as its own instance in the datastore. + * @param embedded <code>true</code> if the field is stored as part of the + * instance; <code>false</code> otherwise + */ + public void setEmbedded(boolean embedded) { + this.embedded = (embedded ? Boolean.TRUE : Boolean.FALSE); + } + + /** + * Get the corresponding Java field representation for this JDOField. + * @return the corresponding Java field representation + */ + public JavaField getJavaField() { + return javaField; + } + + /** + * Sets the corresponding Java field representation for this JDOField. + * @param javaField the corresponding Java field representation + */ + public void setJavaField (JavaField javaField) { + this.javaField = javaField; + } + + /** + * Determines whether this JDOField is serializable or not. + * @return <code>true</code> if the field is serializable, + * <code>false</code> otherwise + */ + public boolean isSerializable() { + return serializable; + } + + /** + * Set whether this JDOField is serializable or not. + * @param serializable if <code>true</code>, the JDOField is serializable; + * otherwise, it is not + * @exception ModelException if impossible + */ + public void setSerializable(boolean serializable) throws ModelException { + this.serializable = serializable; + } + + /** + * Get the relationship information for this JDOField. The method + * returns null if the field is not part of a relationship + * (e.g. it is a primitive type field). + * @return relationship info of this JDOField or <code>null</code> if + * this JDOField is not a relationship + */ + public JDORelationship getRelationship() { + if (relationship != null) { + // return relationship, if explicitly set by the setter + return relationship; + } + + // not set => calculate + + if (getPersistenceModifier() == PersistenceModifier.NONE) + // field has persistence modifier none => cannot be a relationship + return null; + + // check the type if available + JDORelationship rel = null; + JavaType type = getType(); + if (type != null) { + if (type.isValue() || TypeSupport.isValueArrayType(type)) { + // no relationship + rel = null; + } + else if (type.isJDOSupportedCollection()) { + rel = createJDOCollectionInternal(); + } + else if (type.isJDOSupportedMap()) { + rel = createJDOMapInternal(); + } + else if (type.isArray()) { + rel = createJDOArrayInternal(); + } + else { + rel = createJDOReferenceInternal(); + } + } + return rel; + } + + /** + * Set the relationship information for this JDOField. + * @param relationship the JDORelationship instance + */ + public void setRelationship(JDORelationship relationship) { + this.relationship = relationship; + } + + /** + * Creates and returns a new JDOReference instance. + * This method automatically binds the new JDOReference to this JDOField. + * The following holds true: + * <ul> + * <li> Method [EMAIL PROTECTED] #getRelationship} returns the new created instance + * <li> <code>this.getRelationship().getDeclaringField() == this</code> + * </ul> + * @return a new JDOReference instance bound to this JDOField + * @exception ModelException if impossible + */ + public JDOReference createJDOReference() throws ModelException { + JDOReference ref = createJDOReferenceInternal(); + setRelationship(ref); + return ref; + } + + /** + * Creates and returns a new JDOCollection instance. + * This method automatically binds the new JDOCollection to this JDOField. + * The following holds true: + * <ul> + * <li> Method [EMAIL PROTECTED] #getRelationship} returns the new created instance + * <li> <code>this.getRelationship().getDeclaringField() == this</code> + * </ul> + * @return a new JDOCollection instance bound to this JDOField + * @exception ModelException if impossible + */ + public JDOCollection createJDOCollection() throws ModelException { + JDOCollection col = createJDOCollectionInternal(); + setRelationship(col); + return col; + } + + /** + * Creates and returns a new JDOArray instance. + * This method automatically binds the new JDOArray to this JDOField. + * The following holds true: + * <ul> + * <li> Method [EMAIL PROTECTED] #getRelationship} returns the new created instance + * <li> <code>this.getRelationship().getDeclaringField() == this</code> + * </ul> + * @return a new JDOArray instance bound to this JDOField + * @exception ModelException if impossible + */ + public JDOArray createJDOArray() throws ModelException { + JDOArray array = createJDOArrayInternal(); + setRelationship(array); + return array; + } + + /** + * Creates and returns a new JDOMap instance. + * This method automatically binds the new JDOMap to this JDOField. + * The following holds true: + * <ul> + * <li> Method [EMAIL PROTECTED] #getRelationship} returns the new created instance + * <li> <code>this.getRelationship().getDeclaringField() == this</code> + * </ul> + * @return a new JDOMap instance bound to this JDOField + * @exception ModelException if impossible + */ + public JDOMap createJDOMap() throws ModelException { + JDOMap map = createJDOMapInternal(); + setRelationship(map); + return map; + } + + /** + * Convenience method to check the persistence modifier from this JDOField. + * @return <code>true</code> if this field has the + * [EMAIL PROTECTED] PersistenceModifier#PERSISTENT} modifier; <code>false</code> + * otherwise + */ + public boolean isPersistent() { + switch (getPersistenceModifier()) { + case PersistenceModifier.PERSISTENT: + return true; + case PersistenceModifier.POSSIBLY_PERSISTENT: + // Enable assertion as soon as the enhancer sets the java modifier. + //Assertion.affirm(javaModifier, + // msg.msg("ERR_MissingJavaModifier", + // getDeclaringClass().getName() + "." + getName())); + int mod = getJavaField().getModifiers(); + return !(Modifier.isStatic(mod) || Modifier.isFinal(mod) || + Modifier.isTransient(mod)); + } + return false; + } + + /** + * Convenience method to check the persistence modifier from this JDOField. + * @return <code>true</code> if this field has the + * [EMAIL PROTECTED] PersistenceModifier#TRANSACTIONAL} modifier; <code>false</code> + * otherwise + */ + public boolean isTransactional() { + return (getPersistenceModifier() == PersistenceModifier.TRANSACTIONAL); + } + + /** + * Convenience method to check the persistence modifier from this JDOField. + * A field is a managed field, if it has the persistence-modifier + * [EMAIL PROTECTED] PersistenceModifier#PERSISTENT} or + * [EMAIL PROTECTED] PersistenceModifier#TRANSACTIONAL}. + * @return <code>true</code> if this field is a managed field; + * <code>false</code> otherwise + */ + public boolean isManaged() { + // For now treat POSSIBLY_PERSISTENT as PERSISTENT. This will be removed + // as soon as the enhancer fully supports POSSIBLY_PERSISTENT + int persistenceModifier = getPersistenceModifier(); + return (persistenceModifier == PersistenceModifier.PERSISTENT) || + (persistenceModifier == PersistenceModifier.POSSIBLY_PERSISTENT) || + (persistenceModifier == PersistenceModifier.TRANSACTIONAL); + } + + /** + * Convenience method to check whether this field is a relationship field. + * @return <code>true</code> if this field is a relationship; + * <code>false</code> otherwise + */ + public boolean isRelationship() { + return getRelationship() != null; + } + + /** + * Get the JavaType representation of the type of the field. + * @return JavaType representation of the type of this field. + */ + public JavaType getType() { + return (javaField == null) ? null : javaField.getType(); + } + + /** + * Returns the absolute field number of this JDOField. + * @return the absolute field number + */ + public int getFieldNumber() { + int fieldNumber = getRelativeFieldNumber(); + if (fieldNumber > -1) { + // >-1 denotes a managed field + fieldNumber += getDeclaringClass().getInheritedManagedFieldCount(); + } + return fieldNumber; + } + + /** + * Returns the relative field number of this JDOField. + * @return the relative field number + */ + public int getRelativeFieldNumber() { + JDOField[] fields = getDeclaringClass().getDeclaredManagedFields(); + List fieldList = Arrays.asList(fields); + return fieldList.indexOf(this); + } + + //========= Internal helper methods ========== + + /** + * Creates and returns a new JDOReference instance. + * This method automatically sets this JDOField as the declarinmg field of + * the returned instance. + * @return a new JDOReference instance bound to this JDOField + */ + protected JDOReference createJDOReferenceInternal() { + JDOReferenceImpl ref = new JDOReferenceImpl(); + // update relationship JDORelationship->JDOField + ref.setDeclaringField(this); + return ref; + } + + /** + * Creates and returns a new JDOCollection instance. + * This method automatically this JDOField as the declarinmg field of + * the returned instance. + * @return a new JDOCollection instance bound to this JDOField + */ + protected JDOCollection createJDOCollectionInternal() { + JDOCollectionImplDynamic collection = new JDOCollectionImplDynamic(); + // update relationship JDORelationship->JDOField + collection.setDeclaringField(this); + return collection; + } + + /** + * Creates and returns a new JDOArray instance. + * This method automatically this JDOField as the declarinmg field of + * the returned instance. + * @return a new JDOArray instance bound to this JDOField + */ + protected JDOArray createJDOArrayInternal() { + JDOArrayImplDynamic array = new JDOArrayImplDynamic(); + // update relationship JDORelationship->JDOField + array.setDeclaringField(this); + return array; + } + + /** + * Creates and returns a new JDOMap instance. + * This method automatically this JDOField as the declarinmg field of + * the returned instance. + * @return a new JDOMap instance bound to this JDOField + */ + protected JDOMap createJDOMapInternal() { + JDOMapImplDynamic map = new JDOMapImplDynamic(); + // update relationship JDORelationship->JDOField + map.setDeclaringField(this); + return map; + } + + /** + * Returns <code>true</code> if the name of this JDOField has the + * prefix jdo. + * @return <code>true</code> if the name of this JDOField has the + * prefix jdo; <code>false</code> otherwise. + */ + private boolean nameHasJDOPrefix() { + String name = getName(); + return (name != null) && name.startsWith("jdo"); //NOI18N + } + +}
Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOMapImplDynamic.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOMapImplDynamic.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOMapImplDynamic.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOMapImplDynamic.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,228 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jdo.impl.model.jdo; + +import org.apache.jdo.impl.model.jdo.util.TypeSupport; +import org.apache.jdo.model.ModelFatalException; +import org.apache.jdo.model.java.JavaType; +import org.apache.jdo.model.jdo.JDOClass; +import org.apache.jdo.model.jdo.JDOField; +import org.apache.jdo.model.jdo.JDOMap; +import org.apache.jdo.model.jdo.JDOModel; +import org.apache.jdo.util.I18NHelper; + +/** + * An instance of this class represents the JDO relationship metadata + * (the treatment of keys and values) of a map relationship field. + * This dynamic implementation only stores property values explicitly + * set by setter method. + * + * @author Michael Bouschen + * @since 1.1 + * @version 1.1 + */ +public class JDOMapImplDynamic extends JDORelationshipImpl implements JDOMap { + + /** Property embeddedKey. */ + protected Boolean embeddedKey; + + /** Property keyType. No default. */ + protected transient JavaType keyType; + + /** Property keyTypeName. Defaults to java.lang.Object. */ + private String keyTypeName = "java.lang.Object"; //NOI18N + + /** Property embeddedValue. */ + protected Boolean embeddedValue; + + /** Property valueType. No default. */ + protected transient JavaType valueType; + + /** Property valueTypeName. Defaults to java.lang.Object. */ + private String valueTypeName = "java.lang.Object"; //NOI18N + + /** I18N support */ + private final static I18NHelper msg = + I18NHelper.getInstance(JDOMapImplDynamic.class); + + /** + * Determines whether the keys of the map should be stored if possible as + * part of the instance instead of as their own instances in the datastore. + * @return <code>true</code> if the keys are stored as part of this instance; + * <code>false</code> otherwise + */ + public boolean isEmbeddedKey() { + if (embeddedKey != null) { + // return embeddedKey, if explicitly set by the setter + return embeddedKey.booleanValue(); + } + + // not set => calculate + JavaType type = getKeyType(); + return (type != null) ? + TypeSupport.isEmbeddedElementType(type) : false; + } + + /** + * Set whether the keys of the map should be stored if possible as part + * of the instance instead of as their own instances in the datastore. + * @param embeddedKey <code>true</code> if the keys are stored as part of + * this instance; <code>false</code> otherwise + */ + public void setEmbeddedKey(boolean embeddedKey) { + this.embeddedKey = (embeddedKey ? Boolean.TRUE : Boolean.FALSE); + } + + /** + * Get the type representation of the keys for this JDOMap. + * @return the type of the keys of this JDOMap + */ + public JavaType getKeyType() { + if (keyType != null) { + // return keyType, if explicitly set by the setter + return keyType; + } + + // not set => calculate + JavaType type = null; + if (keyTypeName != null) { + JDOField jdoField = getDeclaringField(); + JDOClass jdoClass = jdoField.getDeclaringClass(); + JDOModel jdoModel = jdoClass.getDeclaringModel(); + type = TypeSupport.resolveType(jdoModel, keyTypeName, + jdoClass.getPackagePrefix()); + if (type == null) { + throw new ModelFatalException( + msg.msg("EXC_CannotResolveKeyType", keyTypeName, + jdoField.getName(), jdoClass.getName())); //NOI18N + } + } + + return type; + } + + /** + * Set the type representation of the keys for this JDOMap. + * @param keyType the type representation of the keys + */ + public void setKeyType(JavaType keyType) { + this.keyType = keyType; + if (keyType != null) { + setKeyTypeName(keyType.getName()); + } + } + + /** + * Get the string representation of the type of the keys for this JDOMap. + * @return the key type as string + */ + public String getKeyTypeName() { + return keyTypeName; + } + + /** + * Set string representation of the type of the keys for this JDOMap. + * @param keyTypeName the name of the key type + */ + public void setKeyTypeName(String keyTypeName) { + this.keyTypeName = keyTypeName; + } + + /** + * Determines whether the values of the map should be stored if possible as + * part of the instance instead of as their own instances in the datastore. + * @return <code>true</code> if the values are stored as part of this + * instance; <code>false</code> otherwise + */ + public boolean isEmbeddedValue() { + if (embeddedValue != null) { + // return embeddedKey, if explicitly set by the setter + return embeddedValue.booleanValue(); + } + + // not set => calculate + JavaType type = getValueType(); + return (type != null) ? + TypeSupport.isEmbeddedElementType(type) : false; + } + + /** + * Set whether the values of the map should be stored if possible as part + * of the instance instead of as their own instances in the datastore. + * @param embeddedValue <code>true</code> if the values are stored as part + * of this instance; <code>false</code> otherwise + */ + public void setEmbeddedValue(boolean embeddedValue) { + this.embeddedValue = (embeddedValue ? Boolean.TRUE : Boolean.FALSE); + } + + /** + * Get the type representation of the values for this JDOMap. + * @return the type of the values of this JDOMap + */ + public JavaType getValueType() { + if (valueType != null) { + // return valueType, if explicitly set by the setter + return valueType; + } + + // not set => calculate + JavaType type = null; + if (valueTypeName != null) { + JDOField jdoField = getDeclaringField(); + JDOClass jdoClass = jdoField.getDeclaringClass(); + JDOModel jdoModel = jdoClass.getDeclaringModel(); + type = TypeSupport.resolveType(jdoModel, valueTypeName, + jdoClass.getPackagePrefix()); + if (type == null) { + throw new ModelFatalException( + msg.msg("EXC_CannotResolveValueType", valueTypeName, + jdoField.getName(), jdoClass.getName())); //NOI18N + } + } + + return type; + } + + /** + * Set the type representation of the values for this JDOMap. + * @param valueType the type representation of the values + */ + public void setValueType(JavaType valueType) { + this.valueType = valueType; + if (valueType != null) { + setKeyTypeName(valueType.getName()); + } + } + + /** + * Get the string representation of the type of the values for this JDOMap. + * @return the key value as string + */ + public String getValueTypeName() { + return valueTypeName; + } + + /** + * Set string representation of the type of the values for this JDOMap. + * @param valueTypeName the name of the value type + */ + public void setValueTypeName(String valueTypeName) { + this.valueTypeName = valueTypeName; + } + +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOMemberImpl.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOMemberImpl.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOMemberImpl.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOMemberImpl.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,165 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jdo.impl.model.jdo; + +import java.text.Collator; + +import org.apache.jdo.model.jdo.JDOClass; +import org.apache.jdo.model.jdo.JDOMember; + +/** + * This is the super interface for named JDO metadata elements, + * such as JDOClass and JDOField. + * + * @author Michael Bouschen + */ +public class JDOMemberImpl + extends JDOElementImpl + implements JDOMember +{ + /** Property name.*/ + private String name; + + /** Relationship JDOClass<->JDOMember. */ + private JDOClass declaringClass; + + /** + * Returns the name of this JDOMember. + * @return the name + */ + public String getName() + { + return name; + } + + /** + * Sets the name of this JDOMember. + * @param name the name + */ + public void setName(String name) + { + this.name = name; + } + + /** + * Get the declaring class of this JDOMember. + * @return the class that owns this JDOMember, or <code>null</code> + * if the element is not attached to any class + */ + public JDOClass getDeclaringClass() + { + return declaringClass; + } + + /** + * Set the declaring class of this JDOMember. + * @param declaringClass the declaring class of this member element + */ + public void setDeclaringClass(JDOClass declaringClass) + { + this.declaringClass = declaringClass; + } + + //================= redefinition of java.lang.Object methods ================ + + /** + * Overrides Object's <code>toString</code> method to return the name + * of this persistence element. + * @return a string representation of the object + */ + public String toString () + { + return getName(); + } + + /** + * Overrides Object's <code>equals</code> method by comparing the name + * of this member with the name of the argument obj. The method returns + * <code>false</code> if obj does not have the same dynamic type as this + * member. + * @return <code>true</code> if this object is the same as the obj argument; + * <code>false</code> otherwise. + * @param obj the reference object with which to compare. + */ + public boolean equals(Object obj) + { + if (obj == null) + return false; + if (obj == this) + return true; + + // check for the right class and then do the name check by + // calling compareTo. + return (getClass() == obj.getClass()) && (compareTo(obj) == 0); + } + + /** Overrides Object's <code>hashCode</code> method to return the hashCode + * of this name. + * @return a hash code value for this object. + */ + public int hashCode() + { + return (getName()==null) ? 0 : getName().hashCode(); + } + + //================= implementation of Comparable ================ + + /** + * Compares this object with the specified object for order. Returns a + * negative integer, zero, or a positive integer as this object is less than, + * equal to, or greater than the specified object. The specified object must + * be a an instance of JDOMember, if not a ClassCastException is thrown. + * The order of JDOMember instances is defined by the order of their names. + * JDOMember instances without name are considered to be less than any named + * member. + * @param o the Object to be compared. + * @return a negative integer, zero, or a positive integer as this object is + * less than, equal to, or greater than the specified object. + * @exception ClassCastException - if the specified object is null or is not + * an instance of JDOMember + */ + public int compareTo(Object o) + { + // null is not allowed + if (o == null) + throw new ClassCastException(); + if (o == this) + return 0; + + String thisName = getName(); + // the following throws a ClassCastException if o is not a JDOMember + String otherName = ((JDOMember)o).getName(); + // if this does not have a name it should compare less than any named + if (thisName == null) { + return (otherName == null) ? 0 : -1; + } + + // if this is named and o does not have a name it should compare greater + if (otherName == null) { + return 1; + } + + // now we know that this and o are named JDOMembers => compare the names + int ret = thisName.compareTo(otherName); + // If both names are equal, both objects might have different types. + // If so order both objects by their type names + // (necessary to be consistent with equals) + if ((ret == 0) && (getClass() != o.getClass())) + ret = getClass().getName().compareTo(o.getClass().getName()); + return ret; + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOModelFactoryImplDynamic.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOModelFactoryImplDynamic.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOModelFactoryImplDynamic.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOModelFactoryImplDynamic.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,89 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jdo.impl.model.jdo; + +import java.util.Map; +import java.util.HashMap; + +import org.apache.jdo.model.java.JavaModel; +import org.apache.jdo.model.jdo.JDOModel; +import org.apache.jdo.model.jdo.JDOModelFactory; + +/** + * Factory for dynamic JDOModel instances. The factory provides a + * mechanism to cache JDOModel instances per JavaModel instances. + * <p> + * TBD: + * <ul> + * <li> Check synchronization. + * </ul> + * + * @author Michael Bouschen + * @since 1.1 + * @version 1.1 + */ +public class JDOModelFactoryImplDynamic implements JDOModelFactory { + + /** + * Map of JDOModel instances, key is the JavaModel + * [EMAIL PROTECTED] #getJDOModel(JavaModel javaModel)} + */ + private Map modelCache = new HashMap(); + + /** The singleton JDOModelFactory instance. */ + private static JDOModelFactory jdoModelFactory = + new JDOModelFactoryImplDynamic(); + + /** + * Creates new JDOModelFactory. This constructor should not be + * called directly; instead, the singleton access method + * [EMAIL PROTECTED] #getInstance} should be used. + */ + protected JDOModelFactoryImplDynamic() {} + + /** + * Get an instance of JDOModelFactory. + * @return an instance of JDOModelFactory + */ + public static JDOModelFactory getInstance() { + return jdoModelFactory; + } + + /** + * Creates a new empty JDOModel instance. + */ + public JDOModel createJDOModel(JavaModel javaModel) { + return new JDOModelImplDynamic(javaModel); + } + + /** + * Returns the JDOModel instance for the specified key. + * @param javaModel the javaModel used to cache the returned JDOModel instance + */ + public JDOModel getJDOModel(JavaModel javaModel) { + synchronized (this.modelCache) { + JDOModel jdoModel = (JDOModel)modelCache.get(javaModel); + if (jdoModel == null) { + // create new model and store it using the specified javaModel + jdoModel = createJDOModel(javaModel); + modelCache.put(javaModel, jdoModel); + } + return jdoModel; + } + } + +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOModelImplDynamic.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOModelImplDynamic.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOModelImplDynamic.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOModelImplDynamic.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,718 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jdo.impl.model.jdo; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.IOException; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; + +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.jdo.impl.model.jdo.xml.JDOHandler; +import org.apache.jdo.impl.model.jdo.xml.JDOHandlerImpl; +import org.apache.jdo.impl.model.jdo.xml.JDOParser; +import org.apache.jdo.model.ModelException; +import org.apache.jdo.model.ModelFatalException; +import org.apache.jdo.model.java.JavaModel; +import org.apache.jdo.model.java.JavaType; +import org.apache.jdo.model.jdo.JDOClass; +import org.apache.jdo.model.jdo.JDOModel; +import org.apache.jdo.model.jdo.JDOPackage; +import org.apache.jdo.util.I18NHelper; + +import org.xml.sax.SAXException; +import org.xml.sax.InputSource; + +/** + * A JDOModel instance bundles a number of JDOClass instances used by an + * application. It provides factory methods to create and retrieve JDOClass + * instances. A fully qualified class name must be unique within a JDOModel + * instance. The model supports multiple classes having the same fully qualified + * name by different JDOModel instances. + * <p> + * The dynamic JDOModel implementation does not store any internally + * calculated values. It is intended to be used in an environment + * where JDO metatdata are likely to be changed (e.g. at development + * time). + * <br> + * There are two exceptions: + * <ul> + * <li>JDOModelImplDynamic caches JDOClass instances. This means a + * second lookup of the same class will return the same JDOClass + * instance. + * <li>JDOModelImplDynamic manages a list of xml resources (.jdo + * files) that are processed already, to avoid reading the same + * resource again. + * <p> + * TBD: + * <ul> + * <li> Other implementations of JavaModel interface: Development + * <li> Check synchronization. + * <li> Check non validating XML parsing + * <li> Open issue: a .jdo file might contain XML for multiple classes. + * Today all the metadata is stored in the same jdoModel instance, but at runtime + * class loading determines the correct jdoModel instance. + * Either we need to be able to change the declaringModel of a JDOClass instance. + * Or reading a .jdo only load metadata for the requested class, so all the other + * metadata is ignored. + * </ul> + * + * @author Michael Bouschen + * @since 1.1 + * @version 1.1 + */ +public class JDOModelImplDynamic extends JDOElementImpl implements JDOModel { + + /** + * Map of JDOPackage managed by this JDOModel instance, + * key is the package name. + */ + private Map jdoPackages = new HashMap(); + + /** + * Map of JDOClass objects managed by this JDOModel instance, + * key is the fully qualified class name. + */ + private Map jdoClasses = new HashMap(); + + /** + * Set of names of XML resources that are processed already + * (see {link #lookupXMLMetadata(String className)}. + */ + private Set processedResources = new HashSet(); + + /** The JavaModel used to get type info. */ + private JavaModel javaModel; + + /** I18N support */ + protected final static I18NHelper msg = + I18NHelper.getInstance(JDOModelImplDynamic.class); + + /** XML Logger */ + protected static Log xmlLogger = + LogFactory.getFactory().getInstance("org.apache.jdo.impl.model.jdo.xml"); // NOI18N + + /** Logger */ + protected static Log logger = + LogFactory.getFactory().getInstance("org.apache.jdo.impl.model.jdo"); // NOI18N + + /** + * Constructor. + * JDOModel instances are created using the JDOModelFactory only. + */ + protected JDOModelImplDynamic(JavaModel javaModel) { + super(); + setJavaModel(javaModel); + } + + /** + * The method returns a JDOClass instance for the specified package name. + * If this JDOModel contains the corresponding JDOPackage instance, + * the existing instance is returned. Otherwise, it creates a new JDOPackage + * instance and returns the new instance. + * @param packageName the name of the JDOPackage instance + * to be returned + * @return a JDOPackage instance for the specified package name + * @exception ModelException if impossible + */ + public JDOPackage createJDOPackage(String packageName) + throws ModelException { + JDOPackage jdoPackage = getJDOPackage(packageName); + if (jdoPackage == null) { + jdoPackage = new JDOPackageImpl(); + jdoPackage.setName(packageName); + jdoPackage.setDeclaringModel(this); + jdoPackages.put(packageName, jdoPackage); + } + return jdoPackage; + } + + /** + * The method returns the JDOPackage instance for the specified package + * name, if present. The method returns <code>null</code> if it cannot + * find a JDOPackage instance for the specified name. + * @param packageName the name of the JDOPackage instance + * to be returned + * @return a JDOPackage instance for the specified package name + * or <code>null</code> if not present + */ + public JDOPackage getJDOPackage(String packageName) { + return (JDOPackage)jdoPackages.get(packageName); + } + + /** + * Returns the collection of JDOPackage instances declared by this JDOModel + * in the format of an array. + * @return the packages declared by this JDOModel + */ + public JDOPackage[] getDeclaredPackages() { + return (JDOPackage[])jdoPackages.values().toArray( + new JDOPackage[jdoPackages.size()]); + } + + /** + * The method returns a JDOClass instance for the specified fully qualified + * class name. If this JDOModel contains the corresponding JDOClass instance, + * the existing instance is returned. Otherwise, it creates a new JDOClass + * instance, sets its declaringModel and returns the new instance. + * <p> + * Invoking this method is method is equivalent to + * <code>createJDOClass(className, true)</code>. + * @param className the fully qualified class name of the JDOClass instance + * to be returned + * @return a JDOClass instance for the specified class name + * @exception ModelException if impossible + */ + public JDOClass createJDOClass(String className) throws ModelException { + return createJDOClass(className, true); + } + + /** + * The method returns a JDOClass instance for the specified fully qualified + * class name. If this JDOModel contains the corresponding JDOClass instance, + * the existing instance is returned. Otherwise, if the flag loadXMLMetadata + * is set to <code>true</code> the method tries to find the JDOClass + * instance by reading the XML metadata. If it could not be found the method + * creates a new JDOClass instance, sets its declaringModel and returns the + * instance. + * @param className the fully qualified class name of the JDOClass instance + * to be returned + * @param loadXMLMetadata indicated whether to read XML metadata or not + * @return a JDOClass instance for the specified class name + * @exception ModelException if impossible + */ + public synchronized JDOClass createJDOClass(String className, + boolean loadXMLMetadata) + throws ModelException { + JDOClass jdoClass = getJDOClass(className, loadXMLMetadata); + if (jdoClass == null) { + if (logger.isDebugEnabled()) + logger.debug("JDOModel.createJDOClass: " + //NOI18N + "create new JDOClass instance " + className); //NOI18N + jdoClass = newJDOClassInstance(); + jdoClass.setName(className); + jdoClass.setDeclaringModel(this); + jdoClasses.put(className, jdoClass); + // create the corresponding JDOPackage + jdoClass.setJDOPackage(createJDOPackage(getPackageName(className))); + } + return jdoClass; + } + + /** + * The method returns the JDOClass instance for the specified fully + * qualified class name if present. The method returns <code>null</code> + * if it cannot find a JDOClass instance for the specified name. + * <p> + * Invoking this method is equivalent to + * <code>getJDOClass(className, true)</code>. + * @param className the fully qualified class name of the JDOClass instance + * to be returned + * @return a JDOClass instance for the specified class name + * or <code>null</code> if not present + */ + public JDOClass getJDOClass(String className) { + return getJDOClass(className, true); + } + + /** + * The method returns the JDOClass instance for the specified fully + * qualified class name if present. If the flag loadXMLMetadata is set + * to <code>true</code> the method tries to find the JDOClass instance by + * reading the XML metadata. The method returns null if it cannot find a + * JDOClass instance for the specified name. + * @param className the fully qualified class name of the JDOClass instance + * to be returned + * @param loadXMLMetadata indicate whether to read XML metatdata or not + * @return a JDOClass instance for the specified class name + * or <code>null</code> if not present + * @exception ModelException if impossible + */ + public synchronized JDOClass getJDOClass(String className, + boolean loadXMLMetadata) { + + boolean trace = logger.isTraceEnabled(); + + // check whether the class is known to be non PC + if (isKnownNonPC(className)) { + if (trace) + logger.trace("JDOModel.getJDOClass: " + className + //NOI18N + " known to be non-persistence-capable"); //NOI18N + return null; + } + + JDOClass jdoClass = (JDOClass)jdoClasses.get(className); + if (trace) + logger.trace("JDOModel.getJDOClass: " + className + //NOI18N + ((jdoClass != null) ? " cached" : " not cached")); //NOI18N + + // check for XML metatdata + if (loadXMLMetadata) { + if (jdoClass == null) + jdoClass = lookupXMLMetadata(className); + else if (!isXMLProcessed(jdoClass)) + jdoClass = lookupXMLMetadata(jdoClass); + + if (jdoClass == null) { + // we loaded XML metadata, but there is no metadata + // for this class => known to be non persistence-capable + knownNonPC(className); + } + } + + return jdoClass; + } + + /** + * Returns the collection of JDOClass instances declared by this JDOModel + * in the format of an array. + * @return the classes declared by this JDOModel + */ + public synchronized JDOClass[] getDeclaredClasses() { + return (JDOClass[])jdoClasses.values().toArray( + new JDOClass[jdoClasses.size()]); + } + + /** + * Returns the JavaModel bound to this JDOModel instance. + * @return the JavaModel + */ + public JavaModel getJavaModel() { + return javaModel; + } + + /** + * Sets the JavaModel for this JDOModel instance. + * @param javaModel the JavaModel + */ + public void setJavaModel(JavaModel javaModel) { + this.javaModel = javaModel; + } + + /** + * Returns the parent JDOModel instance of this JDOModel. + * @return the parent JDOModel + */ + public JDOModel getParent() { + if (javaModel != null) { + JavaModel parentJavaModel = javaModel.getParent(); + if (parentJavaModel != null) + return parentJavaModel.getJDOModel(); + } + return null; + } + + /** + * This method returns the JDOClass instance that defines the specified type + * as its objectId class. In the case of an inheritance hierarchy it returns + * the top most persistence-capable class of the hierarchy (see + * [EMAIL PROTECTED] JDOClass#getPersistenceCapableSuperclass}). + * @param objectIdClass the type representation of the ObjectId class + * @return the JDOClass defining the specified class as ObjectId class + */ + public JDOClass getJDOClassForObjectIdClass(JavaType objectIdClass) { + // Note, method getJDOClassForObjectIdClass is not synchronized to + // avoid a deadlock with PC class registration. + if (logger.isTraceEnabled()) + logger.trace("JDOModel.getJDOClassForObjectIdClass: " + //NOI18N + "check objectIdClass " +objectIdClass); //NOI18N + + if (objectIdClass == null) + return null; + + JDOClass jdoClass = null; + String objectIdClassName = objectIdClass.getName(); + // check all JDOClasses for this JDOModel instance + List classesToActivate = new ArrayList(); + while (true) { + try { + for (Iterator i = jdoClasses.values().iterator(); i.hasNext();) { + JDOClass next = (JDOClass)i.next(); + if (isXMLProcessed(next)) { + // XML metadata is loaded => check the objectIdClass + if (objectIdClassName.equals( + next.getDeclaredObjectIdClassName())) { + // found => return + return next; + } + } + else { + // XML metadata is NOT loaded => + // store the class for later processing. + // Do not load the XML metadata here. This might create + // new JDOClass instances in this model for other pc + // classes listed in the same .jdo file. This would + // change the jdoClasses map while its values are + // iterated => ConcurrentModificationException + classesToActivate.add(next); + } + } + // No ConcurrentModificationException => break the loop + break; + } + catch (ConcurrentModificationException ex) { + // ConcurrentModificationException means a JDOClass was + // added to the JDOModel in parallel => + // start the loop again. + } + } + + // None of the activated JDOClasses knows the objectIdClass => + // activate the classes that were registered but not activated + // and check these classes + for (Iterator i = classesToActivate.iterator(); i.hasNext();) { + JDOClass next = (JDOClass)i.next(); + lookupXMLMetadata(next); + + if (objectIdClass.equals(next.getDeclaredObjectIdClassName())) { + // found => return + return next; + } + } + + // objectIdClass not found in this model => return null + return null; + } + + //========= Internal helper methods ========== + + /** Returns a new instance of the JDOClass implementation class. */ + protected JDOClass newJDOClassInstance() { + return new JDOClassImplDynamic(); + } + + /** + * Checks whether the type with the specified name does NOT denote a + * persistence-capable class. + * @param typeName name of the type to be checked + * @return <code>true</code> if types is a name of a primitive type; + * <code>false</code> otherwise + */ + protected boolean isKnownNonPC(String typeName) { + // Any class from packages java and javax are supposed to be non-pc. + return typeName.startsWith("java.") || //NOI18N + typeName.startsWith("javax."); //NOI18N + } + + /** + * Hook called when a class is known to be non persistence + * capable. Subclasses might want to keep track of classes marked + * as non pc classes and use this in the implementation of + * {link #isKnownNonPC(String typeName)}. + * @param className the name of the non-pc class + */ + protected void knownNonPC(String className) { + } + + /** + * Return true if the specified JDOClass is activated. + * A class is activated, if the class XML metadata is processed + * for this JDOClass. + * @return <code>true</code> if XML metadata is processed; + * <code>false</code> otherwise + */ + private boolean isXMLProcessed(JDOClass jdoClass) { + if (jdoClass instanceof JDOClassImplDynamic) + return ((JDOClassImplDynamic)jdoClass).isXMLProcessed(); + return false; + } + + /** + * The method seaches JDO metadata for the class with the specified + * class name. Chapter 18 of the JDO specification defines the search + * order. The method skips resources that have been tried to load + * before, no matter whether the resource currently exist. + * The method returns the populated JDOClass instance, if there is XML + * metadata available for the specified class name. Otherwise it + * returns <code>null</code>. + * <p> + * The purpose of this method is to populate an existing JDOClass + * instance with the JDO metadata. It throws an exception if there is + * no jdo file for this class. The specified jdoClass must not be + * <code>null</code>; otherwise a NullPointerException is thrown. + * @param jdoClass the non-activated JDOClass instance. + * @return the JDOClass instance for the specified class name or + * <code>null</code> if there is no XML metadata. + * @exception ModelFatalException indicates a problem while parsing the + * XML file or a missing XML file. + * @exception NullPointerException the specified jdoClass is + * <code>null</code>. + */ + private JDOClass lookupXMLMetadata(JDOClass jdoClass) + throws ModelFatalException, NullPointerException { + String className = jdoClass.getName(); + JDOClass activated = lookupXMLMetadata(className); + if (activated == null) { + throw new ModelFatalException(msg.msg( + "EXC_MissingJDOMetadata", className)); //NOI18N + } + else if (activated != jdoClass) { + throw new ModelFatalException(msg.msg( + "ERR_MultipleJDOClassInstances", className)); //NOI18N + } + return jdoClass; + } + + /** + * The method seaches JDO metadata for the class with the specified + * class name. Chapter 18 of the JDO specification defines the search + * order. The method skips resources that have been tried to load + * before, no matter whether the resource currently exist. + * The method returns the populated JDOClass instance, if there is XML + * metadata available for the specified class name. Otherwise it + * returns <code>null</code>. + * @param className the name of the class to check for XML metadata. + * @return the JDOClass instance for the specified class name or + * <code>null</code> if there is no XML metadata. + */ + private JDOClass lookupXMLMetadata(String className) { + boolean debug = xmlLogger.isDebugEnabled(); + JDOClass jdoClass = null; + + if (debug) + xmlLogger.debug("JDOModel.lookupXMLMetadata:" + // NOI18N + " lookup XML for class " + className); // NOI18N + // Iterate possible resources to find JDO metadata for className + Iterator i = new MetadataResourceNameIterator(className); + while((jdoClass == null) && i.hasNext()) { + String resource = (String)i.next(); + if (processedResources.contains(resource)) { + if (debug) + xmlLogger.debug(" XML " + resource + //NOI18N + " processed already"); //NOI18N + // processed already => skip + continue; + } + else { + // add resource to the list of processed resources + // Note, this adds the resource no matter whether the + // resource existst or not. This implies this JDOModel + // instance will not check this resource again, + // even if it exists, again. + processedResources.add(resource); + // load resource + jdoClass = loadXMLResource(resource, className); + } + } + if (debug) + xmlLogger.debug("JDOModel.lookupXMLMetadata: " + //NOI18N + ((jdoClass!=null)?"found":"no") + //NOI18N + " JDO metadata for class " + className); //NOI18N + return jdoClass; + } + + /** + * Load the specified resource assuming it contains JDO metadata for + * one or more persistence capable classes. + * The method returns the populated JDOClass instance, if the specified + * resource has XML metadata for the specified class name. Otherwise it + * returns <code>null</code>. + * @param resource resource to load + * @param className the name of the class to check for XML metadata. + * @return the JDOClass instance for the specified class name or + * <code>null</code> if the specified resource has no XML metadata. + */ + private JDOClass loadXMLResource(String resource, String className) { + boolean debug = xmlLogger.isDebugEnabled(); + JDOClass jdoClass = null; + InputStream stream = javaModel.getInputStreamForResource(resource); + if (stream == null) { + if (debug) + xmlLogger.debug(" XML " + resource + " not available"); //NOI18N + } + else { + // resource exists => parse it + // Store all pc classes specified in this resource in this + // JDOModel instance => pass this to the handler + JDOHandler handler = new JDOHandlerImpl(this); + JDOParser parser = new JDOParser(handler); + try { + if (debug) + xmlLogger.debug(" XML " + resource + //NOI18N + " found, start parsing ..."); //NOI18N + parser.parse(new InputSource(new InputStreamReader(stream))); + } + catch (SAXException ex) { + throw new ModelFatalException( + msg.msg("EXC_XMLError", resource), ex); //NOI18N + } + catch (ParserConfigurationException ex) { + throw new ModelFatalException( + msg.msg("EXC_XMLError", resource), ex); //NOI18N + } + catch (IOException ex) { + throw new ModelFatalException( + msg.msg("EXC_XMLError", resource), ex); //NOI18N + } + finally { + try { stream.close(); } + catch (IOException ex) { + // ignore close exception, stream will be nullified anyway + } + } + stream = null; + + // post process loaded JDOClasses + Collection newJDOClasses = handler.handledJDOClasses(); + if (debug) + xmlLogger.debug(" XML " + resource + //NOI18N + " has JDO metadata for class(es) " + //NOI18N + newJDOClasses); + for (Iterator i = newJDOClasses.iterator(); i.hasNext();) { + JDOClass next = (JDOClass)i.next(); + if (className.equals(next.getName())) { + jdoClass = next; + } + checkSuperclass(next); + } + if (jdoClass == null) + if (debug) + xmlLogger.debug(" XML " + resource + //NOI18N + " does not have JDO metadata for class " + //NOI18N + className); + } + return jdoClass; + } + + /** + * Updates the pcSuperclass property of the specified JDOClass and all its + * superclasses. + * @param jdoClass the class to be checked + */ + private void checkSuperclass(JDOClass jdoClass) { + if (jdoClass != null) { + JDOClass superclass = jdoClass.getPersistenceCapableSuperclass(); + checkSuperclass(superclass); + } + } + + /** Returns the package name of a class name */ + private String getPackageName(String className) { + int index = className.lastIndexOf('.'); + return (index == -1) ? "" : className.substring(0, index); //NOI18N + } + + /** + * This Iterator implementation iterates resource names of possible JDO + * metadata files for the specified class name. Chapter 18 of the JDO + * specification defines the search order as follows: + * META-INF/package.jdo, WEB-INF/package.jdo, package.jdo, + * <package>/.../<package>/package.jdo, and <package>/<class>.jdo. + */ + private static class MetadataResourceNameIterator + implements Iterator { + /** Suffix of a JDO metadata file. */ + private static final String JDO_SUFFIX = ".jdo"; //NOI18N + + /** The name of a package JDO metadata file. */ + private static final String PACKAGE_JDO = "package" + JDO_SUFFIX; //NOI18N + + /** List of constant package JDO metadata file names. */ + private static final String[] constantResources = { + "META-INF/" + PACKAGE_JDO, //NOI18N + "WEB-INF/" + PACKAGE_JDO, //NOI18N + PACKAGE_JDO + }; + + /** Indicates whether this iterator has more elements. */ + private boolean hasNext = true; + + /** The class name as resource name. */ + private final String prefix; + + /** Current index in the list of constant package JDO metadata file names. */ + private int constantResourcesIndex = 0; + + /** Current index in the prefix. */ + private int fromIndex = 0; + + /** Constructor. */ + public MetadataResourceNameIterator(String className) { + this.prefix = className.replace('.', '/'); + } + + /** + * Returns <code>true</code> if the iteration has more elements. + * @return <code>true</code> if the iterator has more elements. + */ + public boolean hasNext() { + return hasNext; + } + + /** + * Returns the next resource name. + * @return the next resource name. + * @exception NoSuchElementException iteration has no more elements. + */ + public Object next() { + String resource = null; + if (!hasNext) { + throw new NoSuchElementException(); + } + else if (constantResourcesIndex < constantResources.length) { + // Use a constant resource name, if there is one left in + // the iteration. + resource = constantResources[constantResourcesIndex]; + constantResourcesIndex++; + } + else { + // No constant resource name left + // build resource names from the package of the class name + // Check for the next package, fromIndex is the index of + // the '/' used in the previous iteration. + int index = prefix.indexOf('/', fromIndex); + if (index != -1) { + // string needs to include '/' => use index+1 + resource = prefix.substring(0, index + 1) + PACKAGE_JDO; + fromIndex = index + 1; + } + else { + // no more package jdo files left => use class .jdo file + resource = prefix + JDO_SUFFIX; + // the class jdo file is the last resource to be checked + hasNext = false; + } + } + return resource; + } + + /** + * This Iterator does not implement this method. + * @exception UnsupportedOperationException if the + * <code>remove</code> operation is not supported by this + * Iterator. + */ + public void remove() { + throw new UnsupportedOperationException(); + } + + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOPackageImpl.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOPackageImpl.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOPackageImpl.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOPackageImpl.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,74 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jdo.impl.model.jdo; + +import java.util.*; + +import org.apache.jdo.model.jdo.JDOModel; +import org.apache.jdo.model.jdo.JDOPackage; + +/** + * A JDOPackage instance represents the JDO package metadata. + * + * @author Michael Bouschen + */ +public class JDOPackageImpl + extends JDOElementImpl + implements JDOPackage +{ + /** The package name. */ + private String name; + + /** Relationship JDOModel<->JDOPackage. Initialized during creation.*/ + private JDOModel declaringModel; + + /** + * Returns the name of this JDOPackage. + * @return the name + */ + public String getName() + { + return name; + } + + /** + * Sets the name of this JDOPackage. + * @param name the name + */ + public void setName(String name) + { + this.name = name; + } + + /** + * Returns the declaring JDOModel of this JDOPackage. + * @return the JDOModel that owns this JDOPackage. + */ + public JDOModel getDeclaringModel() + { + return declaringModel; + } + + /** + * Set the declaring JDOModel for this JDOPackage. + * @param model the declaring JDOModel of this JDOPackage. + */ + public void setDeclaringModel(JDOModel model) + { + this.declaringModel = model; + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOReferenceImpl.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOReferenceImpl.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOReferenceImpl.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDOReferenceImpl.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,31 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jdo.impl.model.jdo; + +import org.apache.jdo.model.jdo.JDOReference; + +/** + * An instance of this class represents the JDO relationship metadata + * of a reference relationship field. + * + * @author Michael Bouschen + */ +public class JDOReferenceImpl extends JDORelationshipImpl + implements JDOReference +{ + // empty implementation +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDORelationshipImpl.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDORelationshipImpl.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDORelationshipImpl.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/JDORelationshipImpl.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,109 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jdo.impl.model.jdo; + +import org.apache.jdo.model.jdo.JDOField; +import org.apache.jdo.model.jdo.JDORelationship; + +/** + * JDORelationship is the super interface for all interfaces representing + * JDO relationship metadata of a managed field of a persistence capable class. + * + * @author Michael Bouschen + */ +public abstract class JDORelationshipImpl extends JDOElementImpl + implements JDORelationship { + + /** Property lowerBound. No default. */ + private int lowerBound; + + /** Property upperBound. No default. */ + private int upperBound; + + /** Relationship JDOField<->JDORelationship. */ + private JDOField declaringField; + + /** Relationship JDORelationship<->JDORelationship. */ + private JDORelationship inverse; + + /** + * Get the lower cardinality bound for this relationship element. + * @return the lower cardinality bound + */ + public int getLowerBound() { + return lowerBound; + } + + /** + * Set the lower cardinality bound for this relationship element. + * @param lowerBound an integer indicating the lower cardinality bound + */ + public void setLowerBound(int lowerBound) { + this.lowerBound = lowerBound; + } + + /** + * Get the upper cardinality bound for this relationship element. + * @return the upper cardinality bound + */ + public int getUpperBound() { + return upperBound; + } + + /** + * Set the upper cardinality bound for this relationship element. + * @param upperBound an integer indicating the upper cardinality bound + */ + public void setUpperBound(int upperBound) + { + this.upperBound = upperBound; + } + + /** + * Get the declaring field of this JDORelationship. + * @return the field that owns this JDORelationship, or <code>null</code> + * if the element is not attached to any field + */ + public JDOField getDeclaringField() { + return declaringField; + } + + /** + * Set the declaring field of this JDORelationship. + * @param declaringField the declaring field of this relationship element + */ + public void setDeclaringField(JDOField declaringField) { + this.declaringField = declaringField; + } + + /** + * Get the inverse JDORelationship in the case of a managed relationship. + * @return the inverse relationship + */ + public JDORelationship getInverseRelationship() { + return inverse; + } + + /** + * Set the inverse JDORelationship in the case of a managed relationship. + * @param inverseRelationship the inverse relationship + */ + public void setInverseRelationship(JDORelationship inverseRelationship) { + this.inverse = inverseRelationship; + } + +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/caching/JDOArrayImplCaching.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/caching/JDOArrayImplCaching.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/caching/JDOArrayImplCaching.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/model/jdo/caching/JDOArrayImplCaching.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,64 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jdo.impl.model.jdo.caching; + +import org.apache.jdo.model.java.JavaType; +import org.apache.jdo.impl.model.jdo.JDOArrayImplDynamic; + +/** + * An instance of this class represents the JDO relationship metadata + * of a array relationship field. This caching implementation + * caches any calulated value to avoid re-calculating it if it is + * requested again. + * + * @author Michael Bouschen + * @since 1.1 + * @version 1.1 + */ +public class JDOArrayImplCaching extends JDOArrayImplDynamic { + + /** Type of the array element. */ + private transient JavaType elementType; + + /** + * Determines whether the values of the elements should be stored + * if possible as part of the instance instead of as their own instances + * in the datastore. + * @return <code>true</code> if the elements should be stored as part of + * the instance; <code>false</code> otherwise + */ + public boolean isEmbeddedElement() { + if (embeddedElement == null) { + embeddedElement = + super.isEmbeddedElement() ? Boolean.TRUE : Boolean.FALSE; + } + return embeddedElement.booleanValue(); + } + + /** + * Get the type representation of the array component type. + * @return the array component type + */ + public JavaType getElementType() { + if (elementType == null) { + elementType = super.getElementType(); + } + return elementType; + } + +} +