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