FileDocCategorySizeDatePackage
PersistenceDescriptor.javaAPI DocGlassfish v2 API38918Fri May 04 22:31:22 BST 2007com.sun.enterprise.deployment

PersistenceDescriptor

public final class PersistenceDescriptor extends Descriptor
This class contains information about the persistent state (abstract persistence schema) for EJB2.0 CMP EntityBeans and Join Objects.
author
Sanjeev Krishnan

Fields Summary
private Set
cmpFields
private Set
pkeyFields
private boolean
pkeyIsOneField
private boolean
pkeyFieldSpecified
private String
primaryKeyClassName
private boolean
pkeyStuffInitialized
private boolean
pkeyFieldsAllPrimitive
private static com.sun.enterprise.util.LocalStringManagerImpl
localStrings
private EjbCMPEntityDescriptor
parentDesc
private transient Class
persistentClass
private transient Class
stateClass
private transient Class
primaryKeyClass
private PersistentFieldInfo[]
persFieldInfo
private PersistentFieldInfo[]
persNoPkeyFieldInfo
private PersistentFieldInfo[]
pkeyFieldInfo
private boolean
fieldInfoInitialized
private PersistentFieldInfo[]
fkeyFields
private CMRFieldInfo[]
cmrFieldInfo
private transient Field[]
pkeyClassPkeyFields
private Hashtable
queries
private HashSet
allQueriedMethods
Constructors Summary
public PersistenceDescriptor()


      
    
public PersistenceDescriptor(PersistenceDescriptor pers)
The copy constructor.

	super(pers);

	this.getCMPFields().addAll(pers.getCMPFields());
	//this.primaryKeyFieldDesc = pers.primaryKeyFieldDesc;
    
Methods Summary
public voidaddCMPField(java.lang.String field)

        addCMPField(new FieldDescriptor(field));
    
public voidaddCMPField(FieldDescriptor fieldDesc)

        this.cmpFields.add(fieldDesc);
        setCMPFields(this.cmpFields);
    
public static java.lang.Stringcapitalize(java.lang.String name)

	// EJB2.0 proposed final draft says that CMP/CMR field names
	// must begin with a lower case letter.
	if ( Character.isUpperCase(name.charAt(0)) ) {
	    throw new javax.ejb.EJBException("CMP/CMR field "+name+" must start with a lower case character.");
	}
	else {
	    char chars[] = name.toCharArray();
	    chars[0] = Character.toUpperCase(chars[0]);
	    return new String(chars);
	}
    
public booleanclassesChanged()
Called from EjbCMPEntityDescriptor when some classes in this object are updated.


        // XXX Remove any fields marked as persistent that no longer exist
	// in bean class as getter/setter.
        persistentClass = null;
        stateClass = null;
        Class persClass = getPersistentClass();

        Vector fieldDescriptors = parentDesc.getFieldDescriptors();

        // Remove obsolete cmp fields
        if( this.cmpFields != null ) {
            for(Iterator iter = cmpFields.iterator(); iter.hasNext();) {
                FieldDescriptor next = (FieldDescriptor) iter.next();
                if( !fieldDescriptors.contains(next) ) {
                    iter.remove();
                }
            }
        }

        // Remove obsolete pkey fields
        if( this.pkeyFields != null ) {
            for(Iterator iter = pkeyFields.iterator(); iter.hasNext();) {
                FieldDescriptor next = (FieldDescriptor) iter.next();
                if( !fieldDescriptors.contains(next) ) {
                    iter.remove();
                }
            }
        }

        FieldDescriptor primKeyFieldDesc = parentDesc.getPrimaryKeyFieldDesc();
        if( (primKeyFieldDesc != null) && 
            !fieldDescriptors.contains(primKeyFieldDesc) ) {
            parentDesc.setPrimaryKeyFieldDesc(null);
        }


        // CMP 2.x
        // Remove queries for methods no longer in allQueriedMethods

        // First clone old set of queries
        Hashtable queriesClone = (Hashtable) queries.clone();
        
        queries = new Hashtable();
        initializeAllQueriedMethods();

        Iterator it = queriesClone.keySet().iterator();
        while ( it.hasNext() ) {
            Method oldMethod = (Method)it.next();
            Method newMethod = findEquivalentMethod(allQueriedMethods, 
                                                    oldMethod);
            if( newMethod != null ) {
                QueryDescriptor oldQuery = (QueryDescriptor)
                    queriesClone.get(oldMethod);
                QueryDescriptor newQuery = 
                    new QueryDescriptor(oldQuery, newMethod);
                // Only add to list of methods having queries if
                // it's still in the class.
                queries.put(newMethod, newQuery);
            } 
        }

        // Force the persistence descriptor to regenerate its
        // derived info.
        invalidate();

        return false;
    
