View Javadoc

1   /*
2    $Id: Sequence.java 4098 2006-10-10 16:09:48Z blackdrag $
3   
4    Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5   
6    Redistribution and use of this software and associated documentation
7    ("Software"), with or without modification, are permitted provided
8    that the following conditions are met:
9   
10   1. Redistributions of source code must retain copyright
11      statements and notices.  Redistributions must also contain a
12      copy of this document.
13  
14   2. Redistributions in binary form must reproduce the
15      above copyright notice, this list of conditions and the
16      following disclaimer in the documentation and/or other
17      materials provided with the distribution.
18  
19   3. The name "groovy" must not be used to endorse or promote
20      products derived from this Software without prior written
21      permission of The Codehaus.  For written permission,
22      please contact info@codehaus.org.
23  
24   4. Products derived from this Software may not be called "groovy"
25      nor may "groovy" appear in their names without prior written
26      permission of The Codehaus. "groovy" is a registered
27      trademark of The Codehaus.
28  
29   5. Due credit should be given to The Codehaus -
30      http://groovy.codehaus.org/
31  
32   THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
33   ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
34   NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
35   FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
36   THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
37   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
43   OF THE POSSIBILITY OF SUCH DAMAGE.
44  
45   */
46  package groovy.lang;
47  
48  import java.util.ArrayList;
49  import java.util.Collection;
50  import java.util.Iterator;
51  import java.util.List;
52  
53  import org.codehaus.groovy.runtime.InvokerHelper;
54  import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
55  
56  /***
57   * Represents a sequence of objects which represents zero or many instances of
58   * of objects of a given type. The type can be ommitted in which case any type of
59   * object can be added.
60   *
61   * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
62   * @version $Revision: 4098 $
63   */
64  public class Sequence extends ArrayList implements GroovyObject {
65  
66      private MetaClass metaClass = InvokerHelper.getMetaClass(this);
67      private Class type;
68      private int hashCode;
69  
70      public Sequence() {
71          this(null);
72      }
73  
74      public Sequence(Class type) {
75          this.type = type;
76      }
77  
78      public Sequence(Class type, List content) {
79          super(content.size());
80          this.type = type;
81          addAll(content);
82      }
83  
84      /***
85       * Sets the contents of this sequence to that
86       * of the given collection.
87       */
88      public void set(Collection collection) {
89          checkCollectionType(collection);
90          clear();
91          addAll(collection);
92      }
93      
94      public boolean equals(Object that) {
95          if (that instanceof Sequence) {
96              return equals((Sequence) that);
97          }
98          return false;
99      }
100 
101     public boolean equals(Sequence that) {
102         if (size() == that.size()) {
103             for (int i = 0; i < size(); i++) {
104                 if (!DefaultTypeTransformation.compareEqual(this.get(i), that.get(i))) {
105                     return false;
106                 }
107             }
108             return true;
109         }
110         return false;
111     }
112 
113     public int hashCode() {
114         if (hashCode == 0) {
115             for (int i = 0; i < size(); i++) {
116                 Object value = get(i);
117                 int hash = (value != null) ? value.hashCode() : 0xbabe;
118                 hashCode ^= hash;
119             }
120             if (hashCode == 0) {
121                 hashCode = 0xbabe;
122             }
123         }
124         return hashCode;
125     }
126 
127     public int minimumSize() {
128         return 0;
129     }
130 
131     /***
132      * @return the type of the elements in the sequence or null if there is no
133      * type constraint on this sequence
134      */
135     public Class type() {
136         return type;
137     }
138     
139     public void add(int index, Object element) {
140         checkType(element);
141         hashCode = 0;
142         super.add(index, element);
143     }
144 
145     public boolean add(Object element) {
146         checkType(element);
147         hashCode = 0;
148         return super.add(element);
149     }
150 
151     public boolean addAll(Collection c) {
152         checkCollectionType(c);
153         hashCode = 0;
154         return super.addAll(c);
155     }
156 
157     public boolean addAll(int index, Collection c) {
158         checkCollectionType(c);
159         hashCode = 0;
160         return super.addAll(index, c);
161     }
162 
163     public void clear() {
164         hashCode = 0;
165         super.clear();
166     }
167 
168     public Object remove(int index) {
169         hashCode = 0;
170         return super.remove(index);
171     }
172 
173     protected void removeRange(int fromIndex, int toIndex) {
174         hashCode = 0;
175         super.removeRange(fromIndex, toIndex);
176     }
177 
178     public Object set(int index, Object element) {
179         hashCode = 0;
180         return super.set(index, element);
181     }
182 
183     // GroovyObject interface
184     //-------------------------------------------------------------------------
185     public Object invokeMethod(String name, Object args) {
186         try {
187         return getMetaClass().invokeMethod(this, name, args);
188         }
189         catch (MissingMethodException e) {
190             // lets apply the method to each item in the collection
191             List answer = new ArrayList(size());
192             for (Iterator iter = iterator(); iter.hasNext(); ) {
193                 Object element = iter.next();
194                 Object value = InvokerHelper.invokeMethod(element, name, args);
195                 answer.add(value);
196             }
197             return answer;
198         }
199     }
200 
201     public Object getProperty(String property) {
202         return getMetaClass().getProperty(this, property);
203     }
204 
205     public void setProperty(String property, Object newValue) {
206         getMetaClass().setProperty(this, property, newValue);
207     }
208 
209     public MetaClass getMetaClass() {
210         return metaClass;
211     }
212 
213     public void setMetaClass(MetaClass metaClass) {
214         this.metaClass = metaClass;
215     }
216 
217     // Implementation methods
218     //-------------------------------------------------------------------------
219     
220     /***
221      * Checks that each member of the given collection are of the correct
222      * type
223      */
224     protected void checkCollectionType(Collection c) {
225         if (type != null) {
226             for (Iterator iter = c.iterator(); iter.hasNext(); ) {
227                 Object element = iter.next();
228                 checkType(element);
229             }
230         }
231     }
232 
233 
234     /*** 
235      * Checks that the given object instance is of the correct type
236      * otherwise a runtime exception is thrown
237      */
238     protected void checkType(Object object) {
239         if (object == null) {
240             throw new NullPointerException("Sequences cannot contain null, use a List instead");
241         }
242         if (type != null) {
243             if (!type.isInstance(object)) {
244                 throw new IllegalArgumentException(
245                     "Invalid type of argument for sequence of type: "
246                         + type.getName()
247                         + " cannot add object: "
248                         + object);
249             }
250         }
251     }
252 }