001 package org.apache.ojb.broker.metadata;
002
003 /* Copyright 2002-2005 The Apache Software Foundation
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 import java.io.Serializable;
019 import java.lang.reflect.Constructor;
020 import java.lang.reflect.Method;
021 import java.lang.reflect.Modifier;
022 import java.sql.Timestamp;
023 import java.util.ArrayList;
024 import java.util.Arrays;
025 import java.util.Collection;
026 import java.util.Collections;
027 import java.util.HashMap;
028 import java.util.Iterator;
029 import java.util.List;
030 import java.util.Map;
031 import java.util.Vector;
032
033 import org.apache.commons.lang.builder.ToStringBuilder;
034 import org.apache.commons.lang.builder.ToStringStyle;
035 import org.apache.ojb.broker.PersistenceBrokerException;
036 import org.apache.ojb.broker.accesslayer.ConnectionManagerIF;
037 import org.apache.ojb.broker.accesslayer.RowReader;
038 import org.apache.ojb.broker.accesslayer.RowReaderDefaultImpl;
039 import org.apache.ojb.broker.accesslayer.StatementsForClassFactory;
040 import org.apache.ojb.broker.accesslayer.StatementsForClassIF;
041 import org.apache.ojb.broker.core.ValueContainer;
042 import org.apache.ojb.broker.locking.IsolationLevels;
043 import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
044 import org.apache.ojb.broker.util.ClassHelper;
045 import org.apache.ojb.broker.util.SqlHelper;
046 import org.apache.ojb.broker.util.configuration.Configuration;
047 import org.apache.ojb.broker.util.configuration.Configurator;
048 import org.apache.ojb.broker.util.configuration.impl.OjbConfigurator;
049 import org.apache.ojb.broker.util.logging.LoggerFactory;
050
051
052 /**
053 * A ClassDescriptor contains all information for mapping objects of a
054 * given class to database tables.
055 * <br>
056 * Note: Be careful when use ClassDescriptor variables or caching
057 * ClassDescriptor instances, because instances could become invalid
058 * during runtime (see {@link MetadataManager}).
059 *
060 * @author <a href="mailto:thma@apache.org">Thomas Mahler<a>
061 * @version $Id: ClassDescriptor.java,v 1.1 2007-08-24 22:17:29 ewestfal Exp $
062 */
063 public final class ClassDescriptor extends DescriptorBase
064 implements Serializable, XmlCapable, IsolationLevels
065 {
066 private String persistentFieldClassName;
067
068 private static final long serialVersionUID = -5212253607374173965L;
069
070 public static final String DYNAMIC_STR = "dynamic";
071 public static final String OJB_CONCRETE_CLASS = "ojbConcreteClass";
072 private static final Class[] NO_PARAMS = {};
073
074 //---------------------------------------------------------------
075 /**
076 * The descriptor for the insert procedure/function.
077 */
078 private InsertProcedureDescriptor insertProcedure;
079
080 //---------------------------------------------------------------
081 /**
082 * The descriptor for the update procedure/function.
083 */
084 private UpdateProcedureDescriptor updateProcedure;
085
086 //---------------------------------------------------------------
087 /**
088 * The descriptor for the delete procedure/function.
089 */
090 private DeleteProcedureDescriptor deleteProcedure;
091
092 //---------------------------------------------------------------
093 // transient fields, to make this class serializable we have to declare
094 // some transient fields and some associated string fields to reinitialze
095 // transient fields after serialization
096 //---------------------------------------------------------------
097 /**
098 * optional method to be invoked after instance fields are initialized
099 */
100 private transient Method initializationMethod;
101 private String initializationMethodName;
102
103 private transient Method factoryMethod;
104 private String factoryMethodName;
105 /**
106 * whether we have already tried to look up the zero
107 * argument constructor. Transient declared, because
108 * {@link Constructor} is transient and we need to
109 * reinitialize constructor after serialization.
110 */
111 private transient boolean alreadyLookedupZeroArguments = false;
112 /**
113 * the zero argument constructor for this class
114 */
115 private transient Constructor zeroArgumentConstructor = null;
116
117 /**
118 * used to signal use of ojbConcreteClass field
119 */
120 private transient boolean ojbConcreteFieldCheckDone = false;
121 private transient FieldDescriptor ojbConcreteClassField;
122 /**
123 * We have to bound {@link org.apache.ojb.broker.accesslayer.StatementsForClassIF}
124 * instance to this class, because metadata may change.
125 */
126 private transient StatementsForClassIF statementsForClass;
127 //---------------------------------------------------------------
128 // end transient fields
129 //---------------------------------------------------------------
130
131 private DescriptorRepository m_repository;
132 /**
133 * optional class.method to be invoked to create object instance. Both
134 * of these must be present for this function to be successful.
135 */
136 private Class factoryClass;
137 private int useIdentityColumn = 0;
138
139 private String baseClass = null;
140 /**
141 * transaction isolation level specified for this class, used in the ODMG server
142 */
143 private int m_IsolationLevel;
144 /**
145 * the SQL SCHEMA of the underlying table of this class
146 */
147 private String schema = null;
148 /**
149 * the described class
150 */
151 private Class m_Class = null;
152 /**
153 * whether the described class is abstract
154 */
155 private boolean isAbstract = false;
156 /**
157 * the table name used to store the scalar attributes of this class
158 */
159 private String m_TableName = null;
160 // private Vector superPersistentFieldDescriptors = null;
161 /**
162 * the RowReader for this class
163 */
164 private RowReader m_rowReader = null;
165 /*
166 arminw:
167 TODO: this feature doesn't work, so remove/reuse this in future
168 */
169 /**
170 * the class that this class extends
171 */
172 private String superClass;
173 /**
174 * reference column for the superclass
175 */
176 private int superClassFieldRef;
177 /**
178 * does the described class represent an interface?
179 */
180 private boolean m_isInterface = false;
181 /**
182 * the proxy class for the described class, may be null
183 */
184 private Class proxyClass = null;
185 /**
186 * the proxy class name for the described class, may be null
187 */
188 private String proxyClassName = null;
189 /**
190 * if false do not accept implicit locks on this class
191 */
192 private boolean acceptLocks = true;
193 /**
194 * if true instances of this class are always refreshed
195 * even if they are already in the cache.
196 * false by default.
197 */
198 private boolean alwaysRefresh = false;
199 private int m_ProxyPrefetchingLimit = 50;
200 /**
201 * optional, ObjectCacheDescriptor for representing class
202 */
203 private ObjectCacheDescriptor objectCacheDescriptor;
204 /**
205 * the vector of indices used in DDL generation.
206 */
207 private Vector indexes = new Vector();
208
209 //-----------------------------------------------------------------
210 //-----------------------------------------------------------------
211 // !!! the following arrays and maps have take care of metadata changes!!!
212 //-----------------------------------------------------------------
213 //-----------------------------------------------------------------
214 private FieldDescriptor m_autoIncrementField = null;
215 /**
216 * the FieldDescriptors for the primitive attributes
217 */
218 private FieldDescriptor[] m_FieldDescriptions = null;
219 /**
220 * the descriptors for collection attributes
221 */
222 private Vector m_CollectionDescriptors = new Vector();
223 /**
224 * the descriptor for 1-1 reference attributes
225 */
226 private Vector m_ObjectReferenceDescriptors = new Vector();
227 /**
228 * the non-primary key FieldDescriptors
229 */
230 private FieldDescriptor[] m_nonPkFieldDescriptors = null;
231 /**
232 * the primary key FieldDescriptors
233 */
234 private FieldDescriptor[] m_PkFieldDescriptors = null;
235 /**
236 * the read/write FieldDescriptors BRJ
237 */
238 private FieldDescriptor[] m_RwFieldDescriptors = null;
239 private FieldDescriptor[] m_RwNonPkFieldDescriptors = null;
240 /**
241 * the optimistic lockingFieldDescriptors BRJ
242 */
243 private FieldDescriptor[] m_lockingFieldDescriptors = null;
244 /**
245 * the list of classes in the extent of this class. can be empty
246 */
247 private Vector extentClasses = new Vector();
248 /**
249 * the list of class names in the extent of this class. can be empty
250 */
251 private Vector extentClassNames = new Vector();
252 private Map m_fieldDescriptorNameMap = null;
253 private Map m_collectionDescriptorNameMap = null;
254 private Map m_objectReferenceDescriptorsNameMap = null;
255
256 // BRJ: ClassDescriptor referenced by 'super' ObjectReferenceDescriptor
257 private ClassDescriptor m_superCld = null;
258 private boolean m_superCldSet = false;
259
260 //-----------------------------------------------------------------
261 //-----------------------------------------------------------------
262 // END of cached metadata information
263 //-----------------------------------------------------------------
264 //-----------------------------------------------------------------
265
266
267 //---------------------------------------------------------------
268 /**
269 * Constructor declaration
270 */
271 public ClassDescriptor(DescriptorRepository pRepository)
272 {
273 m_repository = pRepository;
274 m_IsolationLevel = pRepository.getDefaultIsolationLevel();
275 }
276
277
278 //---------------------------------------------------------------
279 // method declarations
280 //---------------------------------------------------------------
281 public String getBaseClass()
282 {
283 return baseClass;
284 }
285 public void setBaseClass(String baseClass)
286 {
287 this.baseClass = baseClass;
288 // first deregister
289 getRepository().deregisterSuperClassMultipleJoinedTables(this);
290 // register classes using mapping of classes to multiple joined tables
291 getRepository().registerSuperClassMultipleJoinedTables(this);
292 }
293
294 // /**
295 // * @deprecated no longer needed map class on multi joined table
296 // */
297 // public void setSuperPersistentFieldDescriptors(Vector superPersistentFieldDescriptors)
298 // {
299 // this.superPersistentFieldDescriptors = superPersistentFieldDescriptors;
300 // }
301 //
302 // /**
303 // * @deprecated no longer needed map class on multi joined table
304 // */
305 // public Vector getSuperPersistentFieldDescriptors()
306 // {
307 // return superPersistentFieldDescriptors;
308 // }
309
310 /**
311 * Returns the appropriate {@link ObjectCacheDescriptor}
312 * or <code>null</code> if not specified.
313 */
314 public ObjectCacheDescriptor getObjectCacheDescriptor()
315 {
316 return objectCacheDescriptor;
317 }
318
319 /**
320 * Sets the {@link ObjectCacheDescriptor} for representing class.
321 */
322 public void setObjectCacheDescriptor(ObjectCacheDescriptor objectCacheDescriptor)
323 {
324 this.objectCacheDescriptor = objectCacheDescriptor;
325 }
326
327
328 /**
329 * sets the row reader class for this descriptor
330 */
331 public void setRowReader(RowReader newReader)
332 {
333 m_rowReader = newReader;
334 }
335
336 /**
337 * Returns the {@link org.apache.ojb.broker.accesslayer.RowReader}
338 * for this descriptor.
339 */
340 public synchronized RowReader getRowReader()
341 {
342 if (m_rowReader == null)
343 {
344 Configurator configurator = OjbConfigurator.getInstance();
345 Configuration config = configurator.getConfigurationFor(null);
346 Class rrClass = config.getClass("RowReaderDefaultClass", RowReaderDefaultImpl.class);
347
348 setRowReader(rrClass.getName());
349 }
350 return m_rowReader;
351 }
352
353 /**
354 * sets the row reader class name for thie class descriptor
355 */
356 public void setRowReader(String newReaderClassName)
357 {
358 try
359 {
360 m_rowReader =
361 (RowReader) ClassHelper.newInstance(
362 newReaderClassName,
363 ClassDescriptor.class,
364 this);
365 }
366 catch (Exception e)
367 {
368 throw new MetadataException("Instantiating of current set RowReader failed", e);
369 }
370 }
371
372 public String getRowReaderClassName()
373 {
374 return m_rowReader != null ? m_rowReader.getClass().getName() : null;
375 }
376
377 /**
378 * returns the name of the described class
379 * @return String name of the described class
380 */
381 public String getClassNameOfObject()
382 {
383 return m_Class != null ? m_Class.getName() : null;
384 }
385
386 /**
387 * returns the class object of the described class
388 * @return Class the described class
389 */
390 public Class getClassOfObject()
391 {
392 return m_Class;
393 }
394
395 /**
396 * sets the class object described by this descriptor.
397 * @param c the class to describe
398 */
399 public void setClassOfObject(Class c)
400 {
401 m_Class = c;
402 isAbstract = Modifier.isAbstract(m_Class.getModifiers());
403 // TODO : Shouldn't the HashMap in DescriptorRepository be updated as well?
404 }
405
406 /**
407 * adds a FIELDDESCRIPTOR to this ClassDescriptor.
408 * @param fld
409 */
410 public void addFieldDescriptor(FieldDescriptor fld)
411 {
412 fld.setClassDescriptor(this); // BRJ
413 if (m_FieldDescriptions == null)
414 {
415 m_FieldDescriptions = new FieldDescriptor[1];
416 m_FieldDescriptions[0] = fld;
417 }
418 else
419 {
420 int size = m_FieldDescriptions.length;
421 FieldDescriptor[] tmpArray = new FieldDescriptor[size + 1];
422 System.arraycopy(m_FieldDescriptions, 0, tmpArray, 0, size);
423 tmpArray[size] = fld;
424 m_FieldDescriptions = tmpArray;
425 // 2. Sort fields according to their getOrder() Property
426 Arrays.sort(m_FieldDescriptions, FieldDescriptor.getComparator());
427 }
428
429 m_fieldDescriptorNameMap = null;
430 m_PkFieldDescriptors = null;
431 m_nonPkFieldDescriptors = null;
432 m_lockingFieldDescriptors = null;
433 m_RwFieldDescriptors = null;
434 m_RwNonPkFieldDescriptors = null;
435 }
436
437 public boolean removeFieldDescriptor(FieldDescriptor fld)
438 {
439 boolean result = false;
440 if(m_FieldDescriptions == null) return result;
441
442 List list = new ArrayList(Arrays.asList(m_FieldDescriptions));
443 result = list.remove(fld);
444 m_FieldDescriptions = (FieldDescriptor[]) list.toArray(new FieldDescriptor[list.size()]);
445
446 m_fieldDescriptorNameMap = null;
447 m_PkFieldDescriptors = null;
448 m_nonPkFieldDescriptors = null;
449 m_lockingFieldDescriptors = null;
450 m_RwFieldDescriptors = null;
451 m_RwNonPkFieldDescriptors = null;
452 return result;
453 }
454
455 /**
456 * Returns all defined {@link CollectionDescriptor} for
457 * this class descriptor.
458 */
459 public Vector getCollectionDescriptors()
460 {
461 return m_CollectionDescriptors;
462 }
463
464 /**
465 * Add a {@link CollectionDescriptor}.
466 */
467 public void addCollectionDescriptor(CollectionDescriptor cod)
468 {
469 m_CollectionDescriptors.add(cod);
470 cod.setClassDescriptor(this); // BRJ
471
472 m_collectionDescriptorNameMap = null;
473 }
474
475 public void removeCollectionDescriptor(CollectionDescriptor cod)
476 {
477 m_CollectionDescriptors.remove(cod);
478 m_collectionDescriptorNameMap = null;
479 }
480
481 /**
482 * Returns all defined {@link ObjectReferenceDescriptor}.
483 */
484 public Vector getObjectReferenceDescriptors()
485 {
486 return m_ObjectReferenceDescriptors;
487 }
488
489 /**
490 * Add a {@link ObjectReferenceDescriptor}.
491 */
492 public void addObjectReferenceDescriptor(ObjectReferenceDescriptor ord)
493 {
494 m_ObjectReferenceDescriptors.add(ord);
495 ord.setClassDescriptor(this); // BRJ
496
497 m_objectReferenceDescriptorsNameMap = null;
498 }
499
500 public void removeObjectReferenceDescriptor(ObjectReferenceDescriptor ord)
501 {
502 m_ObjectReferenceDescriptors.remove(ord);
503 m_objectReferenceDescriptorsNameMap = null;
504 }
505
506 /**
507 * Get an ObjectReferenceDescriptor by name BRJ
508 * @param name
509 * @return ObjectReferenceDescriptor or null
510 */
511 public ObjectReferenceDescriptor getObjectReferenceDescriptorByName(String name)
512 {
513 ObjectReferenceDescriptor ord = (ObjectReferenceDescriptor)
514 getObjectReferenceDescriptorsNameMap().get(name);
515
516 //
517 // BRJ: if the ReferenceDescriptor is not found
518 // look in the ClassDescriptor referenced by 'super' for it
519 //
520 if (ord == null)
521 {
522 ClassDescriptor superCld = getSuperClassDescriptor();
523 if (superCld != null)
524 {
525 ord = superCld.getObjectReferenceDescriptorByName(name);
526 }
527 }
528 return ord;
529 }
530
531 private Map getObjectReferenceDescriptorsNameMap()
532 {
533 if (m_objectReferenceDescriptorsNameMap == null)
534 {
535 HashMap nameMap = new HashMap();
536
537 Vector descriptors = getObjectReferenceDescriptors();
538 for (int i = descriptors.size() - 1; i >= 0; i--)
539 {
540 ObjectReferenceDescriptor ord = (ObjectReferenceDescriptor) descriptors.get(i);
541 nameMap.put(ord.getAttributeName(), ord);
542 }
543 m_objectReferenceDescriptorsNameMap = nameMap;
544 }
545
546 return m_objectReferenceDescriptorsNameMap;
547 }
548
549 /**
550 * Get an CollectionDescriptor by name BRJ
551 * @param name
552 * @return CollectionDescriptor or null
553 */
554 public CollectionDescriptor getCollectionDescriptorByName(String name)
555 {
556 if (name == null)
557 {
558 return null;
559 }
560
561 CollectionDescriptor cod = (CollectionDescriptor) getCollectionDescriptorNameMap().get(name);
562
563 //
564 // BRJ: if the CollectionDescriptor is not found
565 // look in the ClassDescriptor referenced by 'super' for it
566 //
567 if (cod == null)
568 {
569 ClassDescriptor superCld = getSuperClassDescriptor();
570 if (superCld != null)
571 {
572 cod = superCld.getCollectionDescriptorByName(name);
573 }
574 }
575
576 return cod;
577 }
578
579 private Map getCollectionDescriptorNameMap()
580 {
581 if (m_collectionDescriptorNameMap == null)
582 {
583 HashMap nameMap = new HashMap();
584
585 Vector descriptors = getCollectionDescriptors();
586 for (int i = descriptors.size() - 1; i >= 0; i--)
587 {
588 CollectionDescriptor cod = (CollectionDescriptor) descriptors.get(i);
589 nameMap.put(cod.getAttributeName(), cod);
590 }
591 m_collectionDescriptorNameMap = nameMap;
592 }
593
594 return m_collectionDescriptorNameMap;
595 }
596
597 /**
598 * Answers the ClassDescriptor referenced by 'super' ReferenceDescriptor.
599 * @return ClassDescriptor or null
600 */
601 public ClassDescriptor getSuperClassDescriptor()
602 {
603 if (!m_superCldSet)
604 {
605 if(getBaseClass() != null)
606 {
607 m_superCld = getRepository().getDescriptorFor(getBaseClass());
608 if(m_superCld.isAbstract() || m_superCld.isInterface())
609 {
610 throw new MetadataException("Super class mapping only work for real class, but declared super class" +
611 " is an interface or is abstract. Declared class: " + m_superCld.getClassNameOfObject());
612 }
613 }
614 m_superCldSet = true;
615 }
616
617 return m_superCld;
618 }
619
620 /**
621 * add an Extent class to the current descriptor
622 * @param newExtendClass
623 * @deprecated use {@link #addExtentClass(String newExtentClass)} instead
624 */
625 public void addExtentClassName(Class newExtendClass)
626 {
627 addExtentClass(newExtendClass);
628 }
629
630 /**
631 * add an Extent class to the current descriptor
632 * @param newExtendClass
633 */
634 public void addExtentClass(Class newExtendClass)
635 {
636 extentClasses.add(newExtendClass);
637 this.addExtentClass(newExtendClass.getName());
638 }
639
640 /**
641 * add an Extent class to the current descriptor
642 * @param newExtentClassName name of the class to add
643 */
644 public void addExtentClass(String newExtentClassName)
645 {
646 extentClassNames.add(newExtentClassName);
647 if(m_repository != null) m_repository.addExtent(newExtentClassName, this);
648 }
649
650 public void removeExtentClass(String extentClassName)
651 {
652 extentClassNames.remove(extentClassName);
653 if(m_repository != null) m_repository.removeExtent(extentClassName);
654 }
655
656 /**
657 * return all classes in this extent.
658 * Creation date: (02.02.2001 17:49:11)
659 * @return java.util.Vector
660 */
661 public synchronized Vector getExtentClasses()
662 {
663 if (extentClassNames.size() != extentClasses.size())
664 {
665 extentClasses.clear();
666 for (Iterator iter = extentClassNames.iterator(); iter.hasNext();)
667 {
668 String classname = (String) iter.next();
669 Class extentClass;
670 try
671 {
672 extentClass = ClassHelper.getClass(classname);
673 }
674 catch (ClassNotFoundException e)
675 {
676 throw new MetadataException(
677 "Unable to load class ["
678 + classname
679 + "]. Make sure it is available on the classpath.",
680 e);
681 }
682 extentClasses.add(extentClass);
683 }
684 }
685 return extentClasses;
686 }
687
688
689 /**
690 * Return the names of all classes in this extent
691 * @return java.util.Vector a Vector containing the fully qualified names
692 * of all classes in this extent
693 */
694 public synchronized Vector getExtentClassNames()
695 {
696 return this.extentClassNames;
697 }
698
699 /**
700 * Insert the method's description here.
701 * Creation date: (02.02.2001 17:49:11)
702 * @return boolean
703 */
704 public boolean isExtent()
705 {
706 return (getExtentClassNames().size() > 0);
707 }
708
709 /**
710 * Insert the method's description here.
711 * Creation date: (26.01.2001 09:20:09)
712 * @return java.lang.Class
713 */
714 public synchronized Class getProxyClass()
715 {
716 if ((proxyClass == null) && (proxyClassName != null))
717 {
718 if (isDynamicProxy())
719 {
720 /**
721 * AClute: Return the same class back if it is dynamic. This signifies
722 * that this class become the base to a generated sub-class, regadless
723 * of which Proxy implementation is used
724 */
725 return getClassOfObject();
726 }
727 else
728 {
729 try
730 {
731 proxyClass = ClassHelper.getClass(proxyClassName);
732 }
733 catch (ClassNotFoundException e)
734 {
735 throw new MetadataException(e);
736 }
737 }
738 }
739 return proxyClass;
740 }
741
742 public boolean isDynamicProxy()
743 {
744 return DYNAMIC_STR.equalsIgnoreCase(proxyClassName);
745 }
746
747 /**
748 * Sets the proxy class to be used.
749 * @param newProxyClass java.lang.Class
750 */
751 public void setProxyClass(Class newProxyClass)
752 {
753 proxyClass = newProxyClass;
754 if (proxyClass == null)
755 {
756 setProxyClassName(null);
757 }
758 else
759 {
760 proxyClassName = proxyClass.getName();
761 }
762 }
763
764 /**
765 * Sets the name of the proxy class to be used.
766 * using "dynamic" instead of a real classname
767 * will result in usage of dynamic proxies.
768 * @param newProxyClassName the classname or "dynamic"
769 */
770 public void setProxyClassName(String newProxyClassName)
771 {
772 proxyClassName = newProxyClassName;
773 }
774
775 /**
776 * Get the name of the proxy class. This method doesn't try to access
777 * the real class, so it can be called even if the class doesn't exist.
778 */
779 public String getProxyClassName()
780 {
781 return proxyClassName;
782 }
783
784 /**
785 * Returns array of all FieldDescriptors.
786 */
787 public FieldDescriptor[] getFieldDescriptions()
788 {
789 return m_FieldDescriptions;
790 }
791
792 /**
793 * Returns the matching {@link FieldDescriptor}.
794 */
795 public FieldDescriptor getFieldDescriptorByIndex(int index)
796 {
797 return m_FieldDescriptions[index - 1];
798 }
799
800 /**
801 * Returns the matching {@link FieldDescriptor} - only fields
802 * of the current class will be scanned, to include fields defined
803 * the the super-classes too, use method {@link #getFieldDescriptor(boolean)}.
804 */
805 public FieldDescriptor getFieldDescriptorByName(String name)
806 {
807 if (name == null || m_FieldDescriptions == null)
808 {
809 return null;
810 }
811
812 if (m_fieldDescriptorNameMap == null)
813 {
814 HashMap nameMap = new HashMap();
815
816 FieldDescriptor[] descriptors = getFieldDescriptions();
817 for (int i = descriptors.length - 1; i >= 0; i--)
818 {
819 FieldDescriptor fld = descriptors[i];
820 nameMap.put(fld.getPersistentField().getName(), fld);
821 }
822
823 m_fieldDescriptorNameMap = nameMap;
824 }
825
826 return (FieldDescriptor) m_fieldDescriptorNameMap.get(name);
827 }
828
829 /**
830 * return the FieldDescriptor for the Attribute referenced in the path<br>
831 * the path may contain simple attribut names, functions and path expressions
832 * using relationships <br>
833 * ie: name, avg(price), adress.street
834 * @param aPath the path to the attribute
835 * @param pathHints a Map containing the class to be used for a segment or <em>null</em>
836 * if no segment was used.
837 * @return the FieldDescriptor or null (ie: for m:n queries)
838 */
839 public FieldDescriptor getFieldDescriptorForPath(String aPath, Map pathHints)
840 {
841 ArrayList desc = getAttributeDescriptorsForPath(aPath, pathHints);
842 FieldDescriptor fld = null;
843 Object temp;
844
845 if (!desc.isEmpty())
846 {
847 temp = desc.get(desc.size() - 1);
848 if (temp instanceof FieldDescriptor)
849 {
850 fld = (FieldDescriptor) temp;
851 }
852 }
853 return fld;
854 }
855
856 /**
857 * return the FieldDescriptor for the Attribute referenced in the path<br>
858 * the path may contain simple attribut names, functions and path expressions
859 * using relationships <br>
860 * ie: name, avg(price), adress.street
861 * @param aPath the path to the attribute
862 * @return the FieldDescriptor or null (ie: for m:n queries)
863 */
864 public FieldDescriptor getFieldDescriptorForPath(String aPath)
865 {
866 return getFieldDescriptorForPath(aPath, null);
867 }
868 /*
869 arminw:
870 TODO: this feature doesn't work, so remove this in future
871 */
872 /**
873 *
874 * @return this classes FieldDescriptor's as well as it's parents and so on and so on
875 */
876 public FieldDescriptor[] getFieldDescriptorsInHeirarchy()
877 {
878 if (superClass == null)
879 {
880 return getFieldDescriptions();
881 }
882 ClassDescriptor cldSuper = getRepository().getDescriptorFor(superClass);
883 return appendFieldDescriptorArrays(
884 getFieldDescriptions(),
885 cldSuper.getFieldDescriptorsInHeirarchy());
886 }
887
888 private FieldDescriptor[] appendFieldDescriptorArrays(
889 FieldDescriptor[] fieldDescriptions,
890 FieldDescriptor[] fieldDescriptorsInHeirarchy)
891 {
892 // take the 2 arrays and add them into one
893 int size = fieldDescriptions.length + fieldDescriptorsInHeirarchy.length;
894 FieldDescriptor[] newArray = new FieldDescriptor[size];
895 System.arraycopy(fieldDescriptions, 0, newArray, 0, fieldDescriptions.length);
896 System.arraycopy(fieldDescriptorsInHeirarchy, 0, newArray, fieldDescriptions.length, fieldDescriptorsInHeirarchy.length);
897 return newArray;
898 }
899
900 /**
901 * Returns the first found autoincrement field
902 * defined in this class descriptor. Use carefully
903 * when multiple autoincrement field were defined.
904 * @deprecated does not make sense because it's possible to
905 * define more than one autoincrement field. Alternative
906 * see {@link #getAutoIncrementFields}
907 */
908 public FieldDescriptor getAutoIncrementField()
909 {
910 if (m_autoIncrementField == null)
911 {
912 FieldDescriptor[] fds = getPkFields();
913
914 for (int i = 0; i < fds.length; i++)
915 {
916 FieldDescriptor fd = fds[i];
917 if (fd.isAutoIncrement())
918 {
919 m_autoIncrementField = fd;
920 break;
921 }
922 }
923 }
924 if (m_autoIncrementField == null)
925 {
926 LoggerFactory.getDefaultLogger().warn(
927 this.getClass().getName()
928 + ": "
929 + "Could not find autoincrement attribute for class: "
930 + this.getClassNameOfObject());
931 }
932 return m_autoIncrementField;
933 }
934
935 public FieldDescriptor[] getAutoIncrementFields()
936 {
937 ArrayList result = new ArrayList();
938 for (int i = 0; i < m_FieldDescriptions.length; i++)
939 {
940 FieldDescriptor field = m_FieldDescriptions[i];
941 if(field.isAutoIncrement()) result.add(field);
942 }
943 return (FieldDescriptor[]) result.toArray(new FieldDescriptor[result.size()]);
944 }
945
946 /**
947 * returns an Array with an Objects CURRENT locking VALUES , BRJ
948 * @throws PersistenceBrokerException if there is an erros accessing o field values
949 */
950 public ValueContainer[] getCurrentLockingValues(Object o) throws PersistenceBrokerException
951 {
952 FieldDescriptor[] fields = getLockingFields();
953 ValueContainer[] result = new ValueContainer[fields.length];
954 for (int i = 0; i < result.length; i++)
955 {
956 result[i] = new ValueContainer(fields[i].getPersistentField().get(o), fields[i].getJdbcType());
957 }
958 return result;
959 }
960
961 /**
962 * updates the values for locking fields , BRJ
963 * handles int, long, Timestamp
964 * respects updateLock so locking field are only updated when updateLock is true
965 * @throws PersistenceBrokerException if there is an erros accessing obj field values
966 */
967 public void updateLockingValues(Object obj) throws PersistenceBrokerException
968 {
969 FieldDescriptor[] fields = getLockingFields();
970 for (int i = 0; i < fields.length; i++)
971 {
972 FieldDescriptor fmd = fields[i];
973 if (fmd.isUpdateLock())
974 {
975 PersistentField f = fmd.getPersistentField();
976 Object cv = f.get(obj);
977 // int
978 if ((f.getType() == int.class) || (f.getType() == Integer.class))
979 {
980 int newCv = 0;
981 if (cv != null)
982 {
983 newCv = ((Number) cv).intValue();
984 }
985 newCv++;
986 f.set(obj, new Integer(newCv));
987 }
988 // long
989 else if ((f.getType() == long.class) || (f.getType() == Long.class))
990 {
991 long newCv = 0;
992 if (cv != null)
993 {
994 newCv = ((Number) cv).longValue();
995 }
996 newCv++;
997 f.set(obj, new Long(newCv));
998 }
999 // Timestamp
1000 else if (f.getType() == Timestamp.class)
1001 {
1002 long newCv = System.currentTimeMillis();
1003 f.set(obj, new Timestamp(newCv));
1004 }
1005 }
1006 }
1007 }
1008
1009 /**
1010 * return an array of NONPK-FieldDescription sorted ascending
1011 * according to the field-descriptions getOrder() property
1012 */
1013 public FieldDescriptor[] getNonPkFields()
1014 {
1015 if (m_nonPkFieldDescriptors == null)
1016 {
1017 // 1. collect all Primary Key fields from Field list
1018 Vector vec = new Vector();
1019 for (int i = 0; i < m_FieldDescriptions.length; i++)
1020 {
1021 FieldDescriptor fd = m_FieldDescriptions[i];
1022 if (!fd.isPrimaryKey())
1023 {
1024 vec.add(fd);
1025 }
1026 }
1027 // 2. Sort fields according to their getOrder() Property
1028 Collections.sort(vec, FieldDescriptor.getComparator());
1029 m_nonPkFieldDescriptors =
1030 (FieldDescriptor[]) vec.toArray(new FieldDescriptor[vec.size()]);
1031 }
1032 return m_nonPkFieldDescriptors;
1033 }
1034
1035 /**
1036 * Return an array of PK FieldDescription sorted ascending
1037 * according to the field-descriptions getOrder() property
1038 */
1039 public FieldDescriptor[] getPkFields()
1040 {
1041 if (m_PkFieldDescriptors == null)
1042 {
1043 // 1. collect all Primary Key fields from Field list
1044 Vector vec = new Vector();
1045 // 1.a if descriptor describes an interface: take PK fields from an implementors ClassDescriptor
1046 if (m_isInterface)
1047 {
1048 if (getExtentClasses().size() == 0)
1049 {
1050 throw new PersistenceBrokerException(
1051 "No Implementors declared for interface "
1052 + this.getClassOfObject().getName());
1053 }
1054 Class implementor = (Class) getExtentClasses().get(0);
1055 ClassDescriptor implCld = this.getRepository().getDescriptorFor(implementor);
1056 m_PkFieldDescriptors = implCld.getPkFields();
1057 }
1058 else
1059 {
1060 FieldDescriptor[] fields;
1061 // 1.b if not an interface The classdescriptor must have FieldDescriptors
1062 fields = getFieldDescriptions();
1063 // now collect all PK fields
1064 for (int i = 0; i < fields.length; i++)
1065 {
1066 FieldDescriptor fd = fields[i];
1067 if (fd.isPrimaryKey())
1068 {
1069 vec.add(fd);
1070 }
1071 }
1072 // 2. Sort fields according to their getOrder() Property
1073 Collections.sort(vec, FieldDescriptor.getComparator());
1074 m_PkFieldDescriptors = (FieldDescriptor[]) vec.toArray(new FieldDescriptor[vec.size()]);
1075 }
1076 }
1077 return m_PkFieldDescriptors;
1078 }
1079
1080 /**
1081 * Returns array of read/write non pk FieldDescriptors.
1082 */
1083 public FieldDescriptor[] getNonPkRwFields()
1084 {
1085 if (m_RwNonPkFieldDescriptors == null)
1086 {
1087 FieldDescriptor[] fields = getNonPkFields();
1088 Collection rwFields = new ArrayList();
1089
1090 for (int i = 0; i < fields.length; i++)
1091 {
1092 FieldDescriptor fd = fields[i];
1093 if (!fd.isAccessReadOnly())
1094 {
1095 rwFields.add(fd);
1096 }
1097 }
1098 m_RwNonPkFieldDescriptors =
1099 (FieldDescriptor[]) rwFields.toArray(new FieldDescriptor[rwFields.size()]);
1100 }
1101 return m_RwNonPkFieldDescriptors;
1102 }
1103
1104 /**
1105 * Returns array of read/write FieldDescriptors.
1106 */
1107 public FieldDescriptor[] getAllRwFields()
1108 {
1109 if (m_RwFieldDescriptors == null)
1110 {
1111 FieldDescriptor[] fields = getFieldDescriptions();
1112 Collection rwFields = new ArrayList();
1113
1114 for (int i = 0; i < fields.length; i++)
1115 {
1116 FieldDescriptor fd = fields[i];
1117 /*
1118 arminw: if locking is enabled and the increment of locking
1119 values is done by the database, the field is read-only
1120 */
1121 if(fd.isAccessReadOnly() || (fd.isLocking() && !fd.isUpdateLock()))
1122 {
1123 continue;
1124 }
1125 rwFields.add(fd);
1126 }
1127 m_RwFieldDescriptors =
1128 (FieldDescriptor[]) rwFields.toArray(new FieldDescriptor[rwFields.size()]);
1129 }
1130
1131 return m_RwFieldDescriptors;
1132 }
1133
1134 /**
1135 * return an array of FieldDescription for optimistic locking sorted ascending
1136 * according to the field-descriptions getOrder() property
1137 */
1138 public FieldDescriptor[] getLockingFields()
1139 {
1140 if (m_lockingFieldDescriptors == null)
1141 {
1142 // 1. collect all Primary Key fields from Field list
1143 Vector vec = new Vector();
1144 for (int i = 0; i < m_FieldDescriptions.length; i++)
1145 {
1146 FieldDescriptor fd = m_FieldDescriptions[i];
1147 if (fd.isLocking())
1148 {
1149 vec.add(fd);
1150 }
1151 }
1152 // 2. Sort fields according to their getOrder() Property
1153 Collections.sort(vec, FieldDescriptor.getComparator());
1154 m_lockingFieldDescriptors =
1155 (FieldDescriptor[]) vec.toArray(new FieldDescriptor[vec.size()]);
1156 }
1157 return m_lockingFieldDescriptors;
1158 }
1159
1160 /**
1161 * return true if optimistic locking is used
1162 */
1163 public boolean isLocking()
1164 {
1165 return getLockingFields().length > 0;
1166 }
1167
1168 /**
1169 * return all AttributeDescriptors for the path<br>
1170 * ie: partner.addresses.street returns a Collection of 3 AttributeDescriptors
1171 * (ObjectReferenceDescriptor, CollectionDescriptor, FieldDescriptor)<br>
1172 * ie: partner.addresses returns a Collection of 2 AttributeDescriptors
1173 * (ObjectReferenceDescriptor, CollectionDescriptor)
1174 * @param aPath the cleaned path to the attribute
1175 * @return ArrayList of AttributeDescriptors
1176 */
1177 public ArrayList getAttributeDescriptorsForPath(String aPath)
1178 {
1179 return getAttributeDescriptorsForPath(aPath, new HashMap());
1180 }
1181
1182 /**
1183 * return all AttributeDescriptors for the path<br>
1184 * ie: partner.addresses.street returns a Collection of 3 AttributeDescriptors
1185 * (ObjectReferenceDescriptor, CollectionDescriptor, FieldDescriptor)<br>
1186 * ie: partner.addresses returns a Collection of 2 AttributeDescriptors
1187 * (ObjectReferenceDescriptor, CollectionDescriptor)
1188 * @param aPath the cleaned path to the attribute
1189 * @param pathHints a Map containing the class to be used for a segment or <em>null</em>
1190 * if no segment was used.
1191 * @return ArrayList of AttributeDescriptors
1192 */
1193 public ArrayList getAttributeDescriptorsForPath(String aPath, Map pathHints)
1194 {
1195 return getAttributeDescriptorsForCleanPath(SqlHelper.cleanPath(aPath), pathHints);
1196 }
1197
1198 /**
1199 * return all AttributeDescriptors for the path<br>
1200 * ie: partner.addresses.street returns a Collection of 3 AttributeDescriptors
1201 * (ObjectReferenceDescriptor, CollectionDescriptor, FieldDescriptor)<br>
1202 * ie: partner.addresses returns a Collection of 2 AttributeDescriptors
1203 * (ObjectReferenceDescriptor, CollectionDescriptor)
1204 * @param aPath the cleaned path to the attribute
1205 * @param pathHints a Map containing the class to be used for a segment or <em>null</em>
1206 * if no segment is used.
1207 * @return ArrayList of AttributeDescriptors
1208 */
1209 private ArrayList getAttributeDescriptorsForCleanPath(String aPath, Map pathHints)
1210 {
1211 ArrayList result = new ArrayList();
1212 ClassDescriptor cld = this;
1213 ObjectReferenceDescriptor ord;
1214 FieldDescriptor fld;
1215 String currPath = aPath;
1216 String segment;
1217 StringBuffer processedSegment = new StringBuffer();
1218 int sepPos;
1219 Class itemClass;
1220
1221 while (currPath.length() > 0)
1222 {
1223 sepPos = currPath.indexOf(".");
1224 if (sepPos >= 0)
1225 {
1226 segment = currPath.substring(0, sepPos);
1227 currPath = currPath.substring(sepPos + 1);
1228 }
1229 else
1230 {
1231 segment = currPath;
1232 currPath = "";
1233 }
1234
1235 if (processedSegment.length() > 0)
1236 {
1237 processedSegment.append(".");
1238 }
1239 processedSegment.append(segment);
1240
1241 // look for 1:1 or n:1 Relationship
1242 ord = cld.getObjectReferenceDescriptorByName(segment);
1243 if (ord == null)
1244 {
1245 // look for 1:n or m:n Relationship
1246 ord = cld.getCollectionDescriptorByName(segment);
1247 }
1248
1249 if (ord != null)
1250 {
1251 // BRJ : look for hints for the processed segment
1252 // ie: ref pointng to ClassA and ref.ref pointing to ClassC
1253 List hintClasses = pathHints != null ? (List) pathHints.get(processedSegment.toString()) : null;
1254 if (hintClasses != null && hintClasses.get(0) != null)
1255 {
1256 itemClass = (Class) hintClasses.get(0);
1257 }
1258 else
1259 {
1260 itemClass = ord.getItemClass();
1261 }
1262
1263 cld = cld.getRepository().getDescriptorFor(itemClass);
1264 result.add(ord);
1265 }
1266 else
1267 {
1268 // look for Field
1269 fld = cld.getFieldDescriptorByName(segment);
1270 if (fld != null)
1271 {
1272 result.add(fld);
1273 }
1274 }
1275 }
1276
1277 return result;
1278 }
1279
1280 /**
1281 * returns the zero argument constructor for the class represented by this class descriptor
1282 * or null if a zero argument constructor does not exist. If the zero argument constructor
1283 * for this class is not public it is made accessible before being returned.
1284 */
1285 public Constructor getZeroArgumentConstructor()
1286 {
1287 if (zeroArgumentConstructor == null && !alreadyLookedupZeroArguments)
1288 {
1289 try
1290 {
1291 zeroArgumentConstructor = getClassOfObject().getConstructor(NO_PARAMS);
1292 }
1293 catch (NoSuchMethodException e)
1294 {
1295 //no public zero argument constructor available let's try for a private/protected one
1296 try
1297 {
1298 zeroArgumentConstructor = getClassOfObject().getDeclaredConstructor(NO_PARAMS);
1299
1300 //we found one, now let's make it accessible
1301 zeroArgumentConstructor.setAccessible(true);
1302 }
1303 catch (NoSuchMethodException e2)
1304 {
1305 //out of options, log the fact and let the method return null
1306 LoggerFactory.getDefaultLogger().warn(
1307 this.getClass().getName()
1308 + ": "
1309 + "No zero argument constructor defined for "
1310 + this.getClassOfObject());
1311 }
1312 }
1313
1314 alreadyLookedupZeroArguments = true;
1315 }
1316
1317 return zeroArgumentConstructor;
1318 }
1319
1320 /*
1321 * @see XmlCapable#toXML()
1322 */
1323 public String toXML()
1324 {
1325 RepositoryTags tags = RepositoryTags.getInstance();
1326 String eol = System.getProperty("line.separator");
1327
1328 // comment on class
1329 StringBuffer result = new StringBuffer(1024);
1330 result.append( eol);
1331 result.append( " <!-- Mapping for Class ");
1332 result.append( this.getClassNameOfObject());
1333 result.append( " -->");
1334 result.append( eol );
1335
1336 // opening tag and attributes
1337 result.append( " ");
1338 result.append( tags.getOpeningTagNonClosingById(CLASS_DESCRIPTOR));
1339 result.append( eol );
1340
1341 // class
1342 result.append( " ");
1343 result.append( tags.getAttribute(CLASS_NAME, this.getClassNameOfObject()));
1344 result.append( eol );
1345
1346 // isolation level is optional
1347 if (null != getRepository())
1348 {
1349 if (getIsolationLevel() != this.getRepository().getDefaultIsolationLevel())
1350 {
1351 result.append( " ");
1352 result.append( tags.getAttribute(ISOLATION_LEVEL, this.isolationLevelXml()) );
1353 result.append( eol );
1354 }
1355 }
1356
1357 Class theProxyClass = null;
1358 try
1359 {
1360 theProxyClass = this.getProxyClass();
1361 }
1362 catch (Throwable t)
1363 {
1364 // Ignore this exception, just try to get the Class object of the
1365 // proxy class in order to be able to decide, whether the class
1366 // is a dynamic proxy or not.
1367 }
1368
1369 // proxy is optional
1370 if (theProxyClass != null)
1371 {
1372 if (isDynamicProxy()) // tomdz: What about VirtualProxy ?
1373 {
1374 result.append( " ");
1375 result.append( tags.getAttribute(CLASS_PROXY, DYNAMIC_STR));
1376 result.append( eol );
1377 }
1378 else
1379 {
1380 result.append( " ");
1381 result.append( tags.getAttribute(CLASS_PROXY, this.getProxyClassName()));
1382 result.append( eol );
1383 }
1384 result.append( " ");
1385 result.append( tags.getAttribute(PROXY_PREFETCHING_LIMIT, "" + this.getProxyPrefetchingLimit()));
1386 result.append( eol );
1387 }
1388
1389 // schema is optional
1390 if (this.getSchema() != null)
1391 {
1392 result.append( " ");
1393 result.append( tags.getAttribute(SCHEMA_NAME, this.getSchema()));
1394 result.append( eol );
1395 }
1396
1397 // table name
1398 if (this.getTableName() != null)
1399 {
1400 result.append(" ");
1401 result.append( tags.getAttribute(TABLE_NAME, this.getTableName()));
1402 result.append( eol );
1403 }
1404
1405 // rowreader is optional
1406 if (this.getRowReaderClassName() != null)
1407 {
1408 result.append( " ");
1409 result.append( tags.getAttribute(ROW_READER, this.getRowReaderClassName()));
1410 result.append( eol );
1411 }
1412
1413 //accept-locks is optional, enabled by default
1414 if (!this.acceptLocks)
1415 {
1416 result.append( " ");
1417 result.append( tags.getAttribute(ACCEPT_LOCKS, "false"));
1418 result.append( eol );
1419 }
1420 // sequence manager attribute not yet implemented
1421
1422 // initialization method is optional
1423 if (this.getInitializationMethod() != null)
1424 {
1425 result.append( " ");
1426 result.append( tags.getAttribute(INITIALIZATION_METHOD, this.getInitializationMethod().getName()));
1427 result.append( eol );
1428 }
1429
1430 // factory class is optional
1431 if (this.getFactoryClass() != null)
1432 {
1433 result.append( " ");
1434 result.append( tags.getAttribute(FACTORY_CLASS, this.getFactoryClass().getName()) );
1435 result.append( eol );
1436 }
1437
1438 // factory method is optional
1439 if (this.getFactoryMethod() != null)
1440 {
1441 result.append( " ");
1442 result.append( tags.getAttribute(FACTORY_METHOD, this.getFactoryMethod().getName()) );
1443 result.append( eol );
1444 }
1445
1446 //reference refresh is optional, disabled by default
1447 if (isAlwaysRefresh())
1448 {
1449 result.append( " ");
1450 result.append( tags.getAttribute(REFRESH, "true"));
1451 result.append( eol );
1452 }
1453
1454 result.append( " >");
1455 result.append( eol );
1456
1457 // end of attributes
1458
1459 // begin of elements
1460 if (isInterface())
1461 {
1462 // extent-class
1463 for (int i = 0; i < getExtentClassNames().size(); i++)
1464 {
1465 result.append( " ");
1466 result.append( tags.getOpeningTagNonClosingById(CLASS_EXTENT));
1467 result.append( " " );
1468 result.append( tags.getAttribute(CLASS_REF, getExtentClassNames().get(i).toString()) );
1469 result.append( " />");
1470 result.append( eol );
1471 }
1472 }
1473 else
1474 {
1475 // class extent is optional
1476 if (isExtent())
1477 {
1478 for (int i = 0; i < getExtentClassNames().size(); i++)
1479 {
1480 result.append( " ");
1481 result.append( tags.getOpeningTagNonClosingById(CLASS_EXTENT));
1482 result.append( " " );
1483 result.append( tags.getAttribute(CLASS_REF, getExtentClassNames().get(i).toString()) );
1484 result.append( " />");
1485 result.append( eol );
1486 }
1487 }
1488
1489 // write all FieldDescriptors
1490 FieldDescriptor[] fields = getFieldDescriptions();
1491 for (int i = 0; i < fields.length; i++)
1492 {
1493 result.append( fields[i].toXML() );
1494 }
1495
1496 // write optional ReferenceDescriptors
1497 Vector refs = getObjectReferenceDescriptors();
1498 for (int i = 0; i < refs.size(); i++)
1499 {
1500 result.append( ((ObjectReferenceDescriptor) refs.get(i)).toXML() );
1501 }
1502
1503 // write optional CollectionDescriptors
1504 Vector cols = getCollectionDescriptors();
1505 for (int i = 0; i < cols.size(); i++)
1506 {
1507 result.append( ((CollectionDescriptor) cols.get(i)).toXML() );
1508 }
1509
1510 // write optional IndexDescriptors
1511 for (int i = 0; i < indexes.size(); i++)
1512 {
1513 IndexDescriptor indexDescriptor = (IndexDescriptor) indexes.elementAt(i);
1514 result.append( indexDescriptor.toXML() );
1515 }
1516
1517 // Write out the procedures
1518 if (this.getInsertProcedure() != null)
1519 {
1520 result.append( this.getInsertProcedure().toXML() );
1521 }
1522 if (this.getUpdateProcedure() != null)
1523 {
1524 result.append( this.getUpdateProcedure().toXML() );
1525 }
1526 if (this.getDeleteProcedure() != null)
1527 {
1528 result.append( this.getDeleteProcedure().toXML() );
1529 }
1530 }
1531 result.append( " ");
1532 result.append( tags.getClosingTagById(CLASS_DESCRIPTOR) );
1533 return result.toString();
1534 }
1535
1536 private String isolationLevelXml()
1537 {
1538 switch (this.getIsolationLevel())
1539 {
1540 case (IL_OPTIMISTIC) :
1541 {
1542 return LITERAL_IL_OPTIMISTIC;
1543 }
1544 case (IL_READ_COMMITTED) :
1545 {
1546 return LITERAL_IL_READ_COMMITTED;
1547 }
1548 case (IL_READ_UNCOMMITTED) :
1549 {
1550 return LITERAL_IL_READ_UNCOMMITTED;
1551 }
1552 case (IL_REPEATABLE_READ) :
1553 {
1554 return LITERAL_IL_REPEATABLE_READ;
1555 }
1556 case (IL_SERIALIZABLE) :
1557 {
1558 return LITERAL_IL_SERIALIZABLE;
1559 }
1560 default :
1561 {
1562 return LITERAL_IL_READ_UNCOMMITTED;
1563 }
1564 }
1565 }
1566 /*
1567 arminw:
1568 TODO: this feature doesn't work, so remove this in future
1569 */
1570 /**
1571 * Set name of the super class.
1572 */
1573 public void setSuperClass(String classname)
1574 {
1575 this.superClass = classname;
1576 }
1577
1578 /**
1579 * Return the super class or <code>null</code>
1580 * if not declared in repository file.
1581 */
1582 public String getSuperClass()
1583 {
1584 return superClass;
1585 }
1586
1587 /**
1588 * TODO drop this method?
1589 */
1590 public void setSuperClassFieldRef(int fieldId)
1591 {
1592 this.superClassFieldRef = fieldId;
1593 }
1594
1595 /**
1596 * TODO drop this method?
1597 */
1598 public int getSuperClassFieldRef()
1599 {
1600 return superClassFieldRef;
1601 }
1602
1603 /**
1604 * Return true, if the described class is
1605 * an interface.
1606 */
1607 public boolean isInterface()
1608 {
1609 return m_isInterface;
1610 }
1611
1612 /**
1613 * Set <code>true</code> if described class is
1614 * a interface.
1615 */
1616 public void setIsInterface(boolean newIsInterface)
1617 {
1618 m_isInterface = newIsInterface;
1619 }
1620
1621 /**
1622 * @return boolean true if the mapped class is abstract
1623 */
1624 public boolean isAbstract()
1625 {
1626 return isAbstract;
1627 }
1628
1629 /**
1630 * Returns acceptLocks.
1631 * @return boolean
1632 */
1633 public boolean isAcceptLocks()
1634 {
1635 return acceptLocks;
1636 }
1637
1638 /**
1639 * Sets acceptLocks.
1640 * @param acceptLocks The m_acceptLocks to set
1641 */
1642 public void setAcceptLocks(boolean acceptLocks)
1643 {
1644 this.acceptLocks = acceptLocks;
1645 }
1646
1647 /**
1648 * Gets the IndexDescriptors used for DDL generation.
1649 */
1650 public Vector getIndexes()
1651 {
1652 return indexes;
1653 }
1654
1655 /**
1656 * Sets the IndexDescriptors used for DDL generation.
1657 */
1658 public void setIndexes(Vector indexes)
1659 {
1660 this.indexes = indexes;
1661 }
1662
1663 /**
1664 * Gets the repository.
1665 * @return Returns a DescriptorRepository
1666 */
1667 public DescriptorRepository getRepository()
1668 {
1669 return m_repository;
1670 }
1671
1672 /**
1673 * Sets the repository.
1674 * @param repository The repository to set
1675 */
1676 public void setRepository(DescriptorRepository repository)
1677 {
1678 m_repository = repository;
1679 }
1680
1681 /**
1682 * returns the transaction isolation level to be used for this class. Used only in the ODMG server
1683 */
1684 public int getIsolationLevel()
1685 {
1686 return m_IsolationLevel;
1687 }
1688
1689 /**
1690 * Method declaration
1691 * @param isoLevel
1692 */
1693 public void setIsolationLevel(int isoLevel)
1694 {
1695 m_IsolationLevel = isoLevel;
1696 }
1697
1698 /**
1699 * Method declaration
1700 * @return table name
1701 */
1702 private String getTableName()
1703 {
1704 return m_TableName;
1705 }
1706
1707 /**
1708 * Method declaration
1709 * @param str
1710 */
1711 public void setTableName(String str)
1712 {
1713 m_TableName = str;
1714 }
1715
1716 /**
1717 * Answer Table name including schema BRJ
1718 */
1719 public String getFullTableName()
1720 {
1721 if (getSchema() != null)
1722 return getSchema() + "." + getTableName();
1723 else
1724 return getTableName();
1725 }
1726
1727 /**
1728 * Gets the schema.
1729 * @return Returns a String
1730 */
1731 public String getSchema()
1732 {
1733 return schema;
1734 }
1735
1736 /**
1737 * Sets the schema.
1738 * @param schema The schema to set
1739 */
1740 public void setSchema(String schema)
1741 {
1742 this.schema = schema;
1743 }
1744
1745 /**
1746 * Return a string representation of this class.
1747 */
1748 public String toString()
1749 {
1750 ToStringBuilder buf = new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE);
1751 return buf
1752 .append("classNameOfObject", getClassNameOfObject())
1753 .append("tableName", getTableName())
1754 .append("schema", getSchema())
1755 .append("isInterface", isInterface())
1756 .append("extendClassNames", getExtentClassNames().toString())
1757 //.append("[fieldDescriptions:")
1758 .append(getFieldDescriptions())
1759 //.append("]")
1760 .toString();
1761 }
1762
1763 /**
1764 * sets the initialization method for this descriptor
1765 */
1766 private synchronized void setInitializationMethod(Method newMethod)
1767 {
1768 if (newMethod != null)
1769 {
1770 // make sure it's a no argument method
1771 if (newMethod.getParameterTypes().length > 0)
1772 {
1773 throw new MetadataException(
1774 "Initialization methods must be zero argument methods: "
1775 + newMethod.getClass().getName()
1776 + "."
1777 + newMethod.getName());
1778 }
1779
1780 // make it accessible if it's not already
1781 if (!newMethod.isAccessible())
1782 {
1783 newMethod.setAccessible(true);
1784 }
1785 }
1786 this.initializationMethod = newMethod;
1787 }
1788
1789 /**
1790 * sets the initialization method for this descriptor by name
1791 */
1792 public synchronized void setInitializationMethod(String newMethodName)
1793 {
1794 Method newMethod = null;
1795 if (newMethodName != null)
1796 {
1797 initializationMethodName = newMethodName;
1798 try
1799 {
1800 // see if we have a publicly accessible method by the name
1801 newMethod = getClassOfObject().getMethod(newMethodName, NO_PARAMS);
1802 }
1803 catch (NoSuchMethodException e)
1804 {
1805 try
1806 {
1807 // no publicly accessible method, see if there is a private/protected one
1808 newMethod = getClassOfObject().getDeclaredMethod(newMethodName, NO_PARAMS);
1809 }
1810 catch (NoSuchMethodException e2)
1811 {
1812 // there is no such method available
1813 throw new MetadataException(
1814 "Invalid initialization method, there is not"
1815 + " a zero argument method named "
1816 + newMethodName
1817 + " on class "
1818 + getClassOfObject().getName()
1819 + ".");
1820 }
1821 }
1822 }
1823 setInitializationMethod(newMethod);
1824 }
1825
1826 /**
1827 * Returns the initialization method for this descriptor or null if no
1828 * initialization method is defined.
1829 */
1830 public synchronized Method getInitializationMethod()
1831 {
1832 if(this.initializationMethod == null)
1833 {
1834 setInitializationMethod(initializationMethodName);
1835 }
1836 return initializationMethod;
1837 }
1838
1839 /**
1840 * if true instances of this class are always refreshed
1841 * even if they are already in the cache.
1842 * @return boolean
1843 */
1844 public boolean isAlwaysRefresh()
1845 {
1846 return alwaysRefresh;
1847 }
1848
1849 /**
1850 * Sets the alwaysRefresh parameter.
1851 * @param alwaysRefresh The value to set
1852 */
1853 public void setAlwaysRefresh(boolean alwaysRefresh)
1854 {
1855 this.alwaysRefresh = alwaysRefresh;
1856 }
1857
1858 public int getProxyPrefetchingLimit()
1859 {
1860 return m_ProxyPrefetchingLimit;
1861 }
1862
1863 public void setProxyPrefetchingLimit(int proxyPrefetchingLimit)
1864 {
1865 m_ProxyPrefetchingLimit = proxyPrefetchingLimit;
1866 }
1867
1868 /**
1869 * Return factory class.
1870 */
1871 public synchronized Class getFactoryClass()
1872 {
1873 return this.factoryClass;
1874 }
1875
1876 /**
1877 * Return factory method.
1878 */
1879 public synchronized Method getFactoryMethod()
1880 {
1881 if(factoryMethod == null && factoryMethodName != null)
1882 {
1883 setFactoryMethod(factoryMethodName);
1884 }
1885 return this.factoryMethod;
1886 }
1887
1888 /**
1889 * Set the object factory for class described by this
1890 * descriptor.
1891 * @see #setFactoryMethod
1892 */
1893 public synchronized void setFactoryClass(Class newClass)
1894 {
1895 this.factoryClass = newClass;
1896 }
1897
1898 /**
1899 * @see #setFactoryClass
1900 */
1901 public void setFactoryClass(String newClass)
1902 {
1903 if (null != newClass)
1904 {
1905 try
1906 {
1907 Class clazz = ClassHelper.getClass(newClass);
1908 setFactoryClass(clazz);
1909 }
1910 catch (Exception e)
1911 {
1912 // there is no such method available
1913 throw new MetadataException("Invalid factory class: " + newClass + ".");
1914 }
1915 }
1916 else
1917 {
1918 setFactoryClass((Class) null);
1919 }
1920 }
1921
1922 /**
1923 * Specify the method to instantiate objects
1924 * represented by this descriptor.
1925 * @see #setFactoryClass
1926 */
1927 private synchronized void setFactoryMethod(Method newMethod)
1928 {
1929 if (newMethod != null)
1930 {
1931 // make sure it's a no argument method
1932 if (newMethod.getParameterTypes().length > 0)
1933 {
1934 throw new MetadataException(
1935 "Factory methods must be zero argument methods: "
1936 + newMethod.getClass().getName()
1937 + "."
1938 + newMethod.getName());
1939 }
1940
1941 // make it accessible if it's not already
1942 if (!newMethod.isAccessible())
1943 {
1944 newMethod.setAccessible(true);
1945 }
1946 }
1947
1948 this.factoryMethod = newMethod;
1949 }
1950
1951 /**
1952 * sets the initialization method for this descriptor by name
1953 */
1954 public synchronized void setFactoryMethod(String factoryMethodName)
1955 {
1956 Method newMethod = null;
1957 this.factoryMethodName = factoryMethodName;
1958
1959 if (factoryMethodName != null)
1960 {
1961 try
1962 {
1963 // see if we have a publicly accessible method by the name
1964 newMethod = getFactoryClass().getMethod(factoryMethodName, NO_PARAMS);
1965 }
1966 catch (NoSuchMethodException e)
1967 {
1968 try
1969 {
1970 // no publicly accessible method, see if there is a private/protected one
1971 newMethod = getFactoryClass().getDeclaredMethod(factoryMethodName, NO_PARAMS);
1972 }
1973 catch (NoSuchMethodException e2)
1974 {
1975 // there is no such method available
1976 throw new MetadataException(
1977 "Invalid factory method, there is not"
1978 + " a zero argument method named "
1979 + factoryMethodName
1980 + " on class "
1981 + getFactoryClass().getName()
1982 + ".");
1983 }
1984 }
1985 }
1986 setFactoryMethod(newMethod);
1987 }
1988
1989 //---------------------------------------------------------------
1990 /**
1991 * Change the descriptor for the insert procedure/function.
1992 *
1993 * @param newValue the new value.
1994 */
1995 public void setInsertProcedure(InsertProcedureDescriptor newValue)
1996 {
1997 this.insertProcedure = newValue;
1998 }
1999
2000 //---------------------------------------------------------------
2001 /**
2002 * Retrieve the descriptor for the insert procedure/function.
2003 *
2004 * @return The current value
2005 */
2006 public InsertProcedureDescriptor getInsertProcedure()
2007 {
2008 return this.insertProcedure;
2009 }
2010
2011 //---------------------------------------------------------------
2012 /**
2013 * Change the descriptor for the update procedure/function.
2014 *
2015 * @param newValue the new value.
2016 */
2017 public void setUpdateProcedure(UpdateProcedureDescriptor newValue)
2018 {
2019 this.updateProcedure = newValue;
2020 }
2021
2022 //---------------------------------------------------------------
2023 /**
2024 * Retrieve the descriptor for the update procedure/function.
2025 *
2026 * @return The current value
2027 */
2028 public UpdateProcedureDescriptor getUpdateProcedure()
2029 {
2030 return this.updateProcedure;
2031 }
2032
2033 //---------------------------------------------------------------
2034 /**
2035 * Change the descriptor for the delete procedure/function.
2036 *
2037 * @param newValue the new value.
2038 */
2039 public void setDeleteProcedure(DeleteProcedureDescriptor newValue)
2040 {
2041 this.deleteProcedure = newValue;
2042 }
2043
2044 //---------------------------------------------------------------
2045 /**
2046 * Retrieve the descriptor for the delete procedure/function.
2047 *
2048 * @return The current value
2049 */
2050 public DeleteProcedureDescriptor getDeleteProcedure()
2051 {
2052 return this.deleteProcedure;
2053 }
2054
2055 /**
2056 * Returns the ojbConcreteClass field or <code>null</code> if none defined.
2057 */
2058 public FieldDescriptor getOjbConcreteClassField()
2059 {
2060 // if not checked before
2061 if(!ojbConcreteFieldCheckDone)
2062 {
2063 ojbConcreteClassField = getFieldDescriptorByName(OJB_CONCRETE_CLASS);
2064 ojbConcreteFieldCheckDone = true;
2065 }
2066 return ojbConcreteClassField;
2067 }
2068
2069 public StatementsForClassIF getStatementsForClass(ConnectionManagerIF conMan)
2070 {
2071 if(statementsForClass == null)
2072 {
2073 statementsForClass = StatementsForClassFactory.getInstance().
2074 getStatementsForClass(conMan.getConnectionDescriptor(), this);
2075 }
2076 return statementsForClass;
2077 }
2078
2079
2080 /**
2081 * Optional! Set the {@link org.apache.ojb.broker.metadata.fieldaccess.PersistentField}
2082 * implementation class used by this class.
2083 * @param pfClassName The full qualified class name of the
2084 * {@link org.apache.ojb.broker.metadata.fieldaccess.PersistentField}.
2085 */
2086 public void setPersistentFieldClassName(String pfClassName)
2087 {
2088 this.persistentFieldClassName = pfClassName;
2089 }
2090
2091
2092 /**
2093 * Get the used {@link org.apache.ojb.broker.metadata.fieldaccess.PersistentField}
2094 * implementation name.
2095 */
2096 public String getPersistentFieldClassName()
2097 {
2098 return persistentFieldClassName;
2099 }
2100
2101 /**
2102 * Returns <em>true</em> if an DB Identity column field based sequence
2103 * manager was used. In that cases we will find an autoincrement field with
2104 * read-only access and return true, otherwise false.
2105 */
2106 public boolean useIdentityColumnField()
2107 {
2108 if(useIdentityColumn == 0)
2109 {
2110 useIdentityColumn = -1;
2111 FieldDescriptor[] pkFields = getPkFields();
2112 for (int i = 0; i < pkFields.length; i++)
2113 {
2114 // to find the identity column we search for a autoincrement
2115 // read-only field
2116 if (pkFields[i].isAutoIncrement() && pkFields[i].isAccessReadOnly())
2117 {
2118 useIdentityColumn = 1;
2119 break;
2120 }
2121 }
2122 }
2123 return useIdentityColumn == 1;
2124 }
2125
2126 /**
2127 * Returns all defined {@link ObjectReferenceDescriptor}.
2128 *
2129 * @param withInherited If <em>true</em> inherited super class references will be included.
2130 */
2131 public List getObjectReferenceDescriptors(boolean withInherited)
2132 {
2133 if(withInherited && getSuperClassDescriptor() != null)
2134 {
2135 List result = new ArrayList(m_ObjectReferenceDescriptors);
2136 result.addAll(getSuperClassDescriptor().getObjectReferenceDescriptors(true));
2137 return result;
2138 }
2139 else
2140 {
2141 return m_ObjectReferenceDescriptors;
2142 }
2143 }
2144
2145 /**
2146 * Returns all defined {@link CollectionDescriptor} for
2147 * this class descriptor.
2148 *
2149 * @param withInherited If <em>true</em> inherited super class references will be included.
2150 */
2151 public List getCollectionDescriptors(boolean withInherited)
2152 {
2153 if(withInherited && getSuperClassDescriptor() != null)
2154 {
2155 List result = new ArrayList(m_CollectionDescriptors);
2156 result.addAll(getSuperClassDescriptor().getCollectionDescriptors(true));
2157 return result;
2158 }
2159 else
2160 {
2161 return m_CollectionDescriptors;
2162 }
2163 }
2164
2165 /**
2166 * Return an array of all {@link FieldDescriptor} for this represented class, if
2167 * parameter <em>withInherited</em> is <em>true</em> all inherited descriptor
2168 * of declared super classes are included.
2169 *
2170 * @param withInherited If <em>true</em> inherited super class fields will be included.
2171 */
2172 public FieldDescriptor[] getFieldDescriptor(boolean withInherited)
2173 {
2174 if(withInherited && getSuperClassDescriptor() != null)
2175 {
2176 /*
2177 arminw: only return no-PK fields, because all PK fields are declared
2178 in sub-class too.
2179 */
2180 FieldDescriptor[] superFlds = getSuperClassDescriptor().getFieldDescriptorNonPk(true);
2181 if(m_FieldDescriptions == null)
2182 {
2183 m_FieldDescriptions = new FieldDescriptor[0];
2184 }
2185 FieldDescriptor[] result = new FieldDescriptor[m_FieldDescriptions.length + superFlds.length];
2186 System.arraycopy(m_FieldDescriptions, 0, result, 0, m_FieldDescriptions.length);
2187 System.arraycopy(superFlds, 0, result, m_FieldDescriptions.length, superFlds.length);
2188 // System.out.println("all fields: " + ArrayUtils.toString(result));
2189 return result;
2190 }
2191 else
2192 {
2193 return m_FieldDescriptions;
2194 }
2195 }
2196
2197 /**
2198 * Return an array of NON-PK {@link FieldDescriptor}, if parameter <em>withInherited</em>
2199 * is <em>true</em> all inherited descriptor of declared super classes are included.
2200 *
2201 * @param withInherited If <em>true</em> inherited super class fields will be included.
2202 */
2203 public FieldDescriptor[] getFieldDescriptorNonPk(boolean withInherited)
2204 {
2205 if(withInherited && getSuperClassDescriptor() != null)
2206 {
2207 FieldDescriptor[] flds = getNonPkFields();
2208 FieldDescriptor[] superFlds = getSuperClassDescriptor().getFieldDescriptorNonPk(true);
2209 FieldDescriptor[] result = new FieldDescriptor[flds.length + superFlds.length];
2210 System.arraycopy(flds, 0, result, 0, flds.length);
2211 System.arraycopy(superFlds, 0, result, flds.length, superFlds.length);
2212 return result;
2213 }
2214 else
2215 {
2216 return getNonPkFields();
2217 }
2218 }
2219
2220 /**
2221 * Returns the {@link SuperReferenceDescriptor} of this class or <em>null</em>
2222 * if none was used.
2223 *
2224 * @return The reference descriptor for the <em>super</em>-reference or <em>null</em>
2225 * if not exists.
2226 */
2227 public SuperReferenceDescriptor getSuperReference()
2228 {
2229 return (SuperReferenceDescriptor) getObjectReferenceDescriptorByName(SuperReferenceDescriptor.SUPER_FIELD_INTERNAL_NAME);
2230 }
2231 }