KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > deployment > PersistenceDescriptor


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 package com.sun.enterprise.deployment;
25
26 import java.util.*;
27 import java.lang.reflect.*;
28 import javax.ejb.EJBException JavaDoc;
29 import com.sun.enterprise.util.LocalStringManagerImpl;
30 import com.sun.enterprise.util.TypeUtil;
31 import java.util.logging.Level JavaDoc;
32 import com.sun.enterprise.deployment.util.DOLUtils;
33
34 /**
35  * This class contains information about the persistent state
36  * (abstract persistence schema)
37  * for EJB2.0 CMP EntityBeans and Join Objects.
38  *
39  * @author Sanjeev Krishnan
40  */

41
42 public final class PersistenceDescriptor extends Descriptor {
43     
44     private Set cmpFields = new HashSet();
45
46     // there can be 0 or more pkey fields
47
// This set contains FieldDescriptors for fields from bean or pkey class
48
private Set pkeyFields = new HashSet();
49
50     // true if primkey-field is set or for container-generated pk field
51
private boolean pkeyIsOneField = false;
52
53     // false for beans with no primkey-field and pk class = Object
54
private boolean pkeyFieldSpecified = true;
55
56     private String JavaDoc primaryKeyClassName;
57     private boolean pkeyStuffInitialized = false;
58
59     // true for beans whose primary fields are all primitive fields
60
private boolean pkeyFieldsAllPrimitive = false;
61     
62     private static LocalStringManagerImpl localStrings =
63         new LocalStringManagerImpl(PersistenceDescriptor.class);
64
65     private EjbCMPEntityDescriptor parentDesc; //the bean whose persistence I describe
66

67     private Class JavaDoc persistentClass; // the bean class
68
private Class JavaDoc stateClass; // the class which holds persistent fields
69
private Class JavaDoc primaryKeyClass;
70
71     private PersistentFieldInfo[] persFieldInfo;
72     private PersistentFieldInfo[] persNoPkeyFieldInfo;
73     private PersistentFieldInfo[] pkeyFieldInfo;
74     private boolean fieldInfoInitialized=false;
75     private PersistentFieldInfo[] fkeyFields;
76
77     private CMRFieldInfo[] cmrFieldInfo;
78
79     private Field[] pkeyClassPkeyFields; // fields in primary key class
80

81     private Hashtable queries = new Hashtable();
82     private HashSet allQueriedMethods;
83
84     public PersistenceDescriptor() {
85     }
86     
87     /**
88      * The copy constructor.
89      */

90     public PersistenceDescriptor(PersistenceDescriptor pers) {
91     super(pers);
92
93     this.getCMPFields().addAll(pers.getCMPFields());
94     //this.primaryKeyFieldDesc = pers.primaryKeyFieldDesc;
95
}
96
97     public String JavaDoc getCMRFieldReturnType(String JavaDoc field) {
98         String JavaDoc returnType = "java.util.Collection";
99         try {
100             if( !field.trim().equals("") ) {
101                 Class JavaDoc persClass = getPersistentClass();
102                 String JavaDoc methodName = "get" + field.substring(0,1).toUpperCase()
103                     + field.substring(1);
104                 Method method = TypeUtil.getMethod
105                     (persClass, persClass.getClassLoader(), methodName,
106                      new String JavaDoc[] {});
107                 returnType = method.getReturnType().getName();
108             }
109         } catch(Throwable JavaDoc t) {
110             if(DOLUtils.getDefaultLogger().isLoggable(Level.FINE)) {
111                 DOLUtils.getDefaultLogger().log(Level.FINE, t.toString(), t);
112             }
113         }
114         
115         return returnType;
116     }
117
118     /**
119      * Called from EjbCMPEntityDescriptor
120      * when some classes in this object are updated.
121      */

122     public boolean classesChanged() {
123
124         // XXX Remove any fields marked as persistent that no longer exist
125
// in bean class as getter/setter.
126
persistentClass = null;
127         stateClass = null;
128         Class JavaDoc persClass = getPersistentClass();
129
130         Vector fieldDescriptors = parentDesc.getFieldDescriptors();
131
132         // Remove obsolete cmp fields
133
if( this.cmpFields != null ) {
134             for(Iterator iter = cmpFields.iterator(); iter.hasNext();) {
135                 FieldDescriptor next = (FieldDescriptor) iter.next();
136                 if( !fieldDescriptors.contains(next) ) {
137                     iter.remove();
138                 }
139             }
140         }
141
142         // Remove obsolete pkey fields
143
if( this.pkeyFields != null ) {
144             for(Iterator iter = pkeyFields.iterator(); iter.hasNext();) {
145                 FieldDescriptor next = (FieldDescriptor) iter.next();
146                 if( !fieldDescriptors.contains(next) ) {
147                     iter.remove();
148                 }
149             }
150         }
151
152         FieldDescriptor primKeyFieldDesc = parentDesc.getPrimaryKeyFieldDesc();
153         if( (primKeyFieldDesc != null) &&
154             !fieldDescriptors.contains(primKeyFieldDesc) ) {
155             parentDesc.setPrimaryKeyFieldDesc(null);
156         }
157
158
159         // CMP 2.x
160
// Remove queries for methods no longer in allQueriedMethods
161

162         // First clone old set of queries
163
Hashtable queriesClone = (Hashtable) queries.clone();
164         
165         queries = new Hashtable();
166         initializeAllQueriedMethods();
167
168         Iterator it = queriesClone.keySet().iterator();
169         while ( it.hasNext() ) {
170             Method oldMethod = (Method)it.next();
171             Method newMethod = findEquivalentMethod(allQueriedMethods,
172                                                     oldMethod);
173             if( newMethod != null ) {
174                 QueryDescriptor oldQuery = (QueryDescriptor)
175                     queriesClone.get(oldMethod);
176                 QueryDescriptor newQuery =
177                     new QueryDescriptor(oldQuery, newMethod);
178                 // Only add to list of methods having queries if
179
// it's still in the class.
180
queries.put(newMethod, newQuery);
181             }
182         }
183
184         // Force the persistence descriptor to regenerate its
185
// derived info.
186
invalidate();
187
188         return false;
189     }
190
191     /**
192      * Search for a matching method in a list of methods
193      * that might have been loaded with a different classloader.
194      * Because of this possibility, we can't use
195      * java.lang.reflect.Method.equals().
196      * @return matched method or NULL
197      */

198     private Method findEquivalentMethod(Collection methods,
199                                         Method methodToMatch) {
200         Method matchedMethod = null;
201         for(Iterator iter = methods.iterator(); iter.hasNext();) {
202             Object JavaDoc o = iter.next();
203             Method next;
204             if (o instanceof Method) {
205                 next = (Method) o;
206             } else {
207                 next = ((MethodDescriptor) o).getMethod(parentDesc);
208                 if (next==null) {
209                     return null;
210                 }
211             }
212             // Compare methods, ignoring declaring class.
213
if( methodsEqual(next, methodToMatch, false) ) {
214                 matchedMethod = next;
215                 break;
216             }
217         }
218         return matchedMethod;
219     }
220
221     /**
222      * Checks whether two methods that might have been loaded by
223      * different class loaders are equal.
224      * @param compareDeclaringClass if true, declaring class will
225      * be considered as part of equality test.
226      */

227     private boolean methodsEqual(Method m1, Method m2,
228                                  boolean compareDeclaringClass) {
229         boolean equal = false;
230
231         do {
232
233             String JavaDoc m1Name = m1.getName();
234             String JavaDoc m2Name = m2.getName();
235
236             if( !m1Name.equals(m2Name) ) { break; }
237
238             String JavaDoc m1DeclaringClass = m1.getDeclaringClass().getName();
239             String JavaDoc m2DeclaringClass = m2.getDeclaringClass().getName();
240
241             if( compareDeclaringClass ) {
242                 if( !m1DeclaringClass.equals(m2DeclaringClass) ) { break; }
243             }
244
245             Class JavaDoc[] m1ParamTypes = m1.getParameterTypes();
246             Class JavaDoc[] m2ParamTypes = m2.getParameterTypes();
247             
248             if( m1ParamTypes.length != m2ParamTypes.length ) { break; }
249
250             equal = true;
251             for(int pIndex = 0; pIndex < m1ParamTypes.length; pIndex++) {
252                 String JavaDoc m1ParamClass = m1ParamTypes[pIndex].getName();
253                 String JavaDoc m2ParamClass = m2ParamTypes[pIndex].getName();
254                 if( !m1ParamClass.equals(m2ParamClass) ) {
255                     equal = false;
256                     break;
257                 }
258             }
259
260         } while(false);
261
262         return equal;
263     }
264
265     /**
266      * Checks whether two methods that might have been loaded by
267      * different class loaders are equal.
268      * @param compareDeclaringClass if true, declaring class will
269      * be considered as part of equality test.
270      */

271     private boolean methodsEqual(MethodDescriptor m1, Method m2,
272                                  boolean compareDeclaringClass) {
273                                      
274         Method m = m1.getMethod(parentDesc);
275         return methodsEqual(m, m2, compareDeclaringClass);
276         
277     }
278     
279     public void setParentDescriptor(Descriptor parentDesc)
280     {
281     this.parentDesc = (EjbCMPEntityDescriptor)parentDesc;
282     }
283
284     public Descriptor getParentDescriptor()
285     {
286     return parentDesc;
287     }
288    
289     public EjbBundleDescriptor getEjbBundleDescriptor()
290     {
291      return parentDesc.getEjbBundleDescriptor();
292     }
293
294     /**
295      * Get all CMR fields of this bean. All relationships
296      * are stored in EjbBundleDescriptor to avoid the complexity of
297      * keeping the two sets consistent. NOTE : To add or remove
298      * a relationship use EjbBundleDescriptor.
299      */

300     public Set getRelationships()
301     {
302         Set allRelationships = getEjbBundleDescriptor().getRelationships();
303         Set myRelationships = new HashSet();
304         for(Iterator iter = allRelationships.iterator(); iter.hasNext();) {
305             RelationshipDescriptor next = (RelationshipDescriptor) iter.next();
306             if( next.hasParticipant(parentDesc) ) {
307                 myRelationships.add(next);
308             }
309         }
310         return myRelationships;
311     }
312
313     /**
314      * Return array of CMRFieldInfo objects for all CMR fields.
315      */

316     public CMRFieldInfo[] getCMRFieldInfo()
317     {
318     if ( cmrFieldInfo == null ) {
319         try {
320         initCMRFieldStuff();
321         } catch ( Exception JavaDoc ex ) {
322                 DOLUtils.getDefaultLogger().log(Level.SEVERE, "enterprise.deployment.backend.invalidDescriptorMappingFailure",
323                     new Object JavaDoc[] {ex.toString()});
324         throw new EJBException JavaDoc(ex);
325         }
326     }
327     return cmrFieldInfo;
328     }
329
330     /**
331      * Return the CMRFieldInfo object for the given CMR field
332      */

333     public CMRFieldInfo getCMRFieldInfoByName(String JavaDoc fieldName)
334     {
335     CMRFieldInfo[] cmrf = this.getCMRFieldInfo();
336     for ( int i=0; i<cmrf.length; i++ ) {
337         if ( cmrf[i].name.equals(fieldName) )
338         return cmrf[i];
339     }
340     throw new EJBException JavaDoc("CMRFieldInfo not found for field "+fieldName);
341     }
342
343     /**
344      * Ensures that persistence descriptor will regenerate its
345      * derived information after changes have been made to
346      * persistent characteristics.
347      */

348     public void invalidate() {
349         cmrFieldInfo = null;
350     persFieldInfo = null;
351         fieldInfoInitialized = false;
352         pkeyStuffInitialized = false;
353     }
354
355     private void initCMRFieldStuff()
356     throws Exception JavaDoc
357     {
358     if ( !fieldInfoInitialized )
359         initializeFieldInfo();
360
361         Set relationships = getRelationships();
362     Iterator it = relationships.iterator();
363         // set to the biggest possible size when all relationships
364
// are self-referencing
365
CMRFieldInfo[] cmrFieldInfo2 =
366             new CMRFieldInfo[relationships.size() * 2];
367     int count = 0;
368     while ( it.hasNext() ) {
369         RelationshipDescriptor rd = (RelationshipDescriptor)it.next();
370         RelationRoleDescriptor source = rd.getSource();
371         RelationRoleDescriptor sink = rd.getSink();
372         RelationRoleDescriptor myroles[];
373             // if this is a self-referencing relationship, initialize
374
// both source and sink cmr fields
375
if ( source.getPersistenceDescriptor() ==
376                 sink.getPersistenceDescriptor() ) {
377                 myroles = new RelationRoleDescriptor[2];
378                 myroles[0] = source;
379                 myroles[1] = sink;
380             } else {
381                 myroles = new RelationRoleDescriptor[1];
382                 if ( source.getPersistenceDescriptor() == this ) {
383                     myroles[0] = source;
384                 } else {
385                     myroles[0] = sink;
386                 }
387             }
388             
389             // for all relation role elements in myroles, initialize
390
// their cmr fields and put them in cmrFieldInfo2
391
for (int ii = 0; ii < myroles.length; ii++) {
392             CMRFieldInfo finfo = new CMRFieldInfo();
393             cmrFieldInfo2[count++] = finfo;
394
395             PersistenceDescriptor partnerPers =
396             myroles[ii].getPartner().getPersistenceDescriptor();
397
398             // Check if partner has a local interface
399
EjbCMPEntityDescriptor partner =
400                     myroles[ii].getPartner().getOwner();
401                 if ( !partner.isLocalInterfacesSupported() &&
402             myroles[ii].getCMRField() != null ) {
403                 throw new RuntimeException JavaDoc(
404                         "No local interface for target bean of CMR field");
405             }
406
407             String JavaDoc type;
408             if ( myroles[ii].getPartner().getIsMany() == false ) {
409                 // 1-1 and many-1
410
if ( partner.isLocalInterfacesSupported() )
411                 type = partner.getLocalClassName();
412                 else
413                         // a unidirectional relation, partner is
414
// remote-only bean
415
type = partner.getPrimaryKeyClassName();
416             }
417             else {
418                 // 1-many and many-many
419
type = myroles[ii].getCMRFieldType();
420                 if ( type == null ) {
421                 // A unidirectional relationship from partner
422
// to this obj
423
type = "java.util.Collection";
424                 }
425             }
426             finfo.type = getClass(type);
427
428             finfo.name = myroles[ii].getCMRField();
429             if ( finfo.name == null ) {
430                 // A unidirectional relationship from partner to this obj.
431
// We need to maintain a pointer to partner anyway.
432
finfo.name = myroles[ii].composeReverseCmrFieldName();
433             }
434             finfo.role = myroles[ii];
435             myroles[ii].setCMRFieldInfo(finfo);
436
437             if ( rd.isOneOne() && fkeyFields != null ) {
438                 // set foreign key fields corresponding to this CMR field
439
PersistentFieldInfo[] cmrFkeyFields;
440                 PersistentFieldInfo[] partnerPkeyFields =
441                         partnerPers.getPkeyFieldInfo();
442             cmrFkeyFields =
443             new PersistentFieldInfo[partnerPkeyFields.length];
444             for ( int i=0; i<partnerPkeyFields.length; i++ ) {
445                 String JavaDoc fkeyName = "_" + finfo.name + "_"
446                         + partnerPkeyFields[i].name;
447                 for ( int j=0; j<fkeyFields.length; j++ ) {
448                     if ( fkeyFields[j].name.equals(fkeyName) )
449                     cmrFkeyFields[i] = fkeyFields[j];
450                 }
451             }
452             finfo.fkeyFields = cmrFkeyFields;
453             }
454             }
455         }
456
457         // initialize the cmrFieldInfo array with the actual size
458
// and copy the non-null values of cmrFieldInfo2 to it
459
cmrFieldInfo = new CMRFieldInfo[count];
460         System.arraycopy(cmrFieldInfo2, 0, cmrFieldInfo, 0, count);
461
462     // Sort cmrFieldInfo in alphabetical order of CMR field name
463
for ( int i=cmrFieldInfo.length-1; i>0; i-- ) {
464             for ( int j=0; j<i; j++ ) {
465                 if ( cmrFieldInfo[j].name.compareTo(cmrFieldInfo[j+1].name)
466                                     > 0 ) {
467                     CMRFieldInfo tmp = cmrFieldInfo[j];
468                     cmrFieldInfo[j] = cmrFieldInfo[j+1];
469                     cmrFieldInfo[j+1] = tmp;
470                 }
471             }
472         }
473     }
474
475     public void clearCMPFields() {
476         this.cmpFields.clear();
477         setCMPFields(this.cmpFields);
478     }
479
480     public void addCMPField(String JavaDoc field) {
481         addCMPField(new FieldDescriptor(field));
482     }
483
484     public void addCMPField(FieldDescriptor fieldDesc) {
485         this.cmpFields.add(fieldDesc);
486         setCMPFields(this.cmpFields);
487     }
488
489     public void removeCMPField(String JavaDoc field) {
490         removeCMPField(new FieldDescriptor(field));
491     }
492
493     public void removeCMPField(FieldDescriptor fieldDesc) {
494         this.cmpFields.remove(fieldDesc);
495         setCMPFields(this.cmpFields);
496     }
497
498     /**
499      * Set the FieldDescriptor objects that the EJB container will persist
500      * for this bean.
501      */

502     public void setCMPFields(Set cmpFields) {
503     this.cmpFields = cmpFields;
504     persFieldInfo = null;
505     fieldInfoInitialized = false;
506     super.changed();
507     }
508     
509     /**
510      * Has the supplied field object been deemed persistent.
511      */

512     public boolean isCMPField(String JavaDoc field) {
513     return this.getCMPFields().contains(new FieldDescriptor(field));
514     }
515
516     
517     /**
518      * Return the Set of fields deemed persistent.
519      * The elements of this Set are FieldDescriptor objects.
520      * This Set should be modified by calling addCMPField, removeCMPField
521      */

522     public Set getCMPFields() {
523     return this.cmpFields;
524     }
525
526     /**
527     public void clearPkeyFields() {
528         this.pkeyFields.clear();
529         setPkeyFields(this.pkeyFields);
530     }
531
532     public void addPkeyField(String field) {
533         addPkeyField(new FieldDescriptor(field));
534     }
535     
536     public void addPkeyField(FieldDescriptor fieldDesc) {
537         this.pkeyFields.add(fieldDesc);
538         setPkeyFields(this.pkeyFields);
539     }
540
541     public void removePkeyField(String field) {
542         removePkeyField(new FieldDescriptor(field));
543     }
544     
545     public void removePkeyField(FieldDescriptor fieldDesc) {
546         this.pkeyFields.remove(fieldDesc);
547         setPkeyFields(this.pkeyFields);
548     }
549     **/

550
551     /**
552      * Set the FieldDescriptor objects for primary key fields
553      * for this bean.
554      */

555     public void setPkeyFields(Set pkeyFields) {
556     this.pkeyFields = pkeyFields;
557     fieldInfoInitialized = false;
558     persFieldInfo = null;
559     pkeyStuffInitialized = false;
560     super.changed();
561     }
562     
563     /**
564      * Return the Set of primary key fields.
565      * The elements of this Set are FieldDescriptor objects.
566      * This Set can be modified by calling addPkeyField, removePkeyField
567      */

568     public Set getPkeyFields() {
569     if ( !pkeyStuffInitialized )
570         initPkeyInfo();
571     return pkeyFields;
572     }
573
574     /**
575      * Is the supplied field object one of the pkey fields.
576      */

577     public boolean isPkeyField(String JavaDoc field) {
578         return isPkeyField(new FieldDescriptor(field));
579     }
580
581     public boolean isPkeyField(FieldDescriptor fieldDesc) {
582         return this.getPkeyFields().contains(fieldDesc);
583     }
584
585     /**
586      * Initialize pkeyFields, pkeyIsOneField, primaryKeyClassName
587      * Must be called after this PersistenceDescriptor has been attached
588      * to the Ejb/JoinDescriptor which has been
589      * attached to the EjbBundleDescriptor.
590      */

591     private void initPkeyInfo()
592     {
593     try {
594         pkeyIsOneField = false;
595             pkeyFieldSpecified = true;
596         primaryKeyClassName = parentDesc.getPrimaryKeyClassName();
597     
598         FieldDescriptor fd = parentDesc.getPrimaryKeyFieldDesc();
599         if ( pkeyFields == null || pkeyFields.size() == 0 ) {
600             pkeyFields = new HashSet();
601
602             if ( fd != null ) // primkey-field was set
603
pkeyFields.add(fd);
604
605             else if (!primaryKeyClassName.equals("java.lang.Object")) {
606             // get fields of primaryKeyClass
607
primaryKeyClass = getClass(primaryKeyClassName);
608             Field[] fields = primaryKeyClass.getFields();
609             pkeyFieldsAllPrimitive = true;
610             for ( int i=0; i<fields.length; i++ ) {
611                 // ignore static or final fields
612
int m = fields[i].getModifiers();
613                 if ( Modifier.isStatic(m) || Modifier.isFinal(m) )
614                 continue;
615                 if ( !fields[i].getType().isPrimitive() )
616                 pkeyFieldsAllPrimitive = false;
617                 pkeyFields.add(new FieldDescriptor(
618                             fields[i].getName()));
619             }
620             }
621             else {
622             // Will use PM-generated primary key
623
primaryKeyClass = getClass(primaryKeyClassName);
624                        pkeyIsOneField = true;
625                        pkeyFieldSpecified = false;
626             }
627         }
628         if ( fd != null )
629             pkeyIsOneField = true;
630
631         pkeyStuffInitialized = true;
632     }
633     catch ( Exception JavaDoc ex ) {
634             DOLUtils.getDefaultLogger().log(Level.SEVERE, "enterprise.deployment.backend.invalidDescriptorMappingFailure",
635                 new Object JavaDoc[] {ex.toString()});
636             throw new EJBException JavaDoc(ex);
637     }
638     }
639
640     /**
641      * @return true if the primary key of this object is one field
642      * in its class and the type of the field is not a primitive type.
643      * True for EJBs if the primkey-field deployment descriptor element
644      * is specified, or if a container-inserted pk field is used.
645      */

646     public boolean primaryKeyIsOneField()
647     {
648     if ( !pkeyStuffInitialized )
649         initPkeyInfo();
650     return pkeyIsOneField;
651     }
652
653
654     /**
655      * @return false if the primkey-field is not specified and pk class = Object
656      */

657     public boolean primaryKeyIsSpecified()
658     {
659         if( !pkeyStuffInitialized )
660             initPkeyInfo();
661     return pkeyFieldSpecified;
662     }
663
664
665     /**
666      * @return true if the primkey-field is not specified all fields of
667      * pkey class are Java primitive types.
668      */

669     public boolean primaryKeyFieldsAllPrimitive()
670     {
671         if( !pkeyStuffInitialized )
672             initPkeyInfo();
673     return pkeyFieldsAllPrimitive;
674     }
675
676
677
678     /**
679      * Get this bean's primary key class.
680      * For EJBs, this is EjbEntityDescriptor.getPrimaryKeyClassName(),
681      */

682     public Class JavaDoc getPrimaryKeyClass()
683     {
684     if ( !pkeyStuffInitialized )
685         initPkeyInfo();
686     return primaryKeyClass;
687     }
688    
689
690     // May return null for Join objects when called at/before deployment
691
public Class JavaDoc getPersistentClass()
692     {
693     if ( persistentClass == null ) {
694         persistentClass = getClass(parentDesc.getEjbClassName());
695     }
696     return persistentClass;
697     }
698
699     public Class JavaDoc getStateClass()
700     {
701     if ( stateClass == null ) {
702         stateClass = getPersistentClass();
703         if ( parentDesc.isEJB20() ) {
704         if( !Modifier.isAbstract(stateClass.getModifiers()) ) {
705                 throw new EJBException JavaDoc("2.x CMP bean class "
706                         + stateClass.getName() + " must be decleared abstract "
707                         + "or cmp-version for the corresponding bean must be set to 1.x.");
708                 }
709             String JavaDoc stateClassName = parentDesc.getStateImplClassName();
710             stateClass = getClass(stateClassName);
711         }
712     }
713     return stateClass;
714     }
715
716
717
718     private Class JavaDoc getClass(String JavaDoc className)
719     {
720     try {
721         return getEjbBundleDescriptor().getClassLoader().loadClass(className);
722     } catch ( Exception JavaDoc ex ) {
723         //if ( debug ) ex.printStackTrace();
724
throw new EJBException JavaDoc(ex);
725     }
726     }
727
728
729     /**
730      * Set the array of PersistentFieldInfo objects representing the
731      * foreign key fields of this bean.
732      */

733     public void setFkeyFields(PersistentFieldInfo[] fkeyFields) {
734     this.fkeyFields = fkeyFields;
735     fieldInfoInitialized = false;
736     persFieldInfo = null;
737     super.changed();
738     }
739     
740     
741     /**
742      * Return the array of PersistentFieldInfo objects for the
743      * foreign key fields of this bean.
744      */

745     public PersistentFieldInfo[] getFkeyFields() {
746     if ( !fieldInfoInitialized )
747         initializeFieldInfo();
748     return this.fkeyFields;
749     }
750
751
752     /**
753      * Return the array of PersistentFieldInfo objects for the
754      * CMP + foreign key fields
755      */

756     public PersistentFieldInfo[] getPersistentFieldInfo()
757     {
758     if ( !fieldInfoInitialized )
759         initializeFieldInfo();
760     return persFieldInfo;
761     }
762
763
764     /**
765      * Return the PersistentFieldInfo object for the given CMP/fkey field
766      */

767     public PersistentFieldInfo getPersistentFieldInfoByName(String JavaDoc fieldName)
768     {
769     if ( !fieldInfoInitialized )
770         initializeFieldInfo();
771     for ( int i=0; i<persFieldInfo.length; i++ ) {
772         if ( persFieldInfo[i].name.equals(fieldName) )
773         return persFieldInfo[i];
774     }
775     throw new EJBException JavaDoc("PersistentFieldInfo not found for field "+fieldName);
776     }
777
778
779     /**
780      * Return the array of PersistentFieldInfo objects for the CMP fields
781      * which are not primary keys + foreign key fields.
782      */

783     public PersistentFieldInfo[] getNonPkeyPersFieldInfo()
784     {
785     if ( !fieldInfoInitialized )
786         initializeFieldInfo();
787     return persNoPkeyFieldInfo;
788     }
789
790
791     /**
792      * Return the array of PersistentFieldInfo objects for the pkey fields.
793      */

794     public PersistentFieldInfo[] getPkeyFieldInfo()
795     {
796     if ( !fieldInfoInitialized )
797         initializeFieldInfo();
798     return pkeyFieldInfo;
799     }
800
801     /**
802      * Return PersistentFieldInfo object for the given pkey field.
803      */

804     public PersistentFieldInfo getPkeyFieldInfoByName(String JavaDoc fieldName)
805     {
806     if ( !fieldInfoInitialized )
807         initializeFieldInfo();
808     for ( int i=0; i<pkeyFieldInfo.length; i++ ) {
809         if ( pkeyFieldInfo[i].name.equals(fieldName) )
810         return pkeyFieldInfo[i];
811     }
812     throw new EJBException JavaDoc("PersistentFieldInfo not found for pkey field "+fieldName);
813     }
814
815
816
817     /**
818      * @return an array of all Field objects in the primary key class.
819      * Returns null if primaryKeyIsOneField() == true.
820      */

821     public Field[] getPkeyClassFields()
822     {
823     if ( !fieldInfoInitialized )
824         initializeFieldInfo();
825     return pkeyClassPkeyFields;
826     }
827
828
829     // Initialize persFieldInfo, pkeyFieldInfo, persNoPkeyFieldInfo,
830
// pkeyClassPkeyFields
831
private void initializeFieldInfo()
832     {
833     if ( !pkeyStuffInitialized )
834         initPkeyInfo();
835
836     int cmpFieldCount = cmpFields.size();
837         if (cmpFieldCount==0) {
838             throw new EJBException JavaDoc("No cmp field defined for CMP EJB " + parentDesc.getName());
839         }
840
841     int fkeyCount = 0;
842     if ( fkeyFields != null )
843         fkeyCount = fkeyFields.length;
844
845     persFieldInfo = new PersistentFieldInfo[cmpFieldCount + fkeyCount];
846     // Add CMP fields
847
int fcount = 0;
848     Iterator itr = cmpFields.iterator();
849     while ( itr.hasNext() ) {
850         persFieldInfo[fcount] = new PersistentFieldInfo();
851         persFieldInfo[fcount].name =((FieldDescriptor)itr.next()).getName();
852         fcount++;
853     }
854     // Add foreign key fields
855
if ( fkeyFields != null ) {
856         for ( int i=0; i<fkeyFields.length; i++ ) {
857         persFieldInfo[fcount] = fkeyFields[i];
858         fcount++;
859         }
860     }
861
862     // sort persFieldInfo in alphabetical order
863
for ( int i=persFieldInfo.length-1; i>0; i-- ) {
864             for ( int j=0; j<i; j++ ) {
865                 if ( persFieldInfo[j].name.compareTo(persFieldInfo[j+1].name)
866                                     > 0 ) {
867                     PersistentFieldInfo tmp = persFieldInfo[j];
868                     persFieldInfo[j] = persFieldInfo[j+1];
869                     persFieldInfo[j+1] = tmp;
870                 }
871             }
872         }
873
874         // Initialize pkeyFieldInfo[] and persNoPkeyFieldInfo[]
875
// They contain the same PersistentFieldInfo objects as persFieldInfo.
876
pkeyFieldInfo = new PersistentFieldInfo[pkeyFields.size()];
877     if ( pkeyFieldSpecified ) {
878
879             // check if PK class has public non-persistent fields
880
StringBuffer JavaDoc nonPersFieldsInPK = new StringBuffer JavaDoc();
881             for ( Iterator it=pkeyFields.iterator(); it.hasNext(); ) {
882                 FieldDescriptor fd = (FieldDescriptor)it.next();
883                 boolean isPersistent = false;
884                 for ( int i=0; i<persFieldInfo.length; i++ ) {
885                     if ( fd.getName().equals(persFieldInfo[i].name) ) {
886                         isPersistent = true;
887                         break;
888                     }
889                 }
890                 if ( !isPersistent ) {
891                     // if not the first non-persistent field
892
if ( nonPersFieldsInPK.length() != 0 ) {
893                         nonPersFieldsInPK.append(", ");
894                     }
895                     nonPersFieldsInPK.append(fd.getName());
896                 }
897             }
898             if ( nonPersFieldsInPK.length() != 0 ) {
899                 throw new EJBException JavaDoc(localStrings.getLocalString(
900                 "enterprise.deployment.pkhasnopersistentfields",
901                 "CMP bean [{0}], primary key class [{1}] has " +
902                 "public non-persistent field(s) [{2}].",
903                 new Object JavaDoc[] {getParentDescriptor().getName(),
904                 getPrimaryKeyClass().getName(),
905                 nonPersFieldsInPK.toString()}));
906             }
907
908         persNoPkeyFieldInfo = new PersistentFieldInfo[persFieldInfo.length -
909                               pkeyFieldInfo.length];
910         int pkeyCount = 0;
911         int noPkeyCount = 0;
912         for ( int i=0; i<persFieldInfo.length; i++ ) {
913         boolean isPkey = false;
914         for ( Iterator it=pkeyFields.iterator(); it.hasNext(); ) {
915             FieldDescriptor fd = (FieldDescriptor)it.next();
916             if ( fd.getName().equals(persFieldInfo[i].name) ) {
917             isPkey = true;
918             break;
919             }
920         }
921         if ( isPkey )
922             pkeyFieldInfo[pkeyCount++] = persFieldInfo[i];
923         else
924             persNoPkeyFieldInfo[noPkeyCount++] = persFieldInfo[i];
925         }
926     }
927
928     if ( pkeyIsOneField && pkeyFieldSpecified) {
929         // Initialize pkey field type. This is needed for
930
// beans with no pkey field (i.e. PM-generated pkey)
931
// because they wont have get/set for the pkey in the bean class
932
// so the getCMPFieldType() below will bomb if type is not set.
933
// Note: pkeyFieldInfo and persFieldInfo arrays share the same
934
// PersistentFieldInfo objects.
935
pkeyFieldInfo[0].type = getPrimaryKeyClass();
936     }
937
938     // Initialize Java types in persFieldInfo
939
for ( int i=0; i<persFieldInfo.length; i++ ) {
940         // fill type for CMP fields if not there
941
// (fkey types will already be filled)
942
if ( persFieldInfo[i].type == null )
943             persFieldInfo[i].type = getCMPFieldType(persFieldInfo[i].name);
944         }
945
946         // When called from Deploytool, the bean class is abstract,
947
// and doesnt have the CMP fields: they will be in the generated
948
// code after deployment. So all the java.lang.reflect.Field
949
// values in PersistentFieldInfo can only be initialized at runtime.
950
try {
951         if ( persistentClass != null
952          && !Modifier.isAbstract(persistentClass.getModifiers()) ) {
953         for ( int i=0; i<persFieldInfo.length; i++ ) {
954             persFieldInfo[i].field = getField(getStateClass(),
955                               persFieldInfo[i].name);
956         }
957         }
958
959         // Initialize pkeyClassPkeyFields
960
if ( !pkeyIsOneField && primaryKeyClass != null
961                  && !Modifier.isAbstract(primaryKeyClass.getModifiers()) ) {
962         pkeyClassPkeyFields = new Field[pkeyFieldInfo.length];
963         for ( int i=0; i<pkeyFieldInfo.length; i++ ) {
964             pkeyClassPkeyFields[i] = primaryKeyClass.getField(
965                             pkeyFieldInfo[i].name);
966         }
967         }
968     } catch ( NoSuchFieldException JavaDoc ex ) {
969             if(DOLUtils.getDefaultLogger().isLoggable(Level.FINE)) {
970                 DOLUtils.getDefaultLogger().log(Level.FINE, ex.toString(), ex);
971             }
972         throw new EJBException JavaDoc(ex);
973     }
974
975         fieldInfoInitialized = true;
976     }
977
978     private Field getField(final Class JavaDoc c, final String JavaDoc name)
979         throws NoSuchFieldException JavaDoc
980     {
981         // This privileged block is needed because this code can be
982
// called when application code is on the stack, which is not
983
// allowed to reflect on private members of classes.
984
Field field = (Field)java.security.AccessController.doPrivileged(
985             new java.security.PrivilegedAction JavaDoc() {
986                 public Object JavaDoc run() {
987                     try {
988                         // this is needed for EJB2.0 CMP beans whose
989
// generated fields are private.
990
return c.getDeclaredField(name);
991                     }
992                     catch ( NoSuchFieldException JavaDoc ex ) {
993                         return null;
994                     }
995                 }
996             }
997         );
998
999         if ( field == null )
1000            field = c.getField(name);
1001        return field;
1002    }
1003
1004    /**
1005     * @return the Class object corresponding to the type of the given
1006     * CMP field.
1007     */

1008    public Class JavaDoc getTypeFor(String JavaDoc field)
1009    {
1010    return getCMPFieldType(field);
1011    }
1012
1013    private Class JavaDoc getCMPFieldType(String JavaDoc field)
1014    {
1015    Class JavaDoc pclass = getPersistentClass();
1016    if ( Modifier.isAbstract(pclass.getModifiers()) ) {
1017        // An EJB2.0 CMP bean : field is a virtual field
1018
String JavaDoc javaBeanName = capitalize(field);
1019        String JavaDoc getter = "get"+javaBeanName;
1020        try {
1021        Method method = pclass.getMethod(getter, (Class JavaDoc[]) null);
1022        return method.getReturnType();
1023        } catch ( Exception JavaDoc ex ) {
1024        throw new RuntimeException JavaDoc("Cannot find accessor " + getter + " for CMP field "+field);
1025        }
1026    }
1027    else {
1028        // field is a Java field in state class
1029
try {
1030        Field f = getField(getStateClass(), field);
1031        return f.getType();
1032        } catch ( NoSuchFieldException JavaDoc ex ) {
1033        throw new RuntimeException JavaDoc("Cant find CMP field "+field+" in class "+getStateClass().getName());
1034        }
1035    }
1036    }
1037
1038
1039    // called from CMPClassGenerator too
1040
public static String JavaDoc capitalize(String JavaDoc name)
1041    {
1042    // EJB2.0 proposed final draft says that CMP/CMR field names
1043
// must begin with a lower case letter.
1044
if ( Character.isUpperCase(name.charAt(0)) ) {
1045        throw new javax.ejb.EJBException JavaDoc("CMP/CMR field "+name+" must start with a lower case character.");
1046    }
1047    else {
1048        char chars[] = name.toCharArray();
1049        chars[0] = Character.toUpperCase(chars[0]);
1050        return new String JavaDoc(chars);
1051    }
1052    }
1053
1054    public void setQueryFor(MethodDescriptor method, QueryDescriptor query)
1055    {
1056        queries.put(method, query);
1057    }
1058
1059
1060    public QueryDescriptor getQueryFor(MethodDescriptor method)
1061    {
1062    return (QueryDescriptor)queries.get(method);
1063    }
1064
1065    public void removeQueryFor(MethodDescriptor method)
1066    {
1067    queries.remove(method);
1068    }
1069
1070    public void setQueryFor(Method method, QueryDescriptor query)
1071    {
1072        // Use our own method equality check. This prevents problems
1073
// when a different classloader was used to load the input
1074
// method. Also note that two methods with the same name and
1075
// signature on *different* interfaces are considered EQUAL.
1076
// This matches the spec requirement that the same finder
1077
// method defined on the LocalHome and RemoteHome has only
1078
// ONE query-method declaration in the deployment descriptor.
1079
//
1080
MethodDescriptor md = new MethodDescriptor(method,"");
1081        setQueryFor(md, query);
1082    }
1083
1084    public QueryDescriptor getQueryFor(Method method)
1085    {
1086        // Use our own method equality check. See setQueryFor comment
1087
// for more details.
1088
MethodDescriptor md = new MethodDescriptor(method,"");
1089        return (QueryDescriptor) queries.get(md);
1090    }
1091    
1092    /**
1093     * Get all methods for which setQueryFor was done
1094     * @return a Set of Methods
1095     */

1096    public Set getQueriedMethods()
1097    {
1098    return queries.keySet();
1099    }
1100
1101    /**
1102     * Get all HomeIntf.find* and EJBClass.ejbSelect* methods
1103     * for which an EJB-QL query could possibly be set.
1104     * @return a Set of Methods
1105     */

1106    public Set getAllPossibleQueriedMethods()
1107    {
1108    if ( allQueriedMethods == null )
1109        initializeAllQueriedMethods();
1110
1111    return allQueriedMethods;
1112    }
1113
1114    private void initializeAllQueriedMethods()
1115    {
1116    allQueriedMethods = new HashSet();
1117
1118    // add all ejbSelect* methods in persistentClass
1119
Method[] beanMethods = getPersistentClass().getMethods();
1120    for ( int i=0; i<beanMethods.length; i++ ) {
1121        if ( beanMethods[i].getName().startsWith("ejbSelect") ) {
1122        allQueriedMethods.add(new MethodDescriptor(beanMethods[i], MethodDescriptor.EJB_BEAN));
1123        }
1124    }
1125
1126        // add all finders in Home/LocalHome intf, findByPrimaryKey too
1127
if ( parentDesc.isRemoteInterfacesSupported() ) {
1128        Class JavaDoc homeIntf = getClass(parentDesc.getHomeClassName());
1129    
1130        Method[] homeMethods = homeIntf.getMethods();
1131        for ( int i=0; i<homeMethods.length; i++ ) {
1132            String JavaDoc name = homeMethods[i].getName();
1133            if ( name.startsWith("find")
1134                && !name.equals("findByPrimaryKey") ) {
1135            allQueriedMethods.add(new MethodDescriptor(homeMethods[i], MethodDescriptor.EJB_HOME));
1136            }
1137        }
1138        }
1139        if ( parentDesc.isLocalInterfacesSupported() ) {
1140        Class JavaDoc homeIntf = getClass(parentDesc.getLocalHomeClassName());
1141    
1142        Method[] homeMethods = homeIntf.getMethods();
1143        for ( int i=0; i<homeMethods.length; i++ ) {
1144            String JavaDoc name = homeMethods[i].getName();
1145            if ( name.startsWith("find")
1146                && !name.equals("findByPrimaryKey") ) {
1147            allQueriedMethods.add(new MethodDescriptor(homeMethods[i], MethodDescriptor.EJB_LOCALHOME));
1148            }
1149        }
1150        }
1151    }
1152
1153    /**
1154    * Return my formatted string representation.
1155    */

1156    public void print(StringBuffer JavaDoc toStringBuffer) {
1157    super.print(toStringBuffer);
1158    toStringBuffer.append("\n Entity descriptor");
1159    toStringBuffer.append("\n cmpFields ").append(cmpFields);
1160    }
1161}
1162
Popular Tags