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 }