KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ojb > broker > core > proxy > AbstractProxyFactory


1 package org.apache.ojb.broker.core.proxy;
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.lang.reflect.Constructor JavaDoc;
19 import java.lang.reflect.InvocationTargetException JavaDoc;
20 import java.lang.reflect.Modifier JavaDoc;
21 import java.util.Collection JavaDoc;
22 import java.util.List JavaDoc;
23 import java.util.Set JavaDoc;
24
25 import org.apache.ojb.broker.Identity;
26 import org.apache.ojb.broker.ManageableCollection;
27 import org.apache.ojb.broker.PBKey;
28 import org.apache.ojb.broker.PersistenceBrokerException;
29 import org.apache.ojb.broker.metadata.MetadataException;
30 import org.apache.ojb.broker.query.Query;
31 import org.apache.ojb.broker.util.configuration.impl.OjbConfigurator;
32 import org.apache.ojb.broker.util.logging.Logger;
33 import org.apache.ojb.broker.util.logging.LoggerFactory;
34
35 /**
36  * Abstract implementation for the ProxyFactory
37  *
38  * @author andrew.clute
39  * @version $Id:
40  */

41 public abstract class AbstractProxyFactory implements ProxyFactory
42 {
43     /*
44     arminw:
45     Do we need a serializable ProxyFactory implementation? If yes, we have to fix this class.
46     TODO: ProxyFactory is declared as Serializable but Constructor class is not, but used without transient keyword.
47     */

48
49     private static Logger log = LoggerFactory.getLogger(AbstractProxyFactory.class);
50     private static transient ProxyFactory singleton;
51
52     /** The indirection handler class */
53     private Class JavaDoc _indirectionHandlerClass;
54     /** The constructor used for creating indirection handler instances (shortcut) */
55     private transient Constructor JavaDoc _indirectionHandlerConstructor;
56     /** The constructor used for creating list proxies */
57     private Constructor JavaDoc _listProxyConstructor;
58     /** The constructor used for creating set proxies */
59     private Constructor JavaDoc _setProxyConstructor;
60     /** The constructor used for creating collection proxies */
61     private Constructor JavaDoc _collectionProxyConstructor;
62
63     private static ProxyConfiguration getProxyConfiguration()
64     {
65         return (ProxyConfiguration) OjbConfigurator.getInstance().getConfigurationFor(null);
66     }
67
68     /**
69      * Returns the constructor of the indirection handler class.
70      *
71      * @return The constructor for indirection handlers
72      */

73     private synchronized Constructor JavaDoc getIndirectionHandlerConstructor()
74     {
75         if(_indirectionHandlerConstructor == null)
76         {
77             Class JavaDoc[] paramType = {PBKey.class, Identity.class};
78
79             try
80             {
81                 _indirectionHandlerConstructor = getIndirectionHandlerClass().getConstructor(paramType);
82             }
83             catch(NoSuchMethodException JavaDoc ex)
84             {
85                 throw new MetadataException("The class "
86                         + _indirectionHandlerClass.getName()
87                         + " specified for IndirectionHandlerClass"
88                         + " is required to have a public constructor with signature ("
89                         + PBKey.class.getName()
90                         + ", "
91                         + Identity.class.getName()
92                         + ").");
93             }
94         }
95         return _indirectionHandlerConstructor;
96     }
97
98     /**
99      * Returns the indirection handler class.
100      *
101      * @return The class for indirection handlers
102      */

103     public Class JavaDoc getIndirectionHandlerClass()
104     {
105         if(_indirectionHandlerClass == null)
106         {
107             setIndirectionHandlerClass(getProxyConfiguration().getIndirectionHandlerClass());
108         }
109
110         return _indirectionHandlerClass;
111     }
112
113     /**
114      * Sets the indirection handler class.
115      *
116      * @param indirectionHandlerClass The class for indirection handlers
117      */

118     public void setIndirectionHandlerClass(Class JavaDoc indirectionHandlerClass)
119     {
120         if(indirectionHandlerClass == null)
121         {
122             //throw new MetadataException("No IndirectionHandlerClass specified.");
123
/**
124              * andrew.clute
125              * Allow the default IndirectionHandler for the given ProxyFactory implementation
126              * when the parameter is not given
127              */

128             indirectionHandlerClass = getDefaultIndirectionHandlerClass();
129         }
130         if(indirectionHandlerClass.isInterface()
131                 || Modifier.isAbstract(indirectionHandlerClass.getModifiers())
132                 || !getIndirectionHandlerBaseClass().isAssignableFrom(indirectionHandlerClass))
133         {
134             throw new MetadataException("Illegal class "
135                     + indirectionHandlerClass.getName()
136                     + " specified for IndirectionHandlerClass. Must be a concrete subclass of "
137                     + getIndirectionHandlerBaseClass().getName());
138         }
139         _indirectionHandlerClass = indirectionHandlerClass;
140     }
141
142     /**
143      * Creates a new indirection handler instance.
144      *
145      * @param brokerKey The associated {@link PBKey}.
146      * @param id The subject's ids
147      * @return The new instance
148      */

149     public IndirectionHandler createIndirectionHandler(PBKey brokerKey, Identity id)
150     {
151         Object JavaDoc args[] = {brokerKey, id};
152
153         try
154         {
155             return (IndirectionHandler) getIndirectionHandlerConstructor().newInstance(args);
156         }
157         catch(InvocationTargetException JavaDoc ex)
158         {
159             throw new PersistenceBrokerException("Exception while creating a new indirection handler instance", ex);
160         }
161         catch(InstantiationException JavaDoc ex)
162         {
163             throw new PersistenceBrokerException("Exception while creating a new indirection handler instance", ex);
164         }
165         catch(IllegalAccessException JavaDoc ex)
166         {
167             throw new PersistenceBrokerException("Exception while creating a new indirection handler instance", ex);
168         }
169     }
170
171     /**
172      * Retrieves the constructor that is used by OJB to create instances of the given collection proxy
173      * class.
174      *
175      * @param proxyClass The proxy class
176      * @param baseType The required base type of the proxy class
177      * @param typeDesc The type of collection proxy
178      * @return The constructor
179      */

180     private static Constructor JavaDoc retrieveCollectionProxyConstructor(Class JavaDoc proxyClass, Class JavaDoc baseType, String JavaDoc typeDesc)
181     {
182         if(proxyClass == null)
183         {
184             throw new MetadataException("No " + typeDesc + " specified.");
185         }
186         if(proxyClass.isInterface() || Modifier.isAbstract(proxyClass.getModifiers()) || !baseType.isAssignableFrom(proxyClass))
187         {
188             throw new MetadataException("Illegal class "
189                     + proxyClass.getName()
190                     + " specified for "
191                     + typeDesc
192                     + ". Must be a concrete subclass of "
193                     + baseType.getName());
194         }
195
196         Class JavaDoc[] paramType = {PBKey.class, Class JavaDoc.class, Query.class};
197
198         try
199         {
200             return proxyClass.getConstructor(paramType);
201         }
202         catch(NoSuchMethodException JavaDoc ex)
203         {
204             throw new MetadataException("The class "
205                     + proxyClass.getName()
206                     + " specified for "
207                     + typeDesc
208                     + " is required to have a public constructor with signature ("
209                     + PBKey.class.getName()
210                     + ", "
211                     + Class JavaDoc.class.getName()
212                     + ", "
213                     + Query.class.getName()
214                     + ").");
215         }
216     }
217
218     /**
219      * Returns the list proxy class.
220      *
221      * @return The class used for list proxies
222      */

223     public Class JavaDoc getListProxyClass()
224     {
225         return getListProxyConstructor().getDeclaringClass();
226     }
227
228     /**
229      * Returns the constructor of the list proxy class.
230      *
231      * @return The constructor for list proxies
232      */

233     private Constructor JavaDoc getListProxyConstructor()
234     {
235         if(_listProxyConstructor == null)
236         {
237             setListProxyClass(getProxyConfiguration().getListProxyClass());
238         }
239         return _listProxyConstructor;
240     }
241
242     /**
243      * Dets the proxy class to use for collection classes that implement the {@link java.util.List} interface.
244      * Notes that the proxy class must implement the {@link java.util.List} interface, and have a constructor
245      * of the signature ({@link org.apache.ojb.broker.PBKey}, {@link java.lang.Class}, {@link org.apache.ojb.broker.query.Query}).
246      *
247      * @param listProxyClass The proxy class
248      */

249     public void setListProxyClass(Class JavaDoc listProxyClass)
250     {
251         _listProxyConstructor = retrieveCollectionProxyConstructor(listProxyClass, List JavaDoc.class, "ListProxyClass");
252     }
253
254     /**
255      * Returns the set proxy class.
256      *
257      * @return The class used for set proxies
258      */

259     public Class JavaDoc getSetProxyClass()
260     {
261         return getSetProxyConstructor().getDeclaringClass();
262     }
263
264     /**
265      * Returns the constructor of the set proxy class.
266      *
267      * @return The constructor for set proxies
268      */

269     private Constructor JavaDoc getSetProxyConstructor()
270     {
271         if(_setProxyConstructor == null)
272         {
273             setSetProxyClass(getProxyConfiguration().getSetProxyClass());
274         }
275         return _setProxyConstructor;
276     }
277
278     /**
279      * Dets the proxy class to use for collection classes that implement the {@link Set} interface.
280      *
281      * @param setProxyClass The proxy class
282      */

283     public void setSetProxyClass(Class JavaDoc setProxyClass)
284     {
285         _setProxyConstructor = retrieveCollectionProxyConstructor(setProxyClass, Set JavaDoc.class, "SetProxyClass");
286     }
287
288     /**
289      * Returns the collection proxy class.
290      *
291      * @return The class used for collection proxies
292      */

293     public Class JavaDoc getCollectionProxyClass()
294     {
295         return getCollectionProxyConstructor().getDeclaringClass();
296     }
297
298     /**
299      * Returns the constructor of the generic collection proxy class.
300      *
301      * @return The constructor for collection proxies
302      */

303     private Constructor JavaDoc getCollectionProxyConstructor()
304     {
305         if(_collectionProxyConstructor == null)
306         {
307             setCollectionProxyClass(getProxyConfiguration().getCollectionProxyClass());
308         }
309         return _collectionProxyConstructor;
310     }
311
312     /**
313      * Dets the proxy class to use for generic collection classes implementing the {@link java.util.Collection} interface.
314      *
315      * @param collectionProxyClass The proxy class
316      */

317     public void setCollectionProxyClass(Class JavaDoc collectionProxyClass)
318     {
319         _collectionProxyConstructor = retrieveCollectionProxyConstructor(collectionProxyClass, Collection JavaDoc.class, "CollectionProxyClass");
320         // we also require the class to be a subclass of ManageableCollection
321
if(!ManageableCollection.class.isAssignableFrom(collectionProxyClass))
322         {
323             throw new MetadataException("Illegal class "
324                     + collectionProxyClass.getName()
325                     + " specified for CollectionProxyClass. Must be a concrete subclass of "
326                     + ManageableCollection.class.getName());
327         }
328     }
329
330     /**
331      * Determines which proxy to use for the given collection class (list, set or generic collection proxy).
332      *
333      * @param collectionClass The collection class
334      * @return The constructor of the proxy class
335      */

336     private Constructor JavaDoc getCollectionProxyConstructor(Class JavaDoc collectionClass)
337     {
338         if(List JavaDoc.class.isAssignableFrom(collectionClass))
339         {
340             return getListProxyConstructor();
341         }
342         else if(Set JavaDoc.class.isAssignableFrom(collectionClass))
343         {
344             return getSetProxyConstructor();
345         }
346         else
347         {
348             return getCollectionProxyConstructor();
349         }
350     }
351
352     /**
353      * Create a Collection Proxy for a given query.
354      *
355      * @param brokerKey The key of the persistence broker
356      * @param query The query
357      * @param collectionClass The class to build the proxy for
358      * @return The collection proxy
359      */

360     public ManageableCollection createCollectionProxy(PBKey brokerKey, Query query, Class JavaDoc collectionClass)
361     {
362         Object JavaDoc args[] = {brokerKey, collectionClass, query};
363
364         try
365         {
366             return (ManageableCollection) getCollectionProxyConstructor(collectionClass).newInstance(args);
367         }
368         catch(InstantiationException JavaDoc ex)
369         {
370             throw new PersistenceBrokerException("Exception while creating a new collection proxy instance", ex);
371         }
372         catch(InvocationTargetException JavaDoc ex)
373         {
374             throw new PersistenceBrokerException("Exception while creating a new collection proxy instance", ex);
375         }
376         catch(IllegalAccessException JavaDoc ex)
377         {
378             throw new PersistenceBrokerException("Exception while creating a new collection proxy instance", ex);
379         }
380     }
381
382     /**
383      * Get the real Object
384      *
385      * @param objectOrProxy
386      * @return Object
387      */

388     public final Object JavaDoc getRealObject(Object JavaDoc objectOrProxy)
389     {
390         if(isNormalOjbProxy(objectOrProxy))
391         {
392             String JavaDoc msg;
393
394             try
395             {
396                 return getIndirectionHandler(objectOrProxy).getRealSubject();
397             }
398             catch(ClassCastException JavaDoc e)
399             {
400                 // shouldn't happen but still ...
401
msg = "The InvocationHandler for the provided Proxy was not an instance of " + IndirectionHandler.class.getName();
402                 log.error(msg);
403                 throw new PersistenceBrokerException(msg, e);
404             }
405             catch(IllegalArgumentException JavaDoc e)
406             {
407                 msg = "Could not retrieve real object for given Proxy: " + objectOrProxy;
408                 log.error(msg);
409                 throw new PersistenceBrokerException(msg, e);
410             }
411             catch(PersistenceBrokerException e)
412             {
413                 log.error("Could not retrieve real object for given Proxy: " + objectOrProxy);
414                 throw e;
415             }
416         }
417         else if(isVirtualOjbProxy(objectOrProxy))
418         {
419             try
420             {
421                 return ((VirtualProxy) objectOrProxy).getRealSubject();
422             }
423             catch(PersistenceBrokerException e)
424             {
425                 log.error("Could not retrieve real object for VirtualProxy: " + objectOrProxy);
426                 throw e;
427             }
428         }
429         else
430         {
431             return objectOrProxy;
432         }
433     }
434
435     /**
436      * Get the real Object for already materialized Handler
437      *
438      * @param objectOrProxy
439      * @return Object or null if the Handel is not materialized
440      */

441     public Object JavaDoc getRealObjectIfMaterialized(Object JavaDoc objectOrProxy)
442     {
443         if(isNormalOjbProxy(objectOrProxy))
444         {
445             String JavaDoc msg;
446
447             try
448             {
449                 IndirectionHandler handler = getIndirectionHandler(objectOrProxy);
450
451                 return handler.alreadyMaterialized() ? handler.getRealSubject() : null;
452             }
453             catch(ClassCastException JavaDoc e)
454             {
455                 // shouldn't happen but still ...
456
msg = "The InvocationHandler for the provided Proxy was not an instance of " + IndirectionHandler.class.getName();
457                 log.error(msg);
458                 throw new PersistenceBrokerException(msg, e);
459             }
460             catch(IllegalArgumentException JavaDoc e)
461             {
462                 msg = "Could not retrieve real object for given Proxy: " + objectOrProxy;
463                 log.error(msg);
464                 throw new PersistenceBrokerException(msg, e);
465             }
466             catch(PersistenceBrokerException e)
467             {
468                 log.error("Could not retrieve real object for given Proxy: " + objectOrProxy);
469                 throw e;
470             }
471         }
472         else if(isVirtualOjbProxy(objectOrProxy))
473         {
474             try
475             {
476                 VirtualProxy proxy = (VirtualProxy) objectOrProxy;
477
478                 return proxy.alreadyMaterialized() ? proxy.getRealSubject() : null;
479             }
480             catch(PersistenceBrokerException e)
481             {
482                 log.error("Could not retrieve real object for VirtualProxy: " + objectOrProxy);
483                 throw e;
484             }
485         }
486         else
487         {
488             return objectOrProxy;
489         }
490     }
491
492     /**
493      * Get the real Class
494      *
495      * @param objectOrProxy
496      * @return Class
497      */

498     public Class JavaDoc getRealClass(Object JavaDoc objectOrProxy)
499     {
500         IndirectionHandler handler;
501
502         if(isNormalOjbProxy(objectOrProxy))
503         {
504             String JavaDoc msg;
505
506             try
507             {
508                 handler = getIndirectionHandler(objectOrProxy);
509                 /*
510                  arminw:
511                  think we should return the real class
512                  */

513                 // return handler.getIdentity().getObjectsTopLevelClass();
514
return handler.getIdentity().getObjectsRealClass();
515             }
516             catch(ClassCastException JavaDoc e)
517             {
518                 // shouldn't happen but still ...
519
msg = "The InvocationHandler for the provided Proxy was not an instance of " + IndirectionHandler.class.getName();
520                 log.error(msg);
521                 throw new PersistenceBrokerException(msg, e);
522             }
523             catch(IllegalArgumentException JavaDoc e)
524             {
525                 msg = "Could not retrieve real object for given Proxy: " + objectOrProxy;
526                 log.error(msg);
527                 throw new PersistenceBrokerException(msg, e);
528             }
529         }
530         else if(isVirtualOjbProxy(objectOrProxy))
531         {
532             handler = VirtualProxy.getIndirectionHandler((VirtualProxy) objectOrProxy);
533             /*
534              arminw:
535              think we should return the real class
536              */

537             // return handler.getIdentity().getObjectsTopLevelClass();
538
return handler.getIdentity().getObjectsRealClass();
539         }
540         else
541         {
542             return objectOrProxy.getClass();
543         }
544     }
545
546     /**
547      * Determines whether the given object is an OJB proxy.
548      *
549      * @return <code>true</code> if the object is an OJB proxy
550      */

551     public boolean isNormalOjbProxy(Object JavaDoc proxyOrObject)
552     {
553         return proxyOrObject instanceof OJBProxy;
554     }
555
556     /**
557      * Determines whether the given object is an OJB virtual proxy.
558      *
559      * @return <code>true</code> if the object is an OJB virtual proxy
560      */

561     public boolean isVirtualOjbProxy(Object JavaDoc proxyOrObject)
562     {
563         return proxyOrObject instanceof VirtualProxy;
564     }
565
566     /**
567      * Returns <tt>true</tt> if the given object is a {@link java.lang.reflect.Proxy}
568      * or a {@link VirtualProxy} instance.
569      */

570     public boolean isProxy(Object JavaDoc proxyOrObject)
571     {
572         return isNormalOjbProxy(proxyOrObject) || isVirtualOjbProxy(proxyOrObject);
573     }
574
575     /**
576      * Returns the IndirectionHandler associated with a dynamic proxy. Each
577      * subclass is responsible for it's execution
578      */

579     protected abstract IndirectionHandler getDynamicIndirectionHandler(Object JavaDoc obj);
580
581     /**
582      * Returns the invocation handler object of the given proxy object.
583      *
584      * @param obj The object
585      * @return The invocation handler if the object is an OJB proxy, or <code>null</code>
586      * otherwise
587      */

588     public IndirectionHandler getIndirectionHandler(Object JavaDoc obj)
589     {
590         if(obj == null)
591         {
592             return null;
593         }
594         else if(isNormalOjbProxy(obj))
595         {
596             return getDynamicIndirectionHandler(obj);
597         }
598         else if(isVirtualOjbProxy(obj))
599         {
600             return VirtualProxy.getIndirectionHandler((VirtualProxy) obj);
601         }
602         else
603         {
604             return null;
605         }
606
607     }
608
609     /**
610      * Determines whether the object is a materialized object, i.e. no proxy or a
611      * proxy that has already been loaded from the database.
612      *
613      * @param object The object to test
614      * @return <code>true</code> if the object is materialized
615      */

616     public boolean isMaterialized(Object JavaDoc object)
617     {
618         IndirectionHandler handler = getIndirectionHandler(object);
619
620         return handler == null || handler.alreadyMaterialized();
621     }
622
623     /** Return CollectionProxy for item is item is a CollectionProxy, otherwise return null */
624     public CollectionProxy getCollectionProxy(Object JavaDoc item)
625     {
626         if(isCollectionProxy(item))
627         {
628             return (CollectionProxy) item;
629         }
630         else
631         {
632             return null;
633         }
634     }
635
636     /**
637      * Reports if item is a CollectionProxy.
638      *
639      * TODO: Provide handling for pluggable collection proxy implementations
640      */

641     public boolean isCollectionProxy(Object JavaDoc item)
642     {
643         return (item instanceof CollectionProxy);
644     }
645
646     /**
647      * Materialization-safe version of toString. If the object is a yet-unmaterialized proxy,
648      * then only the text "unmaterialized proxy for ..." is returned and the proxy is NOT
649      * materialized. Otherwise, the normal toString method is called. This useful e.g. for
650      * logging etc.
651      *
652      * @param proxy The object for which a string representation shall be generated
653      * @return The string representation
654      */

655     public String JavaDoc toString(Object JavaDoc proxy)
656     {
657         IndirectionHandler handler = getIndirectionHandler(proxy);
658         if((handler != null) && handler.alreadyMaterialized())
659         {
660             return "unmaterialized proxy for " + handler.getIdentity();
661         }
662         else
663         {
664             return proxy.toString();
665         }
666     }
667
668     public synchronized static ProxyFactory getProxyFactory()
669     {
670         /*
671         TODO: Check usage of singleton.
672         arminw: Think the ProxyFactory instance can be a singleton, because the proxy stuff
673         will never change while runtime.
674         */

675         if(singleton == null)
676         {
677             Class JavaDoc proxyFactoryClass = null;
678             try
679             {
680                 proxyFactoryClass = getProxyConfiguration().getProxyFactoryClass();
681                 singleton = (ProxyFactory) proxyFactoryClass.newInstance();
682             }
683             catch(InstantiationException JavaDoc e)
684             {
685                 throw new MetadataException("Illegal class " + proxyFactoryClass.getName() + " specified for ProxyFactoryClass.");
686             }
687             catch(IllegalAccessException JavaDoc e)
688             {
689                 throw new MetadataException("Illegal class " + proxyFactoryClass.getName() + " specified for ProxyFactoryClass.");
690             }
691         }
692         return singleton;
693     }
694
695 }
696
Popular Tags