View Javadoc

    1   /*
    2    $Id: Sequence.java 4098 2006-10-10 16:09:48Z blackdrag $
    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  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     // GroovyObject interface
    184     //-------------------------------------------------------------------------
    185     public Object invokeMethod(String name, Object args) {
    186         try {
    187         return getMetaClass().invokeMethod(this, name, args);
    188         }
    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, 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     // Implementation methods
    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 }