1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.jdo.impl.model.jdo;
19
20 import java.util.*;
21 import java.lang.reflect.Modifier;
22
23 import org.apache.jdo.impl.model.jdo.util.TypeSupport;
24 import org.apache.jdo.model.ModelException;
25 import org.apache.jdo.model.ModelFatalException;
26 import org.apache.jdo.model.java.JavaModel;
27 import org.apache.jdo.model.java.JavaType;
28 import org.apache.jdo.model.jdo.JDOClass;
29 import org.apache.jdo.model.jdo.JDOField;
30 import org.apache.jdo.model.jdo.JDOIdentityType;
31 import org.apache.jdo.model.jdo.JDOMember;
32 import org.apache.jdo.model.jdo.JDOModel;
33 import org.apache.jdo.model.jdo.JDOPackage;
34 import org.apache.jdo.model.jdo.JDOProperty;
35
36 import org.apache.jdo.util.I18NHelper;
37 import org.apache.jdo.util.StringHelper;
38
39 /***
40 * An instance of this class represents the JDO metadata of a persistence
41 * capable class. This dynamic implementation only stores property
42 * values explicitly set by setter method. It does not store any
43 * calculated values such as list of managed or persistent fields,
44 * list of field numbers etc.
45 * <p>
46 * TBD:
47 * <ul>
48 * <li> Property change support
49 * </ul>
50 *
51 * @author Michael Bouschen
52 * @since 1.1
53 * @version 2.0
54 */
55 public class JDOClassImplDynamic
56 extends JDOMemberImpl
57 implements JDOClass
58 {
59 /*** Property shortName. It defaults to the unqualified class name. */
60 protected String shortName;
61
62 /*** Property identityType. Default see {@link #getIdentityType}. */
63 protected int identityType = JDOIdentityType.UNSPECIFIED;
64
65 /*** Property objectIdClass. No default. */
66 protected transient JavaType objectIdClass;
67
68 /*** Property declaredObjectIdClassName. No default. */
69 private String declaredObjectIdClassName;
70
71 /*** Property requiresExtent. It defaults to <code>true</code>. */
72 private boolean requiresExtent = true;
73
74 /*** Property pcSuperclassName. No default. */
75 private String pcSuperclassName;
76
77 /*** Relationship JDOClass<->JDOClass. */
78 protected JDOClass pcSuperclass;
79
80 /*** Property javaType. No default.*/
81 protected transient JavaType javaType;
82
83 /*** Relationship JDOModel<->JDOClass. Initialized during creation.*/
84 private JDOModel declaringModel;
85
86 /***
87 * Relationship JDOClass<->JDOMember.
88 * Map of fields declared by this JDOClass. Key is the unqualified
89 * field name, value is the JDOField instance.
90 */
91 private Map declaredFields = new HashMap();
92
93 /***
94 * Map of properties having associated JDOField instances. Key is the
95 * unqualified field name, value is the JDOField instance.
96 */
97 private Map associatedProperties = new HashMap();
98
99 /***
100 * Relationship JDOClass<->JDOMember.
101 * Map of inner classes declared by this JDOClass.
102 * Key is the unqualified name of the inner class,
103 * value is the JDOClass instance of the inner class.
104 */
105 private Map declaredClasses = new HashMap();
106
107 /*** Relationship JDOClass -> JDOPackage. */
108 private JDOPackage jdoPackage;
109
110 /*** Flag indicating whether XML metadata is processed already. */
111 private boolean xmlMetadataLoaded = false;
112
113 /*** I18N support */
114 protected final static I18NHelper msg =
115 I18NHelper.getInstance(JDOClassImplDynamic.class);
116
117 /*** Constructor. */
118 protected JDOClassImplDynamic(String name) {
119 super(name, null);
120 }
121
122 /*** Constructor for inner classes. */
123 protected JDOClassImplDynamic(String name, JDOClass declaringClass) {
124 super(name, declaringClass);
125 }
126
127 /***
128 * Get the short name of this JDOClass. The short name defaults to the
129 * unqualified class name, if not explicitly set by method
130 * {@link #setShortName(String shortName)}.
131 * @return the short name of this JDOClass.
132 */
133 public String getShortName() {
134 if (shortName != null)
135
136 return shortName;
137
138 return StringHelper.getShortClassName(getName());
139 }
140
141 /***
142 * Set the short name of this JDOClass.
143 * @param shortName the short name.
144 */
145 public void setShortName(String shortName) {
146 this.shortName = shortName;
147 }
148
149 /***
150 * Get the JDO identity type of this JDOClass.
151 * The identity type of the least-derived persistence-capable class defines
152 * the identity type for all persistence-capable classes that extend it.
153 * The identity type of the least-derived persistence-capable class is
154 * defaulted to {@link JDOIdentityType#APPLICATION} if objectid-class is
155 * specified, and {@link JDOIdentityType#DATASTORE}, if not.
156 * @return the JDO identity type, one of
157 * {@link JDOIdentityType#APPLICATION},
158 * {@link JDOIdentityType#DATASTORE}, or
159 * {@link JDOIdentityType#NONDURABLE}
160 */
161 public int getIdentityType() {
162 if (identityType != JDOIdentityType.UNSPECIFIED) {
163
164 return identityType;
165 }
166
167
168 JDOClass pcRoot = getPersistenceCapableRootClass();
169 int result = 0;
170 if (pcRoot == this) {
171
172 result = (pcRoot.getDeclaredObjectIdClassName() != null) ?
173 JDOIdentityType.APPLICATION : JDOIdentityType.DATASTORE;
174 }
175 else {
176
177 result = pcRoot.getIdentityType();
178 }
179
180 return result;
181 }
182
183 /***
184 * Set the object identity type of this JDOClass.
185 * @param identityType an integer indicating the JDO identity type, one of:
186 * {@link JDOIdentityType#APPLICATION},
187 * {@link JDOIdentityType#DATASTORE}, or
188 * {@link JDOIdentityType#NONDURABLE}
189 */
190 public void setIdentityType(int identityType) {
191 this.identityType = identityType;
192 }
193
194 /***
195 * Get the JavaType representation of the object identity class
196 * (primary key class) for this JDOClass.
197 * @return the JavaType representation of the object identity class.
198 */
199 public JavaType getObjectIdClass() {
200 if (objectIdClass != null) {
201
202 return objectIdClass;
203 }
204
205
206 JavaType type = null;
207 String name = getDeclaredObjectIdClassName();
208 if (name != null) {
209 JavaModel javaModel = getDeclaringModel().getJavaModel();
210 type = javaModel.getJavaType(name);
211 if (Modifier.isAbstract(type.getModifiers()))
212
213 type = null;
214 }
215 else {
216 JDOClass superclass = getPersistenceCapableSuperclass();
217 if (superclass != null) {
218 type = superclass.getObjectIdClass();
219 }
220 }
221 return type;
222 }
223
224 /***
225 * Set the JavaType representation of the object identity class
226 * (primary key class) for this JDOClass.
227 * @param objectIdClass the JavaType representation of the
228 * object identity class
229 */
230 public void setObjectIdClass(JavaType objectIdClass) {
231 this.objectIdClass = objectIdClass;
232 }
233
234 /***
235 * Get the fully qualified name of the object identity class
236 * (primary key class) for this JDOClass.
237 * @return the name of the object identity class.
238 */
239 public String getDeclaredObjectIdClassName() {
240 if (declaredObjectIdClassName != null) {
241
242 int index = declaredObjectIdClassName.indexOf('.');
243 if (index == -1) {
244
245 JavaType type = TypeSupport.resolveType(getDeclaringModel(),
246 declaredObjectIdClassName, getPackagePrefix());
247 if (type == null) {
248 throw new ModelFatalException(
249 msg.msg("EXC_CannotResolveObjectIdClass",
250 declaredObjectIdClassName, getName()));
251 }
252 this.declaredObjectIdClassName = type.getName();
253 }
254 }
255 else {
256
257 JDOField[] declaredPKFields = getDeclaredPrimaryKeyFields();
258 if ((declaredPKFields != null) && (declaredPKFields.length == 1)) {
259
260
261 JavaType fieldType = declaredPKFields[0].getType();
262 if (fieldType != null) {
263 return TypeSupport.getSingleFieldObjectIdClassName(
264 fieldType.getName());
265 }
266 }
267 }
268 return declaredObjectIdClassName;
269 }
270
271 /***
272 * Set the fully qualified name of the object identity class
273 * (primary key class) for this JDOClass.
274 * @param declaredObjectIdClassName the name of the object identity class
275 */
276 public void setDeclaredObjectIdClassName(String declaredObjectIdClassName) {
277 this.declaredObjectIdClassName = declaredObjectIdClassName;
278 }
279
280 /***
281 * Determines whether an extent must be managed for the
282 * persistence-capable class described by this JDOClass.
283 * @return <code>true</code> if this class must manage an extent;
284 * <code>false</code> otherwise
285 */
286 public boolean requiresExtent() {
287 return requiresExtent;
288 }
289
290 /***
291 * Set whether an extent must be managed for the
292 * persistence-capable class described by this JDOClass.
293 * @param requiresExtent <code>true</code> if this class must manage
294 * an extent; <code>false</code> otherwise
295 */
296 public void setRequiresExtent(boolean requiresExtent) {
297 this.requiresExtent = requiresExtent;
298 }
299
300 /***
301 * Get the fully qualified class name of the persistence-capable superclass
302 * of the persistence-capable class described by this JDOClass. If this
303 * class does not have a persistence-capable superclass then
304 * <code>null</code> is returned.
305 * @return the fully qualified name of the persistence-capable superclass
306 * or <code>null</code> if there is no persistence-capable superclass
307 */
308 public String getPersistenceCapableSuperclassName() {
309 if (pcSuperclassName != null) {
310
311 int index = pcSuperclassName.indexOf('.');
312 if (index == -1) {
313
314 JavaType type = TypeSupport.resolveType(getDeclaringModel(),
315 pcSuperclassName, getPackagePrefix());
316 if (type == null) {
317 throw new ModelFatalException(
318 msg.msg("EXC_CannotResolvePCSuperClass",
319 pcSuperclassName, getName()));
320 }
321 this.pcSuperclassName = type.getName();
322 }
323 }
324 return pcSuperclassName;
325 }
326
327 /***
328 * Set the fully qualified class name of the persistence-capable superclass
329 * of the persistence-capable class described by this JDOClass.
330 * @param pcSuperclassName the fully qualified name of the
331 * persistence-capable superclass
332 */
333 public void setPersistenceCapableSuperclassName(String pcSuperclassName) {
334 this.pcSuperclassName = pcSuperclassName;
335 }
336
337 /***
338 * Provides the JavaType representaion corresponding to this JDOClass.
339 * <p>
340 * Note the difference between Object.getClass() and this method. The
341 * former returns the class of the object in hand, this returns the class
342 * of the object represented by this meta data.
343 * @return the JavaType object corresponding to this JDOClass.
344 */
345 public JavaType getJavaType() {
346 if (javaType != null) {
347
348 return javaType;
349 }
350
351
352 JavaModel javaModel = declaringModel.getJavaModel();
353 return javaModel.getJavaType(getName());
354 }
355
356 /***
357 * Set the JavaType representation corresponding to this JDOClass.
358 * @param javaType the JavaType representation for this JDOClass
359 */
360 public void setJavaType(JavaType javaType) {
361 this.javaType = javaType;
362 }
363
364 /***
365 * Determines whether the XML metadata for the class represented by this
366 * JDOClass has been loaded.
367 * @return <code>true</code> if XML metadata is loaded;
368 * <code>false</code> otherwise
369 */
370 public boolean isXMLMetadataLoaded() {
371 return xmlMetadataLoaded;
372 }
373
374 /***
375 * Sets the flag indicating that the class XML metadata for this
376 * JDOClass is loaded to <code>true</code>.
377 */
378 public void setXMLMetadataLoaded() {
379 this.xmlMetadataLoaded = true;
380 }
381
382 /***
383 * Remove the supplied member from the collection of members maintained by
384 * this JDOClass.
385 * @param member the member to be removed
386 * @exception ModelException if impossible
387 */
388 public void removeDeclaredMember(JDOMember member) throws ModelException {
389 if (member == null) {
390 throw new ModelException(
391 msg.msg("EXC_InvalidMember", "null"));
392 }
393 String name = member.getName();
394 if (member instanceof JDOField) {
395 JDOField field = (JDOField) member;
396
397 field.setMappedByName(null);
398
399 field.setRelationship(null);
400 if (associatedProperties.containsValue(member)) {
401 associatedProperties.remove(name);
402 }
403 else {
404 declaredFields.remove(name);
405 }
406
407
408
409 JDOProperty prop = getAssociatedProperty(field);
410 if (prop != null) {
411 removeDeclaredMember(prop);
412 }
413 }
414 else if (member instanceof JDOClass) {
415
416 declaredClasses.remove(name);
417 }
418 else {
419 throw new ModelException(
420 msg.msg("EXC_InvalidMember", name));
421 }
422 }
423
424 /***
425 * Returns the collection of JDOMember instances declared by this
426 * JDOClass in form of an array.
427 * @return the members declared by this JDOClass
428 */
429 public JDOMember[] getDeclaredMembers() {
430 List copy = new ArrayList(declaredFields.values());
431 copy.addAll(declaredClasses.values());
432 return (JDOMember[])copy.toArray(new JDOMember[copy.size()]);
433 }
434
435 /***
436 * Returns the declaring JDOModel of this JDOClass.
437 * @return the JDOModel that owns this JDOClass
438 */
439 public JDOModel getDeclaringModel() {
440 return declaringModel;
441 }
442
443 /***
444 * Set the declaring JDOModel for this JDOClass.
445 * @param model the declaring JDOModel of this JDOClass
446 */
447 public void setDeclaringModel(JDOModel model) {
448 this.declaringModel = model;
449 }
450
451 /***
452 * Returns the JDOClass instance for the persistence-capable superclass
453 * of this JDOClass. If this class does not have a persistence-capable
454 * superclass then <code>null</code> is returned.
455 * @return the JDClass instance of the persistence-capable superclass
456 * or <code>null</code> if there is no persistence-capable superclass
457 */
458 public JDOClass getPersistenceCapableSuperclass() {
459 if (pcSuperclass != null) {
460
461 return pcSuperclass;
462
463 }
464
465
466 String name = getPersistenceCapableSuperclassName();
467 if (pcSuperclassName != null) {
468 JavaType type = TypeSupport.resolveType(
469 getDeclaringModel(), pcSuperclassName, getPackagePrefix());
470 if (type == null) {
471 throw new ModelFatalException(
472 msg.msg("EXC_CannotResolvePCSuperClass",
473 pcSuperclassName, getName()));
474 }
475 JDOClass jdoClass = type.getJDOClass();
476
477 this.pcSuperclassName = type.getName();
478 return jdoClass;
479 }
480
481 return null;
482 }
483
484 /***
485 * Set the JDOClass for the persistence-capable superclass
486 * of this JDOClass.
487 * @param pcSuperclass the JDClass instance of the persistence-capable
488 * superclass
489 */
490 public void setPersistenceCapableSuperclass(JDOClass pcSuperclass) {
491 this.pcSuperclass = pcSuperclass;
492 this.pcSuperclassName =
493 pcSuperclass != null ? pcSuperclass.getName() : null;
494 }
495
496 /***
497 * Returns the JDOPackage instance corresponding to the package name
498 * of this JDOClass.
499 * @return the JDOPackage instance of this JDOClass.
500 */
501 public JDOPackage getJDOPackage() {
502 return jdoPackage;
503 }
504
505 /***
506 * Sets the JDOPackage instance corresponding to the package name
507 * of this JDOClass.
508 * @param jdoPackage the JDOPackage of this JDOClass.
509 */
510 public void setJDOPackage(JDOPackage jdoPackage) {
511 this.jdoPackage = jdoPackage;
512 }
513
514 /***
515 * This method returns a JDOField instance for the field with the specified
516 * name. If this JDOClass already declares such a field, the existing
517 * JDOField instance is returned. Otherwise, it creates a new JDOField
518 * instance, sets its declaring JDOClass and returns the new instance.
519 * <P>
520 * Note, if the field numbers for the managed fields of this JDOClass are
521 * calculated, this methid will fail to create a new JDOField. Any new field
522 * would possibly invalidate existing field number
523 * @param name the name of the field
524 * @exception ModelException if impossible
525 */
526 public JDOField createJDOField(String name) throws ModelException {
527
528 JDOField field = getDeclaredField(name);
529 if (field == null) {
530 field = newJDOFieldInstance(name);
531 declaredFields.put(name, field);
532 }
533 else if (field instanceof JDOProperty) {
534 throw new ModelException(
535 msg.msg("EXC_ExistingJDOProperty", name));
536 }
537 return field;
538 }
539
540 /***
541 * This method returns a JDOProperty instance for the property with the
542 * specified name. If this JDOClass already declares such a property, the
543 * existing JDOProperty instance is returned. Otherwise, it creates a new
544 * JDOProperty instance, sets its declaring JDOClass and returns the new
545 * instance.
546 * @param name the name of the property
547 * @return a JDOProperty instance for the specified property
548 * @exception ModelException if impossible
549 */
550 public JDOProperty createJDOProperty(String name) throws ModelException {
551
552 JDOProperty property = null;
553 JDOField field = getDeclaredField(name);
554 if (field == null) {
555 property = newJDOPropertyInstance(name);
556 declaredFields.put(name, property);
557 }
558 else if (field instanceof JDOProperty) {
559 property = (JDOProperty) field;
560 }
561 else {
562 throw new ModelException(
563 msg.msg("EXC_ExistingJDOField", name));
564 }
565 return property;
566 }
567
568 /***
569 * This method returns a JDOProperty instance for the property with the
570 * specified name and associated field. If this JDOClass already declares
571 * such a property the existing JDOProperty instance is returned. If it
572 * declares a property with the specified name but different associated
573 * field, then a ModelException is thrown. If there is no such property,
574 * the method creates a new JDOProperty instance, sets its declaring
575 * JDOClass and associated field and returns the new instance.
576 * @param name the name of the property
577 * @param associatedField the associated JDOField
578 * @return a JDOProperty instance for the specified property
579 * @exception ModelException if impossible
580 */
581 public JDOProperty createJDOProperty(String name,
582 JDOField associatedJDOField)
583 throws ModelException
584 {
585 JDOProperty property = (JDOProperty) associatedProperties.get(name);
586 if (property == null) {
587 property = newJDOPropertyInstance(name, associatedJDOField);
588 associatedProperties.put(name, property);
589 }
590 else {
591 if (property.getAssociatedJDOField() != associatedJDOField) {
592 throw new ModelException(
593 msg.msg("EXC_ExistingJDOAssociatedProperty",
594 name, associatedJDOField));
595 }
596 }
597 return property;
598 }
599
600 /***
601 * This method returns a JDOClass instance representing an inner class of
602 * this JDOClass If this JDOClass already declares such an inner class,
603 * the existing JDOClass instance is returned. Otherwise, it creates a new
604 * JDOClass instance, sets its declaring JDOClass and returns the new
605 * instance.
606 * @param name the name of the inner class
607 * @exception ModelException if impossible
608 */
609 public JDOClass createJDOClass(String name) throws ModelException {
610 JDOClass innerClass = (JDOClass)declaredClasses.get(name);
611 if (innerClass == null) {
612 innerClass = newJDOClassInstance(name);
613 declaredClasses.put(name, innerClass);
614 }
615 return innerClass;
616 }
617
618 /***
619 * Returns the collection of JDOClass instances declared by this JDOClass.
620 * @return the classes declared by this JDOClass
621 */
622 public JDOClass[] getDeclaredClasses() {
623 return (JDOClass[])declaredClasses.values().toArray(
624 new JDOClass[declaredClasses.size()]);
625 }
626
627 /***
628 * Returns the collection of JDOField instances declared by this JDOClass
629 * in the form of an array. This does not include inherited fields.
630 * @return the fields declared by this JDOClass
631 */
632 public JDOField[] getDeclaredFields() {
633 Collection tmp = declaredFields.values();
634 return (JDOField[])tmp.toArray(new JDOField[tmp.size()]);
635 }
636
637 /***
638 * Returns the collection of managed JDOField instances declared by this
639 * JDOClass in the form of an array. The returned array does not include
640 * inherited fields. A field is a managed field, if it has the
641 * persistence-modifier
642 * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT} or
643 * {@link org.apache.jdo.model.jdo.PersistenceModifier#TRANSACTIONAL}.
644 * The position of the fields in the returned array equals their
645 * relative field number as returned by
646 * {@link JDOField#getRelativeFieldNumber()}. The following holds
647 * true for any field in the returned array:
648 * <ul>
649 * <li> <code>getDeclaredManagedFields()[i].getRelativeFieldNumber()
650 * == i</code>
651 * <li> <code>getDeclaredManagedFields()[field.getRelativeFieldNumber()]
652 * == field</code>
653 * </ul>
654 * @return the managed fields declared by this JDOClass
655 */
656 public JDOField[] getDeclaredManagedFields() {
657
658
659 List fieldList = new ArrayList();
660 for (Iterator i = declaredFields.values().iterator(); i.hasNext();) {
661 JDOField field = (JDOField)i.next();
662 if (field.isManaged())
663 fieldList.add(field);
664 }
665
666
667
668 Collections.sort(fieldList);
669 JDOField[] fields = new JDOField[fieldList.size()];
670 fieldList.toArray(fields);
671 return fields;
672 }
673
674 /***
675 * Returns the collection of managed JDOField instances of this JDOClass
676 * in the form of an array. The returned array includes inherited fields.
677 * A field is a managed field, if it has the persistence-modifier
678 * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT} or
679 * {@link org.apache.jdo.model.jdo.PersistenceModifier#TRANSACTIONAL}.
680 * The position of the fields in the returned array equals their
681 * absolute field number as returned by
682 * {@link JDOField#getFieldNumber()}. The following holds true for
683 * any field in the returned array:
684 * <ul>
685 * <li> <code>getManagedFields()[i].getFieldNumber() == i</code>
686 * <li> <code>getManagedFields()[field.getFieldNumber()] == field</code>
687 * </ul>
688 * @return the managed fields of this JDOClass
689 */
690 public JDOField[] getManagedFields() {
691 JDOField[] fields = null;
692 JDOField[] declared = getDeclaredManagedFields();
693 JDOClass superclass = getPersistenceCapableSuperclass();
694 if (superclass == null) {
695
696 fields = declared;
697 }
698 else {
699
700 JDOField[] inherited = superclass.getManagedFields();
701 fields = new JDOField[inherited.length+declared.length];
702 System.arraycopy(inherited, 0, fields, 0, inherited.length);
703 System.arraycopy(declared, 0, fields,
704 inherited.length, declared.length);
705 }
706
707 return fields;
708 }
709
710 /***
711 * Returns the collection of persistent JDOField instances of this JDOClass
712 * in the form of an array. The returned array includes inherited fields.
713 * A field is a persistent field, if it has the persistence-modifier
714 * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT}.
715 * Please note, the position of the fields in the returned array might not
716 * equal their absolute field number as returned by
717 * {@link JDOField#getFieldNumber()}.
718 * @return the persistent fields of this JDOClass
719 */
720 public JDOField[] getPersistentFields() {
721 JDOField[] fields = getManagedFields();
722 JDOField[] tmp = new JDOField[fields.length];
723 int length = 0;
724 for (int i = 0; i < fields.length; i++) {
725 JDOField field = fields[i];
726 if (field.isPersistent()) {
727 tmp[length++] = field;
728 }
729 }
730
731
732 JDOField[] result = new JDOField[length];
733 System.arraycopy(tmp, 0, result, 0, length);
734
735 return result;
736 }
737
738 /***
739 * Returns the collection of identifying fields of this JDOClass in the form
740 * of an array. The method returns the JDOField instances defined as
741 * primary key fields (see {@link JDOField#isPrimaryKey}).
742 * @return the identifying fields of this JDOClass
743 */
744 public JDOField[] getPrimaryKeyFields() {
745 JDOField[] fields = getManagedFields();
746 JDOField[] tmp = new JDOField[fields.length];
747 int length = 0;
748 for (int i = 0; i < fields.length; i++) {
749 JDOField field = fields[i];
750 if (fields[i].isPrimaryKey()) {
751 tmp[length++] = field;
752 }
753 }
754
755
756 JDOField[] result = new JDOField[length];
757 System.arraycopy(tmp, 0, result, 0, length);
758
759 return result;
760 }
761
762 /***
763 * Returns the collection of persistent relationship fields of this JDOClass
764 * in the form of an array. The method returns the JDOField instances
765 * defined as relationship (method {@link JDOField#getRelationship} returns
766 * a non null value) and having the persistence-modifier
767 * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT}.
768 * @return the persistent relationship fields of this JDOClass
769 */
770 public JDOField[] getPersistentRelationshipFields() {
771 JDOField[] fields = getPersistentFields();
772 JDOField[] tmp = new JDOField[fields.length];
773 int length = 0;
774 for (int i = 0; i < fields.length; i++) {
775 JDOField field = fields[i];
776 if (field.isPersistent() && field.isRelationship()) {
777 tmp[length++] = field;
778 }
779 }
780
781
782 JDOField[] result = new JDOField[length];
783 System.arraycopy(tmp, 0, result, 0, length);
784
785 return result;
786 }
787
788 /***
789 * Returns the collection of default fetch group fields of this JDOClass
790 * in the form of an array. The method returns the JDOField instances
791 * defined as part of the default fetch group
792 * (method {@link JDOField#isDefaultFetchGroup} returns <code>true</code>.
793 * @return the default fetch group fields of this JDOClass
794 * @since 1.1
795 */
796 public JDOField[] getDefaultFetchGroupFields() {
797 JDOField[] fields = getManagedFields();
798 JDOField[] tmp = new JDOField[fields.length];
799 int length = 0;
800 for (int i = 0; i < fields.length; i++) {
801 JDOField field = fields[i];
802 if (field.isDefaultFetchGroup()) {
803 tmp[length++] = field;
804 }
805 }
806
807
808 JDOField[] result = new JDOField[length];
809 System.arraycopy(tmp, 0, result, 0, length);
810
811 return result;
812 }
813
814 /***
815 * Returns an array of absolute field numbers of the managed fields of this
816 * JDOClass. The returned array includes field numbers of inherited fields.
817 * A field is a managed field, if it has the persistence-modifier
818 * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT} or
819 * {@link org.apache.jdo.model.jdo.PersistenceModifier#TRANSACTIONAL}.
820 * Only managed fields have a valid field number, thus the field number in
821 * the returned array equals its index:
822 * <br>
823 * <code>getManagedFields()[i] == i</code>
824 */
825 public int[] getManagedFieldNumbers() {
826 JDOField[] fields = getManagedFields();
827 int[] fieldNumbers = new int[fields.length];
828 for (int i = 0; i < fields.length; i++) {
829 fieldNumbers[i] = i;
830 }
831
832 return fieldNumbers;
833 }
834
835 /***
836 * Returns an array of absolute field numbers of the persistent fields of
837 * this JDOClass. The returned array includes field numbers of inherited
838 * fields. A persistent field has the persistence-modifier
839 * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT}.
840 */
841 public int[] getPersistentFieldNumbers() {
842 JDOField[] fields = getManagedFields();
843 int[] tmp = new int[fields.length];
844 int length = 0;
845 for (int i = 0; i < fields.length; i++) {
846 JDOField field = fields[i];
847 if (field.isPersistent()) {
848 tmp[length++] = i;
849 }
850 }
851
852 int[] fieldNumbers = new int[length];
853 System.arraycopy(tmp, 0, fieldNumbers, 0, length);
854
855 return fieldNumbers;
856 }
857
858 /***
859 * Returns an array of absolute field numbers of the identifying fields
860 * of this JDOClass. A field number is included in the returned array,
861 * iff the corresponding JDOField instance is defined as primary key field
862 * (see {@link JDOField#isPrimaryKey}).
863 * @return array of numbers of the identifying fields
864 */
865 public int[] getPrimaryKeyFieldNumbers() {
866 JDOField[] fields = getManagedFields();
867 int[] tmp = new int[fields.length];
868 int length = 0;
869 for (int i = 0; i < fields.length; i++) {
870 JDOField field = fields[i];
871 if (field.isPrimaryKey()) {
872 tmp[length++] = i;
873 }
874 }
875
876 int[] fieldNumbers = new int[length];
877 System.arraycopy(tmp, 0, fieldNumbers, 0, length);
878
879 return fieldNumbers;
880 }
881
882 /***
883 * Returns an array of absolute field numbers of the non identifying,
884 * persistent fields of this JDOClass. A field number is included in the
885 * returned array, iff the corresponding JDOField instance is persistent and
886 * not a not a primary key field (see {@link JDOField#isPrimaryKey}).
887 * A field is a persistent field, if it has the persistence-modifier
888 * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT} or
889 * (see {@link JDOField#getPersistenceModifier}).
890 * @return array of numbers of the non identifying, persistent fields
891 */
892 public int[] getPersistentNonPrimaryKeyFieldNumbers() {
893 JDOField[] fields = getManagedFields();
894 int[] tmp = new int[fields.length];
895 int length = 0;
896 for (int i = 0; i < fields.length; i++) {
897 JDOField field = fields[i];
898 if (field.isPersistent() && !field.isPrimaryKey()) {
899 tmp[length++] = i;
900 }
901 }
902
903 int[] fieldNumbers = new int[length];
904 System.arraycopy(tmp, 0, fieldNumbers, 0, length);
905
906 return fieldNumbers;
907 }
908
909 /***
910 * Returns an array of absolute field numbers of persistent relationship
911 * fields of this JDOClass. A field number is included in the returned
912 * array, iff the corresponding JDOField instance is a relationship (method
913 * {@link JDOField#getRelationship} returns a non null value) and has the
914 * persistence-modifier
915 * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT}.
916 * @return the field numbers of the persistent relationship fields
917 */
918 public int[] getPersistentRelationshipFieldNumbers() {
919 JDOField[] fields = getManagedFields();
920 int[] tmp = new int[fields.length];
921 int length = 0;
922 for (int i = 0; i < fields.length; i++) {
923 JDOField field = fields[i];
924 if (field.isPersistent() && field.isRelationship()) {
925 tmp[length++] = i;
926 }
927 }
928
929 int[] fieldNumbers = new int[length];
930 System.arraycopy(tmp, 0, fieldNumbers, 0, length);
931
932 return fieldNumbers;
933 }
934
935 /***
936 * Returns an array of absolute field numbers of persistent, serializable
937 * fields of this JDOClass. A field number is included in the returned
938 * array, iff the corresponding JDOField instance is serializable (method
939 * {@link JDOField#isSerializable} returns <code>true</code>) and has the
940 * persistence-modifier
941 * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT}.
942 * @return the field numbers of serializable fields
943 */
944 public int[] getPersistentSerializableFieldNumbers() {
945 JDOField[] fields = getManagedFields();
946 int[] tmp = new int[fields.length];
947 int length = 0;
948 for (int i = 0; i < fields.length; i++) {
949 JDOField field = fields[i];
950 if (field.isPersistent() && field.isSerializable()) {
951 tmp[length++] = i;
952 }
953 }
954
955 int[] fieldNumbers = new int[length];
956 System.arraycopy(tmp, 0, fieldNumbers, 0, length);
957
958 return fieldNumbers;
959 }
960
961 /***
962 * Returns JDOField metadata for a particular managed field specified by
963 * field name. It returns <code>null</code> if the specified name does not
964 * denote a managed field of this JDOClass. The field name may be
965 * unqualified and or qualified (see {@link #getField(String fieldName)}).
966 * @param fieldName the name of the managed field for which field metadata
967 * is needed.
968 * @return JDOField metadata for the managed field or <code>null</code>
969 * if there is no such field.
970 */
971 public JDOField getManagedField(String fieldName) {
972 JDOField field = getField(fieldName);
973 if ((field != null) && !field.isManaged())
974
975 return null;
976 return field;
977 }
978
979 /***
980 * Returns JDOField metadata for a particular field specified by field name.
981 * It returns <code>null</code> if the specified name does not denote a
982 * field of this JDOClass.
983 * <p>
984 * The method supports lookup by unqualified and by qualified field name.
985 * <ul>
986 * <li> In the case of an unqualified field name the method starts checking
987 * this JDOClass for a field with the specified name. If this class does not
988 * define such a field, it checks the inheritance hierarchy starting with
989 * its direct persistence-capable superclass. The method finds the first
990 * field with the specified name in a bootom-up lookup of the inheritance
991 * hierarchy. Hidden fields are not visible.
992 * <li> In the case of a qualified field name the method assumes a fully
993 * qualified class name (called qualifier class) as the field qualifier.
994 * The qualifier class must be a either this class or a persistence-capable
995 * superclass (direct or indirect) of this class. Then the method searches
996 * the field definition in the inheritance hierarchy staring with the
997 * qualifier class. Any field declarations with the same name in subclasses
998 * of the qualifier class are not considered. This form allows accessing
999 * fields hidden by subclasses. The method returns <code>null</code> if the
1000 * qualifier class does not denote a valid class or if the qualifier class
1001 * is not a persistence-capable superclass of this class.
1002 * </ul>
1003 * @param fieldName the unqualified or qualified name of field for which
1004 * field metadata is needed.
1005 * @return JDOField metadata for the field or <code>null</code>
1006 * if there is no such field.
1007 */
1008 public JDOField getField(String fieldName) {
1009
1010 if ((fieldName == null) || (fieldName.length() == 0)) {
1011 return null;
1012 }
1013
1014 JDOField field = null;
1015 int index = fieldName.lastIndexOf('.');
1016 if (index != -1) {
1017
1018 String className = fieldName.substring(0, index);
1019 fieldName = fieldName.substring(index + 1);
1020
1021
1022 for (JDOClassImplDynamic next = this; next != null;
1023 next = (JDOClassImplDynamic)next.getPersistenceCapableSuperclass()) {
1024 if (className.equals(next.getName())) {
1025 field = next.getFieldInternal(fieldName);
1026 }
1027 }
1028 }
1029 else {
1030
1031 field = getFieldInternal(fieldName);
1032 }
1033
1034 return field;
1035 }
1036
1037 /***
1038 * Provides metadata for a particular field specified by the absolute field
1039 * number. The field number must be a valid absolute field number for this
1040 * JDOClass: <code>0 <= fieldNumber < this.getManagedFields().length</code>
1041 * If the field number is valid the returned JDoField instance denotes a
1042 * managed field, meaning the field has the persistence-modifier
1043 * {@link org.apache.jdo.model.jdo.PersistenceModifier#PERSISTENT} or
1044 * {@link org.apache.jdo.model.jdo.PersistenceModifier#TRANSACTIONAL}.
1045 * If the field number is not valid then the method returns
1046 * <code>null</code>.
1047 * @param fieldNumber the number for which field metadata is needed.
1048 * @return JDOField metadata for the field or <code>null</code>
1049 * if there is no such field.
1050 */
1051 public JDOField getField(int fieldNumber) {
1052 JDOField field = null;
1053 JDOField[] fields = getManagedFields();
1054 if ((0 <= fieldNumber) && (fieldNumber < fields.length))
1055 field = fields[fieldNumber];
1056 return field;
1057 }
1058
1059 /***
1060 * Returns JDOField metadata for a particular declared field for the
1061 * specified name. Please note, the method does not return inherited
1062 * fields. The field name must not be qualified by a class name. The
1063 * method returns <code>null</code> if the field name does not denote a
1064 * field declared by JDOClass.
1065 * @param name the unqualified name of field for which field metadata
1066 * is needed.
1067 * @return JDOField metadata for the field or <code>null</code>
1068 * if there is no such field declared by this JDOClass.
1069 */
1070 public JDOField getDeclaredField(String name) {
1071 return (JDOField) declaredFields.get(name);
1072 }
1073
1074 /***
1075 * Returns JDOProperty metadata for a property with the specified name
1076 * having an associated JDOField. The method returns <code>null</code>, if
1077 * the name does not denote a property with an associated JDOField of this
1078 * JDOClass. Please note, the method does not check for properties without
1079 * an associated JDOField. It will return <code>null</code> if there is
1080 * a property with the specified name, but this property does not have an
1081 * associated JDOField.
1082 * @param name the name of property with an associated JDOField for which
1083 * metadata is needed.
1084 * @return JDOProperty metadata for the property with an associated
1085 * JDOField or <code>null</code> if there is no such property.
1086 */
1087 public JDOProperty getAssociatedProperty(String name) {
1088
1089 JDOProperty prop = (JDOProperty) associatedProperties.get(name);
1090 if (prop != null) {
1091 return prop;
1092 }
1093
1094
1095 JDOClass superclass = getPersistenceCapableSuperclass();
1096 if (superclass != null) {
1097 return superclass.getAssociatedProperty(name);
1098 }
1099
1100
1101 return null;
1102 }
1103
1104 /***
1105 * Returns JDOProperty metadata for a property having the specified
1106 * JDOField as associated JDOField. The method returns <code>null</code>,
1107 * if this JDOClass does not have a property with the specified JDOField
1108 * as associated JDOField.
1109 * @param JDOField the assoaciated JDOField of the property for which
1110 * metadata is needed.
1111 * @return JDOProperty metadata for the property the specified JDOField as
1112 * associated JDOField or <code>null</code> if there is no such property.
1113 */
1114 public JDOProperty getAssociatedProperty(JDOField field) {
1115 Collection props = associatedProperties.values();
1116 for (Iterator i = props.iterator(); i.hasNext();) {
1117 JDOProperty prop = (JDOProperty)i.next();
1118 if (prop.getAssociatedJDOField() == field) {
1119
1120 return prop;
1121 }
1122 }
1123
1124
1125 return null;
1126 }
1127
1128 /***
1129 * Returns the number of managed fields declared in the class represented
1130 * by this JDOClass. This does not include inherited fields.
1131 * @return number of declared managed fields
1132 */
1133 public int getDeclaredManagedFieldCount() {
1134 return getDeclaredManagedFields().length;
1135 }
1136
1137 /***
1138 * Returns the number of inherited managed fields for the class
1139 * represented by this JDOClass.
1140 * @return number of inherited managed fields
1141 */
1142 public int getInheritedManagedFieldCount() {
1143 int count = 0;
1144 JDOClass superclass = getPersistenceCapableSuperclass();
1145 if (superclass != null) {
1146 count =
1147 superclass.getInheritedManagedFieldCount() +
1148 superclass.getDeclaredManagedFieldCount();
1149 }
1150
1151 return count;
1152 }
1153
1154 /***
1155 * Returns the number of managed fields for the class represented by this
1156 * JDOClass. The value returned by this method is equal to
1157 * <code>getDeclaredManagedFieldCount() +
1158 * getInheritedManagedFieldCount()</code>.
1159 * @return number of managed fields
1160 */
1161 public int getManagedFieldCount() {
1162 return getDeclaredManagedFieldCount() + getInheritedManagedFieldCount();
1163 }
1164
1165 /***
1166 * Returns the package name including a terminating dot if this class has a
1167 * package. The method returns the empty string if this class is in the
1168 * default package.
1169 * @return package prefix for this class.
1170 */
1171 public String getPackagePrefix() {
1172 String className = getName();
1173 int index = className.lastIndexOf('.');
1174 return (index == -1) ? "" : className.substring(0, index + 1);
1175 }
1176
1177 /***
1178 * Returns the least-derived (topmost) persistence-capable class in the
1179 * hierarchy of this JDOClass. It returns this JDOClass if it has no
1180 * persistence-capable superclass.
1181 * @return the topmost persistence-capable class in the hierarchy.
1182 */
1183 public JDOClass getPersistenceCapableRootClass() {
1184 JDOClass superclass = getPersistenceCapableSuperclass();
1185 if (superclass == null) {
1186
1187 return this;
1188 }
1189 else {
1190 return superclass.getPersistenceCapableRootClass();
1191 }
1192 }
1193
1194
1195
1196 /***
1197 * Returns the JDOField definition for the specified field.
1198 * The method expects unqualified field names. The method
1199 * performs a bottom up lookup in the case of multiple fields
1200 * with the same name in an inheritance hierarchy. So it starts
1201 * checking this class, then it checks its superclas, etc.
1202 * @param fieldName the unqualified field name
1203 * @return the corresponding JDOField instance if exists;
1204 * <code>null</code> otherwise.
1205 */
1206 protected JDOField getFieldInternal(String fieldName) {
1207
1208 JDOField field = (JDOField)declaredFields.get(fieldName);
1209 if (field != null) {
1210 return field;
1211 }
1212
1213
1214 JDOClassImplDynamic superclass =
1215 (JDOClassImplDynamic)getPersistenceCapableSuperclass();
1216 if (superclass != null) {
1217 return superclass.getFieldInternal(fieldName);
1218 }
1219
1220
1221 return null;
1222 }
1223
1224 /***
1225 * Returns the collection of identifying declared fields of this JDOClass
1226 * in the form of an array. The method returns the JDOField instances
1227 * declared by this JDOClass defined as primary key fields (see {@link
1228 * JDOField#isPrimaryKey}).
1229 * @return the identifying fields of this JDOClass
1230 */
1231 protected JDOField[] getDeclaredPrimaryKeyFields() {
1232 JDOField[] fields = getDeclaredFields();
1233 JDOField[] tmp = new JDOField[fields.length];
1234 int length = 0;
1235 for (int i = 0; i < fields.length; i++) {
1236 JDOField field = fields[i];
1237 if (field.isManaged() && field.isPrimaryKey()) {
1238 tmp[length++] = field;
1239 }
1240 }
1241
1242
1243 JDOField[] result = new JDOField[length];
1244 System.arraycopy(tmp, 0, result, 0, length);
1245
1246 return result;
1247 }
1248
1249 /***
1250 * Returns a new instance of the JDOClass implementation class.
1251 */
1252 protected JDOClass newJDOClassInstance(String name) {
1253 return new JDOClassImplDynamic(name, this);
1254 }
1255
1256 /***
1257 * Returns a new instance of the JDOField implementation class.
1258 */
1259 protected JDOField newJDOFieldInstance(String name) {
1260 return new JDOFieldImplDynamic(name, this);
1261 }
1262
1263 /***
1264 * Returns a new instance of the JDOProperty implementation class.
1265 */
1266 protected JDOProperty newJDOPropertyInstance(String name) {
1267 return new JDOPropertyImplDynamic(name, this);
1268 }
1269
1270 /***
1271 * Returns a new instance of the JDOProperty implementation class.
1272 */
1273 protected JDOProperty newJDOPropertyInstance(
1274 String name, JDOField associatedJDOField) throws ModelException {
1275 return new JDOAssociatedPropertyImplDynamic(
1276 name, this, associatedJDOField);
1277 }
1278
1279 }