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