View Javadoc

1   // SECTION-START[License Header]
2   // <editor-fold defaultstate="collapsed" desc=" Generated License ">
3   /*
4    *   Java Object Management and Configuration
5    *   Copyright (C) Christian Schulte, 2011-313
6    *   All rights reserved.
7    *
8    *   Redistribution and use in source and binary forms, with or without
9    *   modification, are permitted provided that the following conditions
10   *   are met:
11   *
12   *     o Redistributions of source code must retain the above copyright
13   *       notice, this list of conditions and the following disclaimer.
14   *
15   *     o Redistributions in binary form must reproduce the above copyright
16   *       notice, this list of conditions and the following disclaimer in
17   *       the documentation and/or other materials provided with the
18   *       distribution.
19   *
20   *   THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
21   *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22   *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23   *   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
24   *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25   *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26   *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27   *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28   *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29   *   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30   *
31   *   $JOMC: RuntimeInstance.java 4588 2012-06-03 06:01:30Z schulte2005 $
32   *
33   */
34  // </editor-fold>
35  // SECTION-END
36  package org.jomc.ri.model;
37  
38  import java.lang.ref.Reference;
39  import java.lang.ref.WeakReference;
40  import java.lang.reflect.Constructor;
41  import java.lang.reflect.Method;
42  import java.util.Map;
43  import javax.xml.bind.annotation.XmlTransient;
44  import org.jomc.model.Instance;
45  import org.jomc.model.Specification;
46  import org.jomc.util.WeakIdentityHashMap;
47  import static org.jomc.ri.model.RuntimeModelObjects.BOOTSTRAP_CLASSLOADER_KEY;
48  import static org.jomc.ri.model.RuntimeModelObjects.classesByClassLoaderAndNameCache;
49  import static org.jomc.ri.model.RuntimeModelObjects.createMap;
50  
51  // SECTION-START[Documentation]
52  // <editor-fold defaultstate="collapsed" desc=" Generated Documentation ">
53  /**
54   * Runtime {@code Instance}.
55   *
56   * <dl>
57   *   <dt><b>Identifier:</b></dt><dd>org.jomc.ri.model.RuntimeInstance</dd>
58   *   <dt><b>Name:</b></dt><dd>JOMC RI RuntimeInstance</dd>
59   *   <dt><b>Specifications:</b></dt>
60   *     <dd>org.jomc.ri.model.RuntimeModelObject @ 1.2</dd>
61   *   <dt><b>Abstract:</b></dt><dd>No</dd>
62   *   <dt><b>Final:</b></dt><dd>No</dd>
63   *   <dt><b>Stateless:</b></dt><dd>No</dd>
64   * </dl>
65   *
66   * @author <a href="mailto:schulte2005@users.sourceforge.net">Christian Schulte</a> 1.2
67   * @version 1.2
68   */
69  // </editor-fold>
70  // SECTION-END
71  // SECTION-START[Annotations]
72  // <editor-fold defaultstate="collapsed" desc=" Generated Annotations ">
73  @javax.annotation.Generated( value = "org.jomc.tools.SourceFileProcessor 1.3", comments = "See http://jomc.sourceforge.net/jomc/1.3/jomc-tools-1.3" )
74  // </editor-fold>
75  // SECTION-END
76  public class RuntimeInstance extends Instance implements RuntimeModelObject
77  {
78      // SECTION-START[RuntimeInstance]
79  
80      /** Classes by class loader any instance cache. */
81      @XmlTransient
82      static final Map<ClassLoader, Map<String, Reference<Class<?>[]>>> classesByClassLoaderAndInstanceCache =
83          new WeakIdentityHashMap<ClassLoader, Map<String, Reference<Class<?>[]>>>();
84  
85      /** Constructors by class loader any instance cache. */
86      @XmlTransient
87      static final Map<ClassLoader, Map<String, Reference<Constructor<?>>>> constructorsByClassLoaderAndInstanceCache =
88          new WeakIdentityHashMap<ClassLoader, Map<String, Reference<Constructor<?>>>>();
89  
90      /** Methods by class loader any instance cache. */
91      @XmlTransient
92      static final Map<ClassLoader, Map<String, Reference<Method>>> methodsByClassLoaderAndInstanceCache =
93          new WeakIdentityHashMap<ClassLoader, Map<String, Reference<Method>>>();
94  
95      /** Assignable flags by class loader any instance cache. */
96      @XmlTransient
97      static final Map<ClassLoader, Map<String, Boolean>> assignableFlagsByClassLoaderAndInstanceCache =
98          new WeakIdentityHashMap<ClassLoader, Map<String, Boolean>>();
99  
100     /** Proxy classes by class loader any instance cache. */
101     @XmlTransient
102     static final Map<ClassLoader, Map<String, Reference<Class<?>>>> proxyClassesByClassLoaderAndInstanceCache =
103         new WeakIdentityHashMap<ClassLoader, Map<String, Reference<Class<?>>>>();
104 
105     /** Method name. */
106     @XmlTransient
107     private volatile String javaClassFactoryMethodName;
108 
109     /**
110      * Creates a new {@code RuntimeInstance} instance by deeply copying a given {@code Instance} instance.
111      *
112      * @param instance The instance to copy.
113      *
114      * @throws NullPointerException if {@code instance} is {@code null}.
115      */
116     public RuntimeInstance( final Instance instance )
117     {
118         super( instance );
119 
120         if ( this.getAuthors() != null )
121         {
122             this.setAuthors( RuntimeModelObjects.getInstance().copyOf( this.getAuthors() ) );
123         }
124         if ( this.getDependencies() != null )
125         {
126             this.setDependencies( RuntimeModelObjects.getInstance().copyOf( this.getDependencies() ) );
127         }
128         if ( this.getDocumentation() != null )
129         {
130             this.setDocumentation( RuntimeModelObjects.getInstance().copyOf( this.getDocumentation() ) );
131         }
132         if ( this.getMessages() != null )
133         {
134             this.setMessages( RuntimeModelObjects.getInstance().copyOf( this.getMessages() ) );
135         }
136         if ( this.getProperties() != null )
137         {
138             this.setProperties( RuntimeModelObjects.getInstance().copyOf( this.getProperties() ) );
139         }
140         if ( this.getSpecifications() != null )
141         {
142             this.setSpecifications( RuntimeModelObjects.getInstance().copyOf( this.getSpecifications() ) );
143         }
144     }
145 
146     /**
147      * Gets the Java class of the instance for a given class loader.
148      * <p>This method queries an internal cache for a result object to return for the given argument values. If no
149      * cached result object is available, this method queries the super-class for a result object to return and caches
150      * the outcome of that query for use on successive calls.</p>
151      * <p><b>Note:</b><br/>Method {@code RuntimeModelObjects.clear()} must be used to synchronize the state of the
152      * internal cache with the state of the class loader, should the state of the class loader change.</p>
153      *
154      * @param classLoader The class loader to get the Java class from or {@code null}, to get the Java class from the
155      * platform's bootstrap class loader.
156      *
157      * @return The Java class of the instance.
158      *
159      * @throws ClassNotFoundException if the Java class is not found.
160      *
161      * @see #getClazz()
162      * @see RuntimeModelObjects#clear()
163      */
164     @Override
165     public Class<?> getJavaClass( final ClassLoader classLoader ) throws ClassNotFoundException
166     {
167         ClassLoader classLoaderKey = classLoader;
168         if ( classLoaderKey == null )
169         {
170             classLoaderKey = BOOTSTRAP_CLASSLOADER_KEY;
171         }
172 
173         synchronized ( classesByClassLoaderAndNameCache )
174         {
175             Class<?> javaClass = null;
176             Map<String, Reference<Class<?>>> map = classesByClassLoaderAndNameCache.get( classLoaderKey );
177 
178             if ( map == null )
179             {
180                 map = createMap();
181                 classesByClassLoaderAndNameCache.put( classLoaderKey, map );
182             }
183 
184             final Reference<Class<?>> reference = map.get( this.getClazz() );
185 
186             if ( reference != null )
187             {
188                 javaClass = reference.get();
189             }
190 
191             if ( javaClass == null )
192             {
193                 javaClass = super.getJavaClass( classLoader );
194                 map.put( this.getClazz(), new WeakReference<Class<?>>( javaClass ) );
195             }
196 
197             return javaClass;
198         }
199     }
200 
201     /**
202      * Gets the Java classes of all specifications of the instance for a given class loader.
203      * <p>This method queries an internal cache for a result object to return for the given argument values. If no
204      * cached result object is available, this method queries the super-class for a result object to return and caches
205      * the outcome of that query for use on successive calls.</p>
206      * <p><b>Note:</b><br/>Method {@code RuntimeModelObjects.clear()} must be used to synchronize the state of the
207      * internal cache with the state of the instance and class loader, should the state of the instance or class loader
208      * change.</p>
209      *
210      * @param classLoader The class loader to get the Java classes from or {@code null}, to get the Java classes from
211      * the platform's bootstrap class loader.
212      *
213      * @return The Java classes of all specifications of the instance.
214      *
215      * @throws ClassNotFoundException if a Java class is not found.
216      *
217      * @see #getSpecifications()
218      * @see Specification#getClazz()
219      * @see RuntimeModelObjects#clear()
220      */
221     @Override
222     public Class<?>[] getJavaClasses( final ClassLoader classLoader ) throws ClassNotFoundException
223     {
224         ClassLoader classLoaderKey = classLoader;
225         if ( classLoaderKey == null )
226         {
227             classLoaderKey = BOOTSTRAP_CLASSLOADER_KEY;
228         }
229 
230         synchronized ( classesByClassLoaderAndInstanceCache )
231         {
232             Class<?>[] javaClasses = null;
233             Map<String, Reference<Class<?>[]>> map = classesByClassLoaderAndInstanceCache.get( classLoaderKey );
234 
235             if ( map == null )
236             {
237                 map = createMap();
238                 classesByClassLoaderAndInstanceCache.put( classLoaderKey, map );
239             }
240 
241             final Reference<Class<?>[]> reference = map.get( this.getIdentifier() );
242 
243             if ( reference != null )
244             {
245                 javaClasses = reference.get();
246             }
247 
248             if ( javaClasses == null && ( reference != null || !map.containsKey( this.getIdentifier() ) ) )
249             {
250                 javaClasses = super.getJavaClasses( classLoader );
251                 map.put( this.getIdentifier(), new WeakReference<Class<?>[]>( javaClasses ) );
252             }
253 
254             return javaClasses;
255         }
256     }
257 
258     /**
259      * Gets the Java constructor to use for creating objects of the instance.
260      * <p>This method queries an internal cache for a result object to return for the given argument values. If no
261      * cached result object is available, this method queries the super-class for a result object to return and caches
262      * the outcome of that query for use on successive calls.</p>
263      * <p><b>Note:</b><br/>Method {@code RuntimeModelObjects.clear()} must be used to synchronize the state of the
264      * internal cache with the state of the instance and class loader, should the state of the instance or class loader
265      * change.</p>
266      *
267      * @param classLoader The class loader to get the Java class from or {@code null}, to get the Java class from the
268      * platform's bootstrap class loader.
269      *
270      * @return The public default Java constructor of the Java class of the instance or {@code null}, if that class
271      * does not declare such a constructor, is abstract or is not public.
272      *
273      * @throws ClassNotFoundException if the Java class is not found.
274      *
275      * @see #getJavaClass(java.lang.ClassLoader)
276      * @see RuntimeModelObjects#clear()
277      */
278     @Override
279     public Constructor<?> getJavaConstructor( final ClassLoader classLoader ) throws ClassNotFoundException
280     {
281         ClassLoader classLoaderKey = classLoader;
282         if ( classLoaderKey == null )
283         {
284             classLoaderKey = BOOTSTRAP_CLASSLOADER_KEY;
285         }
286 
287         synchronized ( constructorsByClassLoaderAndInstanceCache )
288         {
289             Constructor<?> javaClassConstructor = null;
290             Map<String, Reference<Constructor<?>>> map = constructorsByClassLoaderAndInstanceCache.get( classLoaderKey );
291 
292             if ( map == null )
293             {
294                 map = createMap();
295                 constructorsByClassLoaderAndInstanceCache.put( classLoaderKey, map );
296             }
297 
298             final Reference<Constructor<?>> reference = map.get( this.getIdentifier() );
299 
300             if ( reference != null )
301             {
302                 javaClassConstructor = reference.get();
303             }
304 
305             if ( javaClassConstructor == null && ( reference != null || !map.containsKey( this.getIdentifier() ) ) )
306             {
307                 javaClassConstructor = super.getJavaConstructor( classLoader );
308                 map.put( this.getIdentifier(), new WeakReference<Constructor<?>>( javaClassConstructor ) );
309             }
310 
311             return javaClassConstructor;
312         }
313     }
314 
315     /**
316      * Gets the name of the Java method to use for creating objects of the instance.
317      * <p>This method queries an internal cache for a result object to return. If no cached result object is available,
318      * this method queries the super-class for a result object to return and caches the outcome of that query for use on
319      * successive calls.</p>
320      * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
321      * state of the instance, should the state of the instance change.</p>
322      *
323      * @return The name of the Java method to use for creating objects of the instance or {@code null}, if no such
324      * method name is supported.
325      *
326      * @see #getName()
327      * @see #clear()
328      */
329     @Override
330     public String getJavaFactoryMethodName()
331     {
332         if ( this.javaClassFactoryMethodName == null )
333         {
334             this.javaClassFactoryMethodName = super.getJavaFactoryMethodName();
335         }
336 
337         return this.javaClassFactoryMethodName;
338     }
339 
340     /**
341      * Gets the Java method to use for creating objects of the instance.
342      * <p>This method queries an internal cache for a result object to return for the given argument values. If no
343      * cached result object is available, this method queries the super-class for a result object to return and caches
344      * the outcome of that query for use on successive calls.</p>
345      * <p><b>Note:</b><br/>Method {@code RuntimeModelObjects.clear()} must be used to synchronize the state of the
346      * internal cache with the state of the instance and class loader, should the state of the instance or class loader
347      * change.</p>
348      *
349      * @param classLoader The class loader to get the Java class from or {@code null}, to get the Java class from the
350      * platform's bootstrap class loader.
351      *
352      * @return The public Java method of the Java class of the instance to use for creating objects of the instance or
353      * {@code null}, if that class does not declare such a method.
354      *
355      * @throws ClassNotFoundException if the Java class is not found.
356      *
357      * @see #getJavaClass(java.lang.ClassLoader)
358      * @see #getJavaFactoryMethodName()
359      * @see RuntimeModelObjects#clear()
360      */
361     @Override
362     public Method getJavaFactoryMethod( final ClassLoader classLoader ) throws ClassNotFoundException
363     {
364         ClassLoader classLoaderKey = classLoader;
365         if ( classLoaderKey == null )
366         {
367             classLoaderKey = BOOTSTRAP_CLASSLOADER_KEY;
368         }
369 
370         synchronized ( methodsByClassLoaderAndInstanceCache )
371         {
372             Method javaClassFactoryMethod = null;
373             Map<String, Reference<Method>> map = methodsByClassLoaderAndInstanceCache.get( classLoaderKey );
374 
375             if ( map == null )
376             {
377                 map = createMap();
378                 methodsByClassLoaderAndInstanceCache.put( classLoaderKey, map );
379             }
380 
381             final Reference<Method> reference = map.get( this.getIdentifier() );
382 
383             if ( reference != null )
384             {
385                 javaClassFactoryMethod = reference.get();
386             }
387 
388             if ( javaClassFactoryMethod == null && ( reference != null || !map.containsKey( this.getIdentifier() ) ) )
389             {
390                 javaClassFactoryMethod = super.getJavaFactoryMethod( classLoader );
391                 map.put( this.getIdentifier(), new WeakReference<Method>( javaClassFactoryMethod ) );
392             }
393 
394             return javaClassFactoryMethod;
395         }
396     }
397 
398     /**
399      * Gets a flag indicating the Java class of the instance is assignable to all Java classes of all specifications of
400      * the instance.
401      * <p>This method queries an internal cache for a result object to return for the given argument values. If no
402      * cached result object is available, this method queries the super-class for a result object to return and caches
403      * the outcome of that query for use on successive calls.</p>
404      * <p><b>Note:</b><br/>Method {@code RuntimeModelObjects.clear()} must be used to synchronize the state of the
405      * internal cache with the state of the instance and class loader, should the state of the instance or class loader
406      * change.</p>
407      *
408      * @param classLoader The class loader to get the Java classes from or {@code null}, to get the Java classes from
409      * the platform's bootstrap class loader.
410      *
411      * @return {@code true}, if the Java class of the instance is assignable to all Java classes of all specifications
412      * of the instance; {@code false}, if the Java class of the instance is not assignable to all Java classes of all
413      * specifications of the instance.
414      *
415      * @throws ClassNotFoundException if a Java class is not found.
416      *
417      * @see #getJavaClass(java.lang.ClassLoader)
418      * @see #getJavaClasses(java.lang.ClassLoader)
419      * @see RuntimeModelObjects#clear()
420      */
421     @Override
422     public boolean isJavaClassAssignable( final ClassLoader classLoader ) throws ClassNotFoundException
423     {
424         ClassLoader classLoaderKey = classLoader;
425         if ( classLoaderKey == null )
426         {
427             classLoaderKey = BOOTSTRAP_CLASSLOADER_KEY;
428         }
429 
430         synchronized ( assignableFlagsByClassLoaderAndInstanceCache )
431         {
432             Map<String, Boolean> map = assignableFlagsByClassLoaderAndInstanceCache.get( classLoaderKey );
433 
434             if ( map == null )
435             {
436                 map = createMap();
437                 assignableFlagsByClassLoaderAndInstanceCache.put( classLoaderKey, map );
438             }
439 
440             Boolean javaClassAssignable = map.get( this.getIdentifier() );
441 
442             if ( javaClassAssignable == null && !map.containsKey( this.getIdentifier() ) )
443             {
444                 javaClassAssignable = super.isJavaClassAssignable( classLoader );
445                 map.put( this.getIdentifier(), javaClassAssignable );
446             }
447 
448             return javaClassAssignable == null ? false : javaClassAssignable;
449         }
450     }
451 
452     /**
453      * Gets the Java proxy class for a given class loader.
454      * <p>This method queries an internal cache for a result object to return for the given argument values. If no
455      * cached result object is available, this method queries the super-class for a result object to return and caches
456      * the outcome of that query for use on successive calls.</p>
457      * <p><b>Note:</b><br/>Method {@code RuntimeModelObjects.clear()} must be used to synchronize the state of the
458      * internal cache with the state of the instance and class loader, should the state of the instance or class loader
459      * change.</p>
460      *
461      * @param classLoader The class loader to get the Java proxy class for.
462      *
463      * @return The Java proxy class for {@code classLoader} or {@code null}, if the instance does not support a Java
464      * proxy class.
465      *
466      * @throws ClassNotFoundException if a Java class is not found.
467      *
468      * @see #getJavaClasses(java.lang.ClassLoader)
469      * @see RuntimeModelObjects#clear()
470      */
471     @Override
472     public Class<?> getJavaProxyClass( final ClassLoader classLoader ) throws ClassNotFoundException
473     {
474         ClassLoader classLoaderKey = classLoader;
475         if ( classLoaderKey == null )
476         {
477             classLoaderKey = BOOTSTRAP_CLASSLOADER_KEY;
478         }
479 
480         synchronized ( proxyClassesByClassLoaderAndInstanceCache )
481         {
482             Class<?> javaProxyClass = null;
483             Map<String, Reference<Class<?>>> map = proxyClassesByClassLoaderAndInstanceCache.get( classLoaderKey );
484 
485             if ( map == null )
486             {
487                 map = createMap();
488                 proxyClassesByClassLoaderAndInstanceCache.put( classLoaderKey, map );
489             }
490 
491             final Reference<Class<?>> reference = map.get( this.getIdentifier() );
492 
493             if ( reference != null )
494             {
495                 javaProxyClass = reference.get();
496             }
497 
498             if ( javaProxyClass == null && ( reference != null || !map.containsKey( this.getIdentifier() ) ) )
499             {
500                 javaProxyClass = super.getJavaProxyClass( classLoader );
501                 map.put( this.getIdentifier(), new WeakReference<Class<?>>( javaProxyClass ) );
502             }
503 
504             return javaProxyClass;
505         }
506     }
507 
508     // SECTION-END
509     // SECTION-START[RuntimeModelObject]
510     public void gc()
511     {
512         this.gcOrClear( true, false );
513     }
514 
515     public void clear()
516     {
517         this.javaClassFactoryMethodName = null;
518         this.gcOrClear( false, true );
519     }
520 
521     private void gcOrClear( final boolean gc, final boolean clear )
522     {
523         if ( this.getAuthors() instanceof RuntimeModelObject )
524         {
525             if ( gc )
526             {
527                 ( (RuntimeModelObject) this.getAuthors() ).gc();
528             }
529             if ( clear )
530             {
531                 ( (RuntimeModelObject) this.getAuthors() ).clear();
532             }
533         }
534         if ( this.getDependencies() instanceof RuntimeModelObject )
535         {
536             if ( gc )
537             {
538                 ( (RuntimeModelObject) this.getDependencies() ).gc();
539             }
540             if ( clear )
541             {
542                 ( (RuntimeModelObject) this.getDependencies() ).clear();
543             }
544         }
545         if ( this.getDocumentation() instanceof RuntimeModelObject )
546         {
547             if ( gc )
548             {
549                 ( (RuntimeModelObject) this.getDocumentation() ).gc();
550             }
551             if ( clear )
552             {
553                 ( (RuntimeModelObject) this.getDocumentation() ).clear();
554             }
555         }
556         if ( this.getMessages() instanceof RuntimeModelObject )
557         {
558             if ( gc )
559             {
560                 ( (RuntimeModelObject) this.getMessages() ).gc();
561             }
562             if ( clear )
563             {
564                 ( (RuntimeModelObject) this.getMessages() ).clear();
565             }
566         }
567         if ( this.getProperties() instanceof RuntimeModelObject )
568         {
569             if ( gc )
570             {
571                 ( (RuntimeModelObject) this.getProperties() ).gc();
572             }
573             if ( clear )
574             {
575                 ( (RuntimeModelObject) this.getProperties() ).clear();
576             }
577         }
578         if ( this.getSpecifications() instanceof RuntimeModelObject )
579         {
580             if ( gc )
581             {
582                 ( (RuntimeModelObject) this.getSpecifications() ).gc();
583             }
584             if ( clear )
585             {
586                 ( (RuntimeModelObject) this.getSpecifications() ).clear();
587             }
588         }
589     }
590 
591     // SECTION-END
592     // SECTION-START[Constructors]
593     // <editor-fold defaultstate="collapsed" desc=" Generated Constructors ">
594     /** Creates a new {@code RuntimeInstance} instance. */
595     @javax.annotation.Generated( value = "org.jomc.tools.SourceFileProcessor 1.3", comments = "See http://jomc.sourceforge.net/jomc/1.3/jomc-tools-1.3" )
596     public RuntimeInstance()
597     {
598         // SECTION-START[Default Constructor]
599         super();
600         // SECTION-END
601     }
602     // </editor-fold>
603     // SECTION-END
604     // SECTION-START[Dependencies]
605     // SECTION-END
606     // SECTION-START[Properties]
607     // SECTION-END
608     // SECTION-START[Messages]
609     // SECTION-END
610 }