View Javadoc

1   /*
2    * Copyright 2005 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at 
7    * 
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software 
11   * distributed under the License is distributed on an "AS IS" BASIS, 
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
13   * See the License for the specific language governing permissions and 
14   * limitations under the License.
15   */
16  
17  package org.apache.jdo.impl.model.jdo.caching;
18  
19  import org.apache.jdo.model.java.JavaType;
20  import org.apache.jdo.model.ModelException;
21  import org.apache.jdo.model.jdo.JDOClass;
22  import org.apache.jdo.model.jdo.JDOField;
23  import org.apache.jdo.model.jdo.JDOIdentityType;
24  import org.apache.jdo.model.jdo.JDOMember;
25  import org.apache.jdo.model.jdo.JDOProperty;
26  
27  import org.apache.jdo.impl.model.jdo.JDOClassImplDynamic;
28  
29  /***
30   * An instance of this class represents the JDO metadata of a persistence 
31   * capable class. This caching implementation caches any calulated
32   * value to avoid re-calculating it if it is requested again.
33   *
34   * @author Michael Bouschen
35   * @since 1.1
36   * @version 2.0
37   */
38  public class JDOClassImplCaching extends JDOClassImplDynamic
39  {
40  
41      /*** Flag indicating whether the objectIdClass is resolved already. */
42      private boolean objectIdClassResolved = false;
43  
44      /*** Flag indicating whether the pcSuperclass is resolved already. */
45      private boolean pcSuperclassResolved = false;
46  
47      /*** Array of declared managed fields, sorted by name (see JDO spec).  */
48      private JDOField[] declaredManagedFields;
49  
50      /*** 
51       * Array of managed fields, incluing inherited fields. The fields are 
52       * sorted by name (see JDO Spec) per class in the inheritance hierarchy.
53       */
54      private JDOField[] managedFields;
55  
56      /*** 
57       * Array of persistent fields, incluing inherited fields. The fields are 
58       * sorted by name (see JDO Spec) per class in the inheritance hierarchy.
59       */
60      private JDOField[] persistentFields;
61  
62      /*** Primary key fields. */
63      private JDOField[] primaryKeyFields;
64  
65      /*** Persistent relationship fields. */
66      private JDOField[] persistentRelationshipFields;
67      
68      /*** Default fetch group fields. */
69      private JDOField[] defaultFetchGroupFields;
70      
71      /*** Number of inherited fields. */
72      private int inheritedManagedFieldCount = -1;
73      
74      /*** Field numbers of managed fields. */
75      private int[] managedFieldNumbers;
76  
77      /*** Field numbers of PERSISTENT fields. */
78      private int[] persistentFieldNumbers;
79  
80      /*** Field numbers of primaryKey fields. */
81      private int[] primaryKeyFieldNumbers;
82  
83      /*** Field numbers of managed non primaryKey fields. */
84      private int[] nonPrimaryKeyFieldNumbers;
85  
86      /*** Field numbers of persistent non primaryKey fields. */
87      private int[] persistentNonPrimaryKeyFieldNumbers;
88  
89      /*** Field numbers of persistent relationship fields. */
90      private int[] persistentRelationshipFieldNumbers;
91  
92      /*** Field numbers of persistent, serializable fields. */
93      private int[] persistentSerializableFieldNumbers;
94  
95      /*** Flag indicating wthere field numbers are calculated already. */
96      private boolean fieldNumbersCalculated = false;
97  
98      /*** Constructor. */
99      protected JDOClassImplCaching(String name) {
100         super(name);
101     }
102 
103     /*** Constructor for inner classes. */
104     protected JDOClassImplCaching(String name, JDOClass declaringClass) {
105         super(name, declaringClass);
106     }
107 
108     /*** 
109      * Get the short name of this JDOClass. The short name defaults to the
110      * unqualified class name, if not explicitly set by method
111      * {@link #setShortName(String shortName)}.
112      * @return the short name of this JDOClass.
113      */
114     public String getShortName() {
115         if (shortName == null) {
116             shortName = super.getShortName();
117         }
118         return shortName;
119     }
120 
121     /*** 
122      * Get the JDO identity type of this JDOClass.
123      * The identity type of the least-derived persistence-capable class defines
124      * the identity type for all persistence-capable classes that extend it.
125      * The identity type of the least-derived persistence-capable class is
126      * defaulted to {@link JDOIdentityType#APPLICATION} if objectid-class is 
127      * specified, and {@link JDOIdentityType#DATASTORE}, if not. 
128      * @return the JDO identity type, one of 
129      * {@link JDOIdentityType#APPLICATION}, 
130      * {@link JDOIdentityType#DATASTORE}, or 
131      * {@link JDOIdentityType#NONDURABLE}
132      */
133     public int getIdentityType() {
134         if (identityType == JDOIdentityType.UNSPECIFIED) {
135             identityType = super.getIdentityType();
136         }
137         return identityType;
138     }
139 
140     /*** 
141      * Get the JavaType representation of the object identity class 
142      * (primary key class) for this JDOClass. 
143      * @return the JavaType representation of the object identity class.
144      */
145     public JavaType getObjectIdClass() {
146         if (!objectIdClassResolved) {
147             objectIdClassResolved = true;
148             objectIdClass = super.getObjectIdClass();
149         }
150         return objectIdClass;
151     }
152 
153     /***
154      * Returns the JDOClass instance for the persistence-capable superclass 
155      * of this JDOClass. If this class does not have a persistence-capable 
156      * superclass then <code>null</code> is returned.
157      * @return the JDClass instance of the persistence-capable superclass
158      * or <code>null</code> if there is no persistence-capable superclass 
159      */
160     public JDOClass getPersistenceCapableSuperclass() {
161         if(!pcSuperclassResolved) {
162             pcSuperclass = super.getPersistenceCapableSuperclass();
163         }
164         return pcSuperclass;
165     }
166 
167     /***
168      * Provides the JavaType representaion corresponding to this JDOClass.
169      * <p>
170      * Note the difference between Object.getClass() and this method. The
171      * former returns the class of the object in hand, this returns the class
172      * of the object represented by this meta data.
173      * @return the JavaType object corresponding to this JDOClass.
174      */
175     public JavaType getJavaType() {
176         if (javaType == null) {
177             javaType = super.getJavaType();
178         }
179         return javaType;
180     }
181 
182     /*** 
183      * Remove the supplied member from the collection of members maintained by
184      * this JDOClass.
185      * @param member the member to be removed
186      * @exception ModelException if impossible
187      */
188     public void removeDeclaredMember(JDOMember member) throws ModelException {
189         if ((member instanceof JDOField) && fieldNumbersCalculated) {
190             throw new ModelException(
191                 msg.msg("EXC_CannotRemoveJDOField")); //NOI18N
192         }
193 
194         // nullify JDOField arrays storing calculated field lists
195         declaredManagedFields = null;
196         managedFields = null;
197         persistentFields = null;
198         primaryKeyFields = null;
199         persistentRelationshipFields = null;
200         defaultFetchGroupFields = null;
201 
202         super.removeDeclaredMember(member);
203     }
204 
205     /***
206      * This method returns a JDOField instance for the field with the specified 
207      * name. If this JDOClass already declares such a field, the existing 
208      * JDOField instance is returned. Otherwise, it creates a new JDOField 
209      * instance, sets its declaringClass and returns the new instance.
210      * <P> 
211      * Note, if the field numbers for the managed fields of this JDOClass are 
212      * calculated, this methid will fail to create a new JDOField. Any new field
213      * would possibly invalidate existing field number 
214      * @param name the name of the field
215      * @exception ModelException if impossible
216      */
217     public JDOField createJDOField(String name) throws ModelException {
218         if ((getDeclaredField(name) == null) && fieldNumbersCalculated) {
219             throw new ModelException(
220                 msg.msg("EXC_CannotCreateJDOField")); //NOI18N
221         }
222         return super.createJDOField(name);
223     }
224 
225     /***
226      * Returns the collection of managed JDOField instances declared by this
227      * JDOClass in the form of an array. The returned array does not include 
228      * inherited fields. A field is a managed field, if it has the 
229      * persistence-modifier 
230      * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT} or 
231      * {@link org.apache.jdo.model.jdo.PersistenceModifier#TRANSACTIONAL}. 
232      * The position of the fields in the returned array equals their
233      * relative field number as returned by 
234      * {@link JDOField#getRelativeFieldNumber()}. The following holds
235      * true for any field in the returned array: 
236      * <ul>
237      * <li> <code>getDeclaredManagedFields()[i].getRelativeFieldNumber() 
238      * == i</code>
239      * <li> <code>getDeclaredManagedFields()[field.getRelativeFieldNumber()] 
240      * == field</code>
241      * </ul> 
242      * @return the managed fields declared by this JDOClass
243      */
244     public JDOField[] getDeclaredManagedFields() {
245         if (declaredManagedFields == null) {
246             declaredManagedFields = super.getDeclaredManagedFields();
247         }
248         return declaredManagedFields;
249     }
250             
251     /***
252      * Returns the collection of managed JDOField instances of this JDOClass 
253      * in the form of an array. The returned array includes inherited fields.
254      * A field is a managed field, if it has the persistence-modifier 
255      * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT} or 
256      * {@link org.apache.jdo.model.jdo.PersistenceModifier#TRANSACTIONAL}. 
257      * The position of the fields in the returned array equals their
258      * absolute field number as returned by 
259      * {@link JDOField#getFieldNumber()}. The following holds true for
260      * any field in the returned array: 
261      * <ul>
262      * <li> <code>getManagedFields()[i].getFieldNumber() == i</code>
263      * <li> <code>getManagedFields()[field.getFieldNumber()] == field</code>
264      * </ul> 
265      * @return the managed fields of this JDOClass
266      */
267     public JDOField[] getManagedFields() {
268         if (managedFields == null) {
269             managedFields = super.getManagedFields();
270         }
271         return managedFields;
272     }
273     
274     /***
275      * Returns the collection of persistent JDOField instances of this JDOClass 
276      * in the form of an array. The returned array includes inherited fields.
277      * A field is a persistent field, if it has the persistence-modifier 
278      * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT}.
279      * Please note, the position of the fields in the returned array might not 
280      * equal their absolute field number as returned by 
281      * {@link JDOField#getFieldNumber()}.
282      * @return the persistent fields of this JDOClass
283      */
284     public JDOField[] getPersistentFields() {
285         if (persistentFields == null) {
286             persistentFields = super.getPersistentFields();
287         }
288         return persistentFields;
289     }
290 
291     /***
292      * Returns the collection of identifying fields of this JDOClass in the form
293      * of an array. The method returns the JDOField instances defined as 
294      * primary key fields (see {@link JDOField#isPrimaryKey}).
295      * @return the identifying fields of this JDOClass
296      */
297     public JDOField[] getPrimaryKeyFields() {
298         if (primaryKeyFields == null) {
299             primaryKeyFields = super.getPrimaryKeyFields();
300         }
301         return primaryKeyFields;
302     }
303 
304     /***
305      * Returns the collection of persistent relationship fields of this JDOClass
306      * in the form of an array. The method returns the JDOField instances 
307      * defined as relationship (method {@link JDOField#getRelationship} returns
308      * a non null value) and having the persistence-modifier 
309      * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT}.
310      * @return the persistent relationship fields of this JDOClass
311      */
312     public JDOField[] getPersistentRelationshipFields() {
313         if (persistentRelationshipFields == null) {
314             persistentRelationshipFields = 
315                 super.getPersistentRelationshipFields();
316         }
317         return persistentRelationshipFields;
318     }
319 
320     /***
321      * Returns the collection of default fetch group fields of this JDOClass
322      * in the form of an array. The method returns the JDOField instances 
323      * defined as part of the default fetch group 
324      * (method {@link JDOField#isDefaultFetchGroup} returns <code>true</code>.
325      * @return the default fetch group fields of this JDOClass
326      * @since 1.1
327      */
328     public JDOField[] getDefaultFetchGroupFields() {
329         if (defaultFetchGroupFields == null) {
330             defaultFetchGroupFields = super.getDefaultFetchGroupFields();
331         }
332         return defaultFetchGroupFields;
333     }
334 
335     /***
336      * Returns an array of absolute field numbers of the managed fields of this
337      * JDOClass. The returned array includes field numbers of inherited fields.
338      * A field is a managed field, if it has the persistence-modifier 
339      * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT} or 
340      * {@link org.apache.jdo.model.jdo.PersistenceModifier#TRANSACTIONAL}. 
341      * Only managed fields have a valid field number, thus the field number in 
342      * the returned array equals its index:
343      * <br>
344      *  <code>getManagedFields()[i] == i</code>
345      */
346     public int[] getManagedFieldNumbers() {
347         if (managedFieldNumbers == null) {
348             managedFieldNumbers = super.getManagedFieldNumbers();
349         }
350         return managedFieldNumbers;
351     }
352 
353     /***
354      * Returns an array of absolute field numbers of the persistent fields of 
355      * this JDOClass. The returned array includes field numbers of inherited 
356      * fields. A persistent field has the persistence-modifier 
357      * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT}.
358      */
359     public int[] getPersistentFieldNumbers()
360     {
361         if (persistentFieldNumbers == null) {
362             persistentFieldNumbers = super.getPersistentFieldNumbers();
363         }
364         return persistentFieldNumbers;
365     }
366     
367     /***
368      * Returns an array of absolute field numbers of the identifying fields 
369      * of this JDOClass. A field number is included in the returned array, 
370      * iff the corresponding JDOField instance is defined as primary  key field
371      * (see {@link JDOField#isPrimaryKey}).
372      * @return array of numbers of the identifying fields
373      */
374     public int[] getPrimaryKeyFieldNumbers() {
375         if (primaryKeyFieldNumbers == null) {
376             primaryKeyFieldNumbers = super.getPrimaryKeyFieldNumbers();
377         }
378         return primaryKeyFieldNumbers;
379     }
380 
381     /***
382      * Returns an array of absolute field numbers of the non identifying, 
383      * persistent fields of this JDOClass. A field number is included in the 
384      * returned array, iff the corresponding JDOField instance is persistent and 
385      * not a not a primary key field (see {@link JDOField#isPrimaryKey}).
386      * A field is a persistent field, if it has the persistence-modifier 
387      * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT} or 
388      * (see {@link JDOField#getPersistenceModifier}). 
389      * @return array of numbers of the non identifying, persistent fields
390      */
391     public int[] getPersistentNonPrimaryKeyFieldNumbers() {
392         if (persistentNonPrimaryKeyFieldNumbers == null) {
393             persistentNonPrimaryKeyFieldNumbers = 
394                 super.getPersistentNonPrimaryKeyFieldNumbers();
395         }
396         return persistentNonPrimaryKeyFieldNumbers;
397     }
398     
399     /***
400      * Returns an array of absolute field numbers of persistent relationship 
401      * fields of this JDOClass. A field number is included in the returned 
402      * array, iff the corresponding JDOField instance is a relationship (method 
403      * {@link JDOField#getRelationship} returns a non null value) and has the 
404      * persistence-modifier 
405      * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT}.
406      * @return the field numbers of the persistent relationship fields
407      */
408     public int[] getPersistentRelationshipFieldNumbers() {
409         if (persistentRelationshipFieldNumbers == null) {
410             persistentRelationshipFieldNumbers = 
411                 super.getPersistentRelationshipFieldNumbers();
412         }
413         return persistentRelationshipFieldNumbers;
414     }
415 
416     /***
417      * Returns an array of absolute field numbers of persistent, serializable 
418      * fields of this JDOClass. A field number is included in the returned 
419      * array, iff the corresponding JDOField instance is serializable (method 
420      * {@link JDOField#isSerializable} returns <code>true</code>) and has the 
421      * persistence-modifier 
422      * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT}.
423      * @return the field numbers of serializable fields
424      */
425     public int[] getPersistentSerializableFieldNumbers() {
426         if (persistentSerializableFieldNumbers == null) {
427             persistentSerializableFieldNumbers = 
428                 super.getPersistentSerializableFieldNumbers();
429         }
430         return persistentSerializableFieldNumbers;
431     }
432 
433     /***
434      * Returns the number of inherited managed fields for this class.  
435      * @return number of inherited fields
436      */
437     public synchronized int getInheritedManagedFieldCount() {
438         // inheritedManagedFieldCount < 0 indicates check is not done yet.
439         if (inheritedManagedFieldCount < 0) {
440             inheritedManagedFieldCount = super.getInheritedManagedFieldCount();
441         }
442         return inheritedManagedFieldCount;
443     }    
444 
445     //========= Internal helper methods ==========
446 
447     /***
448      * This method calculates the relative field number of the
449      * declared managed fields of this JDOClass and uddates the
450      * relativeFieldNumber property of the JDOField instance.
451      */
452     protected void calculateFieldNumbers() {
453         if (!fieldNumbersCalculated) {
454             fieldNumbersCalculated = true;
455             JDOField[] fields = getDeclaredManagedFields();
456             // now set the relativeFieldNumber of the JDOField
457             for (int i = 0; i < fields.length; i++) {
458                 ((JDOFieldImplCaching)fields[i]).setRelativeFieldNumber(i);
459             }
460         }
461     }
462 
463     /***
464      * Returns a new instance of the JDOClass implementation class.
465      */
466     protected JDOClass newJDOClassInstance(String name) {
467         return new JDOClassImplCaching(name, this);
468     }
469 
470     /***
471      * Returns a new instance of the JDOField implementation class.
472      */
473     protected JDOField newJDOFieldInstance(String name) {
474         return new JDOFieldImplCaching(name, this);
475     }
476 
477     /***
478      * Returns a new instance of the JDOProperty implementation class.
479      */
480     protected JDOProperty newJDOPropertyInstance(String name) {
481         return new JDOPropertyImplCaching(name, this);
482     }
483 
484     /***
485      * Returns a new instance of the JDOProperty implementation class.
486      */
487     protected JDOProperty newJDOPropertyInstance(
488         String name, JDOField associatedJDOField) throws ModelException {
489         return new JDOAssociatedPropertyImplCaching(
490             name, this, associatedJDOField);
491     }
492 }