KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > logicalcobwebs > cglib > proxy > Mixin


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 package org.logicalcobwebs.cglib.proxy;
55
56 import java.lang.reflect.Constructor JavaDoc;
57 import java.lang.reflect.Modifier JavaDoc;
58 import java.util.*;
59 import org.logicalcobwebs.cglib.core.*;
60 import org.logicalcobwebs.asm.ClassVisitor;
61
62 /**
63  * <code>Mixin</code> allows
64  * multiple objects to be combined into a single larger object. The
65  * methods in the generated object simply call the original methods in the
66  * underlying "delegate" objects.
67  * @author Chris Nokleberg
68  * @version $Id: Mixin.java,v 1.1 2003/12/12 19:28:11 billhorsman Exp $
69  */

70 abstract public class Mixin {
71     private static final MixinKey KEY_FACTORY =
72       (MixinKey)KeyFactory.create(MixinKey.class, KeyFactory.CLASS_BY_NAME);
73     private static final Map ROUTE_CACHE = Collections.synchronizedMap(new HashMap());
74
75     interface MixinKey {
76         public Object JavaDoc newInstance(Class JavaDoc[] classes, int[] route);
77     }
78
79     abstract public Mixin newInstance(Object JavaDoc[] delegates);
80
81     /**
82      * Helper method to create an interface mixin. For finer control over the
83      * generated instance, use a new instance of <code>Mixin</code>
84      * instead of this static method.
85      * TODO
86      */

87     public static Mixin create(Object JavaDoc[] delegates) {
88         Generator gen = new Generator();
89         gen.setDelegates(delegates);
90         return gen.create();
91     }
92
93     /**
94      * Helper method to create an interface mixin. For finer control over the
95      * generated instance, use a new instance of <code>Mixin</code>
96      * instead of this static method.
97      * TODO
98      */

99     public static Mixin create(Class JavaDoc[] interfaces, Object JavaDoc[] delegates) {
100         Generator gen = new Generator();
101         gen.setClasses(interfaces);
102         gen.setDelegates(delegates);
103         return gen.create();
104     }
105
106     /**
107      * Helper method to create a bean mixin. For finer control over the
108      * generated instance, use a new instance of <code>Mixin</code>
109      * instead of this static method.
110      * TODO
111      */

112     public static Mixin createBean(Object JavaDoc[] beans) {
113         Generator gen = new Generator();
114         gen.setAsBeans(true);
115         gen.setDelegates(beans);
116         return gen.create();
117     }
118     
119     public static class Generator extends AbstractClassGenerator {
120         private static final Source SOURCE = new Source(Mixin.class.getName());
121
122         private Class JavaDoc[] classes;
123         private Object JavaDoc[] delegates;
124         private int[] route;
125         private boolean asBeans;
126
127         public Generator() {
128             super(SOURCE);
129         }
130
131         protected ClassLoader JavaDoc getDefaultClassLoader() {
132             return delegates[0].getClass().getClassLoader(); // is this right?
133
}
134
135         public void setAsBeans(boolean asBeans) {
136             this.asBeans = asBeans;
137         }
138
139         public void setClasses(Class JavaDoc[] classes) {
140             this.classes = classes;
141         }
142
143         public void setDelegates(Object JavaDoc[] delegates) {
144             this.delegates = delegates;
145         }
146
147         public void setRoute(int[] route) {
148             this.route = route;
149         }
150
151         public Mixin create() {
152             if (classes == null) {
153                 if (asBeans) {
154                     classes = ReflectUtils.getClasses(delegates);
155                     route = null;
156                 } else {
157                     Route r = route(delegates);
158                     classes = r.classes;
159                     route = r.route;
160                 }
161             }
162             setNamePrefix(classes[ReflectUtils.findPackageProtected(classes)].getName());
163             return (Mixin)super.create(KEY_FACTORY.newInstance(classes, route));
164         }
165
166         public void generateClass(ClassVisitor v) {
167             if (asBeans) {
168                 new MixinBeanEmitter(v, getClassName(), classes);
169             } else {
170                 new MixinEmitter(v, getClassName(), classes, route);
171             }
172         }
173
174         protected Object JavaDoc firstInstance(Class JavaDoc type) {
175             return ((Mixin)ReflectUtils.newInstance(type)).newInstance(delegates);
176         }
177
178         protected Object JavaDoc nextInstance(Object JavaDoc instance) {
179             return ((Mixin)instance).newInstance(delegates);
180         }
181     }
182
183     public static Class JavaDoc[] getClasses(Object JavaDoc[] delegates) {
184         return (Class JavaDoc[])route(delegates).classes.clone();
185     }
186
187     public static int[] getRoute(Object JavaDoc[] delegates) {
188         return (int[])route(delegates).route.clone();
189     }
190         
191     private static Route route(Object JavaDoc[] delegates) {
192         Object JavaDoc key = ClassesKey.create(delegates);
193         Route route = (Route)ROUTE_CACHE.get(key);
194         if (route == null) {
195             ROUTE_CACHE.put(key, route = new Route(delegates));
196         }
197         return route;
198     }
199
200     private static class Route
201     {
202         private Class JavaDoc[] classes;
203         private int[] route;
204
205         Route(Object JavaDoc[] delegates) {
206             Map map = new HashMap();
207             ArrayList collect = new ArrayList();
208             for (int i = 0; i < delegates.length; i++) {
209                 Class JavaDoc delegate = delegates[i].getClass();
210                 collect.clear();
211                 collectAllInterfaces(delegate, collect);
212                 for (Iterator it = collect.iterator(); it.hasNext();) {
213                     Class JavaDoc iface = (Class JavaDoc)it.next();
214                     if (!map.containsKey(iface)) {
215                         map.put(iface, new Integer JavaDoc(i));
216                     }
217                 }
218             }
219             classes = new Class JavaDoc[map.size()];
220             route = new int[map.size()];
221             int index = 0;
222             for (Iterator it = map.keySet().iterator(); it.hasNext();) {
223                 Class JavaDoc key = (Class JavaDoc)it.next();
224                 classes[index] = key;
225                 route[index] = ((Integer JavaDoc)map.get(key)).intValue();
226                 index++;
227             }
228         }
229     }
230
231     private static void collectAllInterfaces(Class JavaDoc type, List list) {
232         if (!type.equals(Object JavaDoc.class)) {
233             list.addAll(Arrays.asList(type.getInterfaces()));
234             collectAllInterfaces(type.getSuperclass(), list);
235         }
236     }
237 }
238
Popular Tags