Package org.apache.jdo.impl.model.jdo

Source Code of org.apache.jdo.impl.model.jdo.JDOClassImplDynamic

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.model.jdo.JDOProperty;

import org.apache.jdo.util.I18NHelper;
import org.apache.jdo.util.StringHelper;

/**
* 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 2.0
*/
public class JDOClassImplDynamic
    extends JDOMemberImpl
    implements JDOClass
{
    /** Property shortName. It defaults to the unqualified class name. */
    protected String shortName;

    /** 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();

    /**
     * Map of properties having associated JDOField instances. Key is the
     * unqualified field name, value is the JDOField instance.
     */
    private Map associatedProperties = 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);

    /** Constructor. */
    protected JDOClassImplDynamic(String name) {
        super(name, null);
    }

    /** Constructor for inner classes. */
    protected JDOClassImplDynamic(String name, JDOClass declaringClass) {
        super(name, declaringClass);
    }

    /**
     * Get the short name of this JDOClass. The short name defaults to the
     * unqualified class name, if not explicitly set by method
     * {@link #setShortName(String shortName)}.
     * @return the short name of this JDOClass.
     */
    public String getShortName() {
        if (shortName != null)
            // return short name, if explicitly set by the setter
            return shortName;

        return StringHelper.getShortClassName(getName());
    }
   
    /**
     * Set the short name of this JDOClass.
     * @param shortName the short name.
     */
    public void setShortName(String shortName) {
        this.shortName = shortName;
    }
   
    /**
     * 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();
            }
        }
        else {
            // not declared, check for single field ObjectId class
            JDOField[] declaredPKFields = getDeclaredPrimaryKeyFields();
            if ((declaredPKFields != null) && (declaredPKFields.length == 1)) {
                // there is one pk field declared by this class =>
                // check the type
                JavaType fieldType = declaredPKFields[0].getType();
                if (fieldType != null) {
                    return TypeSupport.getSingleFieldObjectIdClassName(
                        fieldType.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 == null) {
            throw new ModelException(
                msg.msg("EXC_InvalidMember", "null")); //NOI18N
        }
        String name = member.getName();
        if (member instanceof JDOField) {
            JDOField field = (JDOField) member;
            // nullify mappedByName which removes mappedBy info
            field.setMappedByName(null);
            // nullify relationship which updates its inverse
            field.setRelationship(null);
            if (associatedProperties.containsValue(member)) {
                associatedProperties.remove(name);
            }
            else {
                declaredFields.remove(name);
            }

            // There might be a property with the field to be removed as
            // associated JDOField => remove the property too.
            JDOProperty prop = getAssociatedProperty(field);
            if (prop != null) {
                removeDeclaredMember(prop);
            }
        }
        else if (member instanceof JDOClass) {
            // inner class
            declaredClasses.remove(name);
        }
        else {
            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 declaring JDOClass 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 = getDeclaredField(name);
        if (field == null) {
            field = newJDOFieldInstance(name);
            declaredFields.put(name, field);
        }
        else if (field instanceof JDOProperty) {
            throw new ModelException(
                msg.msg("EXC_ExistingJDOProperty", name)); //NOI18N
        }
        return field;
    }
   
    /**
     * This method returns a JDOProperty instance for the property with the
     * specified name. If this JDOClass already declares such a property, the
     * existing JDOProperty instance is returned. Otherwise, it creates a new
     * JDOProperty instance, sets its declaring JDOClass and returns the new
     * instance.
     * @param name the name of the property
     * @return a JDOProperty instance for the specified property
     * @exception ModelException if impossible
     */
    public JDOProperty createJDOProperty(String name) throws ModelException {
        // check whether there is a field or property with the specified name
        JDOProperty property = null;
        JDOField field = getDeclaredField(name);
        if (field == null) {
            property = newJDOPropertyInstance(name);
            declaredFields.put(name, property);
        }
        else if (field instanceof JDOProperty) {
            property = (JDOProperty) field;
        }
        else {
            throw new ModelException(
                msg.msg("EXC_ExistingJDOField", name)); //NOI18N
        }
        return property;
    }

    /**
     * This method returns a JDOProperty instance for the property with the
     * specified name and associated field. If this JDOClass already declares
     * such a property the existing JDOProperty instance is returned. If it
     * declares a property with the specified name but different associated
     * field, then a ModelException is thrown. If there is no such property,
     * the method creates a new JDOProperty instance, sets its declaring
     * JDOClass and associated field and returns the new instance.
     * @param name the name of the property
     * @param associatedField the associated JDOField
     * @return a JDOProperty instance for the specified property
     * @exception ModelException if impossible
     */
    public JDOProperty createJDOProperty(String name,
                                         JDOField associatedJDOField)
        throws ModelException
    {
        JDOProperty property = (JDOProperty) associatedProperties.get(name);
        if (property == null) {
            property = newJDOPropertyInstance(name, associatedJDOField);
            associatedProperties.put(name, property);
        }
        else {
            if (property.getAssociatedJDOField() != associatedJDOField) {
                throw new ModelException(
                    msg.msg("EXC_ExistingJDOAssociatedProperty", //NOI18N
                            name, associatedJDOField));
            }
        }
        return property;
    }
   
    /**
     * 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 declaring JDOClass 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(name);
            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 for the
     * specified 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 name 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 name) {
        return (JDOField) declaredFields.get(name);
    }

    /**
     * Returns JDOProperty metadata for a property with the specified name
     * having an associated JDOField. The method returns <code>null</code>, if
     * the name does not denote a property with an associated JDOField of this
     * JDOClass. Please note, the method does not check for properties without
     * an associated JDOField. It will return <code>null</code> if there is
     * a property with the specified name, but this property does not have an
     * associated JDOField.
     * @param name the name of property with an associated JDOField for which
     * metadata is needed.
     * @return JDOProperty metadata for the property with an associated
     * JDOField or <code>null</code> if there is no such property.
     */
    public JDOProperty getAssociatedProperty(String name) {
        // first check the associated properties from this class
        JDOProperty prop = (JDOProperty) associatedProperties.get(name);
        if (prop != null) {
            return prop;
        }
       
        // not in this class => check superclass
        JDOClass superclass = getPersistenceCapableSuperclass();
        if (superclass != null) {
            return superclass.getAssociatedProperty(name);
        }
       
        // not found => return null
        return null;
    }

    /**
     * Returns JDOProperty metadata for a property having the specified
     * JDOField as associated JDOField. The method returns <code>null</code>,
     * if this JDOClass does not have a property with the specified JDOField
     * as associated JDOField.
     * @param JDOField the assoaciated JDOField of the property for which
     * metadata is needed.
     * @return JDOProperty metadata for the property the specified JDOField as
     * associated JDOField or <code>null</code> if there is no such property.
     */
    public JDOProperty getAssociatedProperty(JDOField field) {
        Collection props = associatedProperties.values();
        for (Iterator i = props.iterator(); i.hasNext();) {
            JDOProperty prop = (JDOProperty)i.next();
            if (prop.getAssociatedJDOField() == field) {
                // found property => return
                return prop;
            }
        }

        // not found => return null
        return null;
    }

    /**
     * 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 this class => check superclass
        JDOClassImplDynamic superclass =
            (JDOClassImplDynamic)getPersistenceCapableSuperclass();
        if (superclass != null) {
            return superclass.getFieldInternal(fieldName);
        }
       
        // not found => return null
        return null;
    }
   
    /**
     * Returns the collection of identifying declared fields of this JDOClass
     * in the form of an array. The method returns the JDOField instances
     * declared by this JDOClass defined as primary key fields (see {@link
     * JDOField#isPrimaryKey}).
     * @return the identifying fields of this JDOClass
     */
    protected JDOField[] getDeclaredPrimaryKeyFields() {
        JDOField[] fields = getDeclaredFields();
        JDOField[] tmp = new JDOField[fields.length];
        int length = 0;
        for (int i = 0; i < fields.length; i++) {
            JDOField field = fields[i];
            if (field.isManaged() && field.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 a new instance of the JDOClass implementation class.
     */
    protected JDOClass newJDOClassInstance(String name) {
        return new JDOClassImplDynamic(name, this);
    }

    /**
     * Returns a new instance of the JDOField implementation class.
     */
    protected JDOField newJDOFieldInstance(String name) {
        return new JDOFieldImplDynamic(name, this);
    }

    /**
     * Returns a new instance of the JDOProperty implementation class.
     */
    protected JDOProperty newJDOPropertyInstance(String name) {
        return new JDOPropertyImplDynamic(name, this);
    }
   
    /**
     * Returns a new instance of the JDOProperty implementation class.
     */
    protected JDOProperty newJDOPropertyInstance(
        String name, JDOField associatedJDOField) throws ModelException {
        return new JDOAssociatedPropertyImplDynamic(
            name, this, associatedJDOField);
    }
   
}
TOP

Related Classes of org.apache.jdo.impl.model.jdo.JDOClassImplDynamic

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.