View Javadoc

    1   /*
    2    $Id: Sequence.java,v 1.3 2004/02/24 23:03:48 jstrachan Exp $
    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
    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     // GroovyObject interface
    183     //-------------------------------------------------------------------------
    184     public Object invokeMethod(String name, Object args) {
    185         try {
    186         return getMetaClass().invokeMethod(this, name, args);
    187         }
    188         catch (MissingMethodException e) {
    189             // lets apply the method to each item in the collection
    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     // Implementation methods
    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 }