View Javadoc

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