public voidclearCMPFields()

        this.cmpFields.clear();
        setCMPFields(this.cmpFields);
    
private java.lang.reflect.MethodfindEquivalentMethod(java.util.Collection methods, java.lang.reflect.Method methodToMatch)
Search for a matching method in a list of methods that might have been loaded with a different classloader. Because of this possibility, we can't use java.lang.reflect.Method.equals().

return
matched method or NULL

        Method matchedMethod = null;
        for(Iterator iter = methods.iterator(); iter.hasNext();) {
            Object o = iter.next();
            Method next;
            if (o instanceof Method) {
                next = (Method) o;
            } else {
                next = ((MethodDescriptor) o).getMethod(parentDesc);
                if (next==null) {
                    return null;
                }
            }
            // Compare methods, ignoring declaring class.
            if( methodsEqual(next, methodToMatch, false) ) {
                matchedMethod = next;
                break;
            }
        }
        return matchedMethod;
    
public java.util.SetgetAllPossibleQueriedMethods()
Get all HomeIntf.find* and EJBClass.ejbSelect* methods for which an EJB-QL query could possibly be set.

return
a Set of Methods

	if ( allQueriedMethods == null ) 
	    initializeAllQueriedMethods();

	return allQueriedMethods;
    
private java.lang.ClassgetCMPFieldType(java.lang.String field)

	Class pclass = getPersistentClass();
	if ( Modifier.isAbstract(pclass.getModifiers()) ) {
	    // An EJB2.0 CMP bean : field is a virtual field 
	    String javaBeanName = capitalize(field);
	    String getter = "get"+javaBeanName;
	    try {
		Method method = pclass.getMethod(getter, (Class[]) null);
		return method.getReturnType();
	    } catch ( Exception ex ) {
		throw new RuntimeException("Cannot find accessor " + getter + " for CMP field "+field);
	    }
	}
	else {
	    // field is a Java field in state class
	    try {
		Field f = getField(getStateClass(), field);
		return f.getType();
	    } catch ( NoSuchFieldException ex ) {
		throw new RuntimeException("Cant find CMP field "+field+" in class "+getStateClass().getName());
	    }
	}
    
public java.util.SetgetCMPFields()
Return the Set of fields deemed persistent. The elements of this Set are FieldDescriptor objects. This Set should be modified by calling addCMPField, removeCMPField

	return this.cmpFields;
    
public CMRFieldInfo[]getCMRFieldInfo()
Return array of CMRFieldInfo objects for all CMR fields.

	if ( cmrFieldInfo == null ) {
	    try {
		initCMRFieldStuff();
	    } catch ( Exception ex ) {
                DOLUtils.getDefaultLogger().log(Level.SEVERE, "enterprise.deployment.backend.invalidDescriptorMappingFailure",
                    new Object[] {ex.toString()});
		throw new EJBException(ex);
	    }
	}
	return cmrFieldInfo;
    
public CMRFieldInfogetCMRFieldInfoByName(java.lang.String fieldName)
Return the CMRFieldInfo object for the given CMR field

	CMRFieldInfo[] cmrf = this.getCMRFieldInfo();
	for ( int i=0; i<cmrf.length; i++ ) {
	    if ( cmrf[i].name.equals(fieldName) )
		return cmrf[i];
	}
	throw new EJBException("CMRFieldInfo not found for field "+fieldName);
    
public java.lang.StringgetCMRFieldReturnType(java.lang.String field)

        String returnType = "java.util.Collection";
        try {
            if( !field.trim().equals("") ) {
                Class persClass = getPersistentClass();
                String methodName = "get" + field.substring(0,1).toUpperCase() 
                    + field.substring(1);
                Method method = TypeUtil.getMethod
                    (persClass, persClass.getClassLoader(), methodName,
                     new String[] {});
                returnType = method.getReturnType().getName();
            }
        } catch(Throwable t) {
            if(DOLUtils.getDefaultLogger().isLoggable(Level.FINE)) {            
                DOLUtils.getDefaultLogger().log(Level.FINE, t.toString(), t);
            }
        }
        
        return returnType;
    
