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