View Javadoc

    1   /*
    2    * $Id: MethodKey.java 4661 2007-01-02 16:52:26Z 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 that the
    8    * following conditions are met:
    9    *  1. Redistributions of source code must retain copyright statements and
    10   * notices. Redistributions must also contain a copy of this document.
    11   *  2. Redistributions in binary form must reproduce the above copyright
    12   * notice, this list of conditions and the following disclaimer in the
    13   * documentation and/or other materials provided with the distribution.
    14   *  3. The name "groovy" must not be used to endorse or promote products
    15   * derived from this Software without prior written permission of The Codehaus.
    16   * For written permission, please contact info@codehaus.org.
    17   *  4. Products derived from this Software may not be called "groovy" nor may
    18   * "groovy" appear in their names without prior written permission of The
    19   * Codehaus. "groovy" is a registered trademark of The Codehaus.
    20   *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
    21   *
    22   * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
    23   * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    24   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    25   * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
    26   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    27   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    28   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    29   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    30   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    31   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
    32   * DAMAGE.
    33   *
    34   */
    35  package org.codehaus.groovy.runtime;
    36
    37  import java.util.ArrayList;
    38  import java.util.Collections;
    39  import java.util.List;
    40
    41  /***
    42   * An abstract base class for a key used for comparators and Map keys to lookup a method by
    43   * name and parameter types
    44   *
    45   * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
    46   * @version $Revision: 4661 $
    47   */
    48  public abstract class MethodKey {
    49
    50      private int hash;
    51      private String name;
    52      private Class sender;
    53      private boolean isCallToSuper;
    54
    55      public MethodKey(Class sender, String name, boolean isCallToSuper) {
    56          this.sender = sender;
    57          this.name = name;
    58          this.isCallToSuper = isCallToSuper;
    59      }
    60
    61      /***
    62       * Creates an immutable copy that we can cache.
    63       */
    64      public MethodKey createCopy() {
    65          int size = getParameterCount();
    66          Class[] paramTypes = new Class[size];
    67          for (int i = 0; i < size; i++) {
    68              paramTypes[i] = getParameterType(i);
    69          }
    70          return new DefaultMethodKey(sender, name, paramTypes, isCallToSuper);
    71      }
    72
    73      public boolean equals(Object that) {
    74          if (this == that) {
    75              return true;
    76          }
    77          else if (hashCode() == that.hashCode() && that instanceof MethodKey) {
    78              return equals((MethodKey) that);
    79          }
    80          return false;
    81      }
    82
    83      public boolean equals(MethodKey that) {
    84          int size = getParameterCount();
    85          if (sender!=that.sender) return false;
    86          if (isCallToSuper!=that.isCallToSuper) return false;
    87          if (name.equals(that.name) && size == that.getParameterCount()) {
    88              for (int i = 0; i < size; i++) {
    89                  if (!getParameterType(i).equals(that.getParameterType(i))) {
    90                      return false;
    91                  }
    92              }
    93              return true;
    94          }
    95          return false;
    96      }
    97
    98      public int hashCode() {
    99          if (hash == 0) {
    100             hash = createHashCode();
    101             if (hash == 0) {
    102                 hash = 0xcafebabe;
    103             }
    104         }
    105         return hash;
    106     }
    107
    108     public String toString() {
    109         return super.toString() + "[name:" + name + "; params:" + getParamterTypes();
    110     }
    111
    112     public String getName() {
    113         return name;
    114     }
    115
    116     public List getParamterTypes() {
    117         int size = getParameterCount();
    118         if (size <= 0) {
    119             return Collections.EMPTY_LIST;
    120         }
    121         List params = new ArrayList(size);
    122         for (int i = 0; i < size; i++) {
    123             params.add(getParameterType(i));
    124         }
    125         return params;
    126     }
    127
    128     public abstract int getParameterCount();
    129     public abstract Class getParameterType(int index);
    130
    131     protected int createHashCode() {
    132         int answer = name.hashCode();
    133         int size = getParameterCount();
    134
    135         /*** @todo we should use the real Josh Bloch algorithm here */
    136
    137         // can't remember the exact Josh Bloch algorithm and I've not got the book handy
    138         // but its something like this IIRC
    139         for (int i = 0; i < size; i++) {
    140             answer *= 37;
    141             answer += 1 + getParameterType(i).hashCode();
    142         }
    143         answer *= 37;
    144         answer += isCallToSuper?1:0;
    145         answer *= 37;
    146         answer += 1 + sender.hashCode();
    147         return answer;
    148     }
    149 }