private java.lang.ClassgetClass(java.lang.String className)

            
	try {
	    return getEjbBundleDescriptor().getClassLoader().loadClass(className);
	} catch ( Exception ex ) {
	    //if ( debug ) ex.printStackTrace();
	    throw new EJBException(ex);
	}
    
public EjbBundleDescriptorgetEjbBundleDescriptor()

	 return parentDesc.getEjbBundleDescriptor();
    
private java.lang.reflect.FieldgetField(java.lang.Class c, java.lang.String name)

        // This privileged block is needed because this code can be
        // called when application code is on the stack, which is not
        // allowed to reflect on private members of classes.
        Field field = (Field)java.security.AccessController.doPrivileged(
            new java.security.PrivilegedAction() {
                public Object run()  {
                    try {
                        // this is needed for EJB2.0 CMP beans whose 
                        // generated fields are private.
                        return c.getDeclaredField(name);
                    }
                    catch ( NoSuchFieldException ex ) {
                        return null;
                    }
                }
            }
        );

        if ( field == null )
            field = c.getField(name);
        return field;
    
public PersistentFieldInfo[]getFkeyFields()
Return the array of PersistentFieldInfo objects for the foreign key fields of this bean.

	if ( !fieldInfoInitialized )
	    initializeFieldInfo();
	return this.fkeyFields;
    
public PersistentFieldInfo[]getNonPkeyPersFieldInfo()
Return the array of PersistentFieldInfo objects for the CMP fields which are not primary keys + foreign key fields.

	if ( !fieldInfoInitialized )
	    initializeFieldInfo();
	return persNoPkeyFieldInfo;
    
public DescriptorgetParentDescriptor()

	return parentDesc;
    
public java.lang.ClassgetPersistentClass()

	if ( persistentClass == null ) {
	    persistentClass = getClass(parentDesc.getEjbClassName());
	}
	return persistentClass;
    
public PersistentFieldInfo[]getPersistentFieldInfo()
Return the array of PersistentFieldInfo objects for the CMP + foreign key fields

	if ( !fieldInfoInitialized )
	    initializeFieldInfo();
	return persFieldInfo;
    
public PersistentFieldInfogetPersistentFieldInfoByName(java.lang.String fieldName)
Return the PersistentFieldInfo object for the given CMP/fkey field

	if ( !fieldInfoInitialized )
	    initializeFieldInfo();
	for ( int i=0; i<persFieldInfo.length; i++ ) {
	    if ( persFieldInfo[i].name.equals(fieldName) )
		return persFieldInfo[i];
	}
	throw new EJBException("PersistentFieldInfo not found for field "+fieldName);
    
public java.lang.reflect.Field[]getPkeyClassFields()

return
an array of all Field objects in the primary key class. Returns null if primaryKeyIsOneField() == true.

	if ( !fieldInfoInitialized )
	    initializeFieldInfo();
	return pkeyClassPkeyFields;
    
public PersistentFieldInfo[]getPkeyFieldInfo()
Return the array of PersistentFieldInfo objects for the pkey fields.

	if ( !fieldInfoInitialized )
	    initializeFieldInfo();
	return pkeyFieldInfo;
    
public PersistentFieldInfogetPkeyFieldInfoByName(java.lang.String fieldName)
Return PersistentFieldInfo object for the given pkey field.

	if ( !fieldInfoInitialized )
	    initializeFieldInfo();
	for ( int i=0; i<pkeyFieldInfo.length; i++ ) {
	    if ( pkeyFieldInfo[i].name.equals(fieldName) )
		return pkeyFieldInfo[i];
	}
	throw new EJBException("PersistentFieldInfo not found for pkey field "+fieldName);
    
public java.util.SetgetPkeyFields()
Return the Set of primary key fields. The elements of this Set are FieldDescriptor objects. This Set can be modified by calling addPkeyField, removePkeyField

	if ( !pkeyStuffInitialized )
	    initPkeyInfo();
	return pkeyFields;
    
public java.lang.ClassgetPrimaryKeyClass()
Get this bean's primary key class. For EJBs, this is EjbEntityDescriptor.getPrimaryKeyClassName(),

	if ( !pkeyStuffInitialized )
	    initPkeyInfo();
	return primaryKeyClass;
    
public java.util.SetgetQueriedMethods()
Get all methods for which setQueryFor was done

return
a Set of Methods

	return queries.keySet();
    
