001// SECTION-START[License Header]
002// <editor-fold defaultstate="collapsed" desc=" Generated License ">
003/*
004 *   Java Object Management and Configuration
005 *   Copyright (C) Christian Schulte, 2011-313
006 *   All rights reserved.
007 *
008 *   Redistribution and use in source and binary forms, with or without
009 *   modification, are permitted provided that the following conditions
010 *   are met:
011 *
012 *     o Redistributions of source code must retain the above copyright
013 *       notice, this list of conditions and the following disclaimer.
014 *
015 *     o Redistributions in binary form must reproduce the above copyright
016 *       notice, this list of conditions and the following disclaimer in
017 *       the documentation and/or other materials provided with the
018 *       distribution.
019 *
020 *   THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
021 *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
022 *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
023 *   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
024 *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
025 *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
026 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
027 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
028 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
029 *   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
030 *
031 *   $JOMC: RuntimeImplementation.java 4712 2013-01-02 13:56:12Z schulte $
032 *
033 */
034// </editor-fold>
035// SECTION-END
036package org.jomc.ri.model;
037
038import java.lang.ref.Reference;
039import java.lang.ref.WeakReference;
040import java.net.URI;
041import java.util.Map;
042import javax.xml.bind.annotation.XmlTransient;
043import org.jomc.model.Implementation;
044import org.jomc.model.JavaTypeName;
045import org.jomc.model.ModelObjectException;
046import static org.jomc.ri.model.RuntimeModelObjects.BOOTSTRAP_CLASSLOADER_KEY;
047import static org.jomc.ri.model.RuntimeModelObjects.classesByClassLoaderAndNameCache;
048import static org.jomc.ri.model.RuntimeModelObjects.createMap;
049
050// SECTION-START[Documentation]
051// <editor-fold defaultstate="collapsed" desc=" Generated Documentation ">
052/**
053 * Runtime {@code Implementation}.
054 *
055 * <dl>
056 *   <dt><b>Identifier:</b></dt><dd>org.jomc.ri.model.RuntimeImplementation</dd>
057 *   <dt><b>Name:</b></dt><dd>JOMC ⁑ RI ⁑ RuntimeImplementation</dd>
058 *   <dt><b>Specifications:</b></dt>
059 *     <dd>org.jomc.ri.model.RuntimeModelObject @ 1.2</dd>
060 *   <dt><b>Abstract:</b></dt><dd>No</dd>
061 *   <dt><b>Final:</b></dt><dd>No</dd>
062 *   <dt><b>Stateless:</b></dt><dd>No</dd>
063 * </dl>
064 *
065 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> 1.2
066 * @version 1.2
067 */
068// </editor-fold>
069// SECTION-END
070// SECTION-START[Annotations]
071// <editor-fold defaultstate="collapsed" desc=" Generated Annotations ">
072@javax.annotation.Generated( value = "org.jomc.tools.SourceFileProcessor 1.4", comments = "See http://www.jomc.org/jomc/1.4/jomc-tools-1.4" )
073// </editor-fold>
074// SECTION-END
075public class RuntimeImplementation extends Implementation implements RuntimeModelObject
076{
077    // SECTION-START[RuntimeImplementation]
078
079    /** Cached location URI. */
080    private volatile URI locationUri;
081
082    /** Java type name. */
083    @XmlTransient
084    private volatile JavaTypeName javaTypeName;
085
086    /**
087     * Creates a new {@code RuntimeImplementation} instance by deeply copying a given {@code Implementation} instance.
088     *
089     * @param implementation The instance to copy.
090     *
091     * @throws NullPointerException if {@code implementation} is {@code null}.
092     */
093    public RuntimeImplementation( final Implementation implementation )
094    {
095        super( implementation );
096
097        if ( this.getAuthors() != null )
098        {
099            this.setAuthors( RuntimeModelObjects.getInstance().copyOf( this.getAuthors() ) );
100        }
101        if ( this.getDependencies() != null )
102        {
103            this.setDependencies( RuntimeModelObjects.getInstance().copyOf( this.getDependencies() ) );
104        }
105        if ( this.getDocumentation() != null )
106        {
107            this.setDocumentation( RuntimeModelObjects.getInstance().copyOf( this.getDocumentation() ) );
108        }
109        if ( this.getImplementations() != null )
110        {
111            this.setImplementations( RuntimeModelObjects.getInstance().copyOf( this.getImplementations() ) );
112        }
113        if ( this.getMessages() != null )
114        {
115            this.setMessages( RuntimeModelObjects.getInstance().copyOf( this.getMessages() ) );
116        }
117        if ( this.getProperties() != null )
118        {
119            this.setProperties( RuntimeModelObjects.getInstance().copyOf( this.getProperties() ) );
120        }
121        if ( this.getSpecifications() != null )
122        {
123            this.setSpecifications( RuntimeModelObjects.getInstance().copyOf( this.getSpecifications() ) );
124        }
125    }
126
127    /**
128     * Gets the location URI used for locating instances of this implementation.
129     * <p>This method queries an internal cache for a result object to return. If no cached result object is available,
130     * this method queries the super-class for a result object to return and caches the outcome of that query for use on
131     * successive calls.</p>
132     * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
133     * state of the instance, should the state of the instance change.</p>
134     *
135     * @return The location URI used for locating instances of this implementation or {@code null}, if instances of this
136     * implementation do not need to be located.
137     *
138     * @throws ModelObjectException if parsing the location to an {@code URI} object fails.
139     *
140     * @see #getLocation()
141     * @see #clear()
142     */
143    @Override
144    public URI getLocationUri() throws ModelObjectException
145    {
146        if ( this.locationUri == null )
147        {
148            this.locationUri = super.getLocationUri();
149        }
150
151        return this.locationUri;
152    }
153
154    /**
155     * Gets the Java class of the implementation for a given class loader.
156     * <p>This method queries an internal cache for a result object to return for the given argument values. If no
157     * cached result object is available, this method queries the super-class for a result object to return and caches
158     * the outcome of that query for use on successive calls.</p>
159     * <p><b>Note:</b><br/>Method {@code RuntimeModelObjects.clear()} must be used to synchronize the state of the
160     * internal cache with the state of the class loader, should the state of the class loader change.</p>
161     *
162     * @param classLoader The class loader to get the Java class from or {@code null}, to get the Java class from the
163     * platform's bootstrap class loader.
164     *
165     * @return The Java class of the implementation or {@code null}, if the implementation does not declare a class.
166     *
167     * @throws ClassNotFoundException if the Java class is not found.
168     * @throws ModelObjectException if parsing the name of the referenced type fails.
169     *
170     * @see #getClazz()
171     * @see RuntimeModelObjects#clear()
172     */
173    @Override
174    public Class<?> getJavaClass( final ClassLoader classLoader )
175        throws ModelObjectException, ClassNotFoundException
176    {
177        Class<?> javaClass = null;
178
179        if ( this.getJavaTypeName() != null )
180        {
181            ClassLoader classLoaderKey = classLoader;
182            if ( classLoaderKey == null )
183            {
184                classLoaderKey = BOOTSTRAP_CLASSLOADER_KEY;
185            }
186
187            synchronized ( classesByClassLoaderAndNameCache )
188            {
189                Map<String, Reference<Class<?>>> map = classesByClassLoaderAndNameCache.get( classLoaderKey );
190
191                if ( map == null )
192                {
193                    map = createMap();
194                    classesByClassLoaderAndNameCache.put( classLoaderKey, map );
195                }
196
197                final Reference<Class<?>> reference = map.get( this.getJavaTypeName().getClassName() );
198
199                if ( reference != null )
200                {
201                    javaClass = reference.get();
202                }
203
204                if ( javaClass == null )
205                {
206                    javaClass = super.getJavaClass( classLoader );
207                    map.put( this.getJavaTypeName().getClassName(), new WeakReference<Class<?>>( javaClass ) );
208                }
209            }
210        }
211
212        return javaClass;
213    }
214
215    /**
216     * Gets the Java type name of the type referenced by the implementation.
217     * <p>This method queries an internal cache for a result object to return. If no cached result object is available,
218     * this method queries the super-class for a result object to return and caches the outcome of that query for use on
219     * successive calls.</p>
220     * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
221     * state of the instance, should the state of the instance change.</p>
222     *
223     * @return The Java type name of the type referenced by the implementation or {@code null}, if the implementation
224     * does not reference a type.
225     *
226     * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
227     *
228     * @since 1.4
229     *
230     * @see #getJavaTypeName()
231     * @see #clear()
232     */
233    @Override
234    public JavaTypeName getJavaTypeName() throws ModelObjectException
235    {
236        if ( this.javaTypeName == null )
237        {
238            this.javaTypeName = super.getJavaTypeName();
239        }
240
241        return this.javaTypeName;
242    }
243
244    // SECTION-END
245    // SECTION-START[RuntimeModelObject]
246    public void gc()
247    {
248        this.gcOrClear( true, false );
249    }
250
251    public void clear()
252    {
253        this.locationUri = null;
254        this.javaTypeName = null;
255        this.gcOrClear( false, true );
256    }
257
258    private void gcOrClear( final boolean gc, final boolean clear )
259    {
260        if ( this.getAuthors() instanceof RuntimeModelObject )
261        {
262            if ( gc )
263            {
264                ( (RuntimeModelObject) this.getAuthors() ).gc();
265            }
266            if ( clear )
267            {
268                ( (RuntimeModelObject) this.getAuthors() ).clear();
269            }
270        }
271        if ( this.getDependencies() instanceof RuntimeModelObject )
272        {
273            if ( gc )
274            {
275                ( (RuntimeModelObject) this.getDependencies() ).gc();
276            }
277            if ( clear )
278            {
279                ( (RuntimeModelObject) this.getDependencies() ).clear();
280            }
281        }
282        if ( this.getDocumentation() instanceof RuntimeModelObject )
283        {
284            if ( gc )
285            {
286                ( (RuntimeModelObject) this.getDocumentation() ).gc();
287            }
288            if ( clear )
289            {
290                ( (RuntimeModelObject) this.getDocumentation() ).clear();
291            }
292        }
293        if ( this.getImplementations() instanceof RuntimeModelObject )
294        {
295            if ( gc )
296            {
297                ( (RuntimeModelObject) this.getImplementations() ).gc();
298            }
299            if ( clear )
300            {
301                ( (RuntimeModelObject) this.getImplementations() ).clear();
302            }
303        }
304        if ( this.getMessages() instanceof RuntimeModelObject )
305        {
306            if ( gc )
307            {
308                ( (RuntimeModelObject) this.getMessages() ).gc();
309            }
310            if ( clear )
311            {
312                ( (RuntimeModelObject) this.getMessages() ).clear();
313            }
314        }
315        if ( this.getProperties() instanceof RuntimeModelObject )
316        {
317            if ( gc )
318            {
319                ( (RuntimeModelObject) this.getProperties() ).gc();
320            }
321            if ( clear )
322            {
323                ( (RuntimeModelObject) this.getProperties() ).clear();
324            }
325        }
326        if ( this.getSpecifications() instanceof RuntimeModelObject )
327        {
328            if ( gc )
329            {
330                ( (RuntimeModelObject) this.getSpecifications() ).gc();
331            }
332            if ( clear )
333            {
334                ( (RuntimeModelObject) this.getSpecifications() ).clear();
335            }
336        }
337    }
338
339    // SECTION-END
340    // SECTION-START[Constructors]
341    // <editor-fold defaultstate="collapsed" desc=" Generated Constructors ">
342    /** Creates a new {@code RuntimeImplementation} instance. */
343    @javax.annotation.Generated( value = "org.jomc.tools.SourceFileProcessor 1.4", comments = "See http://www.jomc.org/jomc/1.4/jomc-tools-1.4" )
344    public RuntimeImplementation()
345    {
346        // SECTION-START[Default Constructor]
347        super();
348        // SECTION-END
349    }
350    // </editor-fold>
351    // SECTION-END
352    // SECTION-START[Dependencies]
353    // SECTION-END
354    // SECTION-START[Properties]
355    // SECTION-END
356    // SECTION-START[Messages]
357    // SECTION-END
358}