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 <cs@schulte.it>, 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 5061 2015-05-31 13:20:40Z 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.9", comments = "See http://www.jomc.org/jomc/1.9/jomc-tools-1.9" )
073// </editor-fold>
074// SECTION-END
075public class RuntimeImplementation extends Implementation implements RuntimeModelObject
076{
077    // SECTION-START[RuntimeImplementation]
078
079    /**
080     * Cached location URI.
081     */
082    private volatile URI locationUri;
083
084    /**
085     * Java type name.
086     */
087    @XmlTransient
088    private volatile JavaTypeName javaTypeName;
089
090    /**
091     * Creates a new {@code RuntimeImplementation} instance by deeply copying a given {@code Implementation} instance.
092     *
093     * @param implementation The instance to copy.
094     *
095     * @throws NullPointerException if {@code implementation} is {@code null}.
096     */
097    public RuntimeImplementation( final Implementation implementation )
098    {
099        super( implementation );
100
101        if ( this.getAuthors() != null )
102        {
103            this.setAuthors( RuntimeModelObjects.getInstance().copyOf( this.getAuthors() ) );
104        }
105        if ( this.getDependencies() != null )
106        {
107            this.setDependencies( RuntimeModelObjects.getInstance().copyOf( this.getDependencies() ) );
108        }
109        if ( this.getDocumentation() != null )
110        {
111            this.setDocumentation( RuntimeModelObjects.getInstance().copyOf( this.getDocumentation() ) );
112        }
113        if ( this.getImplementations() != null )
114        {
115            this.setImplementations( RuntimeModelObjects.getInstance().copyOf( this.getImplementations() ) );
116        }
117        if ( this.getMessages() != null )
118        {
119            this.setMessages( RuntimeModelObjects.getInstance().copyOf( this.getMessages() ) );
120        }
121        if ( this.getProperties() != null )
122        {
123            this.setProperties( RuntimeModelObjects.getInstance().copyOf( this.getProperties() ) );
124        }
125        if ( this.getSpecifications() != null )
126        {
127            this.setSpecifications( RuntimeModelObjects.getInstance().copyOf( this.getSpecifications() ) );
128        }
129    }
130
131    /**
132     * Gets the location URI used for locating instances of this implementation.
133     * <p>
134     * This method queries an internal cache for a result object to return. If no cached result object is available,
135     * this method queries the super-class for a result object to return and caches the outcome of that query for use on
136     * successive calls.
137     * </p>
138     * <p>
139     * <b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
140     * state of the instance, should the state of the instance change.
141     * </p>
142     *
143     * @return The location URI used for locating instances of this implementation or {@code null}, if instances of this
144     * implementation do not need to be located.
145     *
146     * @throws ModelObjectException if parsing the location to an {@code URI} object fails.
147     *
148     * @see #getLocation()
149     * @see #clear()
150     */
151    @Override
152    public URI getLocationUri() throws ModelObjectException
153    {
154        if ( this.locationUri == null )
155        {
156            this.locationUri = super.getLocationUri();
157        }
158
159        return this.locationUri;
160    }
161
162    /**
163     * Gets the Java class of the implementation for a given class loader.
164     * <p>
165     * This method queries an internal cache for a result object to return for the given argument values. If no
166     * cached result object is available, this method queries the super-class for a result object to return and caches
167     * the outcome of that query for use on successive calls.
168     * </p>
169     * <p>
170     * <b>Note:</b><br/>Method {@code RuntimeModelObjects.clear()} must be used to synchronize the state of the
171     * internal cache with the state of the class loader, should the state of the class loader change.
172     * </p>
173     *
174     * @param classLoader The class loader to get the Java class from or {@code null}, to get the Java class from the
175     * platform's bootstrap class loader.
176     *
177     * @return The Java class of the implementation or {@code null}, if the implementation does not declare a class.
178     *
179     * @throws ClassNotFoundException if the Java class is not found.
180     * @throws ModelObjectException if parsing the name of the referenced type fails.
181     *
182     * @see #getClazz()
183     * @see RuntimeModelObjects#clear()
184     */
185    @Override
186    public Class<?> getJavaClass( final ClassLoader classLoader )
187        throws ModelObjectException, ClassNotFoundException
188    {
189        Class<?> javaClass = null;
190
191        if ( this.getJavaTypeName() != null )
192        {
193            ClassLoader classLoaderKey = classLoader;
194            if ( classLoaderKey == null )
195            {
196                classLoaderKey = BOOTSTRAP_CLASSLOADER_KEY;
197            }
198
199            synchronized ( classesByClassLoaderAndNameCache )
200            {
201                Map<String, Reference<Class<?>>> map = classesByClassLoaderAndNameCache.get( classLoaderKey );
202
203                if ( map == null )
204                {
205                    map = createMap();
206                    classesByClassLoaderAndNameCache.put( classLoaderKey, map );
207                }
208
209                final Reference<Class<?>> reference = map.get( this.getJavaTypeName().getClassName() );
210
211                if ( reference != null )
212                {
213                    javaClass = reference.get();
214                }
215
216                if ( javaClass == null )
217                {
218                    javaClass = super.getJavaClass( classLoader );
219                    map.put( this.getJavaTypeName().getClassName(), new WeakReference<Class<?>>( javaClass ) );
220                }
221            }
222        }
223
224        return javaClass;
225    }
226
227    /**
228     * Gets the Java type name of the type referenced by the implementation.
229     * <p>
230     * This method queries an internal cache for a result object to return. If no cached result object is available,
231     * this method queries the super-class for a result object to return and caches the outcome of that query for use on
232     * successive calls.
233     * </p>
234     * <p>
235     * <b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
236     * state of the instance, should the state of the instance change.
237     * </p>
238     *
239     * @return The Java type name of the type referenced by the implementation or {@code null}, if the implementation
240     * does not reference a type.
241     *
242     * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
243     *
244     * @since 1.4
245     *
246     * @see #getJavaTypeName()
247     * @see #clear()
248     */
249    @Override
250    public JavaTypeName getJavaTypeName() throws ModelObjectException
251    {
252        if ( this.javaTypeName == null )
253        {
254            this.javaTypeName = super.getJavaTypeName();
255        }
256
257        return this.javaTypeName;
258    }
259
260    // SECTION-END
261    // SECTION-START[RuntimeModelObject]
262    public void gc()
263    {
264        this.gcOrClear( true, false );
265    }
266
267    public void clear()
268    {
269        this.locationUri = null;
270        this.javaTypeName = null;
271        this.gcOrClear( false, true );
272    }
273
274    private void gcOrClear( final boolean gc, final boolean clear )
275    {
276        if ( this.getAuthors() instanceof RuntimeModelObject )
277        {
278            if ( gc )
279            {
280                ( (RuntimeModelObject) this.getAuthors() ).gc();
281            }
282            if ( clear )
283            {
284                ( (RuntimeModelObject) this.getAuthors() ).clear();
285            }
286        }
287        if ( this.getDependencies() instanceof RuntimeModelObject )
288        {
289            if ( gc )
290            {
291                ( (RuntimeModelObject) this.getDependencies() ).gc();
292            }
293            if ( clear )
294            {
295                ( (RuntimeModelObject) this.getDependencies() ).clear();
296            }
297        }
298        if ( this.getDocumentation() instanceof RuntimeModelObject )
299        {
300            if ( gc )
301            {
302                ( (RuntimeModelObject) this.getDocumentation() ).gc();
303            }
304            if ( clear )
305            {
306                ( (RuntimeModelObject) this.getDocumentation() ).clear();
307            }
308        }
309        if ( this.getImplementations() instanceof RuntimeModelObject )
310        {
311            if ( gc )
312            {
313                ( (RuntimeModelObject) this.getImplementations() ).gc();
314            }
315            if ( clear )
316            {
317                ( (RuntimeModelObject) this.getImplementations() ).clear();
318            }
319        }
320        if ( this.getMessages() instanceof RuntimeModelObject )
321        {
322            if ( gc )
323            {
324                ( (RuntimeModelObject) this.getMessages() ).gc();
325            }
326            if ( clear )
327            {
328                ( (RuntimeModelObject) this.getMessages() ).clear();
329            }
330        }
331        if ( this.getProperties() instanceof RuntimeModelObject )
332        {
333            if ( gc )
334            {
335                ( (RuntimeModelObject) this.getProperties() ).gc();
336            }
337            if ( clear )
338            {
339                ( (RuntimeModelObject) this.getProperties() ).clear();
340            }
341        }
342        if ( this.getSpecifications() instanceof RuntimeModelObject )
343        {
344            if ( gc )
345            {
346                ( (RuntimeModelObject) this.getSpecifications() ).gc();
347            }
348            if ( clear )
349            {
350                ( (RuntimeModelObject) this.getSpecifications() ).clear();
351            }
352        }
353    }
354
355    // SECTION-END
356    // SECTION-START[Constructors]
357    // <editor-fold defaultstate="collapsed" desc=" Generated Constructors ">
358    /** Creates a new {@code RuntimeImplementation} instance. */
359    @javax.annotation.Generated( value = "org.jomc.tools.SourceFileProcessor 1.9", comments = "See http://www.jomc.org/jomc/1.9/jomc-tools-1.9" )
360    public RuntimeImplementation()
361    {
362        // SECTION-START[Default Constructor]
363        super();
364        // SECTION-END
365    }
366    // </editor-fold>
367    // SECTION-END
368    // SECTION-START[Dependencies]
369    // SECTION-END
370    // SECTION-START[Properties]
371    // SECTION-END
372    // SECTION-START[Messages]
373    // SECTION-END
374
375}