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: RuntimeSpecifications.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.Specification;
041    import org.jomc.model.SpecificationReference;
042    import org.jomc.model.Specifications;
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 Specifications}.
049     *
050     * <dl>
051     *   <dt><b>Identifier:</b></dt><dd>org.jomc.ri.model.RuntimeSpecifications</dd>
052     *   <dt><b>Name:</b></dt><dd>JOMC RI RuntimeSpecifications</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 RuntimeSpecifications extends Specifications implements RuntimeModelObject
071    {
072        // SECTION-START[RuntimeSpecifications]
073    
074        /** Cache map. */
075        @XmlTransient
076        private transient final Map<String, Specification> specificationsByIdentifierCache = createMap();
077    
078        /** Cache map. */
079        @XmlTransient
080        private transient final Map<String, Specification> specificationsByClassCache = createMap();
081    
082        /** Cache map. */
083        @XmlTransient
084        private transient final Map<String, SpecificationReference> referencesByIdentifierCache = createMap();
085    
086        /**
087         * Creates a new {@code RuntimeSpecifications} instance by deeply copying a given {@code Specifications} instance.
088         *
089         * @param specifications The instance to copy.
090         *
091         * @throws NullPointerException if {@code specifications} is {@code null}.
092         */
093        public RuntimeSpecifications( final Specifications specifications )
094        {
095            super( specifications );
096    
097            if ( this.getAuthors() != null )
098            {
099                this.setAuthors( RuntimeModelObjects.getInstance().copyOf( this.getAuthors() ) );
100            }
101            if ( this.getDocumentation() != null )
102            {
103                this.setDocumentation( RuntimeModelObjects.getInstance().copyOf( this.getDocumentation() ) );
104            }
105    
106            this.copySpecifications();
107            this.copyReferences();
108        }
109    
110        /**
111         * Gets a specification for a given identifier from the list of specifications.
112         * <p>This method queries an internal cache for a result object to return for the given argument values. If no
113         * cached result object is available, this method queries the super-class for a result object to return and caches
114         * the outcome of that query for use on successive calls.</p>
115         * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
116         * state of the instance, should the state of the instance change.</p>
117         *
118         * @param specification The identifier of the specification to return.
119         *
120         * @return The first matching specification or {@code null}, if no such specification is found.
121         *
122         * @throws NullPointerException if {@code specification} is {@code null}.
123         *
124         * @see #getSpecification()
125         * @see Specification#getIdentifier()
126         * @see #clear()
127         */
128        @Override
129        public Specification getSpecification( final String specification )
130        {
131            if ( specification == null )
132            {
133                throw new NullPointerException( "specification" );
134            }
135    
136            synchronized ( this.specificationsByIdentifierCache )
137            {
138                Specification s = this.specificationsByIdentifierCache.get( specification );
139    
140                if ( s == null && !this.specificationsByIdentifierCache.containsKey( specification ) )
141                {
142                    s = super.getSpecification( specification );
143                    this.specificationsByIdentifierCache.put( specification, s );
144                }
145    
146                return s;
147            }
148        }
149    
150        /**
151         * Gets a specification for a given class from the list of specifications.
152         * <p>This method queries an internal cache for a result object to return for the given argument values. If no
153         * cached result object is available, this method queries the super-class for a result object to return and caches
154         * the outcome of that query for use on successive calls.</p>
155         * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
156         * state of the instance, should the state of the instance change.</p>
157         *
158         * @param specification The class of the specification to return.
159         *
160         * @return The first matching specification or {@code null}, if no such specification is found.
161         *
162         * @throws NullPointerException if {@code specification} is {@code null}.
163         *
164         * @see #getSpecification()
165         * @see Specification#isClassDeclaration()
166         * @see Specification#getClazz()
167         * @see #clear()
168         */
169        @Override
170        public Specification getSpecification( final Class<?> specification )
171        {
172            if ( specification == null )
173            {
174                throw new NullPointerException( "specification" );
175            }
176    
177            synchronized ( this.specificationsByClassCache )
178            {
179                Specification s = this.specificationsByClassCache.get( specification.getName() );
180    
181                if ( s == null && !this.specificationsByClassCache.containsKey( specification.getName() ) )
182                {
183                    s = super.getSpecification( specification );
184                    this.specificationsByClassCache.put( specification.getName(), s );
185                }
186    
187                return s;
188            }
189        }
190    
191        /**
192         * Gets a specification reference for a given identifier from the list of references.
193         * <p>This method queries an internal cache for a result object to return for the given argument values. If no
194         * cached result object is available, this method queries the super-class for a result object to return and caches
195         * the outcome of that query for use on successive calls.</p>
196         * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
197         * state of the instance, should the state of the instance change.</p>
198         *
199         * @param specification The identifier of the reference to return.
200         *
201         * @return The first matching specification reference or {@code null}, if no such specification reference is found.
202         *
203         * @throws NullPointerException if {@code specification} is {@code null}.
204         *
205         * @see #getReference()
206         * @see SpecificationReference#getIdentifier()
207         * @see #clear()
208         */
209        @Override
210        public SpecificationReference getReference( final String specification )
211        {
212            if ( specification == null )
213            {
214                throw new NullPointerException( "specification" );
215            }
216    
217            synchronized ( this.referencesByIdentifierCache )
218            {
219                SpecificationReference r = this.referencesByIdentifierCache.get( specification );
220    
221                if ( r == null && !this.referencesByIdentifierCache.containsKey( specification ) )
222                {
223                    r = super.getReference( specification );
224                    this.referencesByIdentifierCache.put( specification, r );
225                }
226    
227                return r;
228            }
229        }
230    
231        private void copySpecifications()
232        {
233            for ( int i = 0, s0 = this.getSpecification().size(); i < s0; i++ )
234            {
235                final Specification s = this.getSpecification().get( i );
236                this.getSpecification().set( i, RuntimeModelObjects.getInstance().copyOf( s ) );
237            }
238        }
239    
240        private void copyReferences()
241        {
242            for ( int i = 0, s0 = this.getReference().size(); i < s0; i++ )
243            {
244                final SpecificationReference r = this.getReference().get( i );
245                this.getReference().set( i, RuntimeModelObjects.getInstance().copyOf( r ) );
246            }
247        }
248    
249        // SECTION-END
250        // SECTION-START[RuntimeModelObject]
251        public void gc()
252        {
253            this.gcOrClear( true, false );
254        }
255    
256        public void clear()
257        {
258            synchronized ( this.specificationsByClassCache )
259            {
260                this.specificationsByClassCache.clear();
261            }
262            synchronized ( this.specificationsByIdentifierCache )
263            {
264                this.specificationsByIdentifierCache.clear();
265            }
266            synchronized ( this.referencesByIdentifierCache )
267            {
268                this.referencesByIdentifierCache.clear();
269            }
270    
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.getDocumentation() instanceof RuntimeModelObject )
288            {
289                if ( gc )
290                {
291                    ( (RuntimeModelObject) this.getDocumentation() ).gc();
292                }
293                if ( clear )
294                {
295                    ( (RuntimeModelObject) this.getDocumentation() ).clear();
296                }
297            }
298    
299            this.gcOrClearReferences( gc, clear );
300            this.gcOrClearSpecifications( gc, clear );
301        }
302    
303        private void gcOrClearSpecifications( final boolean gc, final boolean clear )
304        {
305            for ( int i = 0, s0 = this.getSpecification().size(); i < s0; i++ )
306            {
307                final Specification s = this.getSpecification().get( i );
308                if ( s instanceof RuntimeModelObject )
309                {
310                    if ( gc )
311                    {
312                        ( (RuntimeModelObject) s ).gc();
313                    }
314                    if ( clear )
315                    {
316                        ( (RuntimeModelObject) s ).clear();
317                    }
318                }
319            }
320        }
321    
322        private void gcOrClearReferences( final boolean gc, final boolean clear )
323        {
324            for ( int i = 0, s0 = this.getReference().size(); i < s0; i++ )
325            {
326                final SpecificationReference r = this.getReference().get( i );
327                if ( r instanceof RuntimeModelObject )
328                {
329                    if ( gc )
330                    {
331                        ( (RuntimeModelObject) r ).gc();
332                    }
333                    if ( clear )
334                    {
335                        ( (RuntimeModelObject) r ).clear();
336                    }
337                }
338            }
339        }
340        // SECTION-END
341        // SECTION-START[Constructors]
342        // <editor-fold defaultstate="collapsed" desc=" Generated Constructors ">
343        /** Creates a new {@code RuntimeSpecifications} instance. */
344        @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" )
345        public RuntimeSpecifications()
346        {
347            // SECTION-START[Default Constructor]
348            super();
349            // SECTION-END
350        }
351        // </editor-fold>
352        // SECTION-END
353        // SECTION-START[Dependencies]
354        // SECTION-END
355        // SECTION-START[Properties]
356        // SECTION-END
357        // SECTION-START[Messages]
358        // SECTION-END
359    }