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

svn commit: r171348 [3/7] - in /incubator/jdo/trunk/core20: ./ src/ src/conf/ src/java/ src/java/org/ src/java/org/apache/ src/java/org/apache/jdo/ src/java/org/apache/jdo/impl/ src/java/org/apache/jdo/impl/model/ src/java/org/apache/jdo/impl/model/java/ src/java/org/apache/jdo/impl/model/java/reflection/ src/java/org/apache/jdo/impl/model/jdo/ src/java/org/apache/jdo/impl/model/jdo/caching/ src/java/org/apache/jdo/impl/model/jdo/util/ src/java/org/apache/jdo/impl/model/jdo/xml/ src/java/org/apache/jdo/model/ src/java/org/apache/jdo/model/java/ src/java/org/apache/jdo/model/jdo/ src/java/org/apache/jdo/util/

Added: incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/jdo/JDOClassImplDynamic.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/jdo/JDOClassImplDynamic.java?rev=171348&view=auto
==============================================================================
--- incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/jdo/JDOClassImplDynamic.java (added)
+++ incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/jdo/JDOClassImplDynamic.java Sun May 22 10:44:19 2005
@@ -0,0 +1,1043 @@
+/*
+ * 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 java.lang.reflect.Modifier;
+
+import org.apache.jdo.impl.model.jdo.util.TypeSupport;
+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.JDOField;
+import org.apache.jdo.model.jdo.JDOIdentityType;
+import org.apache.jdo.model.jdo.JDOMember;
+import org.apache.jdo.model.jdo.JDOModel;
+import org.apache.jdo.model.jdo.JDOPackage;
+
+import org.apache.jdo.util.I18NHelper;
+
+/**
+ * An instance of this class represents the JDO metadata of a persistence 
+ * capable class. This dynamic implementation only stores property
+ * values explicitly set by setter method. It does not store any
+ * calculated values such as list of managed or persistent fields, 
+ * list of field numbers etc. 
+ * <p>
+ * TBD:
+ * <ul>
+ * <li> Property change support
+ * </ul> 
+ *
+ * @author Michael Bouschen
+ * @since 1.1
+ * @version 1.1
+ */
+public class JDOClassImplDynamic
+    extends JDOMemberImpl
+    implements JDOClass
+{
+    /** Property identityType. Default see {@link #getIdentityType}. */
+    protected int identityType = JDOIdentityType.UNSPECIFIED;
+
+    /** Property objectIdClass. No default. */
+    protected transient JavaType objectIdClass;
+
+    /** Property declaredObjectIdClassName. No default. */
+    private String declaredObjectIdClassName;
+
+    /** Property requiresExtent. It defaults to <code>true</code>. */
+    private boolean requiresExtent = true;
+
+    /** Property pcSuperclassName. No default. */
+    private String pcSuperclassName;
+
+    /** Relationship JDOClass<->JDOClass. */
+    protected JDOClass pcSuperclass;
+
+    /** Property javaType. No default.*/
+    protected transient JavaType javaType;
+
+    /** Relationship JDOModel<->JDOClass. Initialized during creation.*/
+    private JDOModel declaringModel;
+
+    /**
+     * Relationship JDOClass<->JDOMember.
+     * Map of fields declared by this JDOClass. Key is the unqualified 
+     * field name, value is the JDOField instance. 
+     */
+    private Map declaredFields = new HashMap();
+
+    /**
+     * Relationship JDOClass<->JDOMember.
+     * Map of inner classes declared by this JDOClass. 
+     * Key is the unqualified name of the inner class, 
+     * value is the JDOClass instance of the inner class.
+     */
+    private Map declaredClasses = new HashMap();
+
+    /** Relationship JDOClass -> JDOPackage. */
+    private JDOPackage jdoPackage;
+
+    /** Flag indicating whether XML metadata is processed already. */
+    private boolean xmlMetadataLoaded = false;
+
+    /** I18N support */
+    protected final static I18NHelper msg =  
+        I18NHelper.getInstance(JDOClassImplDynamic.class);
+
+    /** 
+     * Get the JDO identity type of this JDOClass.
+     * The identity type of the least-derived persistence-capable class defines
+     * the identity type for all persistence-capable classes that extend it.
+     * The identity type of the least-derived persistence-capable class is
+     * defaulted to {@link JDOIdentityType#APPLICATION} if objectid-class is 
+     * specified, and {@link JDOIdentityType#DATASTORE}, if not. 
+     * @return the JDO identity type, one of 
+     * {@link JDOIdentityType#APPLICATION}, 
+     * {@link JDOIdentityType#DATASTORE}, or 
+     * {@link JDOIdentityType#NONDURABLE}
+     */
+    public int getIdentityType() {
+        if (identityType != JDOIdentityType.UNSPECIFIED) {
+            // return identity type, if explicitly set by the setter
+            return identityType;
+        }
+        
+        // not set => caclulate 
+        JDOClass pcRoot = getPersistenceCapableRootClass();
+        int result = 0;
+        if (pcRoot == this) {
+            // this is the least-derived pc class
+            result = (pcRoot.getDeclaredObjectIdClassName() != null) ? 
+                JDOIdentityType.APPLICATION : JDOIdentityType.DATASTORE; 
+        }
+        else {
+            // get the identityType from the least-derived pc class
+            result = pcRoot.getIdentityType();
+        }
+
+        return result;
+    }
+
+    /** 
+     * Set the object identity type of this JDOClass.
+     * @param identityType an integer indicating the JDO identity type, one of:
+     * {@link JDOIdentityType#APPLICATION}, 
+     * {@link JDOIdentityType#DATASTORE}, or 
+     * {@link JDOIdentityType#NONDURABLE}
+     */
+    public void setIdentityType(int identityType) {
+        this.identityType = identityType;
+    }
+    
+    /** 
+     * Get the JavaType representation of the object identity class 
+     * (primary key class) for this JDOClass. 
+     * @return the JavaType representation of the object identity class.
+     */
+    public JavaType getObjectIdClass() {
+        if (objectIdClass != null) {
+            // return objectIdClass if explicitly set by the setter
+            return objectIdClass;
+        }
+
+        // not set => try to resolve ObjectId class 
+        JavaType type = null;
+        String name = getDeclaredObjectIdClassName();
+        if (name != null) {
+            JavaModel javaModel = getDeclaringModel().getJavaModel();
+            type = javaModel.getJavaType(name);
+            if (Modifier.isAbstract(type.getModifiers()))
+                // do not return ObjectId class if abstract
+                type = null;
+        }
+        else {
+            JDOClass superclass = getPersistenceCapableSuperclass();
+            if (superclass != null) {
+                type = superclass.getObjectIdClass();
+            }
+        }
+        return type;
+    }
+
+    /** 
+     * Set the JavaType representation of the object identity class 
+     * (primary key class) for this JDOClass. 
+     * @param objectIdClass the JavaType representation of the 
+     * object identity class
+     */
+    public void setObjectIdClass(JavaType objectIdClass) {
+        this.objectIdClass = objectIdClass;
+    }
+
+    /** 
+     * Get the fully qualified name of the object identity class 
+     * (primary key class) for this JDOClass. 
+     * @return the name of the object identity class.
+     */
+    public String getDeclaredObjectIdClassName() {
+        if (declaredObjectIdClassName != null) {
+            // ObjectId is declared, but it might not be qualified
+            int index = declaredObjectIdClassName.indexOf('.');
+            if (index == -1) {
+                // not qualified => try to resolve it
+                JavaType type = TypeSupport.resolveType(getDeclaringModel(), 
+                    declaredObjectIdClassName, getPackagePrefix());
+                if (type == null) {
+                    throw new ModelFatalException(
+                        msg.msg("EXC_CannotResolveObjectIdClass", //NOI18N
+                                declaredObjectIdClassName, getName()));
+                }
+                this.declaredObjectIdClassName = type.getName();
+            }
+        }
+        return declaredObjectIdClassName;
+    }
+    
+    /** 
+     * Set the fully qualified name of the object identity class 
+     * (primary key class) for this JDOClass. 
+     * @param declaredObjectIdClassName the name of the object identity class
+     */
+    public void setDeclaredObjectIdClassName(String declaredObjectIdClassName) {
+        this.declaredObjectIdClassName = declaredObjectIdClassName;
+    }
+
+    /**
+     * Determines whether an extent must be managed for the 
+     * persistence-capable class described by this JDOClass.
+     * @return <code>true</code> if this class must manage an extent; 
+     * <code>false</code> otherwise
+     */
+    public boolean requiresExtent() {
+        return requiresExtent;
+    }
+    
+    /**
+     * Set whether an extent must be managed for the 
+     * persistence-capable class described by this JDOClass.
+     * @param requiresExtent <code>true</code> if this class must manage 
+     * an extent; <code>false</code> otherwise
+     */
+    public void setRequiresExtent(boolean requiresExtent) {
+        this.requiresExtent = requiresExtent;
+    }
+
+    /**
+     * Get the fully qualified class name of the persistence-capable superclass 
+     * of the persistence-capable class described by this JDOClass. If this 
+     * class does not have a persistence-capable superclass then 
+     * <code>null</code> is returned.
+     * @return the fully qualified name of the persistence-capable superclass 
+     * or <code>null</code> if there is no persistence-capable superclass 
+     */
+    public String getPersistenceCapableSuperclassName() {
+        if (pcSuperclassName != null) {
+            // pcSuperclassName is declared, but it might not be qualified
+            int index = pcSuperclassName.indexOf('.');
+            if (index == -1) {
+                // not qualified => try to resolve it
+                JavaType type = TypeSupport.resolveType(getDeclaringModel(),
+                    pcSuperclassName, getPackagePrefix());
+                if (type == null) {
+                    throw new ModelFatalException(
+                        msg.msg("EXC_CannotResolvePCSuperClass", //NOI18N
+                                pcSuperclassName, getName()));
+                }
+                this.pcSuperclassName = type.getName();
+            }
+        }
+        return pcSuperclassName;
+    }
+    
+    /**
+     * Set the fully qualified class name of the persistence-capable superclass 
+     * of the persistence-capable class described by this JDOClass.
+     * @param pcSuperclassName the fully qualified name of the 
+     * persistence-capable superclass 
+     */
+    public void setPersistenceCapableSuperclassName(String pcSuperclassName) {
+        this.pcSuperclassName = pcSuperclassName;
+    }
+
+    /**
+     * Provides the JavaType representaion corresponding to this JDOClass.
+     * <p>
+     * Note the difference between Object.getClass() and this method. The
+     * former returns the class of the object in hand, this returns the class
+     * of the object represented by this meta data.
+     * @return the JavaType object corresponding to this JDOClass.
+     */
+    public JavaType getJavaType() {
+        if (javaType != null) {
+            // return java type, if explicitly set by the setter
+            return javaType;
+        }
+        
+        // not set => calculate
+        JavaModel javaModel = declaringModel.getJavaModel();
+        return javaModel.getJavaType(getName());
+    }
+
+    /**
+     * Set the JavaType representation corresponding to this JDOClass.
+     * @param javaType the JavaType representation for this JDOClass
+     */
+    public void setJavaType(JavaType javaType) {
+        this.javaType = javaType;
+    }
+
+    /** 
+     * Determines whether the XML metadata for the class represented by this
+     * JDOClass has been loaded. 
+     * @return <code>true</code> if XML metadata is loaded;
+     * <code>false</code> otherwise
+     */
+    public boolean isXMLMetadataLoaded() {
+        return xmlMetadataLoaded;
+    }
+
+    /**
+     * Sets the flag indicating that the class XML metadata for this
+     * JDOClass is loaded to <code>true</code>.
+     */
+    public void setXMLMetadataLoaded() {
+        this.xmlMetadataLoaded = true;
+    }
+
+    /** 
+     * Remove the supplied member from the collection of members maintained by
+     * this JDOClass.
+     * @param member the member to be removed
+     * @exception ModelException if impossible
+     */
+    public void removeDeclaredMember(JDOMember member) throws ModelException {
+        if (member instanceof JDOField) {
+            declaredFields.remove(member.getName());
+        }
+        else if (member instanceof JDOClass) {
+            declaredClasses.remove(member.getName());
+        }
+        else {
+            String name = (member == null) ? "null" : member.getName(); //NOI18N
+            throw new ModelException(
+                msg.msg("EXC_InvalidMember", name)); //NOI18N
+        }
+    }
+    
+    /** 
+     * Returns the collection of JDOMember instances declared by this
+     * JDOClass in form of an array.
+     * @return the members declared by this JDOClass
+     */
+    public JDOMember[] getDeclaredMembers() {
+        List copy = new ArrayList(declaredFields.values());
+        copy.addAll(declaredClasses.values());
+        return (JDOMember[])copy.toArray(new JDOMember[copy.size()]);
+    }
+
+    /**
+     * Returns the declaring JDOModel of this JDOClass.
+     * @return the JDOModel that owns this JDOClass
+     */
+    public JDOModel getDeclaringModel() {
+        return declaringModel;
+    }
+
+    /**
+     * Set the declaring JDOModel for this JDOClass.
+     * @param model the declaring JDOModel of this JDOClass
+     */
+    public void setDeclaringModel(JDOModel model) {
+        this.declaringModel = model;
+    }
+    
+    /**
+     * Returns the JDOClass instance for the persistence-capable superclass 
+     * of this JDOClass. If this class does not have a persistence-capable 
+     * superclass then <code>null</code> is returned.
+     * @return the JDClass instance of the persistence-capable superclass
+     * or <code>null</code> if there is no persistence-capable superclass 
+     */
+    public JDOClass getPersistenceCapableSuperclass() {
+        if (pcSuperclass != null) {
+            // return pcSuperclass if explicitly set by the setter
+            return pcSuperclass;
+            
+        }
+        
+        // not set => try to resolve persistence capable superclass
+        String name = getPersistenceCapableSuperclassName();
+        if (pcSuperclassName != null) {
+            JavaType type = TypeSupport.resolveType(
+                getDeclaringModel(), pcSuperclassName, getPackagePrefix());
+            if (type == null) {
+                throw new ModelFatalException(
+                    msg.msg("EXC_CannotResolvePCSuperClass", //NOI18N
+                            pcSuperclassName, getName()));
+            }
+            JDOClass jdoClass = type.getJDOClass();
+            // pcSuperclassName might be unqualified
+            this.pcSuperclassName = type.getName();
+            return jdoClass;
+        }
+
+        return null;
+    }
+    
+    /**
+     * Set the JDOClass for the persistence-capable superclass 
+     * of this JDOClass.
+     * @param pcSuperclass the JDClass instance of the persistence-capable
+     * superclass
+     */
+    public void setPersistenceCapableSuperclass(JDOClass pcSuperclass) {
+        this.pcSuperclass = pcSuperclass;
+        this.pcSuperclassName = 
+            pcSuperclass != null ? pcSuperclass.getName() : null;
+    }
+
+    /**
+     * Returns the JDOPackage instance corresponding to the package name 
+     * of this JDOClass. 
+     * @return the JDOPackage instance of this JDOClass.
+     */
+    public JDOPackage getJDOPackage() {
+        return jdoPackage;
+    }
+
+    /**
+     * Sets the JDOPackage instance corresponding to the package name 
+     * of this JDOClass.
+     * @param jdoPackage the JDOPackage of this JDOClass.
+     */
+    public void setJDOPackage(JDOPackage jdoPackage) {
+        this.jdoPackage = jdoPackage;
+    }
+    
+    /**
+     * This method returns a JDOField instance for the field with the specified 
+     * name. If this JDOClass already declares such a field, the existing 
+     * JDOField instance is returned. Otherwise, it creates a new JDOField 
+     * instance, sets its declaringClass and returns the new instance.
+     * <P> 
+     * Note, if the field numbers for the managed fields of this JDOClass are 
+     * calculated, this methid will fail to create a new JDOField. Any new field
+     * would possibly invalidate existing field number 
+     * @param name the name of the field
+     * @exception ModelException if impossible
+     */
+    public JDOField createJDOField(String name) throws ModelException {
+        // check whether there is a field with the specified name
+        JDOField field = (JDOField)declaredFields.get(name);
+        if (field == null) {
+            field = newJDOFieldInstance();
+            field.setName(name);
+            field.setDeclaringClass(this);
+            declaredFields.put(name, field);
+        }
+        return field;
+    }
+    
+    /**
+     * This method returns a JDOClass instance representing an inner class of 
+     * this JDOClass If this JDOClass already declares such an inner class, 
+     * the existing JDOClass instance is returned. Otherwise, it creates a new 
+     * JDOClass instance, sets its declaringClass and returns the new instance.
+     * @param name the name of the inner class
+     * @exception ModelException if impossible
+     */
+    public JDOClass createJDOClass(String name) throws ModelException {
+        JDOClass innerClass = (JDOClass)declaredClasses.get(name);
+        if (innerClass == null) {
+            innerClass = newJDOClassInstance();
+            innerClass.setName(name);
+            innerClass.setDeclaringClass(this);
+            declaredClasses.put(name, innerClass);
+        }
+        return innerClass;
+    }
+
+    /**
+     * Returns the collection of JDOClass instances declared by this JDOClass.  
+     * @return the classes declared by this JDOClass
+     */
+    public JDOClass[] getDeclaredClasses() {
+        return (JDOClass[])declaredClasses.values().toArray(
+            new JDOClass[declaredClasses.size()]);
+    }
+
+    /**
+     * Returns the collection of JDOField instances declared by this JDOClass 
+     * in the form of an array. This does not include inherited fields.
+     * @return the fields declared by this JDOClass
+     */
+    public JDOField[] getDeclaredFields() {
+        Collection tmp = declaredFields.values();
+        return (JDOField[])tmp.toArray(new JDOField[tmp.size()]);
+    }
+
+    /**
+     * Returns the collection of managed JDOField instances declared by this
+     * JDOClass in the form of an array. The returned array does not include 
+     * inherited fields. A field is a managed field, if it has the 
+     * persistence-modifier 
+     * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT} or 
+     * {@link org.apache.jdo.model.jdo.PersistenceModifier#TRANSACTIONAL}. 
+     * The position of the fields in the returned array equals their
+     * relative field number as returned by
+     * {@link JDOField#getRelativeFieldNumber()}. The following holds
+     * true for any field in the returned array: 
+     * <ul>
+     * <li> <code>getDeclaredManagedFields()[i].getRelativeFieldNumber() 
+     * == i</code>
+     * <li> <code>getDeclaredManagedFields()[field.getRelativeFieldNumber()] 
+     * == field</code>
+     * </ul> 
+     * @return the managed fields declared by this JDOClass
+     */
+    public JDOField[] getDeclaredManagedFields() {
+        // Get the list of declared fields, skip the non managed fields
+        // and store the remaining fields into a list
+        List fieldList = new ArrayList();
+        for (Iterator i = declaredFields.values().iterator(); i.hasNext();) {
+            JDOField field = (JDOField)i.next();
+            if (field.isManaged())
+                fieldList.add(field);
+        }
+            
+        // Sort all declared fields. JDOFieldImpl implements Comparable.
+        // It uses the field name for comparison.
+        Collections.sort(fieldList);
+        JDOField[] fields = new JDOField[fieldList.size()];
+        fieldList.toArray(fields);
+        return fields;
+    }
+
+    /**
+     * Returns the collection of managed JDOField instances of this JDOClass 
+     * in the form of an array. The returned array includes inherited fields.
+     * A field is a managed field, if it has the persistence-modifier 
+     * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT} or 
+     * {@link org.apache.jdo.model.jdo.PersistenceModifier#TRANSACTIONAL}. 
+     * The position of the fields in the returned array equals their
+     * absolute field number as returned by 
+     * {@link JDOField#getFieldNumber()}. The following holds true for
+     * any field in the returned array: 
+     * <ul>
+     * <li> <code>getManagedFields()[i].getFieldNumber() == i</code>
+     * <li> <code>getManagedFields()[field.getFieldNumber()] == field</code>
+     * </ul> 
+     * @return the managed fields of this JDOClass
+     */
+    public JDOField[] getManagedFields() {
+        JDOField[] fields = null;
+        JDOField[] declared = getDeclaredManagedFields();
+        JDOClass superclass = getPersistenceCapableSuperclass();
+        if (superclass == null) {
+            // no pc superclass
+            fields = declared;
+        }
+        else {
+            // pc superclass
+            JDOField[] inherited = superclass.getManagedFields();
+            fields = new JDOField[inherited.length+declared.length];
+            System.arraycopy(inherited, 0, fields, 0, inherited.length);
+            System.arraycopy(declared, 0, fields, 
+                             inherited.length, declared.length);
+        }
+
+        return fields;
+    }
+
+    /**
+     * Returns the collection of persistent JDOField instances of this JDOClass 
+     * in the form of an array. The returned array includes inherited fields.
+     * A field is a persistent field, if it has the persistence-modifier 
+     * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT}.
+     * Please note, the position of the fields in the returned array might not 
+     * equal their absolute field number as returned by 
+     * {@link JDOField#getFieldNumber()}.
+     * @return the persistent fields of this JDOClass
+     */
+    public JDOField[] getPersistentFields() {
+        JDOField[] fields = getManagedFields();
+        JDOField[] tmp = new JDOField[fields.length];
+        int length = 0;
+        for (int i = 0; i < fields.length; i++) {
+            JDOField field = fields[i];
+            if (field.isPersistent()) {
+                tmp[length++] = field;
+            }
+        }
+        // now fill he returned array
+        // the array should have the correct length
+        JDOField[] result = new JDOField[length];
+        System.arraycopy(tmp, 0, result, 0, length);
+
+        return result;
+    }
+
+    /**
+     * Returns the collection of identifying fields of this JDOClass in the form
+     * of an array. The method returns the JDOField instances defined as 
+     * primary key fields (see {@link JDOField#isPrimaryKey}).
+     * @return the identifying fields of this JDOClass
+     */
+    public JDOField[] getPrimaryKeyFields() {
+        JDOField[] fields = getManagedFields();
+        JDOField[] tmp = new JDOField[fields.length];
+        int length = 0;
+        for (int i = 0; i < fields.length; i++) {
+            JDOField field = fields[i];
+            if (fields[i].isPrimaryKey()) {
+                tmp[length++] = field;
+            }
+        }
+        // now fill the returned array 
+        // the array should have the correct length
+        JDOField[] result = new JDOField[length];
+        System.arraycopy(tmp, 0, result, 0, length);
+
+        return result;
+    }
+
+    /**
+     * Returns the collection of persistent relationship fields of this JDOClass
+     * in the form of an array. The method returns the JDOField instances 
+     * defined as relationship (method {@link JDOField#getRelationship} returns
+     * a non null value) and having the persistence-modifier 
+     * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT}.
+     * @return the persistent relationship fields of this JDOClass
+     */
+    public JDOField[] getPersistentRelationshipFields() {
+        JDOField[] fields = getPersistentFields();
+        JDOField[] tmp = new JDOField[fields.length];
+        int length = 0;
+        for (int i = 0; i < fields.length; i++) {
+            JDOField field = fields[i];
+            if (field.isPersistent() && field.isRelationship()) {
+                tmp[length++] = field;
+            }
+        }
+        // now fill the returned array,
+        // the arrays should have the correct length
+        JDOField[] result = new JDOField[length];
+        System.arraycopy(tmp, 0, result, 0, length);
+
+        return result;
+    }
+
+    /**
+     * Returns the collection of default fetch group fields of this JDOClass
+     * in the form of an array. The method returns the JDOField instances 
+     * defined as part of the default fetch group 
+     * (method {@link JDOField#isDefaultFetchGroup} returns <code>true</code>.
+     * @return the default fetch group fields of this JDOClass
+     * @since 1.1
+     */
+    public JDOField[] getDefaultFetchGroupFields() {
+        JDOField[] fields = getManagedFields();
+        JDOField[] tmp = new JDOField[fields.length];
+        int length = 0;
+        for (int i = 0; i < fields.length; i++) {
+            JDOField field = fields[i];
+            if (field.isDefaultFetchGroup()) {
+                tmp[length++] = field;
+            }
+        }
+        // now fill defaultFetchGroupFields
+        // the arrays should have the correct length
+        JDOField[] result = new JDOField[length];
+        System.arraycopy(tmp, 0, result, 0, length);
+
+        return result;
+    }
+
+    /**
+     * Returns an array of absolute field numbers of the managed fields of this
+     * JDOClass. The returned array includes field numbers of inherited fields.
+     * A field is a managed field, if it has the persistence-modifier 
+     * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT} or 
+     * {@link org.apache.jdo.model.jdo.PersistenceModifier#TRANSACTIONAL}. 
+     * Only managed fields have a valid field number, thus the field number in 
+     * the returned array equals its index:
+     * <br>
+     *  <code>getManagedFields()[i] == i</code>
+     */
+    public int[] getManagedFieldNumbers() {
+        JDOField[] fields = getManagedFields();
+        int[] fieldNumbers = new int[fields.length];
+        for (int i = 0; i < fields.length; i++) {
+            fieldNumbers[i] = i;
+        }
+
+        return fieldNumbers;
+    }
+
+    /**
+     * Returns an array of absolute field numbers of the persistent fields of 
+     * this JDOClass. The returned array includes field numbers of inherited 
+     * fields. A persistent field has the persistence-modifier 
+     * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT}.
+     */
+    public int[] getPersistentFieldNumbers() {
+        JDOField[] fields = getManagedFields();
+        int[] tmp = new int[fields.length];
+        int length = 0;
+        for (int i = 0; i < fields.length; i++) {
+            JDOField field = fields[i];
+            if (field.isPersistent()) {
+                tmp[length++] = i;
+            }
+        }
+        // now fill the returned array, it should have the correct length
+        int[] fieldNumbers = new int[length];
+        System.arraycopy(tmp, 0, fieldNumbers, 0, length);
+
+        return fieldNumbers;
+    }
+    
+    /**
+     * Returns an array of absolute field numbers of the identifying fields 
+     * of this JDOClass. A field number is included in the returned array, 
+     * iff the corresponding JDOField instance is defined as primary  key field
+     * (see {@link JDOField#isPrimaryKey}).
+     * @return array of numbers of the identifying fields
+     */
+    public int[] getPrimaryKeyFieldNumbers() {
+        JDOField[] fields = getManagedFields();
+        int[] tmp = new int[fields.length];
+        int length = 0;
+        for (int i = 0; i < fields.length; i++) {
+            JDOField field = fields[i];
+            if (field.isPrimaryKey()) {
+                tmp[length++] = i;
+            }
+        }
+        // now fill the returned array, it should have the correct length
+        int[] fieldNumbers = new int[length];
+        System.arraycopy(tmp, 0, fieldNumbers, 0, length);
+
+        return fieldNumbers;
+    }
+
+    /**
+     * Returns an array of absolute field numbers of the non identifying, 
+     * persistent fields of this JDOClass. A field number is included in the 
+     * returned array, iff the corresponding JDOField instance is persistent and 
+     * not a not a primary key field (see {@link JDOField#isPrimaryKey}).
+     * A field is a persistent field, if it has the persistence-modifier 
+     * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT} or 
+     * (see {@link JDOField#getPersistenceModifier}). 
+     * @return array of numbers of the non identifying, persistent fields
+     */
+    public int[] getPersistentNonPrimaryKeyFieldNumbers() {
+        JDOField[] fields = getManagedFields();
+        int[] tmp = new int[fields.length];
+        int length = 0;
+        for (int i = 0; i < fields.length; i++) {
+            JDOField field = fields[i];
+            if (field.isPersistent() && !field.isPrimaryKey()) {
+                tmp[length++] = i;
+            }
+        }
+        // now fill the returned array, it should have the correct length
+        int[] fieldNumbers = new int[length];
+        System.arraycopy(tmp, 0, fieldNumbers, 0, length);
+
+        return fieldNumbers;
+    }
+    
+    /**
+     * Returns an array of absolute field numbers of persistent relationship 
+     * fields of this JDOClass. A field number is included in the returned 
+     * array, iff the corresponding JDOField instance is a relationship (method 
+     * {@link JDOField#getRelationship} returns a non null value) and has the 
+     * persistence-modifier 
+     * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT}.
+     * @return the field numbers of the persistent relationship fields
+     */
+    public int[] getPersistentRelationshipFieldNumbers() {
+        JDOField[] fields = getManagedFields();
+        int[] tmp = new int[fields.length];
+        int length = 0;
+        for (int i = 0; i < fields.length; i++) {
+            JDOField field = fields[i];
+            if (field.isPersistent() && field.isRelationship()) {
+                tmp[length++] = i;
+            }
+        }
+        // now fill the returned array, it should have the correct length
+        int[] fieldNumbers = new int[length];
+        System.arraycopy(tmp, 0, fieldNumbers, 0, length);
+
+        return fieldNumbers;
+    }
+
+    /**
+     * Returns an array of absolute field numbers of persistent, serializable 
+     * fields of this JDOClass. A field number is included in the returned 
+     * array, iff the corresponding JDOField instance is serializable (method 
+     * {@link JDOField#isSerializable} returns <code>true</code>) and has the 
+     * persistence-modifier 
+     * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT}.
+     * @return the field numbers of serializable fields
+     */
+    public int[] getPersistentSerializableFieldNumbers() {
+        JDOField[] fields = getManagedFields();
+        int[] tmp = new int[fields.length];
+        int length = 0;
+        for (int i = 0; i < fields.length; i++) {
+            JDOField field = fields[i];
+            if (field.isPersistent() && field.isSerializable()) {
+                tmp[length++] = i;
+            }
+        }
+        // now fill the returned array it should have the correct length
+        int[] fieldNumbers = new int[length];
+        System.arraycopy(tmp, 0, fieldNumbers, 0, length);
+
+        return fieldNumbers;
+    }
+    
+    /**
+     * Returns JDOField metadata for a particular managed field specified by 
+     * field name. It returns <code>null</code> if the specified name does not 
+     * denote a managed field of this JDOClass. The field name may be 
+     * unqualified and or qualified (see {@link #getField(String fieldName)}).
+     * @param fieldName the name of the managed field for which field metadata
+     * is needed.
+     * @return JDOField metadata for the managed field or <code>null</code>
+     * if there is no such field.
+     */
+    public JDOField getManagedField(String fieldName) {
+        JDOField field = getField(fieldName);
+        if ((field != null) && !field.isManaged())
+            // return null for a non managed field
+            return null;
+        return field;
+    }
+    
+    /**
+     * Returns JDOField metadata for a particular field specified by field name.
+     * It returns <code>null</code> if the specified name does not denote a 
+     * field of this JDOClass.
+     * <p>
+     * The method supports lookup by unqualified and by qualified field name. 
+     * <ul>
+     * <li> In the case of an unqualified field name the method starts checking 
+     * this JDOClass for a field with the specified name. If this class does not
+     * define such a field, it checks the inheritance hierarchy starting with 
+     * its direct persistence-capable superclass. The method finds the first 
+     * field with the specified name in a bootom-up lookup of the inheritance 
+     * hierarchy. Hidden fields are not visible.
+     * <li> In the case of a qualified field name the method assumes a fully 
+     * qualified class name (called qualifier class) as the field qualifier. 
+     * The qualifier class must be a either this class or a persistence-capable 
+     * superclass (direct or indirect) of this class. Then the method searches 
+     * the field definition in the inheritance hierarchy staring with the 
+     * qualifier class. Any field declarations with the same name in subclasses
+     * of the qualifier class are not considered. This form allows accessing 
+     * fields hidden by subclasses. The method returns <code>null</code> if the 
+     * qualifier class does not denote a valid class or if the qualifier class 
+     * is not a persistence-capable superclass of this class.
+     * </ul>
+     * @param fieldName the unqualified or qualified name of field for which 
+     * field metadata is needed.
+     * @return JDOField metadata for the field or <code>null</code>
+     * if there is no such field.
+     */
+    public JDOField getField(String fieldName) {
+        // check fieldName
+        if ((fieldName == null) || (fieldName.length() == 0)) {
+            return null;
+        }
+        
+        JDOField field = null;
+        int index = fieldName.lastIndexOf('.');
+        if (index != -1) {
+            // qualified field name
+            String className = fieldName.substring(0, index);
+            fieldName = fieldName.substring(index + 1);
+            // move to the specified class in the inheritance hierarchy,
+            // starting with the current class and get the field from there
+            for (JDOClassImplDynamic next = this; next != null; 
+                 next = (JDOClassImplDynamic)next.getPersistenceCapableSuperclass()) {
+                 if (className.equals(next.getName())) {
+                     field = next.getFieldInternal(fieldName);
+                 }
+            }
+        }
+        else {
+            // unqualified field name => call getFieldInternal
+            field = getFieldInternal(fieldName);
+        }
+        
+        return field;
+    }
+         
+    /**
+     * Provides metadata for a particular field specified by the absolute field 
+     * number. The field number must be a valid absolute field number for this 
+     * JDOClass: <code>0 <= fieldNumber < this.getManagedFields().length</code>
+     * If the field number is valid the returned JDoField instance denotes a 
+     * managed field, meaning the field has the persistence-modifier 
+     * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT} or 
+     * {@link org.apache.jdo.model.jdo.PersistenceModifier#TRANSACTIONAL}. 
+     * If the field number is not valid then the method returns
+     * <code>null</code>. 
+     * @param fieldNumber the number for which field metadata is needed.
+     * @return JDOField metadata for the field or <code>null</code>
+     * if there is no such field.
+     */
+    public JDOField getField(int fieldNumber) {   
+        JDOField field = null;
+        JDOField[] fields = getManagedFields();
+        if ((0 <= fieldNumber) && (fieldNumber < fields.length))
+            field = fields[fieldNumber];
+        return field;
+    }
+
+    /** 
+     * Returns JDOField metadata for a particular declared field specified by 
+     * field name. Please note, the method does not  return inherited fields.
+     * The field name must not be qualified by a class name. The method returns
+     * <code>null</code> if the field name does not denote a field declared by 
+     * JDOClass.
+     * @param fieldName the unqualified name of field for which field metadata 
+     * is needed.
+     * @return JDOField metadata for the field or <code>null</code>
+     * if there is no such field declared by this JDOClass.
+     */
+    public JDOField getDeclaredField(String fieldName) {
+        return (JDOField)declaredFields.get(fieldName);
+    }
+
+    /**
+     * Returns the number of managed fields declared in the class represented
+     * by this JDOClass. This does not include inherited fields.
+     * @return number of declared managed fields
+     */
+    public int getDeclaredManagedFieldCount() {
+        return getDeclaredManagedFields().length;
+    }
+    
+    /**
+     * Returns the number of inherited managed fields for the class
+     * represented by this JDOClass.
+     * @return number of inherited managed fields
+     */
+    public int getInheritedManagedFieldCount() {
+        int count = 0;
+        JDOClass superclass = getPersistenceCapableSuperclass();
+        if (superclass != null) {
+            count = 
+                superclass.getInheritedManagedFieldCount() + 
+                superclass.getDeclaredManagedFieldCount();
+        }
+    
+        return count;
+    }
+    
+    /**
+     * Returns the number of managed fields for the class represented by this
+     * JDOClass. The value returned by this method is equal to
+     * <code>getDeclaredManagedFieldCount() +
+     * getInheritedManagedFieldCount()</code>.
+     * @return number of managed fields
+     */
+    public int getManagedFieldCount() {
+        return getDeclaredManagedFieldCount() + getInheritedManagedFieldCount();
+    }
+    
+    /**
+     * Returns the package name including a terminating dot if this class has a 
+     * package. The method returns the empty string if this class is in the 
+     * default package.
+     * @return package prefix for this class.
+     */
+    public String getPackagePrefix() {
+        String className = getName();
+        int index = className.lastIndexOf('.');
+        return (index == -1) ? "" : className.substring(0, index + 1); //NOI18N
+    }
+    
+    /**
+     * Returns the least-derived (topmost) persistence-capable class in the 
+     * hierarchy of this JDOClass. It returns this JDOClass if it has no 
+     * persistence-capable superclass.
+     * @return the topmost persistence-capable class in the hierarchy.
+     */
+    public JDOClass getPersistenceCapableRootClass() {
+        JDOClass superclass = getPersistenceCapableSuperclass();
+        if (superclass == null) {
+            // no superclass => return this
+            return this;
+        }
+        else {
+            return superclass.getPersistenceCapableRootClass();
+        }
+    }
+    
+    //========= Internal helper methods ==========
+    
+    /**
+     * Returns the JDOField definition for the specified field. 
+     * The method expects unqualified field names. The method 
+     * performs a bottom up lookup in the case of multiple fields 
+     * with the same name in an inheritance hierarchy. So it starts
+     * checking this class, then it checks its superclas, etc.
+     * @param fieldName the unqualified field name
+     * @return the corresponding JDOField instance if exists; 
+     * <code>null</code> otherwise.
+     */
+    protected JDOField getFieldInternal(String fieldName) {
+        // first check the declared fields
+        JDOField field = (JDOField)declaredFields.get(fieldName);
+        if (field != null)
+            return field;
+        
+        // not in actual class => check superclass
+        JDOClassImplDynamic superclass = 
+            (JDOClassImplDynamic)getPersistenceCapableSuperclass();
+        if (superclass != null) {
+            return superclass.getFieldInternal(fieldName);
+        }
+        
+        // not found => return null
+        return null;    
+    }
+    
+    /**
+     * Returns a new instance of the JDOClass implementation class.
+     */
+    protected JDOClass newJDOClassInstance() {
+        return new JDOClassImplDynamic();
+    }
+
+    /**
+     * Returns a new instance of the JDOField implementation class.
+     */
+    protected JDOField newJDOFieldInstance() {
+        return new JDOFieldImplDynamic();
+    }
+    
+}

