001: /*
002: $Id: Sequence.java 4098 2006-10-10 16:09:48Z blackdrag $
003:
004: Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
005:
006: Redistribution and use of this software and associated documentation
007: ("Software"), with or without modification, are permitted provided
008: that the following conditions are met:
009:
010: 1. Redistributions of source code must retain copyright
011: statements and notices. Redistributions must also contain a
012: copy of this document.
013:
014: 2. Redistributions in binary form must reproduce the
015: above copyright notice, this list of conditions and the
016: following disclaimer in the documentation and/or other
017: materials provided with the distribution.
018:
019: 3. The name "groovy" must not be used to endorse or promote
020: products derived from this Software without prior written
021: permission of The Codehaus. For written permission,
022: please contact info@codehaus.org.
023:
024: 4. Products derived from this Software may not be called "groovy"
025: nor may "groovy" appear in their names without prior written
026: permission of The Codehaus. "groovy" is a registered
027: trademark of The Codehaus.
028:
029: 5. Due credit should be given to The Codehaus -
030: http://groovy.codehaus.org/
031:
032: THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
033: ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
034: NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
035: FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
036: THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
037: INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
038: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
039: SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
040: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
041: STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
042: ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
043: OF THE POSSIBILITY OF SUCH DAMAGE.
044:
045: */
046: package groovy.lang;
047:
048: import java.util.ArrayList;
049: import java.util.Collection;
050: import java.util.Iterator;
051: import java.util.List;
052:
053: import org.codehaus.groovy.runtime.InvokerHelper;
054: import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
055:
056: /**
057: * Represents a sequence of objects which represents zero or many instances of
058: * of objects of a given type. The type can be ommitted in which case any type of
059: * object can be added.
060: *
061: * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
062: * @version $Revision: 4098 $
063: */
064: public class Sequence extends ArrayList implements GroovyObject {
065:
066: private MetaClass metaClass = InvokerHelper.getMetaClass(this );
067: private Class type;
068: private int hashCode;
069:
070: public Sequence() {
071: this (null);
072: }
073:
074: public Sequence(Class type) {
075: this .type = type;
076: }
077:
078: public Sequence(Class type, List content) {
079: super (content.size());
080: this .type = type;
081: addAll(content);
082: }
083:
084: /**
085: * Sets the contents of this sequence to that
086: * of the given collection.
087: */
088: public void set(Collection collection) {
089: checkCollectionType(collection);
090: clear();
091: addAll(collection);
092: }
093:
094: public boolean equals(Object that) {
095: if (that instanceof Sequence) {
096: return equals((Sequence) that);
097: }
098: return false;
099: }
100:
101: public boolean equals(Sequence that) {
102: if (size() == that.size()) {
103: for (int i = 0; i < size(); i++) {
104: if (!DefaultTypeTransformation.compareEqual(
105: this .get(i), that.get(i))) {
106: return false;
107: }
108: }
109: return true;
110: }
111: return false;
112: }
113:
114: public int hashCode() {
115: if (hashCode == 0) {
116: for (int i = 0; i < size(); i++) {
117: Object value = get(i);
118: int hash = (value != null) ? value.hashCode() : 0xbabe;
119: hashCode ^= hash;
120: }
121: if (hashCode == 0) {
122: hashCode = 0xbabe;
123: }
124: }
125: return hashCode;
126: }
127:
128: public int minimumSize() {
129: return 0;
130: }
131:
132: /**
133: * @return the type of the elements in the sequence or null if there is no
134: * type constraint on this sequence
135: */
136: public Class type() {
137: return type;
138: }
139:
140: public void add(int index, Object element) {
141: checkType(element);
142: hashCode = 0;
143: super .add(index, element);
144: }
145:
146: public boolean add(Object element) {
147: checkType(element);
148: hashCode = 0;
149: return super .add(element);
150: }
151:
152: public boolean addAll(Collection c) {
153: checkCollectionType(c);
154: hashCode = 0;
155: return super .addAll(c);
156: }
157:
158: public boolean addAll(int index, Collection c) {
159: checkCollectionType(c);
160: hashCode = 0;
161: return super .addAll(index, c);
162: }
163:
164: public void clear() {
165: hashCode = 0;
166: super .clear();
167: }
168:
169: public Object remove(int index) {
170: hashCode = 0;
171: return super .remove(index);
172: }
173:
174: protected void removeRange(int fromIndex, int toIndex) {
175: hashCode = 0;
176: super .removeRange(fromIndex, toIndex);
177: }
178:
179: public Object set(int index, Object element) {
180: hashCode = 0;
181: return super .set(index, element);
182: }
183:
184: // GroovyObject interface
185: //-------------------------------------------------------------------------
186: public Object invokeMethod(String name, Object args) {
187: try {
188: return getMetaClass().invokeMethod(this , name, args);
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,
195: name, args);
196: answer.add(value);
197: }
198: return answer;
199: }
200: }
201:
202: public Object getProperty(String property) {
203: return getMetaClass().getProperty(this , property);
204: }
205:
206: public void setProperty(String property, Object newValue) {
207: getMetaClass().setProperty(this , property, newValue);
208: }
209:
210: public MetaClass getMetaClass() {
211: return metaClass;
212: }
213:
214: public void setMetaClass(MetaClass metaClass) {
215: this .metaClass = metaClass;
216: }
217:
218: // Implementation methods
219: //-------------------------------------------------------------------------
220:
221: /**
222: * Checks that each member of the given collection are of the correct
223: * type
224: */
225: protected void checkCollectionType(Collection c) {
226: if (type != null) {
227: for (Iterator iter = c.iterator(); iter.hasNext();) {
228: Object element = iter.next();
229: checkType(element);
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(
241: "Sequences cannot contain null, use a List instead");
242: }
243: if (type != null) {
244: if (!type.isInstance(object)) {
245: throw new IllegalArgumentException(
246: "Invalid type of argument for sequence of type: "
247: + type.getName()
248: + " cannot add object: " + object);
249: }
250: }
251: }
252: }
|