public QueryDescriptorgetQueryFor(MethodDescriptor method)

	return (QueryDescriptor)queries.get(method);
    
public QueryDescriptorgetQueryFor(java.lang.reflect.Method method)

        // Use our own method equality check. See setQueryFor comment
        // for more details.
        MethodDescriptor md = new MethodDescriptor(method,"");
        return (QueryDescriptor) queries.get(md);
    
public java.util.SetgetRelationships()
Get all CMR fields of this bean. All relationships are stored in EjbBundleDescriptor to avoid the complexity of keeping the two sets consistent. NOTE : To add or remove a relationship use EjbBundleDescriptor.

        Set allRelationships = getEjbBundleDescriptor().getRelationships();
        Set myRelationships  = new HashSet();
        for(Iterator iter = allRelationships.iterator(); iter.hasNext();) {
            RelationshipDescriptor next = (RelationshipDescriptor) iter.next();
            if( next.hasParticipant(parentDesc) ) {
                myRelationships.add(next);
            }
        }
        return myRelationships;
    
public java.lang.ClassgetStateClass()

	if ( stateClass == null ) {
	    stateClass = getPersistentClass();
	    if ( parentDesc.isEJB20() ) {
		if( !Modifier.isAbstract(stateClass.getModifiers()) ) {
	            throw new EJBException("2.x CMP bean class " 
                        + stateClass.getName() + " must be decleared abstract "
                        + "or cmp-version for the corresponding bean must be set to 1.x.");
                }
	        String stateClassName = parentDesc.getStateImplClassName();
	        stateClass = getClass(stateClassName);
	    }
	}
	return stateClass;
    
public java.lang.ClassgetTypeFor(java.lang.String field)

return
the Class object corresponding to the type of the given CMP field.

	return getCMPFieldType(field);
    
private voidinitCMRFieldStuff()

	if ( !fieldInfoInitialized )
	    initializeFieldInfo();

        Set relationships = getRelationships();
	Iterator it = relationships.iterator();
        // set to the biggest possible size when all relationships
        // are self-referencing
	CMRFieldInfo[] cmrFieldInfo2 = 
            new CMRFieldInfo[relationships.size() * 2];
	int count = 0;
	while ( it.hasNext() ) { 
	    RelationshipDescriptor rd = (RelationshipDescriptor)it.next();
	    RelationRoleDescriptor source = rd.getSource();
	    RelationRoleDescriptor sink = rd.getSink();
	    RelationRoleDescriptor myroles[];
            // if this is a self-referencing relationship, initialize 
            // both source and sink cmr fields
	    if ( source.getPersistenceDescriptor() ==  
                sink.getPersistenceDescriptor() ) {
                myroles = new RelationRoleDescriptor[2];
                myroles[0] = source;
                myroles[1] = sink;
            } else {
                myroles = new RelationRoleDescriptor[1];
                if ( source.getPersistenceDescriptor() == this ) {
                    myroles[0] = source;
                } else { 
                    myroles[0] = sink;
                }
            }
            
            // for all relation role elements in myroles, initialize
            // their cmr fields and put them in cmrFieldInfo2
            for (int ii = 0; ii < myroles.length; ii++) {
	        CMRFieldInfo finfo = new CMRFieldInfo();
	        cmrFieldInfo2[count++] = finfo;

	        PersistenceDescriptor partnerPers = 
		    myroles[ii].getPartner().getPersistenceDescriptor();

	        // Check if partner has a local interface
	        EjbCMPEntityDescriptor partner = 
                    myroles[ii].getPartner().getOwner();
                if ( !partner.isLocalInterfacesSupported() &&
		    myroles[ii].getCMRField() != null ) {
      		    throw new RuntimeException(
                        "No local interface for target bean of CMR field");
	        }

	        String type; 
	        if ( myroles[ii].getPartner().getIsMany() == false ) {
	      	    // 1-1 and many-1
                    if ( partner.isLocalInterfacesSupported() )
		        type = partner.getLocalClassName();
	       	    else 
                        // a unidirectional relation, partner is 
                        // remote-only bean
		        type = partner.getPrimaryKeyClassName();
	        }
	        else {
	      	    // 1-many and many-many
		    type = myroles[ii].getCMRFieldType();
      		    if ( type == null ) { 
		        // A unidirectional relationship from partner 
                        // to this obj
		        type = "java.util.Collection";
    		    }
	        }
	        finfo.type = getClass(type);

	        finfo.name = myroles[ii].getCMRField();
	        if ( finfo.name == null ) {
	       	    // A unidirectional relationship from partner to this obj.
	      	    // We need to maintain a pointer to partner anyway. 
       		    finfo.name = myroles[ii].composeReverseCmrFieldName();
	        }
	        finfo.role = myroles[ii];
	        myroles[ii].setCMRFieldInfo(finfo);

	        if ( rd.isOneOne() && fkeyFields != null ) {
	    	    // set foreign key fields corresponding to this CMR field
		    PersistentFieldInfo[] cmrFkeyFields;
      		    PersistentFieldInfo[] partnerPkeyFields =
					    partnerPers.getPkeyFieldInfo();
		    cmrFkeyFields = 
			new PersistentFieldInfo[partnerPkeyFields.length];
		    for ( int i=0; i<partnerPkeyFields.length; i++ ) {
		        String fkeyName = "_" + finfo.name + "_" 
					    + partnerPkeyFields[i].name;
		        for ( int j=0; j<fkeyFields.length; j++ ) {
		    	    if ( fkeyFields[j].name.equals(fkeyName) )
			        cmrFkeyFields[i] = fkeyFields[j];
		        }
		    }
		    finfo.fkeyFields = cmrFkeyFields;
	        }	
            }
        }

        // initialize the cmrFieldInfo array with the actual size
        // and copy the non-null values of cmrFieldInfo2 to it
        cmrFieldInfo = new CMRFieldInfo[count];
        System.arraycopy(cmrFieldInfo2, 0, cmrFieldInfo, 0, count);

	// Sort cmrFieldInfo in alphabetical order of CMR field name
        for ( int i=cmrFieldInfo.length-1; i>0; i-- ) {
            for ( int j=0; j<i; j++ ) {
                if ( cmrFieldInfo[j].name.compareTo(cmrFieldInfo[j+1].name) 
									> 0 ) {
                    CMRFieldInfo tmp = cmrFieldInfo[j];
                    cmrFieldInfo[j] = cmrFieldInfo[j+1];
                    cmrFieldInfo[j+1] = tmp;
                }
            }
        }
    
