KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ojb > broker > metadata > ObjectReferenceDescriptor


1 package org.apache.ojb.broker.metadata;
2
3 /* Copyright 2002-2005 The Apache Software Foundation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 import java.util.Hashtable JavaDoc;
19 import java.util.Iterator JavaDoc;
20 import java.util.Vector JavaDoc;
21
22 import org.apache.commons.lang.builder.ToStringBuilder;
23 import org.apache.ojb.broker.OJBRuntimeException;
24 import org.apache.ojb.broker.PersistenceBrokerException;
25 import org.apache.ojb.broker.core.proxy.ProxyHelper;
26 import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
27
28 /**
29  * Describes a Field containing a reference to another class. Provides handling for foreign keys etc.
30  * <br>
31  * Note: Be careful when use references of this class or caching instances of this class,
32  * because instances could become invalid (see {@link MetadataManager}).
33  *
34  * @author <a HREF="mailto:thma@apache.org">Thomas Mahler<a>
35  *
36  */

37 public class ObjectReferenceDescriptor extends AttributeDescriptorBase implements XmlCapable
38 {
39     private static final long serialVersionUID = 5561562217150972131L;
40
41     public static final int CASCADE_NONE = 17;
42     public static final int CASCADE_LINK = 19;
43     public static final int CASCADE_OBJECT = 23;
44
45     private Class JavaDoc m_ClassOfItems = null;
46     private Vector JavaDoc m_ForeignKeyFields = new Vector JavaDoc();
47     private boolean m_CascadeRetrieve = true;
48     private int m_CascadeStore = CASCADE_NONE;
49     private int m_CascadeDelete = CASCADE_NONE;
50     private int m_ProxyPrefetchingLimit = 50;
51
52     private Class JavaDoc m_ProxyOfItems = null;
53     private boolean m_LookedUpProxy = false;
54     private boolean m_OtmDependent = false;
55
56     /**
57      * holds the foreign-key field descriptor array for a specified class
58      */

59     private Hashtable JavaDoc fkFieldMap = new Hashtable JavaDoc();
60     /**
61      * define loading strategy of the resulting object
62      */

63     private boolean lazy = false;
64     /**
65      * if true relationship is refreshed when owner is found in cache
66      */

67     private boolean refresh = false;
68
69     /**
70      *
71      */

72     public ObjectReferenceDescriptor(ClassDescriptor descriptor)
73     {
74         super(descriptor);
75     }
76
77     /**
78      *
79      */

80     public Class JavaDoc getItemProxyClass() throws PersistenceBrokerException
81     {
82         if (!m_LookedUpProxy)
83         {
84             m_ProxyOfItems = getClassDescriptor().getRepository().
85                                 getDescriptorFor(m_ClassOfItems).getProxyClass();
86             m_LookedUpProxy = true;
87         }
88         return m_ProxyOfItems;
89     }
90
91     /**
92      *
93      */

94     public FieldDescriptor[] getForeignKeyFieldDescriptors(ClassDescriptor cld)
95     {
96         FieldDescriptor[] foreignKeyFieldDescriptors;
97         if ((foreignKeyFieldDescriptors = (FieldDescriptor[]) fkFieldMap.get(cld)) == null)
98         {
99             // 1. collect vector of indices of Fk-Fields
100
Vector JavaDoc v = getForeignKeyFields();
101             // 2. get FieldDescriptor for each index from Class-descriptor
102
// 2A. In a many-to-many relationship foreignkeyfields vector will be null.
103
if (v != null)
104             {
105                 Vector JavaDoc ret;
106                 if (cld.isInterface())
107                 {
108                     //exchange interface class descriptor with first concrete
109
//class
110
Vector JavaDoc extents = cld.getExtentClasses();
111                     Class JavaDoc firstConcreteClass = (Class JavaDoc) extents.get(0);
112                     cld = getClassDescriptor().getRepository().getDescriptorFor(firstConcreteClass);
113                 }
114                 ret = new Vector JavaDoc();
115
116                 Iterator JavaDoc iter = v.iterator();
117                 while (iter.hasNext())
118                 {
119                     Object JavaDoc fk = iter.next();
120                     FieldDescriptor fkfd = null;
121                     /*
122                     OJB-55
123                     it's possible that the FK field is declared in the super classes of this object,
124                     so we can search for a valid field in super class-descriptor
125                     */

126                     ClassDescriptor tmp = cld;
127                     while(tmp != null)
128                     {
129                         if (fk instanceof Integer JavaDoc)
130                         {
131                             Integer JavaDoc index = (Integer JavaDoc) fk;
132                             fkfd = cld.getFieldDescriptorByIndex(index.intValue());
133                         }
134                         else
135                         {
136                             fkfd = tmp.getFieldDescriptorByName((String JavaDoc) fk);
137                         }
138                         if(fkfd != null)
139                         {
140                             break;
141                         }
142                         else
143                         {
144                             tmp = tmp.getSuperClassDescriptor();
145                         }
146                     }
147
148                     if (fkfd == null)
149                     {
150                         throw new OJBRuntimeException("Incorrect or not found field reference name '"
151                                 + fk + "' in descriptor " + this + " for class-descriptor '"
152                                 + (cld != null ? cld.getClassNameOfObject() + "'" : "'null'"));
153                     }
154                     ret.add(fkfd);
155                 }
156                 foreignKeyFieldDescriptors = (FieldDescriptor[]) ret.toArray(new FieldDescriptor[ret.size()]);
157                 fkFieldMap.put(cld, foreignKeyFieldDescriptors);
158             }
159         }
160         return foreignKeyFieldDescriptors;
161     }
162
163     /**
164      * Returns an Object array of all FK field values of the specified object.
165      * If the specified object is an unmaterialized Proxy, it will be materialized
166      * to read the FK values.
167      *
168      * @throws MetadataException if an error occours while accessing ForeingKey values on obj
169      */

170     public Object JavaDoc[] getForeignKeyValues(Object JavaDoc obj, ClassDescriptor mif)
171             throws PersistenceBrokerException
172     {
173         FieldDescriptor[] fks = getForeignKeyFieldDescriptors(mif);
174         // materialize object only if FK fields are declared
175
if(fks.length > 0) obj = ProxyHelper.getRealObject(obj);
176         Object JavaDoc[] result = new Object JavaDoc[fks.length];
177         for (int i = 0; i < result.length; i++)
178         {
179             FieldDescriptor fmd = fks[i];
180             PersistentField f = fmd.getPersistentField();
181
182             // BRJ: do NOT convert.
183
// conversion is done when binding the sql-statement
184
//
185
// FieldConversion fc = fmd.getFieldConversion();
186
// Object val = fc.javaToSql(f.get(obj));
187

188             result[i] = f.get(obj);
189         }
190         return result;
191     }
192
193     /**
194      *
195      */

196     public Class JavaDoc getItemClass()
197     {
198         return m_ClassOfItems;
199     }
200
201     /**
202      * @return the fully qualified name of the item class for this descriptor.
203      */

204     public String JavaDoc getItemClassName()
205     {
206         return this.m_ClassOfItems != null ? this.m_ClassOfItems.getName() : null;
207     }
208
209     /**
210      * sets the item class
211      * @param c the items class object
212      */

213     public void setItemClass(Class JavaDoc c)
214     {
215         m_ClassOfItems = c;
216     }
217
218     /**
219      *
220      */

221     public Vector JavaDoc getForeignKeyFields()
222     {
223         return m_ForeignKeyFields;
224     }
225
226     /**
227      *
228      */

229     public void setForeignKeyFields(Vector JavaDoc vec)
230     {
231         m_ForeignKeyFields = vec;
232     }
233
234     /**
235      * add a foreign key field ID
236      */

237     public void addForeignKeyField(int newId)
238     {
239         if (m_ForeignKeyFields == null)
240         {
241             m_ForeignKeyFields = new Vector JavaDoc();
242         }
243         m_ForeignKeyFields.add(new Integer JavaDoc(newId));
244     }
245
246     /**
247      * add a foreign key field
248      */

249     public void addForeignKeyField(String JavaDoc newField)
250     {
251         if (m_ForeignKeyFields == null)
252         {
253             m_ForeignKeyFields = new Vector JavaDoc();
254         }
255         m_ForeignKeyFields.add(newField);
256     }
257
258     /**
259      * Gets the refresh.
260      * @return Returns a boolean
261      */

262     public boolean isRefresh()
263     {
264         return refresh;
265     }
266
267     /**
268      * Sets the refresh.
269      * @param refresh The refresh to set
270      */

271     public void setRefresh(boolean refresh)
272     {
273         this.refresh = refresh;
274     }
275
276     /**
277      * Gets the lazy.
278      * @return Returns a boolean
279      */

280     public boolean isLazy()
281     {
282         return lazy;
283     }
284
285     /**
286      * Sets the lazy.
287      * @param lazy The lazy to set
288      */

289     public void setLazy(boolean lazy)
290     {
291         this.lazy = lazy;
292     }
293
294     /**
295      *
296      */

297     public boolean getCascadeRetrieve()
298     {
299         return m_CascadeRetrieve;
300     }
301
302     /**
303      *
304      */

305     public void setCascadeRetrieve(boolean b)
306     {
307         m_CascadeRetrieve = b;
308     }
309
310     /**
311      *
312      */

313     public int getCascadingStore()
314     {
315         return m_CascadeStore;
316     }
317
318     /**
319      *
320      */

321     public void setCascadingStore(int cascade)
322     {
323         m_CascadeStore = cascade;
324     }
325
326     public void setCascadingStore(String JavaDoc value)
327     {
328         setCascadingStore(getCascadeStoreValue(value));
329     }
330
331     /**
332      * @deprecated use {@link #getCascadingStore} instead.
333      */

334     public boolean getCascadeStore()
335     {
336         return getCascadingStore() == CASCADE_OBJECT;
337     }
338
339     /**
340      * @deprecated use {@link #setCascadingStore(int)} instead.
341      */

342     public void setCascadeStore(boolean cascade)
343     {
344         if(cascade)
345         {
346             setCascadingStore(getCascadeStoreValue("true"));
347         }
348         else
349         {
350             setCascadingStore(getCascadeStoreValue("false"));
351         }
352     }
353
354     /**
355      *
356      */

357     public int getCascadingDelete()
358     {
359         return m_CascadeDelete;
360     }
361
362     /**
363      *
364      */

365     public void setCascadingDelete(int cascade)
366     {
367         m_CascadeDelete = cascade;
368     }
369
370     public void setCascadingDelete(String JavaDoc value)
371     {
372         setCascadingDelete(getCascadeDeleteValue(value));
373     }
374
375     /**
376      * @deprecated use {@link #getCascadingDelete} instead.
377      */

378     public boolean getCascadeDelete()
379     {
380         return getCascadingDelete() == CASCADE_OBJECT;
381     }
382
383     /**
384      * @deprecated use {@link #setCascadingDelete(int)}
385      */

386     public void setCascadeDelete(boolean cascade)
387     {
388         if(cascade)
389         {
390             setCascadingDelete(getCascadeDeleteValue("true"));
391         }
392         else
393         {
394             setCascadingDelete(getCascadeDeleteValue("false"));
395         }
396     }
397
398     protected int getCascadeStoreValue(String JavaDoc cascade)
399     {
400         if(cascade.equalsIgnoreCase(RepositoryTags.CASCADE_NONE_STR))
401         {
402             return CASCADE_NONE;
403         }
404         else if(cascade.equalsIgnoreCase(RepositoryTags.CASCADE_LINK_STR))
405         {
406             return CASCADE_LINK;
407         }
408         else if(cascade.equalsIgnoreCase(RepositoryTags.CASCADE_OBJECT_STR))
409         {
410             return CASCADE_OBJECT;
411         }
412         else if(cascade.equalsIgnoreCase("true"))
413         {
414             return CASCADE_OBJECT;
415         }
416         else if(cascade.equalsIgnoreCase("false"))
417         {
418             /*
419             in old implementation the FK values of an 1:1 relation are always
420             set. Thus we choose 'link' instead of 'none'
421             The CollectionDescriptor should override this behaviour.
422             */

423             return CASCADE_LINK;
424         }
425         else
426         {
427             throw new OJBRuntimeException("Invalid value! Given value was '" + cascade
428                     + "', expected values are: " + RepositoryTags.CASCADE_NONE_STR + ", "
429                     + RepositoryTags.CASCADE_LINK_STR + ", " + RepositoryTags.CASCADE_OBJECT_STR
430                     + " ('false' and 'true' are deprecated but still valid)");
431         }
432     }
433
434     protected int getCascadeDeleteValue(String JavaDoc cascade)
435     {
436         if(cascade.equalsIgnoreCase(RepositoryTags.CASCADE_NONE_STR))
437         {
438             return CASCADE_NONE;
439         }
440         else if(cascade.equalsIgnoreCase(RepositoryTags.CASCADE_LINK_STR))
441         {
442             return CASCADE_LINK;
443         }
444         else if(cascade.equalsIgnoreCase(RepositoryTags.CASCADE_OBJECT_STR))
445         {
446             return CASCADE_OBJECT;
447         }
448         else if(cascade.equalsIgnoreCase("true"))
449         {
450             return CASCADE_OBJECT;
451         }
452         else if(cascade.equalsIgnoreCase("false"))
453         {
454             return CASCADE_NONE;
455         }
456         else
457         {
458             throw new OJBRuntimeException("Invalid value! Given value was '" + cascade
459                     + "', expected values are: " + RepositoryTags.CASCADE_NONE_STR + ", "
460                     + RepositoryTags.CASCADE_LINK_STR + ", " + RepositoryTags.CASCADE_OBJECT_STR
461                     + " ('false' and 'true' are deprecated but still valid)");
462         }
463     }
464
465     public String JavaDoc getCascadeAsString(int cascade)
466     {
467         String JavaDoc result = null;
468         switch(cascade)
469         {
470             case CASCADE_NONE:
471                 result = RepositoryTags.CASCADE_NONE_STR;
472                 break;
473             case CASCADE_LINK:
474                 result = RepositoryTags.CASCADE_LINK_STR;
475                 break;
476             case CASCADE_OBJECT:
477                 result = RepositoryTags.CASCADE_OBJECT_STR;
478                 break;
479         }
480         return result;
481     }
482
483     public int getProxyPrefetchingLimit()
484     {
485         return m_ProxyPrefetchingLimit;
486     }
487
488     public void setProxyPrefetchingLimit(int proxyPrefetchingLimit)
489     {
490         m_ProxyPrefetchingLimit = proxyPrefetchingLimit;
491     }
492
493     /**
494      *
495      */

496     public boolean getOtmDependent()
497     {
498         return m_OtmDependent;
499     }
500
501     /**
502      *
503      */

504     public void setOtmDependent(boolean b)
505     {
506         m_OtmDependent = b;
507     }
508
509     /**
510      * Returns <code>true</code> if this descriptor was used to
511      * describe a reference to a super class of an object.
512      *
513      * @return always <code>false</code> for this instance.
514      */

515     public boolean isSuperReferenceDescriptor()
516     {
517         return false;
518     }
519
520     /**
521      * Returns <em>true</em> if a foreign key constraint to the referenced object is
522      * declared, else <em>false</em> is returned.
523      */

524     public boolean hasConstraint()
525     {
526         /*
527         arminw: Currently we don't have a ForeignKey descriptor object and
528         a official xml-element to support FK settings. As a workaround I introduce
529         a custom-attribute to handle FK settings in collection-/reference-decriptor
530         */

531         String JavaDoc result = getAttribute("constraint");
532         return result != null && result.equalsIgnoreCase("true");
533     }
534
535     /**
536      * Set a foreign key constraint flag for this reference - see {@link #hasConstraint()}
537      * @param constraint If set <em>true</em>, signals a foreign key constraint in database.
538      */

539     public void setConstraint(boolean constraint)
540     {
541         addAttribute("constraint", constraint ? "true" : "false");
542     }
543
544     public String JavaDoc toString()
545     {
546         return new ToStringBuilder(this)
547                 .append("cascade_retrieve", getCascadeRetrieve())
548                 .append("cascade_store", getCascadeAsString(m_CascadeStore))
549                 .append("cascade_delete", getCascadeAsString(m_CascadeDelete))
550                 .append("is_lazy", lazy)
551                 .append("class_of_Items", m_ClassOfItems)
552                 .toString();
553     }
554
555     /*
556      * @see XmlCapable#toXML()
557      */

558     public String JavaDoc toXML()
559     {
560         RepositoryTags tags = RepositoryTags.getInstance();
561         String JavaDoc eol = System.getProperty( "line.separator" );
562
563         // opening tag
564
StringBuffer JavaDoc result = new StringBuffer JavaDoc( 1024 );
565         result.append( " " );
566         result.append( tags.getOpeningTagNonClosingById( REFERENCE_DESCRIPTOR ) );
567         result.append( eol );
568
569         // attributes
570
// name
571
String JavaDoc name = this.getAttributeName();
572         if( name == null )
573         {
574             name = RepositoryElements.TAG_SUPER;
575         }
576         result.append( " " );
577         result.append( tags.getAttribute( FIELD_NAME, name ) );
578         result.append( eol );
579
580         // class-ref
581
result.append( " " );
582         result.append( tags.getAttribute( REFERENCED_CLASS, this.getItemClassName() ) );
583         result.append( eol );
584
585         // proxyReference is optional
586
if( isLazy() )
587         {
588             result.append( " " );
589             result.append( tags.getAttribute( PROXY_REFERENCE, "true" ) );
590             result.append( eol );
591             result.append( " " );
592             result.append( tags.getAttribute( PROXY_PREFETCHING_LIMIT, "" + this.getProxyPrefetchingLimit() ) );
593             result.append( eol );
594         }
595
596         //reference refresh is optional, disabled by default
597
if( isRefresh() )
598         {
599             result.append( " " );
600             result.append( tags.getAttribute( REFRESH, "true" ) );
601             result.append( eol );
602         }
603
604         //auto retrieve
605
result.append( " " );
606         result.append( tags.getAttribute( AUTO_RETRIEVE, "" + getCascadeRetrieve() ) );
607         result.append( eol );
608
609         //auto update
610
result.append( " " );
611         result.append( tags.getAttribute( AUTO_UPDATE, getCascadeAsString( getCascadingStore() ) ) );
612         result.append( eol );
613
614         //auto delete
615
result.append( " " );
616         result.append( tags.getAttribute( AUTO_DELETE, getCascadeAsString( getCascadingDelete() ) ) );
617         result.append( eol );
618
619         //otm-dependent is optional, disabled by default
620
if( getOtmDependent() )
621         {
622             result.append( " " );
623             result.append( tags.getAttribute( OTM_DEPENDENT, "true" ) );
624             result.append( eol );
625         }
626
627         // close opening tag
628
result.append( " >" );
629         result.append( eol );
630
631         // elements
632
// write foreignkey elements
633
for( int i = 0; i < getForeignKeyFields().size(); i++ )
634         {
635             Object JavaDoc obj = getForeignKeyFields().get( i );
636             if( obj instanceof Integer JavaDoc )
637             {
638                 String JavaDoc fkId = obj.toString();
639                 result.append( " " );
640                 result.append( tags.getOpeningTagNonClosingById( FOREIGN_KEY ) );
641                 result.append( " " );
642                 result.append( tags.getAttribute( FIELD_ID_REF, fkId ) );
643                 result.append( "/>" );
644                 result.append( eol );
645             }
646             else
647             {
648                 String JavaDoc fk = ( String JavaDoc ) obj;
649                 result.append( " " );
650                 result.append( tags.getOpeningTagNonClosingById( FOREIGN_KEY ) );
651                 result.append( " " );
652                 result.append( tags.getAttribute( FIELD_REF, fk ) );
653                 result.append( "/>" );
654                 result.append( eol );
655             }
656         }
657
658         // closing tag
659
result.append( " " );
660         result.append( tags.getClosingTagById( REFERENCE_DESCRIPTOR ) );
661         result.append( eol );
662         return result.toString();
663     }
664 }
665
Popular Tags