001/*
002 *  jDTAUS Core API
003 *  Copyright (C) 2005 Christian Schulte
004 *  <cs@schulte.it>
005 *
006 *  This library is free software; you can redistribute it and/or
007 *  modify it under the terms of the GNU Lesser General Public
008 *  License as published by the Free Software Foundation; either
009 *  version 2.1 of the License, or any later version.
010 *
011 *  This library is distributed in the hope that it will be useful,
012 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014 *  Lesser General Public License for more details.
015 *
016 *  You should have received a copy of the GNU Lesser General Public
017 *  License along with this library; if not, write to the Free Software
018 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
019 *
020 */
021package org.jdtaus.core.container;
022
023import java.io.Serializable;
024import java.util.Arrays;
025import java.util.Collection;
026import java.util.HashMap;
027import java.util.Map;
028
029/**
030 * Collection of messages.
031 *
032 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
033 * @version $JDTAUS: Messages.java 8743 2012-10-07 03:06:20Z schulte $
034 */
035public class Messages extends ModelObject implements Cloneable, Serializable
036{
037    //--Constants---------------------------------------------------------------
038
039    /** Serial version UID for backwards compatibility with 1.5.x classes. */
040    private static final long serialVersionUID = -4280995595863489214L;
041
042    //---------------------------------------------------------------Constants--
043    //--Messages----------------------------------------------------------------
044
045    /**
046     * The messages of the collection.
047     * @serial
048     */
049    private Message[] messages;
050
051    /**
052     * Maps message names to messages.
053     * @serial
054     */
055    private final Map names = new HashMap();
056
057    /**
058     * Hash code.
059     * @serial
060     */
061    private int hashCode;
062
063    /** Creates a new {@code Messages} instance. */
064    public Messages()
065    {
066        super();
067    }
068
069    /**
070     * Gets the messages of the collection.
071     *
072     * @return the messages of the collection.
073     */
074    public Message[] getMessages()
075    {
076        if ( this.messages == null )
077        {
078            this.messages = new Message[ 0 ];
079            this.hashCode = 0;
080        }
081
082        return this.messages;
083    }
084
085    /**
086     * Setter for property {@code messages}.
087     *
088     * @param value the new messages for the instance.
089     *
090     * @throws DuplicateMessageException if {@code value} contains
091     * duplicate messages.
092     */
093    public void setMessages( final Message[] value )
094    {
095        this.names.clear();
096        this.hashCode = 0;
097        this.messages = null;
098
099        if ( value != null )
100        {
101            for ( int i = value.length - 1; i >= 0; i-- )
102            {
103                this.hashCode += value[i].hashCode();
104                if ( this.names.put( value[i].getName(), value[i] ) != null )
105                {
106                    this.names.clear();
107                    this.hashCode = 0;
108
109                    throw new DuplicateMessageException( value[i].getName() );
110                }
111            }
112
113            this.messages = value;
114        }
115    }
116
117    /**
118     * Gets a message for a name.
119     *
120     * @param name the name of the message to return.
121     *
122     * @return a reference to the message with name {@code name}.
123     *
124     * @throws NullPointerException if {@code name} is {@code null}.
125     * @throws MissingMessageException if no message matching
126     * {@code name} exists in the collection.
127     */
128    public Message getMessage( final String name )
129    {
130        if ( name == null )
131        {
132            throw new NullPointerException( "name" );
133        }
134
135        final Message ret = (Message) this.names.get( name );
136
137        if ( ret == null )
138        {
139            throw new MissingMessageException( name );
140        }
141
142        return ret;
143    }
144
145    /**
146     * Gets a message for an index.
147     *
148     * @param index the index of the message to return.
149     *
150     * @return a reference to the message at {@code index}.
151     *
152     * @throws IndexOutOfBoundsException if {@code index} is negativ,
153     * greater than or equal to {@code size()}.
154     */
155    public final Message getMessage( final int index )
156    {
157        if ( index < 0 || index >= this.size() )
158        {
159            throw new ArrayIndexOutOfBoundsException( index );
160        }
161
162        return this.getMessages()[index];
163    }
164
165    /**
166     * Gets the number of messages held by the instance.
167     *
168     * @return the number of messages held by the instance.
169     */
170    public final int size()
171    {
172        return this.getMessages().length;
173    }
174
175    /**
176     * Creates a string representing the properties of the instance.
177     *
178     * @return a string representing the properties of the instance.
179     */
180    private String internalString()
181    {
182        final StringBuffer buf = new StringBuffer( 200 ).append( '{' );
183        buf.append( this.internalString( this ) );
184
185        final Message[] msgs = this.getMessages();
186        for ( int i = msgs.length - 1; i >= 0; i-- )
187        {
188            buf.append( ", [" ).append( i ).append( "]=" ).append( msgs[i] );
189        }
190
191        buf.append( '}' );
192        return buf.toString();
193    }
194
195    //----------------------------------------------------------------Messages--
196    //--Object------------------------------------------------------------------
197
198    /**
199     * Indicates whether some other object is equal to this one by comparing
200     * the values of all properties.
201     *
202     * @param o the reference object with which to compare.
203     *
204     * @return {@code true} if this object is the same as {@code o};
205     * {@code false} otherwise.
206     */
207    public boolean equals( final Object o )
208    {
209        boolean equal = this == o;
210
211        if ( !equal && o instanceof Messages )
212        {
213            final Messages that = (Messages) o;
214            final Collection these = Arrays.asList( this.getMessages() );
215            final Collection those = Arrays.asList( that.getMessages() );
216
217            equal = this.size() == that.size() && these.containsAll( those );
218        }
219
220        return equal;
221    }
222
223    /**
224     * Returns a hash code value for this object.
225     *
226     * @return a hash code value for this object.
227     */
228    public int hashCode()
229    {
230        return this.hashCode;
231    }
232
233    /**
234     * Returns a string representation of the object.
235     *
236     * @return a string representation of the object.
237     */
238    public String toString()
239    {
240        return super.toString() + this.internalString();
241    }
242
243    /**
244     * Creates and returns a deep copy of this object.
245     *
246     * @return a clone of this instance.
247     */
248    public Object clone()
249    {
250        try
251        {
252            final Messages ret = (Messages) super.clone();
253            final Message[] msgs = this.getMessages();
254            final Message[] cloned = new Message[ messages.length ];
255
256            for ( int i = msgs.length - 1; i >= 0; i-- )
257            {
258                cloned[i] = (Message) msgs[i].clone();
259            }
260
261            ret.setMessages( cloned );
262            return ret;
263        }
264        catch ( final CloneNotSupportedException e )
265        {
266            throw new AssertionError( e );
267        }
268    }
269
270    //------------------------------------------------------------------Object--
271}