1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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
183
184 public Object invokeMethod(String name, Object args) {
185 try {
186 return getMetaClass().invokeMethod(this, name, args);
187 }
188 catch (MissingMethodException e) {
189
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
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 }