blob: af0c36516f199840ac89f925e48ebb8f16900070 [file] [log] [blame]
/*
* Copyright 2003-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package groovy.lang;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.codehaus.groovy.runtime.InvokerHelper;
import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
/**
* Represents a sequence of objects which represents zero or many instances of
* of objects of a given type. The type can be ommitted in which case any type of
* object can be added.
*
* @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
* @version $Revision$
*/
public class Sequence extends ArrayList implements GroovyObject {
private MetaClass metaClass = InvokerHelper.getMetaClass(this);
private Class type;
private int hashCode;
public Sequence() {
this(null);
}
public Sequence(Class type) {
this.type = type;
}
public Sequence(Class type, List content) {
super(content.size());
this.type = type;
addAll(content);
}
/**
* Sets the contents of this sequence to that
* of the given collection.
*/
public void set(Collection collection) {
checkCollectionType(collection);
clear();
addAll(collection);
}
public boolean equals(Object that) {
if (that instanceof Sequence) {
return equals((Sequence) that);
}
return false;
}
public boolean equals(Sequence that) {
if (size() == that.size()) {
for (int i = 0; i < size(); i++) {
if (!DefaultTypeTransformation.compareEqual(this.get(i), that.get(i))) {
return false;
}
}
return true;
}
return false;
}
public int hashCode() {
if (hashCode == 0) {
for (int i = 0; i < size(); i++) {
Object value = get(i);
int hash = (value != null) ? value.hashCode() : 0xbabe;
hashCode ^= hash;
}
if (hashCode == 0) {
hashCode = 0xbabe;
}
}
return hashCode;
}
public int minimumSize() {
return 0;
}
/**
* @return the type of the elements in the sequence or null if there is no
* type constraint on this sequence
*/
public Class type() {
return type;
}
public void add(int index, Object element) {
checkType(element);
hashCode = 0;
super.add(index, element);
}
public boolean add(Object element) {
checkType(element);
hashCode = 0;
return super.add(element);
}
public boolean addAll(Collection c) {
checkCollectionType(c);
hashCode = 0;
return super.addAll(c);
}
public boolean addAll(int index, Collection c) {
checkCollectionType(c);
hashCode = 0;
return super.addAll(index, c);
}
public void clear() {
hashCode = 0;
super.clear();
}
public Object remove(int index) {
hashCode = 0;
return super.remove(index);
}
protected void removeRange(int fromIndex, int toIndex) {
hashCode = 0;
super.removeRange(fromIndex, toIndex);
}
public Object set(int index, Object element) {
hashCode = 0;
return super.set(index, element);
}
// GroovyObject interface
//-------------------------------------------------------------------------
public Object invokeMethod(String name, Object args) {
try {
return getMetaClass().invokeMethod(this, name, args);
}
catch (MissingMethodException e) {
// lets apply the method to each item in the collection
List answer = new ArrayList(size());
for (Iterator iter = iterator(); iter.hasNext(); ) {
Object element = iter.next();
Object value = InvokerHelper.invokeMethod(element, name, args);
answer.add(value);
}
return answer;
}
}
public Object getProperty(String property) {
return getMetaClass().getProperty(this, property);
}
public void setProperty(String property, Object newValue) {
getMetaClass().setProperty(this, property, newValue);
}
public MetaClass getMetaClass() {
return metaClass;
}
public void setMetaClass(MetaClass metaClass) {
this.metaClass = metaClass;
}
// Implementation methods
//-------------------------------------------------------------------------
/**
* Checks that each member of the given collection are of the correct
* type
*/
protected void checkCollectionType(Collection c) {
if (type != null) {
for (Iterator iter = c.iterator(); iter.hasNext(); ) {
Object element = iter.next();
checkType(element);
}
}
}
/**
* Checks that the given object instance is of the correct type
* otherwise a runtime exception is thrown
*/
protected void checkType(Object object) {
if (object == null) {
throw new NullPointerException("Sequences cannot contain null, use a List instead");
}
if (type != null) {
if (!type.isInstance(object)) {
throw new IllegalArgumentException(
"Invalid type of argument for sequence of type: "
+ type.getName()
+ " cannot add object: "
+ object);
}
}
}
}