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 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
184
185 public Object invokeMethod(String name, Object args) {
186 try {
187 return getMetaClass().invokeMethod(this, name, args);
188 }
189 catch (MissingMethodException e) {
190
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
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 }