private voidinitPkeyInfo()
Initialize pkeyFields, pkeyIsOneField, primaryKeyClassName Must be called after this PersistenceDescriptor has been attached to the Ejb/JoinDescriptor which has been attached to the EjbBundleDescriptor.

	try {
	    pkeyIsOneField = false;
            pkeyFieldSpecified = true;
	    primaryKeyClassName = parentDesc.getPrimaryKeyClassName();
    
	    FieldDescriptor fd = parentDesc.getPrimaryKeyFieldDesc();
	    if ( pkeyFields == null || pkeyFields.size() == 0 ) {
	        pkeyFields = new HashSet();

	        if ( fd != null ) // primkey-field was set
		    pkeyFields.add(fd);

	        else if (!primaryKeyClassName.equals("java.lang.Object")) {
		    // get fields of primaryKeyClass
		    primaryKeyClass = getClass(primaryKeyClassName);
		    Field[] fields = primaryKeyClass.getFields();
		    pkeyFieldsAllPrimitive = true;
		    for ( int i=0; i<fields.length; i++ ) {
		        // ignore static or final fields
		        int m = fields[i].getModifiers();
		        if ( Modifier.isStatic(m) || Modifier.isFinal(m) )
			    continue;
		        if ( !fields[i].getType().isPrimitive() )
			    pkeyFieldsAllPrimitive = false;
		        pkeyFields.add(new FieldDescriptor(
						    fields[i].getName()));
		    }
	        }
	        else {
		    // Will use PM-generated primary key
		    primaryKeyClass = getClass(primaryKeyClassName);
                       pkeyIsOneField = true;
                       pkeyFieldSpecified = false;
	        }
	    }
	    if ( fd != null )
	        pkeyIsOneField = true;

	    pkeyStuffInitialized = true;
	}
	catch ( Exception ex ) {
            DOLUtils.getDefaultLogger().log(Level.SEVERE, "enterprise.deployment.backend.invalidDescriptorMappingFailure", 
                new Object[] {ex.toString()});
            throw new EJBException(ex);
	}
    
