KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > logicalcobwebs > cglib > core > KeyFactory


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2002 The Apache Software Foundation. All rights
5  * reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in
16  * the documentation and/or other materials provided with the
17  * distribution.
18  *
19  * 3. The end-user documentation included with the redistribution,
20  * if any, must include the following acknowledgment:
21  * "This product includes software developed by the
22  * Apache Software Foundation (http://www.apache.org/)."
23  * Alternately, this acknowledgment may appear in the software itself,
24  * if and wherever such third-party acknowledgments normally appear.
25  *
26  * 4. The names "Apache" and "Apache Software Foundation" must
27  * not be used to endorse or promote products derived from this
28  * software without prior written permission. For written
29  * permission, please contact apache@apache.org.
30  *
31  * 5. Products derived from this software may not be called "Apache",
32  * nor may "Apache" appear in their name, without prior written
33  * permission of the Apache Software Foundation.
34  *
35  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46  * SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Apache Software Foundation. For more
51  * information on the Apache Software Foundation, please see
52  * <http://www.apache.org/>.
53  */

54
55 package org.logicalcobwebs.cglib.core;
56
57 import java.lang.reflect.Method JavaDoc;
58 import org.logicalcobwebs.asm.ClassVisitor;
59 import org.logicalcobwebs.asm.Label;
60 import org.logicalcobwebs.asm.Type;
61
62 /**
63  * Generates classes to handle multi-valued keys, for use in things such as Maps and Sets.
64  * Code for <code>equals</code> and <code>hashCode</code> methods follow the
65  * the rules laid out in <i>Effective Java</i> by Joshua Bloch.
66  * <p>
67  * To generate a <code>KeyFactory</code>, you need to supply an interface which
68  * describes the structure of the key. The interface should have a
69  * single method named <code>newInstance</code>, which returns an
70  * <code>Object</code>. The arguments array can be
71  * <i>anything</i>--Objects, primitive values, or single or
72  * multi-dimension arrays of either. For example:
73  * <p><pre>
74  * private interface IntStringKey {
75  * public Object newInstance(int i, String s);
76  * }
77  * </pre><p>
78  * Once you have made a <code>KeyFactory</code>, you generate a new key by calling
79  * the <code>newInstance</code> method defined by your interface.
80  * <p><pre>
81  * IntStringKey factory = (IntStringKey)KeyFactory.create(IntStringKey.class);
82  * Object key1 = factory.newInstance(4, "Hello");
83  * Object key2 = factory.newInstance(4, "World");
84  * </pre><p>
85  * <b>Note:</b>
86  * <code>hashCode</code> equality between two keys <code>key1</code> and <code>key2</code> is only guaranteed if
87  * <code>key1.equals(key2)</code> <i>and</i> the keys were produced by the same factory.
88  *
89  * @version $Id: KeyFactory.java,v 1.1 2003/12/12 19:28:11 billhorsman Exp $
90  */

91 abstract public class KeyFactory {
92     private static final Signature GET_NAME =
93       TypeUtils.parseSignature("String getName()");
94     private static final Signature GET_CLASS =
95       TypeUtils.parseSignature("Class getClass()");
96     private static final Signature HASH_CODE =
97       TypeUtils.parseSignature("int hashCode()");
98     private static final Signature EQUALS =
99       TypeUtils.parseSignature("boolean equals(Object)");
100     private static final Signature TO_STRING =
101       TypeUtils.parseSignature("String toString()");
102     private static final Signature APPEND_STRING =
103       TypeUtils.parseSignature("StringBuffer append(String)");
104     private static final Type KEY_FACTORY =
105       TypeUtils.parseType("org.logicalcobwebs.cglib.core.KeyFactory");
106     
107     //generated numbers:
108
private final static int PRIMES[] = {
109                11, 73, 179, 331,
110               521, 787, 1213, 1823,
111              2609, 3691, 5189, 7247,
112             10037, 13931, 19289, 26627,
113             36683, 50441, 69403, 95401,
114            131129, 180179, 247501, 340057,
115            467063, 641371, 880603, 1209107,
116           1660097, 2279161, 3129011, 4295723,
117           5897291, 8095873, 11114263, 15257791,
118          20946017, 28754629, 39474179, 54189869,
119          74391461, 102123817, 140194277, 192456917,
120         264202273, 362693231, 497900099, 683510293,
121         938313161, 1288102441, 1768288259 };
122     
123
124     public static final Customizer CLASS_BY_NAME = new Customizer() {
125         public void customize(CodeEmitter e, Type type) {
126             if (type.equals(Constants.TYPE_CLASS)) {
127                 e.invoke_virtual(Constants.TYPE_CLASS, GET_NAME);
128             }
129         }
130     };
131
132     public static final Customizer OBJECT_BY_CLASS = new Customizer() {
133         public void customize(CodeEmitter e, Type type) {
134             e.invoke_virtual(Constants.TYPE_OBJECT, GET_CLASS);
135         }
136     };
137
138     protected KeyFactory() {
139     }
140
141     public static KeyFactory create(Class JavaDoc keyInterface) {
142         return create(keyInterface, null);
143     }
144
145     public static KeyFactory create(Class JavaDoc keyInterface, Customizer customizer) {
146         Generator gen = new Generator();
147         gen.setInterface(keyInterface);
148         gen.setCustomizer(customizer);
149         return gen.create();
150     }
151
152     public static class Generator extends AbstractClassGenerator {
153         private static final Source SOURCE = new Source(KeyFactory.class.getName());
154         private Class JavaDoc keyInterface;
155         private Customizer customizer;
156         private int constant;
157         private int multiplier;
158
159         public Generator() {
160             super(SOURCE);
161         }
162
163         protected ClassLoader JavaDoc getDefaultClassLoader() {
164             return keyInterface.getClassLoader();
165         }
166
167         public void setCustomizer(Customizer customizer) {
168             this.customizer = customizer;
169         }
170
171         public void setInterface(Class JavaDoc keyInterface) {
172             this.keyInterface = keyInterface;
173         }
174
175         public KeyFactory create() {
176             setNamePrefix(keyInterface.getName());
177             return (KeyFactory)super.create(keyInterface.getName());
178         }
179
180         public void setHashConstant(int constant) {
181             this.constant = constant;
182         }
183
184         public void setHashMultiplier(int multiplier) {
185             this.multiplier = multiplier;
186         }
187
188         protected Object JavaDoc firstInstance(Class JavaDoc type) {
189             return ReflectUtils.newInstance(type);
190         }
191
192         protected Object JavaDoc nextInstance(Object JavaDoc instance) {
193             return instance;
194         }
195
196         public void generateClass(ClassVisitor v) {
197             ClassEmitter ce = new ClassEmitter(v);
198             
199             Method JavaDoc newInstance = ReflectUtils.findNewInstance(keyInterface);
200             if (!newInstance.getReturnType().equals(Object JavaDoc.class)) {
201                 throw new IllegalArgumentException JavaDoc("newInstance method must return Object");
202             }
203
204             Type[] parameterTypes = TypeUtils.getTypes(newInstance.getParameterTypes());
205             ce.begin_class(Constants.ACC_PUBLIC,
206                            getClassName(),
207                            KEY_FACTORY,
208                            new Type[]{ Type.getType(keyInterface) },
209                            Constants.SOURCE_FILE);
210             EmitUtils.null_constructor(ce);
211             EmitUtils.factory_method(ce, ReflectUtils.getSignature(newInstance));
212
213             int seed = 0;
214             CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC,
215                                             TypeUtils.parseConstructor(parameterTypes),
216                                             null,
217                                             null);
218             e.load_this();
219             e.super_invoke_constructor();
220             e.load_this();
221             for (int i = 0; i < parameterTypes.length; i++) {
222                 seed += parameterTypes[i].hashCode();
223                 ce.declare_field(Constants.ACC_PRIVATE | Constants.ACC_FINAL,
224                                  getFieldName(i),
225                                  parameterTypes[i],
226                                  null,
227                                  null);
228                 e.dup();
229                 e.load_arg(i);
230                 e.putfield(getFieldName(i));
231             }
232             e.return_value();
233             e.end_method();
234             
235             // hash code
236
e = ce.begin_method(Constants.ACC_PUBLIC, HASH_CODE, null, null);
237             int hc = (constant != 0) ? constant : PRIMES[(int)(Math.abs(seed) % PRIMES.length)];
238             int hm = (multiplier != 0) ? multiplier : PRIMES[(int)(Math.abs(seed * 13) % PRIMES.length)];
239             e.push(hc);
240             for (int i = 0; i < parameterTypes.length; i++) {
241                 e.load_this();
242                 e.getfield(getFieldName(i));
243                 EmitUtils.hash_code(e, parameterTypes[i], hm, customizer);
244             }
245             e.return_value();
246             e.end_method();
247
248             // equals
249
e = ce.begin_method(Constants.ACC_PUBLIC, EQUALS, null, null);
250             Label fail = e.make_label();
251             e.load_arg(0);
252             e.instance_of_this();
253             e.if_jump(e.EQ, fail);
254             for (int i = 0; i < parameterTypes.length; i++) {
255                 e.load_this();
256                 e.getfield(getFieldName(i));
257                 e.load_arg(0);
258                 e.checkcast_this();
259                 e.getfield(getFieldName(i));
260                 EmitUtils.not_equals(e, parameterTypes[i], fail, customizer);
261             }
262             e.push(1);
263             e.return_value();
264             e.mark(fail);
265             e.push(0);
266             e.return_value();
267             e.end_method();
268
269             // toString
270
e = ce.begin_method(Constants.ACC_PUBLIC, TO_STRING, null, null);
271             e.new_instance(Constants.TYPE_STRING_BUFFER);
272             e.dup();
273             e.invoke_constructor(Constants.TYPE_STRING_BUFFER);
274             for (int i = 0; i < parameterTypes.length; i++) {
275                 if (i > 0) {
276                     e.push(", ");
277                     e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING);
278                 }
279                 e.load_this();
280                 e.getfield(getFieldName(i));
281                 EmitUtils.append_string(e, parameterTypes[i], EmitUtils.DEFAULT_DELIMITERS, customizer);
282             }
283             e.invoke_virtual(Constants.TYPE_STRING_BUFFER, TO_STRING);
284             e.return_value();
285             e.end_method();
286
287             ce.end_class();
288         }
289
290         private String JavaDoc getFieldName(int arg) {
291             return "FIELD_" + arg;
292         }
293     }
294 }
295
Popular Tags