View Javadoc

1   /*
2    $Id: Sequence.java,v 1.3 2004/02/24 23:03:48 jstrachan Exp $
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  
55  /***
56   * Represents a sequence of objects which represents zero or many instances of
57   * of objects of a given type. The type can be ommitted in which case any type of
58   * object can be added.
59   *
60   * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
61   * @version $Revision: 1.3 $
62   */
63  public class Sequence extends ArrayList implements GroovyObject {
64  
65      private MetaClass metaClass = InvokerHelper.getMetaClass(this);
66      private Class type;
67      private int hashCode;
68  
69      public Sequence() {
70          this(null);
71      }
72  
73      public Sequence(Class type) {
74          this.type = type;
75      }
76  
77      public Sequence(Class type, List content) {
78          super(content.size());
79          this.type = type;
80          addAll(content);
81      }
82  
83      /***
84       * Sets the contents of this sequence to that
85       * of the given collection.
86       */
87      public void set(Collection collection) {
88          checkCollectionType(collection);
89          clear();
90          addAll(collection);
91      }
92      
93      public boolean equals(Object that) {
94          if (that instanceof Tuple) {
95              return equals(that);
96          }
97          return false;
98      }
99  
100     public boolean equals(Sequence that) {
101         if (size() == that.size()) {
102             for (int i = 0; i < size(); i++) {
103                 if (!InvokerHelper.compareEqual(this.get(i), that.get(i))) {
104                     return false;
105                 }
106             }
107             return true;
108         }
109         return false;
110     }
111 
112     public int hashCode() {
113         if (hashCode == 0) {
114             for (int i = 0; i < size(); i++) {
115                 Object value = get(i);
116                 int hash = (value != null) ? value.hashCode() : 0xbabe;
117                 hashCode ^= hash;
118             }
119             if (hashCode == 0) {
120                 hashCode = 0xbabe;
121             }
122         }
123         return hashCode;
124     }
125 
126     public int minimumSize() {
127         return 0;
128     }
129 
130     /***
131      * @return the type of the elements in the sequence or null if there is no
132      * type constraint on this sequence
133      */
134     public Class type() {
135         return type;
136     }
137     
138     public void add(int index, Object element) {
139         checkType(element);
140         hashCode = 0;
141         super.add(index, element);
142     }
143 
144     public boolean add(Object element) {
145         checkType(element);
146         hashCode = 0;
147         return super.add(element);
148     }
149 
150     public boolean addAll(Collection c) {
151         checkCollectionType(c);
152         hashCode = 0;
153         return super.addAll(c);
154     }
155 
156     public boolean addAll(int index, Collection c) {
157         checkCollectionType(c);
158         hashCode = 0;
159         return super.addAll(index, c);
160     }
161 
162     public void clear() {
163         hashCode = 0;
164         super.clear();
165     }
166 
167     public Object remove(int index) {
168         hashCode = 0;
169         return super.remove(index);
170     }
171 
172     protected void removeRange(int fromIndex, int toIndex) {
173         hashCode = 0;
174         super.removeRange(fromIndex, toIndex);
175     }
176 
177     public Object set(int index, Object element) {
178         hashCode = 0;
179         return super.set(index, element);
180     }
181 
182     // GroovyObject interface
183     //-------------------------------------------------------------------------
184     public Object invokeMethod(String name, Object args) {
185         try {
186         return getMetaClass().invokeMethod(this, name, args);
187         }
188         catch (MissingMethodException e) {
189             // lets apply the method to each item in the collection
190             List answer = new ArrayList(size());
191             for (Iterator iter = iterator(); iter.hasNext(); ) {
192                 Object element = iter.next();
193                 Object value = InvokerHelper.invokeMethod(element, name, args);
194                 answer.add(value);
195             }
196             return answer;
197         }
198     }
199 
200     public Object getProperty(String property) {
201         return getMetaClass().getProperty(this, property);
202     }
203 
204     public void setProperty(String property, Object newValue) {
205         getMetaClass().setProperty(this, property, newValue);
206     }
207 
208     public MetaClass getMetaClass() {
209         return metaClass;
210     }
211 
212     public void setMetaClass(MetaClass metaClass) {
213         this.metaClass = metaClass;
214     }
215 
216     // Implementation methods
217     //-------------------------------------------------------------------------
218     
219     /***
220      * Checks that each member of the given collection are of the correct
221      * type
222      */
223     protected void checkCollectionType(Collection c) {
224         if (type != null) {
225             for (Iterator iter = c.iterator(); iter.hasNext(); ) {
226                 Object element = iter.next();
227                 checkType(element);
228             }
229         }
230     }
231 
232 
233     /*** 
234      * Checks that the given object instance is of the correct type
235      * otherwise a runtime exception is thrown
236      */
237     protected void checkType(Object object) {
238         if (object == null) {
239             throw new NullPointerException("Sequences cannot contain null, use a List instead");
240         }
241         if (type != null) {
242             if (!type.isInstance(object)) {
243                 throw new IllegalArgumentException(
244                     "Invalid type of argument for sequence of type: "
245                         + type.getName()
246                         + " cannot add object: "
247                         + object);
248             }
249         }
250     }
251 }