private voidinitializeAllQueriedMethods()

	allQueriedMethods = new HashSet();	    

	// add all ejbSelect* methods in persistentClass
	Method[] beanMethods = getPersistentClass().getMethods();
	for ( int i=0; i<beanMethods.length; i++ ) {
	    if ( beanMethods[i].getName().startsWith("ejbSelect") ) {
		allQueriedMethods.add(new MethodDescriptor(beanMethods[i], MethodDescriptor.EJB_BEAN));
	    }
	}

        // add all finders in Home/LocalHome intf, findByPrimaryKey too
        if ( parentDesc.isRemoteInterfacesSupported() ) {
	    Class homeIntf = getClass(parentDesc.getHomeClassName());
    
	    Method[] homeMethods = homeIntf.getMethods();
	    for ( int i=0; i<homeMethods.length; i++ ) {
	        String name = homeMethods[i].getName();
	        if ( name.startsWith("find") 
		        && !name.equals("findByPrimaryKey") ) {
		    allQueriedMethods.add(new MethodDescriptor(homeMethods[i], MethodDescriptor.EJB_HOME));
	        }
	    }
        }
        if ( parentDesc.isLocalInterfacesSupported() ) {
	    Class homeIntf = getClass(parentDesc.getLocalHomeClassName());
    
	    Method[] homeMethods = homeIntf.getMethods();
	    for ( int i=0; i<homeMethods.length; i++ ) {
	        String name = homeMethods[i].getName();
	        if ( name.startsWith("find") 
		        && !name.equals("findByPrimaryKey") ) {
		    allQueriedMethods.add(new MethodDescriptor(homeMethods[i], MethodDescriptor.EJB_LOCALHOME));
	        }
	    }
        }
    
