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: RuntimeImplementations.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.util.Map;
039import javax.xml.bind.annotation.XmlTransient;
040import org.jomc.model.Implementation;
041import org.jomc.model.ImplementationReference;
042import org.jomc.model.Implementations;
043import org.jomc.model.ModelObjectException;
044import static org.jomc.ri.model.RuntimeModelObjects.createMap;
045
046// SECTION-START[Documentation]
047// <editor-fold defaultstate="collapsed" desc=" Generated Documentation ">
048/**
049 * Runtime {@code Implementations}.
050 *
051 * <dl>
052 *   <dt><b>Identifier:</b></dt><dd>org.jomc.ri.model.RuntimeImplementations</dd>
053 *   <dt><b>Name:</b></dt><dd>JOMC ⁑ RI ⁑ RuntimeImplementations</dd>
054 *   <dt><b>Specifications:</b></dt>
055 *     <dd>org.jomc.ri.model.RuntimeModelObject @ 1.2</dd>
056 *   <dt><b>Abstract:</b></dt><dd>No</dd>
057 *   <dt><b>Final:</b></dt><dd>No</dd>
058 *   <dt><b>Stateless:</b></dt><dd>No</dd>
059 * </dl>
060 *
061 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> 1.2
062 * @version 1.2
063 */
064// </editor-fold>
065// SECTION-END
066// SECTION-START[Annotations]
067// <editor-fold defaultstate="collapsed" desc=" Generated Annotations ">
068@javax.annotation.Generated( value = "org.jomc.tools.SourceFileProcessor 1.4", comments = "See http://www.jomc.org/jomc/1.4/jomc-tools-1.4" )
069// </editor-fold>
070// SECTION-END
071public class RuntimeImplementations extends Implementations implements RuntimeModelObject
072{
073    // SECTION-START[RuntimeImplementations]
074
075    /** Cache map. */
076    @XmlTransient
077    private transient final Map<String, Implementation> implementationsByIdentifierCache = createMap();
078
079    /** Cache map. */
080    @XmlTransient
081    private transient final Map<String, Implementation> implementationsByClassCache = createMap();
082
083    /** Cache map. */
084    @XmlTransient
085    private transient final Map<String, Implementation> implementationsByNameCache = createMap();
086
087    /** Cache map. */
088    @XmlTransient
089    private transient final Map<String, ImplementationReference> referencesByIdentifierCache = createMap();
090
091    /**
092     * Creates a new {@code RuntimeImplementations} instance by deeply copying a given {@code Implementations} instance.
093     *
094     * @param implementations The instance to copy.
095     *
096     * @throws NullPointerException if {@code implementations} is {@code null}.
097     */
098    public RuntimeImplementations( final Implementations implementations )
099    {
100        super( implementations );
101
102        if ( this.getAuthors() != null )
103        {
104            this.setAuthors( RuntimeModelObjects.getInstance().copyOf( this.getAuthors() ) );
105        }
106        if ( this.getDocumentation() != null )
107        {
108            this.setDocumentation( RuntimeModelObjects.getInstance().copyOf( this.getDocumentation() ) );
109        }
110
111        this.copyImplementations();
112        this.copyImplementationReferences();
113    }
114
115    /**
116     * Gets an implementation for a given identifier from the list of implementations.
117     * <p>This method queries an internal cache for a result object to return for the given argument values. If no
118     * cached result object is available, this method queries the super-class for a result object to return and caches
119     * the outcome of that query for use on successive calls.</p>
120     * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
121     * state of the instance, should the state of the instance change.</p>
122     *
123     * @param implementation The identifier of the implementation to return.
124     *
125     * @return The first matching implementation or {@code null}, if no such implementation is found.
126     *
127     * @throws NullPointerException if {@code implementation} is {@code null}.
128     *
129     * @see #getImplementation()
130     * @see Implementation#getIdentifier()
131     * @see #clear()
132     */
133    @Override
134    public Implementation getImplementation( final String implementation )
135    {
136        if ( implementation == null )
137        {
138            throw new NullPointerException( "implementation" );
139        }
140
141        synchronized ( this.implementationsByIdentifierCache )
142        {
143            Implementation i = this.implementationsByIdentifierCache.get( implementation );
144
145            if ( i == null && !this.implementationsByIdentifierCache.containsKey( implementation ) )
146            {
147                i = super.getImplementation( implementation );
148                this.implementationsByIdentifierCache.put( implementation, i );
149            }
150
151            return i;
152        }
153    }
154
155    /**
156     * Gets an implementation for a given class from the list of implementations.
157     * <p>This method queries an internal cache for a result object to return for the given argument values. If no
158     * cached result object is available, this method queries the super-class for a result object to return and caches
159     * the outcome of that query for use on successive calls.</p>
160     * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
161     * state of the instance, should the state of the instance change.</p>
162     *
163     * @param implementation The class of the implementation to return.
164     *
165     * @return The first matching implementation or {@code null}, if no such implementation is found.
166     *
167     * @throws NullPointerException if {@code implementation} is {@code null}.
168     * @throws ModelObjectException if parsing the name of a referenced type fails.
169     *
170     * @see #getImplementation()
171     * @see Implementation#isClassDeclaration()
172     * @see Implementation#getClazz()
173     * @see #clear()
174     */
175    @Override
176    public Implementation getImplementation( final Class<?> implementation ) throws ModelObjectException
177    {
178        if ( implementation == null )
179        {
180            throw new NullPointerException( "implementation" );
181        }
182
183        synchronized ( this.implementationsByClassCache )
184        {
185            Implementation i = this.implementationsByClassCache.get( implementation.getName() );
186
187            if ( i == null && !this.implementationsByClassCache.containsKey( implementation.getName() ) )
188            {
189                i = super.getImplementation( implementation );
190                this.implementationsByClassCache.put( implementation.getName(), i );
191            }
192
193            return i;
194        }
195    }
196
197    /**
198     * Gets an implementation for a given name from the list of implementations.
199     * <p>This method queries an internal cache for a result object to return for the given argument values. If no
200     * cached result object is available, this method queries the super-class for a result object to return and caches
201     * the outcome of that query for use on successive calls.</p>
202     * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
203     * state of the instance, should the state of the instance change.</p>
204     *
205     * @param name The name of the implementation to return.
206     *
207     * @return The first matching implementation or {@code null}, if no such implementation is found.
208     *
209     * @throws NullPointerException if {@code name} is {@code null}.
210     *
211     * @see #getImplementation()
212     * @see Implementation#getName()
213     * @see #clear()
214     */
215    @Override
216    public Implementation getImplementationByName( final String name )
217    {
218        if ( name == null )
219        {
220            throw new NullPointerException( "name" );
221        }
222
223        synchronized ( this.implementationsByNameCache )
224        {
225            Implementation i = this.implementationsByNameCache.get( name );
226
227            if ( i == null && !this.implementationsByNameCache.containsKey( name ) )
228            {
229                i = super.getImplementationByName( name );
230                this.implementationsByNameCache.put( name, i );
231            }
232
233            return i;
234        }
235    }
236
237    /**
238     * Gets an implementation reference for a given identifier from the list of references.
239     * <p>This method queries an internal cache for a result object to return for the given argument values. If no
240     * cached result object is available, this method queries the super-class for a result object to return and caches
241     * the outcome of that query for use on successive calls.</p>
242     * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
243     * state of the instance, should the state of the instance change.</p>
244     *
245     * @param implementation The identifier of the reference to return.
246     *
247     * @return The first matching implementation reference or {@code null}, if no such reference is found.
248     *
249     * @throws NullPointerException if {@code implementation} is {@code null}.
250     *
251     * @see #getReference()
252     * @see ImplementationReference#getIdentifier()
253     * @see #clear()
254     */
255    @Override
256    public ImplementationReference getReference( final String implementation )
257    {
258        if ( implementation == null )
259        {
260            throw new NullPointerException( "implementation" );
261        }
262
263        synchronized ( this.referencesByIdentifierCache )
264        {
265            ImplementationReference r = this.referencesByIdentifierCache.get( implementation );
266
267            if ( r == null && !this.referencesByIdentifierCache.containsKey( implementation ) )
268            {
269                r = super.getReference( implementation );
270                this.referencesByIdentifierCache.put( implementation, r );
271            }
272
273            return r;
274        }
275    }
276
277    private void copyImplementations()
278    {
279        for ( int i = 0, s0 = this.getImplementation().size(); i < s0; i++ )
280        {
281            final Implementation impl = this.getImplementation().get( i );
282            this.getImplementation().set( i, RuntimeModelObjects.getInstance().copyOf( impl ) );
283        }
284    }
285
286    private void copyImplementationReferences()
287    {
288        for ( int i = 0, s0 = this.getReference().size(); i < s0; i++ )
289        {
290            final ImplementationReference r = this.getReference().get( i );
291            this.getReference().set( i, RuntimeModelObjects.getInstance().copyOf( r ) );
292        }
293    }
294
295    // SECTION-END
296    // SECTION-START[RuntimeModelObject]
297    public void gc()
298    {
299        this.gcOrClear( true, false );
300    }
301
302    public void clear()
303    {
304        synchronized ( this.implementationsByClassCache )
305        {
306            this.implementationsByClassCache.clear();
307        }
308        synchronized ( this.implementationsByIdentifierCache )
309        {
310            this.implementationsByIdentifierCache.clear();
311        }
312        synchronized ( this.implementationsByNameCache )
313        {
314            this.implementationsByNameCache.clear();
315        }
316        synchronized ( this.referencesByIdentifierCache )
317        {
318            this.referencesByIdentifierCache.clear();
319        }
320
321        this.gcOrClear( false, true );
322    }
323
324    private void gcOrClear( final boolean gc, final boolean clear )
325    {
326        if ( this.getAuthors() instanceof RuntimeModelObject )
327        {
328            if ( gc )
329            {
330                ( (RuntimeModelObject) this.getAuthors() ).gc();
331            }
332            if ( clear )
333            {
334                ( (RuntimeModelObject) this.getAuthors() ).clear();
335            }
336        }
337        if ( this.getDocumentation() instanceof RuntimeModelObject )
338        {
339            if ( gc )
340            {
341                ( (RuntimeModelObject) this.getDocumentation() ).gc();
342            }
343            if ( clear )
344            {
345                ( (RuntimeModelObject) this.getDocumentation() ).clear();
346            }
347        }
348
349        this.gcOrClearImplementationReferences( gc, clear );
350        this.gcOrClearImplementations( gc, clear );
351    }
352
353    private void gcOrClearImplementations( final boolean gc, final boolean clear )
354    {
355        for ( int i = 0, s0 = this.getImplementation().size(); i < s0; i++ )
356        {
357            final Implementation impl = this.getImplementation().get( i );
358            if ( impl instanceof RuntimeModelObject )
359            {
360                if ( gc )
361                {
362                    ( (RuntimeModelObject) impl ).gc();
363                }
364                if ( clear )
365                {
366                    ( (RuntimeModelObject) impl ).clear();
367                }
368            }
369        }
370    }
371
372    private void gcOrClearImplementationReferences( final boolean gc, final boolean clear )
373    {
374        for ( int i = 0, s0 = this.getReference().size(); i < s0; i++ )
375        {
376            final ImplementationReference r = this.getReference().get( i );
377            if ( r instanceof RuntimeModelObject )
378            {
379                if ( gc )
380                {
381                    ( (RuntimeModelObject) r ).gc();
382                }
383                if ( clear )
384                {
385                    ( (RuntimeModelObject) r ).clear();
386                }
387            }
388        }
389    }
390
391    // SECTION-END
392    // SECTION-START[Constructors]
393    // <editor-fold defaultstate="collapsed" desc=" Generated Constructors ">
394    /** Creates a new {@code RuntimeImplementations} instance. */
395    @javax.annotation.Generated( value = "org.jomc.tools.SourceFileProcessor 1.4", comments = "See http://www.jomc.org/jomc/1.4/jomc-tools-1.4" )
396    public RuntimeImplementations()
397    {
398        // SECTION-START[Default Constructor]
399        super();
400        // SECTION-END
401    }
402    // </editor-fold>
403    // SECTION-END
404    // SECTION-START[Dependencies]
405    // SECTION-END
406    // SECTION-START[Properties]
407    // SECTION-END
408    // SECTION-START[Messages]
409    // SECTION-END
410}