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: RuntimeMessages.java 4588 2012-06-03 06:01:30Z schulte2005 $
032 *
033 */
034// </editor-fold>
035// SECTION-END
036package org.jomc.ri.model;
037
038import java.util.Map;
039import javax.xml.bind.annotation.XmlTransient;
040import org.jomc.model.Message;
041import org.jomc.model.MessageReference;
042import org.jomc.model.Messages;
043import static org.jomc.ri.model.RuntimeModelObjects.createMap;
044
045// SECTION-START[Documentation]
046// <editor-fold defaultstate="collapsed" desc=" Generated Documentation ">
047/**
048 * Runtime {@code Messages}.
049 *
050 * <dl>
051 *   <dt><b>Identifier:</b></dt><dd>org.jomc.ri.model.RuntimeMessages</dd>
052 *   <dt><b>Name:</b></dt><dd>JOMC RI RuntimeMessages</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.3", comments = "See http://jomc.sourceforge.net/jomc/1.3/jomc-tools-1.3" )
068// </editor-fold>
069// SECTION-END
070public class RuntimeMessages extends Messages implements RuntimeModelObject
071{
072    // SECTION-START[RuntimeMessages]
073
074    /** Cache map. */
075    @XmlTransient
076    private transient final Map<String, Message> messagesByNameCache = createMap();
077
078    /** Cache map. */
079    @XmlTransient
080    private transient final Map<String, MessageReference> referencesByNameCache = createMap();
081
082    /**
083     * Creates a new {@code RuntimeMessages} instance by deeply copying a given {@code Messages} instance.
084     *
085     * @param messages The instance to copy.
086     *
087     * @throws NullPointerException if {@code messages} is {@code null}.
088     */
089    public RuntimeMessages( final Messages messages )
090    {
091        super( messages );
092
093        if ( this.getAuthors() != null )
094        {
095            this.setAuthors( RuntimeModelObjects.getInstance().copyOf( this.getAuthors() ) );
096        }
097        if ( this.getDocumentation() != null )
098        {
099            this.setDocumentation( RuntimeModelObjects.getInstance().copyOf( this.getDocumentation() ) );
100        }
101
102        this.copyMessages();
103        this.copyMessageReferences();
104    }
105
106    /**
107     * Gets a message for a given name from the list of messages.
108     * <p>This method queries an internal cache for a result object to return for the given argument values. If no
109     * cached result object is available, this method queries the super-class for a result object to return and caches
110     * the outcome of that query for use on successive calls.</p>
111     * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
112     * state of the instance, should the state of the instance change.</p>
113     *
114     * @param name The name of the message to return.
115     *
116     * @return The first matching message or {@code null}, if no such message is found.
117     *
118     * @throws NullPointerException if {@code name} is {@code null}.
119     *
120     * @see #getMessage()
121     * @see Message#getName()
122     * @see #clear()
123     */
124    @Override
125    public Message getMessage( final String name )
126    {
127        if ( name == null )
128        {
129            throw new NullPointerException( "name" );
130        }
131
132        synchronized ( this.messagesByNameCache )
133        {
134            Message m = this.messagesByNameCache.get( name );
135
136            if ( m == null && !this.messagesByNameCache.containsKey( name ) )
137            {
138                m = super.getMessage( name );
139                this.messagesByNameCache.put( name, m );
140            }
141
142            return m;
143        }
144    }
145
146    /**
147     * Gets a message reference for a given name from the list of references.
148     * <p>This method queries an internal cache for a result object to return for the given argument values. If no
149     * cached result object is available, this method queries the super-class for a result object to return and caches
150     * the outcome of that query for use on successive calls.</p>
151     * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the
152     * state of the instance, should the state of the instance change.</p>
153     *
154     * @param name The name of the message reference to return.
155     *
156     * @return The first matching message reference or {@code null}, if no such reference is found.
157     *
158     * @throws NullPointerException if {@code name} is {@code null}.
159     *
160     * @see #getReference()
161     * @see MessageReference#getName()
162     * @see #clear()
163     */
164    @Override
165    public MessageReference getReference( final String name )
166    {
167        if ( name == null )
168        {
169            throw new NullPointerException( "name" );
170        }
171
172        synchronized ( this.referencesByNameCache )
173        {
174            MessageReference r = this.referencesByNameCache.get( name );
175
176            if ( r == null && !this.referencesByNameCache.containsKey( name ) )
177            {
178                r = super.getReference( name );
179                this.referencesByNameCache.put( name, r );
180            }
181
182            return r;
183        }
184    }
185
186    private void copyMessages()
187    {
188        for ( int i = 0, s0 = this.getMessage().size(); i < s0; i++ )
189        {
190            final Message m = this.getMessage().get( i );
191            this.getMessage().set( i, RuntimeModelObjects.getInstance().copyOf( m ) );
192        }
193    }
194
195    private void copyMessageReferences()
196    {
197        for ( int i = 0, s0 = this.getReference().size(); i < s0; i++ )
198        {
199            final MessageReference r = this.getReference().get( i );
200            this.getReference().set( i, RuntimeModelObjects.getInstance().copyOf( r ) );
201        }
202    }
203
204    // SECTION-END
205    // SECTION-START[RuntimeModelObject]
206    public void gc()
207    {
208        this.gcOrClear( true, false );
209    }
210
211    public void clear()
212    {
213        synchronized ( this.messagesByNameCache )
214        {
215            this.messagesByNameCache.clear();
216        }
217        synchronized ( this.referencesByNameCache )
218        {
219            this.referencesByNameCache.clear();
220        }
221
222        this.gcOrClear( false, true );
223    }
224
225    private void gcOrClear( final boolean gc, final boolean clear )
226    {
227        if ( this.getAuthors() instanceof RuntimeModelObject )
228        {
229            if ( gc )
230            {
231                ( (RuntimeModelObject) this.getAuthors() ).gc();
232            }
233            if ( clear )
234            {
235                ( (RuntimeModelObject) this.getAuthors() ).clear();
236            }
237        }
238        if ( this.getDocumentation() instanceof RuntimeModelObject )
239        {
240            if ( gc )
241            {
242                ( (RuntimeModelObject) this.getDocumentation() ).gc();
243            }
244            if ( clear )
245            {
246                ( (RuntimeModelObject) this.getDocumentation() ).clear();
247            }
248        }
249
250        this.gcOrClearMessageReferences( gc, clear );
251        this.gcOrClearMessages( gc, clear );
252    }
253
254    private void gcOrClearMessages( final boolean gc, final boolean clear )
255    {
256        for ( int i = 0, s0 = this.getMessage().size(); i < s0; i++ )
257        {
258            final Message m = this.getMessage().get( i );
259            if ( m instanceof RuntimeModelObject )
260            {
261                if ( gc )
262                {
263                    ( (RuntimeModelObject) m ).gc();
264                }
265                if ( clear )
266                {
267                    ( (RuntimeModelObject) m ).clear();
268                }
269            }
270        }
271    }
272
273    private void gcOrClearMessageReferences( final boolean gc, final boolean clear )
274    {
275        for ( int i = 0, s0 = this.getReference().size(); i < s0; i++ )
276        {
277            final MessageReference r = this.getReference().get( i );
278            if ( r instanceof RuntimeModelObject )
279            {
280                if ( gc )
281                {
282                    ( (RuntimeModelObject) r ).gc();
283                }
284                if ( clear )
285                {
286                    ( (RuntimeModelObject) r ).clear();
287                }
288            }
289        }
290    }
291    // SECTION-END
292    // SECTION-START[Constructors]
293    // <editor-fold defaultstate="collapsed" desc=" Generated Constructors ">
294    /** Creates a new {@code RuntimeMessages} instance. */
295    @javax.annotation.Generated( value = "org.jomc.tools.SourceFileProcessor 1.3", comments = "See http://jomc.sourceforge.net/jomc/1.3/jomc-tools-1.3" )
296    public RuntimeMessages()
297    {
298        // SECTION-START[Default Constructor]
299        super();
300        // SECTION-END
301    }
302    // </editor-fold>
303    // SECTION-END
304    // SECTION-START[Dependencies]
305    // SECTION-END
306    // SECTION-START[Properties]
307    // SECTION-END
308    // SECTION-START[Messages]
309    // SECTION-END
310}