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 arguments.
033     *
034     * @author <a href="mailto:schulte2005@users.sourceforge.net">Christian Schulte</a>
035     * @version $Id: Arguments.java 8044 2009-07-02 01:29:05Z schulte2005 $
036     */
037    public class Arguments extends ModelObject
038        implements Cloneable, Serializable
039    {
040        //--Constants---------------------------------------------------------------
041    
042        /** Serial version UID for backwards compatibility with 1.5.x classes. */
043        private static final long serialVersionUID = -36607029931578091L;
044    
045        //---------------------------------------------------------------Constants--
046        //--Arguments---------------------------------------------------------------
047    
048        /**
049         * The arguments of the collection.
050         * @serial
051         */
052        private Argument[] arguments;
053    
054        /**
055         * Maps argument names to arguments.
056         * @serial
057         */
058        private final Map names = new HashMap();
059    
060        /**
061         * Hash code.
062         * @serial
063         */
064        private int hashCode;
065    
066        /**
067         * Gets the arguments of the collection.
068         *
069         * @return the arguments of the collection.
070         */
071        public Argument[] getArguments()
072        {
073            if ( this.arguments == null )
074            {
075                this.arguments = new Argument[ 0 ];
076                this.hashCode = 0;
077            }
078    
079            return this.arguments;
080        }
081    
082        /**
083         * Setter for property {@code arguments}.
084         *
085         * @param value the new arguments for the instance.
086         *
087         * @throws DuplicateArgumentException if {@code value} contains
088         * duplicate arguments.
089         */
090        public void setArguments( final Argument[] value )
091        {
092            this.names.clear();
093            this.hashCode = 0;
094            this.arguments = null;
095    
096            if ( value != null )
097            {
098                for ( int i = 0; i < value.length; i++ )
099                {
100                    this.hashCode += value[i].hashCode();
101                    if ( this.names.put( value[i].getName(), value[i] ) != null )
102                    {
103                        this.names.clear();
104                        this.hashCode = 0;
105    
106                        throw new DuplicateArgumentException( value[i].getName() );
107                    }
108                }
109    
110                this.arguments = value;
111            }
112        }
113    
114        /**
115         * Gets an argument for a name.
116         *
117         * @param name the name of the argument to return.
118         *
119         * @return a reference to the argument with name {@code name}.
120         *
121         * @throws NullPointerException if {@code name} is {@code null}.
122         * @throws MissingArgumentException if no argument matching {@code name}
123         * exists in the collection.
124         */
125        public Argument getArgument( final String name )
126        {
127            if ( name == null )
128            {
129                throw new NullPointerException( "name" );
130            }
131    
132            final Argument ret = (Argument) this.names.get( name );
133    
134            if ( ret == null )
135            {
136                throw new MissingArgumentException( name );
137            }
138    
139            return ret;
140        }
141    
142        /**
143         * Gets an argument for an index.
144         *
145         * @param index the index of the argument to return.
146         *
147         * @return a reference to the argument at {@code index}.
148         *
149         * @throws IndexOutOfBoundsException if {@code index} is negativ,
150         * greater than or equal to {@code size()}.
151         */
152        public final Argument getArgument( final int index )
153        {
154            if ( index < 0 || index >= this.size() )
155            {
156                throw new ArrayIndexOutOfBoundsException( index );
157            }
158    
159            return this.getArguments()[index];
160        }
161    
162        /**
163         * Gets the number of arguments held by the instance.
164         *
165         * @return the number of arguments held by the instance.
166         */
167        public final int size()
168        {
169            return this.getArguments().length;
170        }
171    
172        /**
173         * Creates a string representing the properties of the instance.
174         *
175         * @return a string representing the properties of the instance.
176         */
177        private String internalString()
178        {
179            final StringBuffer buf = new StringBuffer( 200 ).append( '{' );
180            buf.append( this.internalString( this ) );
181    
182            final Argument[] args = this.getArguments();
183            for ( int i = args.length - 1; i >= 0; i-- )
184            {
185                buf.append( ", [" ).append( i ).append( "]=" ).
186                    append( args[i] );
187    
188            }
189    
190            buf.append( '}' );
191            return buf.toString();
192        }
193    
194        //----------------------------------------------------------Specifications--
195        //--Object------------------------------------------------------------------
196    
197        /**
198         * Indicates whether some other object is equal to this one by comparing
199         * the values of all properties.
200         *
201         * @param o the reference object with which to compare.
202         *
203         * @return {@code true} if this object is the same as {@code o};
204         * {@code false} otherwise.
205         */
206        public boolean equals( final Object o )
207        {
208            boolean equal = this == o;
209    
210            if ( !equal && o instanceof Arguments )
211            {
212                final Arguments that = (Arguments) o;
213                final Collection these = Arrays.asList( this.getArguments() );
214                final Collection those = Arrays.asList( that.getArguments() );
215    
216                equal = this.size() == that.size() && these.containsAll( those );
217            }
218    
219            return equal;
220        }
221    
222        /**
223         * Returns a hash code value for this object.
224         *
225         * @return a hash code value for this object.
226         */
227        public int hashCode()
228        {
229            return this.hashCode;
230        }
231    
232        /**
233         * Returns a string representation of the object.
234         *
235         * @return a string representation of the object.
236         */
237        public String toString()
238        {
239            return super.toString() + this.internalString();
240        }
241    
242        /**
243         * Creates and returns a deep copy of this object.
244         *
245         * @return a clone of this instance.
246         */
247        public Object clone()
248        {
249            try
250            {
251                final Arguments ret = (Arguments) super.clone();
252                final Argument[] args = this.getArguments();
253                final Argument[] cloned = new Argument[ args.length ];
254    
255                for ( int i = args.length - 1; i >= 0; i-- )
256                {
257                    cloned[i] = (Argument) args[i].clone();
258                }
259    
260                ret.setArguments( cloned );
261                return ret;
262            }
263            catch ( CloneNotSupportedException e )
264            {
265                throw new AssertionError( e );
266            }
267        }
268    
269        //------------------------------------------------------------------Object--
270    }