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