Added: incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/jdo/JDOCollectionImplDynamic.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/jdo/JDOCollectionImplDynamic.java?rev=171348&view=auto
==============================================================================
--- incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/jdo/JDOCollectionImplDynamic.java (added)
+++ incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/jdo/JDOCollectionImplDynamic.java Sun May 22 10:44:19 2005
@@ -0,0 +1,138 @@
+/*
+ * 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.JDOCollection;
+import org.apache.jdo.model.jdo.JDOField;
+import org.apache.jdo.model.jdo.JDOModel;
+import org.apache.jdo.util.I18NHelper;
+
+/**
+ * An instance of this class represents the JDO relationship metadata 
+ * of a collection 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 JDOCollectionImplDynamic extends JDORelationshipImpl
+    implements JDOCollection {
+    
+    /** Property embeddedElement. */
+    protected Boolean embeddedElement;
+
+    /** Property elementType. */
+    protected transient JavaType elementType;
+
+    /** Property elementTypeName. Defaults to java.lang.Object. */
+    private String elementTypeName = "java.lang.Object"; //NOI18N
+
+    /** I18N support */
+    private final static I18NHelper msg =  
+        I18NHelper.getInstance(JDOCollectionImplDynamic.class);
+    
+    /**
+     * 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) {
+            // return embeddedElement, if explicitly set by the setter
+            return embeddedElement.booleanValue();
+        }
+        
+        // not set => calculate
+        JavaType type = getElementType();
+        return (type != null) ? 
+            TypeSupport.isEmbeddedElementType(type) : false;
+    }
+    
+    /**
+     * Set 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.
+     * @param embeddedElement <code>true</code> if elements should be stored 
+     * as part of the instance
+     */
+    public void setEmbeddedElement(boolean embeddedElement) {
+        this.embeddedElement = (embeddedElement ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /** 
+     * Get the type representation of the collection elements. 
+     * @return the element type
+     */
+    public JavaType getElementType() {
+        if (elementType != null) {
+            // return elementType, if explicitly set by the setter
+            return elementType;
+        }
+    
+        // not set => calculate
+        JavaType type = null;
+        if (elementTypeName != null) {
+            JDOField jdoField = getDeclaringField();
+            JDOClass jdoClass = jdoField.getDeclaringClass();
+            JDOModel jdoModel = jdoClass.getDeclaringModel();
+            type = TypeSupport.resolveType(jdoModel, elementTypeName,
+                                           jdoClass.getPackagePrefix());
+            if (type == null) {
+                throw new ModelFatalException(
+                    msg.msg("EXC_CannotResolveElementType", elementTypeName,
+                            jdoField.getName(), jdoClass.getName())); //NOI18N
+            }
+        }
+        
+        return type;
+    }
+
+    /** 
+     * Set the type representation of the collection elements.
+     * @param elementType the type representation of the collection elements
+     */
+    public void setElementType(JavaType elementType) {
+        this.elementType = elementType;
+        if (elementType != null) {
+            setElementTypeName(elementType.getName());
+        }
+    }
+
+    /** 
+     * Get the type of collection elements as string.
+     * @return the element type as string
+     */
+    public String getElementTypeName() {
+        return elementTypeName;
+    }
+
+    /** 
+     * Set string representation of the type of collection elements.
+     * @param elementTypeName a string representation of the type of elements in
+     * the collection. 
+     */
+    public void setElementTypeName(String elementTypeName) {
+        this.elementTypeName = elementTypeName;
+    }
+    
+}

Added: incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/jdo/JDOElementImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/jdo/JDOElementImpl.java?rev=171348&view=auto
==============================================================================
--- incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/jdo/JDOElementImpl.java (added)
+++ incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/jdo/JDOElementImpl.java Sun May 22 10:44:19 2005
@@ -0,0 +1,152 @@
+/*
+ * 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.List;
+import java.util.ArrayList;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.beans.PropertyVetoException;
+import java.beans.VetoableChangeListener;
+import java.beans.VetoableChangeSupport;
+
+import org.apache.jdo.model.jdo.JDOElement;
+import org.apache.jdo.model.jdo.JDOExtension;
+
+/**
+ * This is the super interface for JDO metadata elements, 
+ * such as JDOClass, JDOField and JDORelationship.
+ *
+ * @author Michael Bouschen
+ */
+public class JDOElementImpl
+    implements JDOElement
+{
+    /** List of vendorExtensions. */
+    private List vendorExtensions = new ArrayList();
+
+    /** Property change support. */
+    private transient PropertyChangeSupport propertyChangeSupport;
+
+    /** Vetoable change support. */
+    private transient VetoableChangeSupport vetoableChangeSupport;
+
+    /**
+     * Remove the supplied vendor extension from the collection of extensions 
+     * maintained by this JDOElement.
+     */
+    public void removeJDOExtension(JDOExtension vendorExtension)
+    {
+        vendorExtensions.remove(vendorExtension);
+    }
+
+    /**
+     * Returns the collection of vendor extensions for this JDOElement
+     * in the form of an array.
+     * @return the vendor extensions for this JDOClass
+     */
+    public JDOExtension[] getJDOExtensions()
+    {
+        return (JDOExtension[])vendorExtensions.toArray(
+            new JDOExtension[vendorExtensions.size()]);
+    }
+
+    /**
+     * Creates a new JDOExtension instance and attaches it to the specified 
+     * JDOElement object.
+     */
+    public JDOExtension createJDOExtension()
+    {
+        JDOExtension jdoExtension = new JDOExtensionImpl();
+        vendorExtensions.add(jdoExtension);
+        return jdoExtension;
+    }
+
+    /** 
+     * Fires property change event.
+     * @param name property name
+     * @param o old value
+     * @param n new value
+     */
+    protected void firePropertyChange (String name, Object o, Object n)
+    {
+        if (propertyChangeSupport != null) {
+            propertyChangeSupport.firePropertyChange(name, o, n);
+        }
+    }
+
+    /** 
+     * Add a property change listener.
+     * @param l the listener to add
+     */
+    public synchronized void addPropertyChangeListener (PropertyChangeListener l)
+    {
+        if (propertyChangeSupport == null) {
+            propertyChangeSupport = new PropertyChangeSupport(this);
+        }
+        propertyChangeSupport.addPropertyChangeListener(l);
+    }
+
+    /** 
+     * Remove a property change listener.
+     * @param l the listener to remove
+     */
+    public synchronized void removePropertyChangeListener(PropertyChangeListener l)
+    {
+        if (propertyChangeSupport != null) {
+            propertyChangeSupport.removePropertyChangeListener(l);
+        }
+    }
+
+    /** Fires vetoable change event.
+     * @param name property name
+     * @param o old value
+     * @param n new value
+     * @exception PropertyVetoException when the change is vetoed by a listener
+     */
+    protected void fireVetoableChange (String name, Object o, Object n)
+        throws PropertyVetoException
+    {
+        if (vetoableChangeSupport != null) {
+            vetoableChangeSupport.fireVetoableChange(name, o, n);
+        }
+    }
+
+    /** 
+     * Add a vetoable change listener.
+     * @param l the listener to add
+     */
+    public void addVetoableChangeListener(VetoableChangeListener l)
+    {
+        if (vetoableChangeSupport == null) {
+            vetoableChangeSupport = new VetoableChangeSupport(this);
+        }
+        vetoableChangeSupport.addVetoableChangeListener(l);
+    }
+
+    /** 
+     * Remove a vetoable change listener.
+     * @param l the listener to remove
+     */
+    public void removeVetoableChangeListener(VetoableChangeListener l)
+    {
+        if (vetoableChangeSupport != null) {
+            vetoableChangeSupport.removeVetoableChangeListener(l);
+        }
+        
+    }
+}

Added: incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/jdo/JDOExtensionImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/jdo/JDOExtensionImpl.java?rev=171348&view=auto
==============================================================================
--- incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/jdo/JDOExtensionImpl.java (added)
+++ incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/jdo/JDOExtensionImpl.java Sun May 22 10:44:19 2005
@@ -0,0 +1,86 @@
+/*
+ * 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.JDOExtension;
+
+/**
+ * An instance of this class represents a JDO vendor specific extension.
+ * 
+ * @author Michael Bouschen
+ */
+public class JDOExtensionImpl
+    implements JDOExtension
+{
+    /** Property vendorName. No default. */
+    private String vendorName;
+
+    /** Property key. No default. */
+    private String key;
+
+    /** Property value. No default. */
+    private Object value;
+
+    /**
+     * Returns the vendor name of this vendor extension.
+     */
+    public String getVendorName()
+    {
+        return vendorName;
+    }
+
+    /**
+     * Sets the vendor name for this vendor extension.
+     */
+    public void setVendorName(String vendorName)
+    {
+        this.vendorName = vendorName;
+    }
+    
+    /**
+     * Returns the key of this vendor extension.
+     */
+    public String getKey()
+    {
+        return key;
+    }
+
+    /**
+     * Sets the key for this vendor extension.
+     */
+    public void setKey(String key)
+    {
+        this.key = key;
+    }
+    
+    /**
+     * Returns the value of this vendor extension.
+     */
+    public Object getValue()
+    {
+        return value;
+    }
+
+    /**
+     * Sets the value for this vendor extension.
+     */
+    public void setValue(Object value)
+    {
+        this.value = value;
+    }
+    
+}

Added: incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/jdo/JDOFieldImplDynamic.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/jdo/JDOFieldImplDynamic.java?rev=171348&view=auto
==============================================================================
--- incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/jdo/JDOFieldImplDynamic.java (added)
+++ incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/jdo/JDOFieldImplDynamic.java Sun May 22 10:44:19 2005
@@ -0,0 +1,566 @@
+/*
+ * 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 {@link #getRelationship}.  
+ * The getter will always return a new Java Instance, unless the
+ * relationship is explicitly set by the setter 
+ * {@link #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 {@link #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 {@link #isDefaultFetchGroup}. */
+    protected Boolean defaultFetchGroup;
+
+    /** Property embedded. Default see {@link #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 
+     * {@link PersistenceModifier#NONE}, 
+     * {@link PersistenceModifier#PERSISTENT},
+     * {@link PersistenceModifier#TRANSACTIONAL}, or
+     * {@link 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: {@link PersistenceModifier#UNSPECIFIED}, 
+     * {@link PersistenceModifier#NONE}, 
+     * {@link PersistenceModifier#PERSISTENT},
+     * {@link PersistenceModifier#TRANSACTIONAL}, or
+     * {@link 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 
+     * {@link NullValueTreatment#NONE}, {@link NullValueTreatment#EXCEPTION} or
+     * {@link 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: {@link NullValueTreatment#NONE}, 
+     * {@link NullValueTreatment#EXCEPTION} or 
+     * {@link 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() {
+        if (javaField != null) {
+            // return java field, if explicitly set by the setter
+            return javaField;
+        }
+        
+        // not set => calculate
+        JavaType javaType = getDeclaringClass().getJavaType();
+        return javaType.getJavaField(getName());
+    }
+    
+    /**
+     * 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 {@link #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 {@link #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 {@link #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 {@link #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  
+     * {@link 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  
+     * {@link 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 
+     * {@link PersistenceModifier#PERSISTENT} or 
+     * {@link 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() {
+        JavaField field = getJavaField();
+        return (field == null) ? null : field.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/core20/src/java/org/apache/jdo/impl/model/jdo/JDOMapImplDynamic.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/jdo/JDOMapImplDynamic.java?rev=171348&view=auto
==============================================================================
--- incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/jdo/JDOMapImplDynamic.java (added)
+++ incubator/jdo/trunk/core20/src/java/org/apache/jdo/impl/model/jdo/JDOMapImplDynamic.java Sun May 22 10:44:19 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;
+    }
+
+}