private voidinitializeFieldInfo()

	if ( !pkeyStuffInitialized )
	    initPkeyInfo();

	int cmpFieldCount = cmpFields.size();
        if (cmpFieldCount==0) {
            throw new EJBException("No cmp field defined for CMP EJB " + parentDesc.getName());
        }

	int fkeyCount = 0;
	if ( fkeyFields != null )
	    fkeyCount = fkeyFields.length;

	persFieldInfo = new PersistentFieldInfo[cmpFieldCount + fkeyCount];
	// Add CMP fields
	int fcount = 0;
	Iterator itr = cmpFields.iterator();
	while ( itr.hasNext() ) {
	    persFieldInfo[fcount] = new PersistentFieldInfo();
	    persFieldInfo[fcount].name =((FieldDescriptor)itr.next()).getName();
	    fcount++;
	}
	// Add foreign key fields
	if ( fkeyFields != null ) {
	    for ( int i=0; i<fkeyFields.length; i++ ) {
		persFieldInfo[fcount] = fkeyFields[i];
		fcount++;
	    }
	}

	// sort persFieldInfo in alphabetical order
        for ( int i=persFieldInfo.length-1; i>0; i-- ) {
            for ( int j=0; j<i; j++ ) {
                if ( persFieldInfo[j].name.compareTo(persFieldInfo[j+1].name) 
									> 0 ) {
                    PersistentFieldInfo tmp = persFieldInfo[j];
                    persFieldInfo[j] = persFieldInfo[j+1];
                    persFieldInfo[j+1] = tmp;
                }
            }
        }

        // Initialize pkeyFieldInfo[] and persNoPkeyFieldInfo[] 
	// They contain the same PersistentFieldInfo objects as persFieldInfo.
        pkeyFieldInfo = new PersistentFieldInfo[pkeyFields.size()];
	if ( pkeyFieldSpecified ) {

            // check if PK class has public non-persistent fields
            StringBuffer nonPersFieldsInPK = new StringBuffer();
            for ( Iterator it=pkeyFields.iterator(); it.hasNext(); ) {
                FieldDescriptor fd = (FieldDescriptor)it.next();
                boolean isPersistent = false;
                for ( int i=0; i<persFieldInfo.length; i++ ) {
                    if ( fd.getName().equals(persFieldInfo[i].name) ) {
                        isPersistent = true;
                        break;
                    }
                }
                if ( !isPersistent ) {
                    // if not the first non-persistent field
                    if ( nonPersFieldsInPK.length() != 0 ) {
                        nonPersFieldsInPK.append(", ");
                    }
                    nonPersFieldsInPK.append(fd.getName());
                }
            }
            if ( nonPersFieldsInPK.length() != 0 ) {
                throw new EJBException(localStrings.getLocalString(
                "enterprise.deployment.pkhasnopersistentfields",
                "CMP bean [{0}], primary key class [{1}] has " + 
                "public non-persistent field(s) [{2}].",
                new Object[] {getParentDescriptor().getName(),
                getPrimaryKeyClass().getName(),
                nonPersFieldsInPK.toString()}));
            }

	    persNoPkeyFieldInfo = new PersistentFieldInfo[persFieldInfo.length -
							  pkeyFieldInfo.length];
	    int pkeyCount = 0;
	    int noPkeyCount = 0;
	    for ( int i=0; i<persFieldInfo.length; i++ ) {
		boolean isPkey = false;
		for ( Iterator it=pkeyFields.iterator(); it.hasNext(); ) {
		    FieldDescriptor fd = (FieldDescriptor)it.next();
		    if ( fd.getName().equals(persFieldInfo[i].name) ) {
			isPkey = true;
			break;
		    }
		}
		if ( isPkey ) 
		    pkeyFieldInfo[pkeyCount++] = persFieldInfo[i];
		else
		    persNoPkeyFieldInfo[noPkeyCount++] = persFieldInfo[i];
	    }
	}

	if ( pkeyIsOneField  && pkeyFieldSpecified) {
	    // Initialize pkey field type. This is needed for
	    // beans with no pkey field (i.e. PM-generated pkey)
	    // because they wont have get/set for the pkey in the bean class
	    // so the getCMPFieldType() below will bomb if type is not set.
	    // Note: pkeyFieldInfo and persFieldInfo arrays share the same
	    // PersistentFieldInfo objects.
	    pkeyFieldInfo[0].type = getPrimaryKeyClass();
	}

	// Initialize Java types in persFieldInfo
	for ( int i=0; i<persFieldInfo.length; i++ ) {
	    // fill type for CMP fields if not there 
	    // (fkey types will already be filled)
	    if ( persFieldInfo[i].type == null )
	        persFieldInfo[i].type = getCMPFieldType(persFieldInfo[i].name);
        }

        // When called from Deploytool, the bean class is abstract,
        // and doesnt have the CMP fields: they will be in the generated 
        // code after deployment. So all the java.lang.reflect.Field 
	// values in PersistentFieldInfo can only be initialized at runtime.
	try {
	    if ( persistentClass != null 
		 && !Modifier.isAbstract(persistentClass.getModifiers()) ) {
		for ( int i=0; i<persFieldInfo.length; i++ ) {
		    persFieldInfo[i].field = getField(getStateClass(), 
						      persFieldInfo[i].name);
		}
	    }

	    // Initialize pkeyClassPkeyFields
	    if ( !pkeyIsOneField && primaryKeyClass != null 
                 && !Modifier.isAbstract(primaryKeyClass.getModifiers()) ) {
		pkeyClassPkeyFields = new Field[pkeyFieldInfo.length];
		for ( int i=0; i<pkeyFieldInfo.length; i++ ) {
		    pkeyClassPkeyFields[i] = primaryKeyClass.getField(
							pkeyFieldInfo[i].name); 
		}
	    } 
	} catch ( NoSuchFieldException ex ) {
            if(DOLUtils.getDefaultLogger().isLoggable(Level.FINE)) {            
                DOLUtils.getDefaultLogger().log(Level.FINE, ex.toString(), ex);
            }
	    throw new EJBException(ex);
	}

        fieldInfoInitialized = true;
    
public voidinvalidate()
Ensures that persistence descriptor will regenerate its derived information after changes have been made to persistent characteristics.

        cmrFieldInfo = null;
	persFieldInfo = null;
        fieldInfoInitialized = false;
        pkeyStuffInitialized = false;
    
public booleanisCMPField(java.lang.String field)
Has the supplied field object been deemed persistent.

	return this.getCMPFields().contains(new FieldDescriptor(field));
    
public booleanisPkeyField(java.lang.String field)
Is the supplied field object one of the pkey fields.

        return isPkeyField(new FieldDescriptor(field));
    
public booleanisPkeyField(FieldDescriptor fieldDesc)

        return this.getPkeyFields().contains(fieldDesc);
    
private booleanmethodsEqual(java.lang.reflect.Method m1, java.lang.reflect.Method m2, boolean compareDeclaringClass)
Checks whether two methods that might have been loaded by different class loaders are equal.

