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: RuntimeModules.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.List;
039    import java.util.Map;
040    import javax.xml.bind.annotation.XmlTransient;
041    import org.jomc.model.Dependencies;
042    import org.jomc.model.Dependency;
043    import org.jomc.model.Implementation;
044    import org.jomc.model.Implementations;
045    import org.jomc.model.Instance;
046    import org.jomc.model.Message;
047    import org.jomc.model.Messages;
048    import org.jomc.model.Module;
049    import org.jomc.model.Modules;
050    import org.jomc.model.Properties;
051    import org.jomc.model.Property;
052    import org.jomc.model.Specification;
053    import org.jomc.model.Specifications;
054    import static org.jomc.ri.model.RuntimeModelObjects.createMap;
055    
056    // SECTION-START[Documentation]
057    // <editor-fold defaultstate="collapsed" desc=" Generated Documentation ">
058    /**
059     * Runtime {@code Modules}.
060     *
061     * <dl>
062     *   <dt><b>Identifier:</b></dt><dd>org.jomc.ri.model.RuntimeModules</dd>
063     *   <dt><b>Name:</b></dt><dd>JOMC RI RuntimeModules</dd>
064     *   <dt><b>Specifications:</b></dt>
065     *     <dd>org.jomc.ri.model.RuntimeModelObject @ 1.2</dd>
066     *   <dt><b>Abstract:</b></dt><dd>No</dd>
067     *   <dt><b>Final:</b></dt><dd>No</dd>
068     *   <dt><b>Stateless:</b></dt><dd>No</dd>
069     * </dl>
070     *
071     * @author <a href="mailto:schulte2005@users.sourceforge.net">Christian Schulte</a> 1.2
072     * @version 1.2
073     */
074    // </editor-fold>
075    // SECTION-END
076    // SECTION-START[Annotations]
077    // <editor-fold defaultstate="collapsed" desc=" Generated Annotations ">
078    @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" )
079    // </editor-fold>
080    // SECTION-END
081    public class RuntimeModules extends Modules implements RuntimeModelObject
082    {
083        // SECTION-START[RuntimeModules]
084    
085        /** Cache map. */
086        @XmlTransient
087        private transient final Map<String, Module> modulesByNameCache = createMap();
088    
089        /** Cache map. */
090        @XmlTransient
091        private transient final Map<String, Specifications> specificationsCache = createMap();
092    
093        /** Cache map. */
094        @XmlTransient
095        private transient final Map<String, Implementations> implementationsCache = createMap();
096    
097        /** Cache map. */
098        @XmlTransient
099        private transient final Map<String, Module> moduleBySpecificationIdentifierCache = createMap();
100    
101        /** Cache map. */
102        @XmlTransient
103        private transient final Map<String, Module> moduleByImplementationIdentifierCache = createMap();
104    
105        /** Cache map. */
106        @XmlTransient
107        private transient final Map<String, Specification> specificationByIdentifierCache = createMap();
108    
109        /** Cache map. */
110        @XmlTransient
111        private transient final Map<String, Specification> specificationByClassNameCache = createMap();
112    
113        /** Cache map. */
114        @XmlTransient
115        private transient final Map<String, Specifications> specificationsByImplemenationIdentifierCache = createMap();
116    
117        /** Cache map. */
118        @XmlTransient
119        private transient final Map<String, Implementation> implementationByIdentifierCache = createMap();
120    
121        /** Cache map. */
122        @XmlTransient
123        private transient final Map<String, Implementation> implementationByClassNameCache = createMap();
124    
125        /** Cache map. */
126        @XmlTransient
127        private transient final Map<String, Implementation> implementationByObjectClassNameCache = createMap();
128    
129        /** Cache map. */
130        @XmlTransient
131        private transient final Map<String, Implementation> implementationBySpecificationAndNameCache = createMap();
132    
133        /** Cache map. */
134        @XmlTransient
135        private transient final Map<String, Dependencies> dependenciesByImplementationIdentifierCache = createMap();
136    
137        /** Cache map. */
138        @XmlTransient
139        private transient final Map<String, Properties> propertiesByImplementationIdentifierCache = createMap();
140    
141        /** Cache map. */
142        @XmlTransient
143        private transient final Map<String, Properties> specifiedPropertiesByImplementationIdentifierCache = createMap();
144    
145        /** Cache map. */
146        @XmlTransient
147        private transient final Map<String, Messages> messagesByImplementationIdentifierCache = createMap();
148    
149        /** Cache map. */
150        @XmlTransient
151        private transient final Map<String, Implementations> implementationsBySpecificationIdentifierCache = createMap();
152    
153        /** Cache map. */
154        @XmlTransient
155        private transient final Map<String, List<Object>> anyObjectsByImplemenationIdentifierCache = createMap();
156    
157        /**
158         * Creates a new {@code RuntimeModules} instance by deeply copying a given {@code Modules} instance.
159         *
160         * @param modules The instance to copy.
161         *
162         * @throws NullPointerException if {@code modules} is {@code null}.
163         */
164        public RuntimeModules( final Modules modules )
165        {
166            super( modules );
167    
168            if ( this.getAuthors() != null )
169            {
170                this.setAuthors( RuntimeModelObjects.getInstance().copyOf( this.getAuthors() ) );
171            }
172            if ( this.getDocumentation() != null )
173            {
174                this.setDocumentation( RuntimeModelObjects.getInstance().copyOf( this.getDocumentation() ) );
175            }
176    
177            this.copyModules();
178        }
179    
180        /**
181         * Creates a new {@code DefaultModules} instance by deeply copying a given {@code Modules} instance taking a map
182         * backing the instance.
183         *
184         * @param modules The instance to copy.
185         * @param objects The map backing the instance.
186         *
187         * @throws NullPointerException if {@code modules} or {@code objects} is {@code null}.
188         */
189        public RuntimeModules( final Modules modules, final Map<Object, Instance> objects )
190        {
191            super( modules, objects );
192    
193            if ( this.getAuthors() != null )
194            {
195                this.setAuthors( RuntimeModelObjects.getInstance().copyOf( this.getAuthors() ) );
196            }
197            if ( this.getDocumentation() != null )
198            {
199                this.setDocumentation( RuntimeModelObjects.getInstance().copyOf( this.getDocumentation() ) );
200            }
201    
202            this.copyModules();
203        }
204    
205        /**
206         * Gets a module for a given name from the list of modules.
207         * <p>This method queries an internal cache for a result object to return for the given argument values. If no
208         * cached result object is available, this method queries the super-class for a result object to return and caches
209         * the outcome of that query for use on successive calls.</p>
210         * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
211         * state of the instance, should the state of the instance change.</p>
212         *
213         * @param name The name of the module to return.
214         *
215         * @return The first matching module or {@code null}, if no such module is found.
216         *
217         * @throws NullPointerException if {@code name} is {@code null}.
218         *
219         * @see #getModule()
220         * @see Module#getName()
221         * @see #clear()
222         */
223        @Override
224        public Module getModule( final String name )
225        {
226            if ( name == null )
227            {
228                throw new NullPointerException( "name" );
229            }
230    
231            synchronized ( this.modulesByNameCache )
232            {
233                Module m = this.modulesByNameCache.get( name );
234    
235                if ( m == null && !this.modulesByNameCache.containsKey( name ) )
236                {
237                    m = super.getModule( name );
238                    this.modulesByNameCache.put( name, m );
239                }
240    
241                return m;
242            }
243        }
244    
245        /**
246         * Gets all specifications of the list of modules.
247         * <p>This method queries an internal cache for a result object to return. If no cached result object is available,
248         * this method queries the super-class for a result object to return and caches the outcome of that query for use on
249         * successive calls.</p>
250         * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
251         * state of the instance, should the state of the instance change.</p>
252         *
253         * @return All specifications or {@code null}, if no specifications are found.
254         *
255         * @see #getModule()
256         * @see #clear()
257         */
258        @Override
259        public Specifications getSpecifications()
260        {
261            synchronized ( this.specificationsCache )
262            {
263                Specifications s = this.specificationsCache.get( RuntimeModules.class.getName() );
264    
265                if ( s == null && !this.specificationsCache.containsKey( RuntimeModules.class.getName() ) )
266                {
267                    s = super.getSpecifications();
268    
269                    if ( s != null )
270                    {
271                        s = RuntimeModelObjects.getInstance().copyOf( s );
272                    }
273    
274                    this.specificationsCache.put( RuntimeModules.class.getName(), s );
275                }
276    
277                return s;
278            }
279        }
280    
281        /**
282         * Gets all specifications of the list of modules.
283         * <p>This method queries an internal cache for a result object to return. If no cached result object is available,
284         * this method queries the super-class for a result object to return and caches the outcome of that query for use on
285         * successive calls.</p>
286         * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
287         * state of the instance, should the state of the instance change.</p>
288         *
289         * @return All specifications or {@code null}, if no specifications are found.
290         *
291         * @see #getModule()
292         * @see #clear()
293         */
294        @Override
295        public Implementations getImplementations()
296        {
297            synchronized ( this.implementationsCache )
298            {
299                Implementations i = this.implementationsCache.get( RuntimeModules.class.getName() );
300    
301                if ( i == null && !this.implementationsCache.containsKey( RuntimeModules.class.getName() ) )
302                {
303                    i = super.getImplementations();
304    
305                    if ( i != null )
306                    {
307                        i = RuntimeModelObjects.getInstance().copyOf( i );
308                    }
309    
310                    this.implementationsCache.put( RuntimeModules.class.getName(), i );
311                }
312    
313                return i;
314            }
315        }
316    
317        /**
318         * Gets the module declaring a given specification from the list of modules.
319         * <p>This method queries an internal cache for a result object to return for the given argument values. If no
320         * cached result object is available, this method queries the super-class for a result object to return and caches
321         * the outcome of that query for use on successive calls.</p>
322         * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
323         * state of the instance, should the state of the instance change.</p>
324         *
325         * @param specification The identifier of the specification whose declaring module to return.
326         *
327         * @return The first matching module or {@code null}, if no such module is found.
328         *
329         * @throws NullPointerException if {@code specification} is {@code null}.
330         *
331         * @see #getModule()
332         * @see Module#getSpecifications()
333         * @see Specifications#getSpecification( java.lang.String )
334         * @see #clear()
335         */
336        @Override
337        public Module getModuleOfSpecification( final String specification )
338        {
339            if ( specification == null )
340            {
341                throw new NullPointerException( "specification" );
342            }
343    
344            synchronized ( this.moduleBySpecificationIdentifierCache )
345            {
346                Module m = this.moduleBySpecificationIdentifierCache.get( specification );
347    
348                if ( m == null && !this.moduleBySpecificationIdentifierCache.containsKey( specification ) )
349                {
350                    m = super.getModuleOfSpecification( specification );
351                    this.moduleBySpecificationIdentifierCache.put( specification, m );
352                }
353    
354                return m;
355            }
356        }
357    
358        /**
359         * Gets the module declaring a given implementation from the list of modules.
360         * <p>This method queries an internal cache for a result object to return for the given argument values. If no
361         * cached result object is available, this method queries the super-class for a result object to return and caches
362         * the outcome of that query for use on successive calls.</p>
363         * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
364         * state of the instance, should the state of the instance change.</p>
365         *
366         * @param implementation The identifier of the implementation whose declaring module to return.
367         *
368         * @return The first matching module or {@code null}, if no such module is found.
369         *
370         * @throws NullPointerException if {@code implementation} is {@code null}.
371         *
372         * @see #getModule()
373         * @see Module#getImplementations()
374         * @see Implementations#getImplementation( java.lang.String )
375         * @see #clear()
376         */
377        @Override
378        public Module getModuleOfImplementation( final String implementation )
379        {
380            if ( implementation == null )
381            {
382                throw new NullPointerException( "implementation" );
383            }
384    
385            synchronized ( this.moduleByImplementationIdentifierCache )
386            {
387                Module m = this.moduleByImplementationIdentifierCache.get( implementation );
388    
389                if ( m == null && !this.moduleByImplementationIdentifierCache.containsKey( implementation ) )
390                {
391                    m = super.getModuleOfImplementation( implementation );
392                    this.moduleByImplementationIdentifierCache.put( implementation, m );
393                }
394    
395                return m;
396            }
397        }
398    
399        /**
400         * Gets a specification for a given identifier from the list of modules.
401         * <p>This method queries an internal cache for a result object to return for the given argument values. If no
402         * cached result object is available, this method queries the super-class for a result object to return and caches
403         * the outcome of that query for use on successive calls.</p>
404         * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
405         * state of the instance, should the state of the instance change.</p>
406         *
407         * @param specification The identifier of the specification to return.
408         *
409         * @return The first matching specification or {@code null}, if no such specification is found.
410         *
411         * @throws NullPointerException if {@code specification} is {@code null}.
412         *
413         * @see #getModule()
414         * @see Module#getSpecifications()
415         * @see Specifications#getSpecification( java.lang.String )
416         * @see #clear()
417         */
418        @Override
419        public Specification getSpecification( final String specification )
420        {
421            if ( specification == null )
422            {
423                throw new NullPointerException( "specification" );
424            }
425    
426            synchronized ( this.specificationByIdentifierCache )
427            {
428                Specification s = this.specificationByIdentifierCache.get( specification );
429    
430                if ( s == null && !this.specificationByIdentifierCache.containsKey( specification ) )
431                {
432                    s = super.getSpecification( specification );
433                    this.specificationByIdentifierCache.put( specification, s );
434                }
435    
436                return s;
437            }
438        }
439    
440        /**
441         * Gets a specification for a given class from the list of modules.
442         * <p>This method queries an internal cache for a result object to return for the given argument values. If no
443         * cached result object is available, this method queries the super-class for a result object to return and caches
444         * the outcome of that query for use on successive calls.</p>
445         * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
446         * state of the instance, should the state of the instance change.</p>
447         *
448         * @param specification The class of the specification to return.
449         *
450         * @return The first matching specification or {@code null}, if no such specification is found.
451         *
452         * @throws NullPointerException if {@code specification} is {@code null}.
453         *
454         * @see #getModule()
455         * @see Module#getSpecifications()
456         * @see Specifications#getSpecification( java.lang.Class )
457         * @see #clear()
458         */
459        @Override
460        public Specification getSpecification( final Class<?> specification )
461        {
462            if ( specification == null )
463            {
464                throw new NullPointerException( "specification" );
465            }
466    
467            synchronized ( this.specificationByClassNameCache )
468            {
469                Specification s = this.specificationByClassNameCache.get( specification.getName() );
470    
471                if ( s == null && !this.specificationByClassNameCache.containsKey( specification.getName() ) )
472                {
473                    s = super.getSpecification( specification );
474                    this.specificationByClassNameCache.put( specification.getName(), s );
475                }
476    
477                return s;
478            }
479        }
480    
481        /**
482         * Gets all specifications an implementation implements from the list of modules.
483         * <p>This method queries an internal cache for a result object to return for the given argument values. If no
484         * cached result object is available, this method queries the super-class for a result object to return and caches
485         * the outcome of that query for use on successive calls.</p>
486         * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
487         * state of the instance, should the state of the instance change.</p>
488         *
489         * @param implementation The identifier of the implementation to get all implemented specifications of.
490         *
491         * @return All specifications implemented by the first matching implementation or {@code null}, if no such
492         * implementation is found or if the first matching implementation does not implement any specification.
493         *
494         * @throws NullPointerException if {@code implementation} is {@code null}.
495         *
496         * @see #getModule()
497         * @see #getImplementation( java.lang.String )
498         * @see Implementation#getImplementations()
499         * @see Implementations#getReference()
500         * @see #clear()
501         */
502        @Override
503        public Specifications getSpecifications( final String implementation )
504        {
505            if ( implementation == null )
506            {
507                throw new NullPointerException( "implementation" );
508            }
509    
510            synchronized ( this.specificationsByImplemenationIdentifierCache )
511            {
512                Specifications s = this.specificationsByImplemenationIdentifierCache.get( implementation );
513    
514                if ( s == null && !this.specificationsByImplemenationIdentifierCache.containsKey( implementation ) )
515                {
516                    s = super.getSpecifications( implementation );
517    
518                    if ( s != null )
519                    {
520                        s = RuntimeModelObjects.getInstance().copyOf( s );
521                    }
522    
523                    this.specificationsByImplemenationIdentifierCache.put( implementation, s );
524                }
525    
526                return s;
527            }
528        }
529    
530        /**
531         * Gets an implementation for a given identifier from the list of modules.
532         * <p>This method queries an internal cache for a result object to return for the given argument values. If no
533         * cached result object is available, this method queries the super-class for a result object to return and caches
534         * the outcome of that query for use on successive calls.</p>
535         * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
536         * state of the instance, should the state of the instance change.</p>
537         *
538         * @param implementation The identifier of the implementation to return.
539         *
540         * @return The first matching implementation or {@code null}, if no such implementation is found.
541         *
542         * @throws NullPointerException if {@code implementation} is {@code null}.
543         *
544         * @see #getModule()
545         * @see Module#getImplementations()
546         * @see Implementations#getImplementation( java.lang.String )
547         * @see #clear()
548         */
549        @Override
550        public Implementation getImplementation( final String implementation )
551        {
552            if ( implementation == null )
553            {
554                throw new NullPointerException( "implementation" );
555            }
556    
557            synchronized ( this.implementationByIdentifierCache )
558            {
559                Implementation i = this.implementationByIdentifierCache.get( implementation );
560    
561                if ( i == null && !this.implementationByIdentifierCache.containsKey( implementation ) )
562                {
563                    i = super.getImplementation( implementation );
564                    this.implementationByIdentifierCache.put( implementation, i );
565                }
566    
567                return i;
568            }
569        }
570    
571        /**
572         * Gets an implementation for a given class from the list of modules.
573         * <p>This method queries an internal cache for a result object to return for the given argument values. If no
574         * cached result object is available, this method queries the super-class for a result object to return and caches
575         * the outcome of that query for use on successive calls.</p>
576         * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
577         * state of the instance, should the state of the instance change.</p>
578         *
579         * @param implementation The class of the implementation to return.
580         *
581         * @return The first matching implementation or {@code null}, if no such implementation is found.
582         *
583         * @throws NullPointerException if {@code implementation} is {@code null}.
584         *
585         * @see #getModule()
586         * @see Module#getImplementations()
587         * @see Implementations#getImplementation( java.lang.Class )
588         * @see #clear()
589         */
590        @Override
591        public Implementation getImplementation( final Class<?> implementation )
592        {
593            if ( implementation == null )
594            {
595                throw new NullPointerException( "implementation" );
596            }
597    
598            synchronized ( this.implementationByClassNameCache )
599            {
600                Implementation i = this.implementationByClassNameCache.get( implementation.getName() );
601    
602                if ( i == null && !this.implementationByClassNameCache.containsKey( implementation.getName() ) )
603                {
604                    i = super.getImplementation( implementation );
605                    this.implementationByClassNameCache.put( implementation.getName(), i );
606                }
607    
608                return i;
609            }
610        }
611    
612        /**
613         * Gets an implementation for a given object from the list of modules.
614         * <p>This method queries an internal cache for a result object to return for the given argument values. If no
615         * cached result object is available, this method queries the super-class for a result object to return and caches
616         * the outcome of that query for use on successive calls.</p>
617         * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
618         * state of the instance, should the state of the instance change.</p>
619         *
620         * @param object The object of the implementation to return.
621         *
622         * @return The first matching implementation or {@code null}, if no such implementation is found.
623         *
624         * @throws NullPointerException if {@code object} is {@code null}.
625         *
626         * @see #getModule()
627         * @see #getImplementation( java.lang.Class )
628         * @see #clear()
629         */
630        @Override
631        public Implementation getImplementation( final Object object )
632        {
633            if ( object == null )
634            {
635                throw new NullPointerException( "object" );
636            }
637    
638            synchronized ( this.implementationByObjectClassNameCache )
639            {
640                Implementation i = this.implementationByObjectClassNameCache.get( object.getClass().getName() );
641    
642                if ( i == null && !this.implementationByObjectClassNameCache.containsKey( object.getClass().getName() ) )
643                {
644                    i = super.getImplementation( object );
645                    this.implementationByObjectClassNameCache.put( object.getClass().getName(), i );
646                }
647    
648                return i;
649            }
650        }
651    
652        /**
653         * Gets an implementation for a given name implementing a given specification from the list of modules.
654         * <p>This method queries an internal cache for a result object to return for the given argument values. If no
655         * cached result object is available, this method queries the super-class for a result object to return and caches
656         * the outcome of that query for use on successive calls.</p>
657         * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
658         * state of the instance, should the state of the instance change.</p>
659         *
660         * @param specification The identifier of the specification to return an implementation of.
661         * @param name The name of the implementation to return.
662         *
663         * @return The first matching implementation or {@code null}, if no such implementation is found.
664         *
665         * @throws NullPointerException if {@code specification} or {@code name} is {@code null}.
666         *
667         * @see #getModule()
668         * @see #getImplementations( java.lang.String )
669         * @see Implementations#getImplementationByName( java.lang.String )
670         * @see #clear()
671         */
672        @Override
673        public Implementation getImplementation( final String specification, final String name )
674        {
675            if ( specification == null )
676            {
677                throw new NullPointerException( "specification" );
678            }
679            if ( name == null )
680            {
681                throw new NullPointerException( "name" );
682            }
683    
684            synchronized ( this.implementationBySpecificationAndNameCache )
685            {
686                final String key = specification + "|" + name;
687                Implementation i = this.implementationBySpecificationAndNameCache.get( key );
688    
689                if ( i == null && !this.implementationBySpecificationAndNameCache.containsKey( key ) )
690                {
691                    i = super.getImplementation( specification, name );
692                    this.implementationBySpecificationAndNameCache.put( key, i );
693                }
694    
695                return i;
696            }
697        }
698    
699        /**
700         * Gets all dependencies of an implementation from the list of modules.
701         * <p>This method queries an internal cache for a result object to return for the given argument values. If no
702         * cached result object is available, this method queries the super-class for a result object to return and caches
703         * the outcome of that query for use on successive calls.</p>
704         * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
705         * state of the instance, should the state of the instance change.</p>
706         *
707         * @param implementation The identifier of the implementation to get all dependencies of.
708         *
709         * @return All dependencies of the first matching implementation or {@code null}, if no such implementation is
710         * found or if the first matching implementation does not have any dependencies.
711         *
712         * @throws NullPointerException if {@code implementation} is {@code null}.
713         *
714         * @see #getModule()
715         * @see #getImplementation( java.lang.String )
716         * @see Implementation#getImplementations()
717         * @see Implementations#getReference()
718         * @see #clear()
719         */
720        @Override
721        public Dependencies getDependencies( final String implementation )
722        {
723            if ( implementation == null )
724            {
725                throw new NullPointerException( "implementation" );
726            }
727    
728            synchronized ( this.dependenciesByImplementationIdentifierCache )
729            {
730                Dependencies d = this.dependenciesByImplementationIdentifierCache.get( implementation );
731    
732                if ( d == null && !this.dependenciesByImplementationIdentifierCache.containsKey( implementation ) )
733                {
734                    d = super.getDependencies( implementation );
735    
736                    if ( d != null )
737                    {
738                        d = RuntimeModelObjects.getInstance().copyOf( d );
739                    }
740    
741                    this.dependenciesByImplementationIdentifierCache.put( implementation, d );
742                }
743    
744                return d;
745            }
746        }
747    
748        /**
749         * Gets all properties of an implementation from the list of modules.
750         * <p>This method queries an internal cache for a result object to return for the given argument values. If no
751         * cached result object is available, this method queries the super-class for a result object to return and caches
752         * the outcome of that query for use on successive calls.</p>
753         * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
754         * state of the instance, should the state of the instance change.</p>
755         *
756         * @param implementation The identifier of the implementation to get all properties of.
757         *
758         * @return All properties of the first matching implementation or {@code null}, if no such implementation is found
759         * or if the first matching implementation does not have any properties.
760         *
761         * @throws NullPointerException if {@code implementation} is {@code null}.
762         *
763         * @see #getModule()
764         * @see #getImplementation( java.lang.String )
765         * @see Implementation#getImplementations()
766         * @see Implementations#getReference()
767         * @see #clear()
768         */
769        @Override
770        public Properties getProperties( final String implementation )
771        {
772            if ( implementation == null )
773            {
774                throw new NullPointerException( "implementation" );
775            }
776    
777            synchronized ( this.propertiesByImplementationIdentifierCache )
778            {
779                Properties p = this.propertiesByImplementationIdentifierCache.get( implementation );
780    
781                if ( p == null && !this.propertiesByImplementationIdentifierCache.containsKey( implementation ) )
782                {
783                    p = super.getProperties( implementation );
784    
785                    if ( p != null )
786                    {
787                        p = RuntimeModelObjects.getInstance().copyOf( p );
788                    }
789    
790                    this.propertiesByImplementationIdentifierCache.put( implementation, p );
791                }
792    
793                return p;
794            }
795        }
796    
797        /**
798         * Gets all properties specified for an implementation from the list of modules.
799         * <p>This method queries an internal cache for a result object to return for the given argument values. If no
800         * cached result object is available, this method queries the super-class for a result object to return and caches
801         * the outcome of that query for use on successive calls.</p>
802         * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
803         * state of the instance, should the state of the instance change.</p>
804         *
805         * @param implementation The identifier of the implementation to return specified properties of.
806         *
807         * @return All properties specified for the first matching implementation or {@code null}, if no such implementation
808         * is found or if the first matching implementation does not have any specified properties.
809         *
810         * @throws NullPointerException if {@code implementation} is {@code null}.
811         *
812         * @see #getModule()
813         * @see #getSpecifications( java.lang.String )
814         * @see Specification#getProperties()
815         * @see #clear()
816         */
817        @Override
818        public Properties getSpecifiedProperties( final String implementation )
819        {
820            if ( implementation == null )
821            {
822                throw new NullPointerException( "implementation" );
823            }
824    
825            synchronized ( this.specifiedPropertiesByImplementationIdentifierCache )
826            {
827                Properties p = this.specifiedPropertiesByImplementationIdentifierCache.get( implementation );
828    
829                if ( p == null && !this.specifiedPropertiesByImplementationIdentifierCache.containsKey( implementation ) )
830                {
831                    p = super.getSpecifiedProperties( implementation );
832    
833                    if ( p != null )
834                    {
835                        p = RuntimeModelObjects.getInstance().copyOf( p );
836                    }
837    
838                    this.specifiedPropertiesByImplementationIdentifierCache.put( implementation, p );
839                }
840    
841                return p;
842            }
843        }
844    
845        /**
846         * Gets all messages of an implementation from the list of modules.
847         * <p>This method queries an internal cache for a result object to return for the given argument values. If no
848         * cached result object is available, this method queries the super-class for a result object to return and caches
849         * the outcome of that query for use on successive calls.</p>
850         * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
851         * state of the instance, should the state of the instance change.</p>
852         *
853         * @param implementation The identifier of the implementation to get all messages of.
854         *
855         * @return All messages of the first matching implementation or {@code null}, if no such implementation is found
856         * or if the first matching implementation does not have any messages.
857         *
858         * @throws NullPointerException if {@code implementation} is {@code null}.
859         *
860         * @see #getModule()
861         * @see #getImplementation( java.lang.String )
862         * @see Implementation#getImplementations()
863         * @see Implementations#getReference()
864         * @see #clear()
865         */
866        @Override
867        public Messages getMessages( final String implementation )
868        {
869            if ( implementation == null )
870            {
871                throw new NullPointerException( "implementation" );
872            }
873    
874            synchronized ( this.messagesByImplementationIdentifierCache )
875            {
876                Messages m = this.messagesByImplementationIdentifierCache.get( implementation );
877    
878                if ( m == null && !this.messagesByImplementationIdentifierCache.containsKey( implementation ) )
879                {
880                    m = super.getMessages( implementation );
881    
882                    if ( m != null )
883                    {
884                        m = RuntimeModelObjects.getInstance().copyOf( m );
885                    }
886    
887                    this.messagesByImplementationIdentifierCache.put( implementation, m );
888                }
889    
890                return m;
891            }
892        }
893    
894        /**
895         * Gets all implementations implementing a given specification from the list of modules.
896         * <p>This method queries an internal cache for a result object to return for the given argument values. If no
897         * cached result object is available, this method queries the super-class for a result object to return and caches
898         * the outcome of that query for use on successive calls.</p>
899         * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
900         * state of the instance, should the state of the instance change.</p>
901         *
902         * @param specification The identifier of the specification to return all implementations of.
903         *
904         * @return All implementations implementing the first matching specification or {@code null}, if no such
905         * specification is found or if the first matching specification does not have any implementations.
906         *
907         * @throws NullPointerException if {@code specification} is {@code null}.
908         *
909         * @see #getModule()
910         * @see #getSpecifications( java.lang.String )
911         * @see #clear()
912         */
913        @Override
914        public Implementations getImplementations( final String specification )
915        {
916            if ( specification == null )
917            {
918                throw new NullPointerException( "specification" );
919            }
920    
921            synchronized ( this.implementationsBySpecificationIdentifierCache )
922            {
923                Implementations i = this.implementationsBySpecificationIdentifierCache.get( specification );
924    
925                if ( i == null && !this.implementationsBySpecificationIdentifierCache.containsKey( specification ) )
926                {
927                    i = super.getImplementations( specification );
928    
929                    if ( i != null )
930                    {
931                        i = RuntimeModelObjects.getInstance().copyOf( i );
932                    }
933    
934                    this.implementationsBySpecificationIdentifierCache.put( specification, i );
935                }
936    
937                return i;
938            }
939        }
940    
941        /**
942         * Gets any objects of an implementation from the list of modules.
943         * <p>This method queries an internal cache for a result object to return for the given argument values. If no
944         * cached result object is available, this method queries the super-class for a result object to return and caches
945         * the outcome of that query for use on successive calls.</p>
946         * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
947         * state of the instance, should the state of the instance change.</p>
948         *
949         * @param implementation The identifier of the implementation to get any objects of.
950         *
951         * @return Any objects of the first matching implementation or {@code null}, if no such implementation is found.
952         *
953         * @throws NullPointerException if {@code implementation} is {@code null}.
954         *
955         * @see #getModule()
956         * @see #getImplementation( java.lang.String )
957         * @see Implementation#getImplementations()
958         * @see Implementations#getReference()
959         * @see #clear()
960         */
961        @Override
962        public List<Object> getAnyObjects( final String implementation )
963        {
964            if ( implementation == null )
965            {
966                throw new NullPointerException( "implementation" );
967            }
968    
969            synchronized ( this.anyObjectsByImplemenationIdentifierCache )
970            {
971                List<Object> any = this.anyObjectsByImplemenationIdentifierCache.get( implementation );
972    
973                if ( any == null && !this.anyObjectsByImplemenationIdentifierCache.containsKey( implementation ) )
974                {
975                    any = super.getAnyObjects( implementation );
976                    this.anyObjectsByImplemenationIdentifierCache.put( implementation, any );
977                }
978    
979                return any;
980            }
981        }
982    
983        /**
984         * Gets an instance for an implementation from the list of modules.
985         *
986         * @param implementation The identifier of the implementation to get an instance for.
987         *
988         * @return A new instance for the first matching implementation or {@code null}, if no such implementation is found.
989         *
990         * @throws NullPointerException if {@code implementation} is {@code null}.
991         *
992         * @see #getModule()
993         * @see #getImplementation( java.lang.String )
994         * @see #getDependencies(java.lang.String)
995         * @see #getProperties(java.lang.String)
996         * @see #getMessages(java.lang.String)
997         * @see #getSpecifications(java.lang.String)
998         * @see #getAnyObjects(java.lang.String)
999         */
1000        @Override
1001        public Instance getInstance( final String implementation )
1002        {
1003            if ( implementation == null )
1004            {
1005                throw new NullPointerException( "implementation" );
1006            }
1007    
1008            final Implementation i = this.getImplementation( implementation );
1009    
1010            if ( i != null && i.getClazz() != null )
1011            {
1012                final Instance instance = new RuntimeInstance();
1013                instance.setIdentifier( i.getIdentifier() );
1014                instance.setName( i.getName() );
1015                instance.setClazz( i.getClazz() );
1016                instance.setStateless( i.isStateless() );
1017                instance.setDependencies( this.getDependencies( implementation ) );
1018                instance.setProperties( this.getProperties( implementation ) );
1019                instance.setMessages( this.getMessages( implementation ) );
1020                instance.setSpecifications( this.getSpecifications( implementation ) );
1021                instance.getAny().addAll( this.getAnyObjects( implementation ) );
1022                return instance;
1023            }
1024    
1025            return null;
1026        }
1027    
1028        /**
1029         * Gets an instance for an implementation from the list of modules overridden with a given dependency.
1030         *
1031         * @param implementation The identifier of the implementation to get an instance for.
1032         * @param dependency The dependency to use for overriding model objects of the instance.
1033         *
1034         * @return An instance for the first matching implementation with any model objects overridden using
1035         * {@code dependency} or {@code null}, if no such implementation is found.
1036         *
1037         * @throws NullPointerException if {@code implementation} or {@code dependency} is {@code null}.
1038         *
1039         * @see #getModule()
1040         * @see #getInstance( java.lang.String )
1041         */
1042        @Override
1043        public Instance getInstance( final String implementation, final Dependency dependency )
1044        {
1045            if ( implementation == null )
1046            {
1047                throw new NullPointerException( "implementation" );
1048            }
1049            if ( dependency == null )
1050            {
1051                throw new NullPointerException( "dependency" );
1052            }
1053    
1054            Instance instance = this.getInstance( implementation );
1055    
1056            if ( instance != null )
1057            {
1058                final Specification dependencySpecification = this.getSpecification( dependency.getIdentifier() );
1059    
1060                if ( dependencySpecification != null && dependencySpecification.getScope() == null )
1061                {
1062                    if ( dependency.getDependencies() != null && !dependency.getDependencies().getDependency().isEmpty() )
1063                    {
1064                        final Dependencies dependencies =
1065                            RuntimeModelObjects.getInstance().copyOf( dependency.getDependencies() );
1066    
1067                        if ( instance.getDependencies() != null )
1068                        {
1069                            for ( int i = 0, s0 = instance.getDependencies().getDependency().size(); i < s0; i++ )
1070                            {
1071                                final Dependency d = instance.getDependencies().getDependency().get( i );
1072                                final Dependency td = dependencies.getDependency( d.getName() );
1073    
1074                                if ( td == null )
1075                                {
1076                                    dependencies.getDependency().add( d );
1077    
1078                                    if ( dependencies instanceof RuntimeModelObject )
1079                                    {
1080                                        ( (RuntimeModelObject) dependencies ).clear();
1081                                    }
1082                                }
1083                                else
1084                                {
1085                                    this.collectDependencies( d, td );
1086                                }
1087                            }
1088                        }
1089    
1090                        instance.setDependencies( dependencies );
1091                    }
1092    
1093                    if ( dependency.getMessages() != null && !dependency.getMessages().getMessage().isEmpty() )
1094                    {
1095                        final Messages messages =
1096                            RuntimeModelObjects.getInstance().copyOf( dependency.getMessages() );
1097    
1098                        if ( instance.getMessages() != null )
1099                        {
1100                            for ( int i = 0, s0 = instance.getMessages().getMessage().size(); i < s0; i++ )
1101                            {
1102                                final Message m = instance.getMessages().getMessage().get( i );
1103    
1104                                if ( messages.getMessage( m.getName() ) == null )
1105                                {
1106                                    messages.getMessage().add( m );
1107    
1108                                    if ( messages instanceof RuntimeModelObject )
1109                                    {
1110                                        ( (RuntimeModelObject) messages ).clear();
1111                                    }
1112                                }
1113                            }
1114                        }
1115    
1116                        instance.setMessages( messages );
1117                    }
1118    
1119                    if ( dependency.getProperties() != null && !dependency.getProperties().getProperty().isEmpty() )
1120                    {
1121                        final Properties properties =
1122                            RuntimeModelObjects.getInstance().copyOf( dependency.getProperties() );
1123    
1124                        if ( instance.getProperties() != null )
1125                        {
1126                            for ( int i = 0, s0 = instance.getProperties().getProperty().size(); i < s0; i++ )
1127                            {
1128                                final Property p = instance.getProperties().getProperty().get( i );
1129    
1130                                if ( properties.getProperty( p.getName() ) == null )
1131                                {
1132                                    properties.getProperty().add( p );
1133    
1134                                    if ( properties instanceof RuntimeModelObject )
1135                                    {
1136                                        ( (RuntimeModelObject) properties ).clear();
1137                                    }
1138                                }
1139                            }
1140                        }
1141    
1142                        instance.setProperties( properties );
1143                    }
1144                }
1145            }
1146    
1147            return instance;
1148        }
1149    
1150        private void collectDependencies( final Dependency source, final Dependency target )
1151        {
1152            if ( source.getMessages() != null )
1153            {
1154                if ( target.getMessages() == null )
1155                {
1156                    target.setMessages( new RuntimeMessages() );
1157                }
1158    
1159                for ( int i = 0, s0 = source.getMessages().getMessage().size(); i < s0; i++ )
1160                {
1161                    final Message m = source.getMessages().getMessage().get( i );
1162    
1163                    if ( target.getMessages().getMessage( m.getName() ) == null )
1164                    {
1165                        target.getMessages().getMessage().add( m );
1166    
1167                        if ( target.getMessages() instanceof RuntimeModelObject )
1168                        {
1169                            ( (RuntimeModelObject) target.getMessages() ).clear();
1170                        }
1171                    }
1172                }
1173            }
1174    
1175            if ( source.getProperties() != null )
1176            {
1177                if ( target.getProperties() == null )
1178                {
1179                    target.setProperties( new RuntimeProperties() );
1180                }
1181    
1182                for ( int i = 0, s0 = source.getProperties().getProperty().size(); i < s0; i++ )
1183                {
1184                    final Property p = source.getProperties().getProperty().get( i );
1185    
1186                    if ( target.getProperties().getProperty( p.getName() ) == null )
1187                    {
1188                        target.getProperties().getProperty().add( p );
1189    
1190                        if ( target.getProperties() instanceof RuntimeModelObject )
1191                        {
1192                            ( (RuntimeModelObject) target.getProperties() ).clear();
1193                        }
1194                    }
1195                }
1196            }
1197    
1198            if ( source.getDependencies() != null )
1199            {
1200                if ( target.getDependencies() == null )
1201                {
1202                    target.setDependencies( new RuntimeDependencies() );
1203                }
1204    
1205                for ( int i = 0, s0 = source.getDependencies().getDependency().size(); i < s0; i++ )
1206                {
1207                    final Dependency sd = source.getDependencies().getDependency().get( i );
1208                    final Dependency td = target.getDependencies().getDependency( sd.getName() );
1209    
1210                    if ( td == null )
1211                    {
1212                        target.getDependencies().getDependency().add( sd );
1213    
1214                        if ( target.getDependencies() instanceof RuntimeModelObject )
1215                        {
1216                            ( (RuntimeModelObject) target.getDependencies() ).clear();
1217                        }
1218                    }
1219                    else
1220                    {
1221                        this.collectDependencies( sd, td );
1222                    }
1223                }
1224            }
1225        }
1226    
1227        private void copyModules()
1228        {
1229            for ( int i = 0, s0 = this.getModule().size(); i < s0; i++ )
1230            {
1231                final Module m = this.getModule().get( i );
1232                this.getModule().set( i, RuntimeModelObjects.getInstance().copyOf( m ) );
1233            }
1234        }
1235    
1236        // SECTION-END
1237        // SECTION-START[RuntimeModelObject]
1238        public void gc()
1239        {
1240            gcMap( this.specificationsCache );
1241            gcMap( this.implementationsCache );
1242            gcMap( this.specificationsByImplemenationIdentifierCache );
1243            gcMap( this.dependenciesByImplementationIdentifierCache );
1244            gcMap( this.propertiesByImplementationIdentifierCache );
1245            gcMap( this.specifiedPropertiesByImplementationIdentifierCache );
1246            gcMap( this.messagesByImplementationIdentifierCache );
1247            gcMap( this.implementationsBySpecificationIdentifierCache );
1248            this.gcOrClear( true, false );
1249        }
1250    
1251        public void clear()
1252        {
1253            synchronized ( this.anyObjectsByImplemenationIdentifierCache )
1254            {
1255                this.anyObjectsByImplemenationIdentifierCache.clear();
1256            }
1257            synchronized ( this.dependenciesByImplementationIdentifierCache )
1258            {
1259                this.dependenciesByImplementationIdentifierCache.clear();
1260            }
1261            synchronized ( this.implementationByClassNameCache )
1262            {
1263                this.implementationByClassNameCache.clear();
1264            }
1265            synchronized ( this.implementationByIdentifierCache )
1266            {
1267                this.implementationByIdentifierCache.clear();
1268            }
1269            synchronized ( this.implementationByObjectClassNameCache )
1270            {
1271                this.implementationByObjectClassNameCache.clear();
1272            }
1273            synchronized ( this.implementationBySpecificationAndNameCache )
1274            {
1275                this.implementationBySpecificationAndNameCache.clear();
1276            }
1277            synchronized ( this.implementationsBySpecificationIdentifierCache )
1278            {
1279                this.implementationsBySpecificationIdentifierCache.clear();
1280            }
1281            synchronized ( this.implementationsCache )
1282            {
1283                this.implementationsCache.clear();
1284            }
1285            synchronized ( this.messagesByImplementationIdentifierCache )
1286            {
1287                this.messagesByImplementationIdentifierCache.clear();
1288            }
1289            synchronized ( this.moduleByImplementationIdentifierCache )
1290            {
1291                this.moduleByImplementationIdentifierCache.clear();
1292            }
1293            synchronized ( this.moduleBySpecificationIdentifierCache )
1294            {
1295                this.moduleBySpecificationIdentifierCache.clear();
1296            }
1297            synchronized ( this.modulesByNameCache )
1298            {
1299                this.modulesByNameCache.clear();
1300            }
1301            synchronized ( this.propertiesByImplementationIdentifierCache )
1302            {
1303                this.propertiesByImplementationIdentifierCache.clear();
1304            }
1305            synchronized ( this.specificationByClassNameCache )
1306            {
1307                this.specificationByClassNameCache.clear();
1308            }
1309            synchronized ( this.specificationByIdentifierCache )
1310            {
1311                this.specificationByIdentifierCache.clear();
1312            }
1313            synchronized ( this.specificationsByImplemenationIdentifierCache )
1314            {
1315                this.specificationsByImplemenationIdentifierCache.clear();
1316            }
1317            synchronized ( this.specificationsCache )
1318            {
1319                this.specificationsCache.clear();
1320            }
1321            synchronized ( this.specifiedPropertiesByImplementationIdentifierCache )
1322            {
1323                this.specifiedPropertiesByImplementationIdentifierCache.clear();
1324            }
1325    
1326            this.gcOrClear( false, true );
1327        }
1328    
1329        private void gcOrClear( final boolean gc, final boolean clear )
1330        {
1331            if ( this.getAuthors() instanceof RuntimeModelObject )
1332            {
1333                if ( gc )
1334                {
1335                    ( (RuntimeModelObject) this.getAuthors() ).gc();
1336                }
1337                if ( clear )
1338                {
1339                    ( (RuntimeModelObject) this.getAuthors() ).clear();
1340                }
1341            }
1342            if ( this.getDocumentation() instanceof RuntimeModelObject )
1343            {
1344                if ( gc )
1345                {
1346                    ( (RuntimeModelObject) this.getDocumentation() ).gc();
1347                }
1348                if ( clear )
1349                {
1350                    ( (RuntimeModelObject) this.getDocumentation() ).clear();
1351                }
1352            }
1353    
1354            this.gcOrClearModules( gc, clear );
1355        }
1356    
1357        private void gcOrClearModules( final boolean gc, final boolean clear )
1358        {
1359    
1360            for ( int i = 0, s0 = this.getModule().size(); i < s0; i++ )
1361            {
1362                final Module m = this.getModule().get( i );
1363                if ( m instanceof RuntimeModelObject )
1364                {
1365                    if ( gc )
1366                    {
1367                        ( (RuntimeModelObject) m ).gc();
1368                    }
1369                    if ( clear )
1370                    {
1371                        ( (RuntimeModelObject) m ).clear();
1372                    }
1373                }
1374            }
1375        }
1376    
1377        private static void gcMap( final Map<?, ?> map )
1378        {
1379            synchronized ( map )
1380            {
1381                for ( Map.Entry<?, ?> e : map.entrySet() )
1382                {
1383                    if ( e.getValue() instanceof RuntimeModelObject )
1384                    {
1385                        ( (RuntimeModelObject) e.getValue() ).gc();
1386                    }
1387                }
1388            }
1389        }
1390    
1391        // SECTION-END
1392        // SECTION-START[Constructors]
1393        // <editor-fold defaultstate="collapsed" desc=" Generated Constructors ">
1394        /** Creates a new {@code RuntimeModules} instance. */
1395        @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" )
1396        public RuntimeModules()
1397        {
1398            // SECTION-START[Default Constructor]
1399            super();
1400            // SECTION-END
1401        }
1402        // </editor-fold>
1403        // SECTION-END
1404        // SECTION-START[Dependencies]
1405        // SECTION-END
1406        // SECTION-START[Properties]
1407        // SECTION-END
1408        // SECTION-START[Messages]
1409        // SECTION-END
1410    }