param
compareDeclaringClass if true, declaring class will be considered as part of equality test.

        boolean equal = false;

        do {

            String m1Name = m1.getName();
            String m2Name = m2.getName();

            if( !m1Name.equals(m2Name) ) { break; }

            String m1DeclaringClass = m1.getDeclaringClass().getName();
            String m2DeclaringClass = m2.getDeclaringClass().getName();

            if( compareDeclaringClass ) {
                if( !m1DeclaringClass.equals(m2DeclaringClass) ) { break; }
            }

            Class[] m1ParamTypes = m1.getParameterTypes();
            Class[] m2ParamTypes = m2.getParameterTypes();
            
            if( m1ParamTypes.length != m2ParamTypes.length ) { break; }

            equal = true;
            for(int pIndex = 0; pIndex < m1ParamTypes.length; pIndex++) {
                String m1ParamClass = m1ParamTypes[pIndex].getName();
                String m2ParamClass = m2ParamTypes[pIndex].getName();
                if( !m1ParamClass.equals(m2ParamClass) ) {
                    equal = false;
                    break;
                }
            } 

        } while(false);

        return equal;
    
private booleanmethodsEqual(MethodDescriptor m1, java.lang.reflect.Method m2, boolean compareDeclaringClass)
Checks whether two methods that might have been loaded by different class loaders are equal.

param
compareDeclaringClass if true, declaring class will be considered as part of equality test.

                                     
        Method m = m1.getMethod(parentDesc);
        return methodsEqual(m, m2, compareDeclaringClass);
        
    
public booleanprimaryKeyFieldsAllPrimitive()

return
true if the primkey-field is not specified all fields of pkey class are Java primitive types.

        if( !pkeyStuffInitialized )
            initPkeyInfo();
	return pkeyFieldsAllPrimitive;
    
public booleanprimaryKeyIsOneField()

return
true if the primary key of this object is one field in its class and the type of the field is not a primitive type. True for EJBs if the primkey-field deployment descriptor element is specified, or if a container-inserted pk field is used.

	if ( !pkeyStuffInitialized )
	    initPkeyInfo();
	return pkeyIsOneField;
    
public booleanprimaryKeyIsSpecified()

return
false if the primkey-field is not specified and pk class = Object

        if( !pkeyStuffInitialized )
            initPkeyInfo();
	return pkeyFieldSpecified;
    
public voidprint(java.lang.StringBuffer toStringBuffer)
Return my formatted string representation.

	super.print(toStringBuffer);
	toStringBuffer.append("\n Entity descriptor");
	toStringBuffer.append("\n cmpFields ").append(cmpFields);
    
public voidremoveCMPField(java.lang.String field)

        removeCMPField(new FieldDescriptor(field));
    
public voidremoveCMPField(FieldDescriptor fieldDesc)

        this.cmpFields.remove(fieldDesc);
        setCMPFields(this.cmpFields);
    
public voidremoveQueryFor(MethodDescriptor method)

           
	queries.remove(method);
    
public voidsetCMPFields(java.util.Set cmpFields)
Set the FieldDescriptor objects that the EJB container will persist for this bean.

	this.cmpFields = cmpFields;
	persFieldInfo = null;
	fieldInfoInitialized = false;
	super.changed();
    
public voidsetFkeyFields(PersistentFieldInfo[] fkeyFields)
Set the array of PersistentFieldInfo objects representing the foreign key fields of this bean.

	this.fkeyFields = fkeyFields;
	fieldInfoInitialized = false;
	persFieldInfo = null;
	super.changed();
    
public voidsetParentDescriptor(Descriptor parentDesc)

	this.parentDesc = (EjbCMPEntityDescriptor)parentDesc;
    
public voidsetPkeyFields(java.util.Set pkeyFields)
Set the FieldDescriptor objects for primary key fields for this bean.

	this.pkeyFields = pkeyFields;
	fieldInfoInitialized = false;
	persFieldInfo = null;
	pkeyStuffInitialized = false;
	super.changed();
    
public voidsetQueryFor(MethodDescriptor method, QueryDescriptor query)

		queries.put(method, query);
    
public voidsetQueryFor(java.lang.reflect.Method method, QueryDescriptor query)

        // Use our own method equality check. This prevents problems
        // when a different classloader was used to load the input
        // method.  Also note that two methods with the same name and
        // signature on *different* interfaces are considered EQUAL.
        // This matches the spec requirement that the same finder
        // method defined on the LocalHome and RemoteHome has only
        // ONE query-method declaration in the deployment descriptor.
        // 
        MethodDescriptor md = new MethodDescriptor(method,"");
        setQueryFor(md, query);