KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > cglib > proxy > Mixin


1 /*
2  * Copyright 2003,2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package net.sf.cglib.proxy;
17
18 import java.lang.reflect.Constructor JavaDoc;
19 import java.lang.reflect.Modifier JavaDoc;
20 import java.util.*;
21 import net.sf.cglib.core.*;
22 import org.objectweb.asm.ClassVisitor;
23
24
25
26 /**
27  * <code>Mixin</code> allows
28  * multiple objects to be combined into a single larger object. The
29  * methods in the generated object simply call the original methods in the
30  * underlying "delegate" objects.
31  * @author Chris Nokleberg
32  * @version $Id: Mixin.java,v 1.7 2005/09/27 11:42:27 baliuka Exp $
33  */

34 abstract public class Mixin {
35     private static final MixinKey KEY_FACTORY =
36       (MixinKey)KeyFactory.create(MixinKey.class, KeyFactory.CLASS_BY_NAME);
37     private static final Map ROUTE_CACHE = Collections.synchronizedMap(new HashMap());
38
39     public static final int STYLE_INTERFACES = 0;
40     public static final int STYLE_BEANS = 1;
41     public static final int STYLE_EVERYTHING = 2;
42
43     interface MixinKey {
44         public Object JavaDoc newInstance(int style, String JavaDoc[] classes, int[] route);
45     }
46
47     abstract public Mixin newInstance(Object JavaDoc[] delegates);
48
49     /**
50      * Helper method to create an interface mixin. For finer control over the
51      * generated instance, use a new instance of <code>Mixin</code>
52      * instead of this static method.
53      * TODO
54      */

55     public static Mixin create(Object JavaDoc[] delegates) {
56         Generator gen = new Generator();
57         gen.setDelegates(delegates);
58         return gen.create();
59     }
60
61     /**
62      * Helper method to create an interface mixin. For finer control over the
63      * generated instance, use a new instance of <code>Mixin</code>
64      * instead of this static method.
65      * TODO
66      */

67     public static Mixin create(Class JavaDoc[] interfaces, Object JavaDoc[] delegates) {
68         Generator gen = new Generator();
69         gen.setClasses(interfaces);
70         gen.setDelegates(delegates);
71         return gen.create();
72     }
73
74     
75     public static Mixin createBean(Object JavaDoc[] beans) {
76     
77         return createBean(null, beans);
78     
79     }
80     /**
81      * Helper method to create a bean mixin. For finer control over the
82      * generated instance, use a new instance of <code>Mixin</code>
83      * instead of this static method.
84      * TODO
85      */

86     public static Mixin createBean(ClassLoader JavaDoc loader,Object JavaDoc[] beans) {
87         Generator gen = new Generator();
88         gen.setStyle(STYLE_BEANS);
89         gen.setDelegates(beans);
90         gen.setClassLoader(loader);
91         return gen.create();
92     }
93     
94     public static class Generator extends AbstractClassGenerator {
95         private static final Source SOURCE = new Source(Mixin.class.getName());
96
97         private Class JavaDoc[] classes;
98         private Object JavaDoc[] delegates;
99         private int style = STYLE_INTERFACES;
100         
101         private int[] route;
102
103         public Generator() {
104             super(SOURCE);
105         }
106
107         protected ClassLoader JavaDoc getDefaultClassLoader() {
108             return classes[0].getClassLoader(); // is this right?
109
}
110
111         public void setStyle(int style) {
112             switch (style) {
113             case STYLE_INTERFACES:
114             case STYLE_BEANS:
115             case STYLE_EVERYTHING:
116                 this.style = style;
117                 break;
118             default:
119                 throw new IllegalArgumentException JavaDoc("Unknown mixin style: " + style);
120             }
121         }
122
123         public void setClasses(Class JavaDoc[] classes) {
124             this.classes = classes;
125         }
126
127         public void setDelegates(Object JavaDoc[] delegates) {
128             this.delegates = delegates;
129         }
130
131         public Mixin create() {
132             if (classes == null && delegates == null) {
133                 throw new IllegalStateException JavaDoc("Either classes or delegates must be set");
134             }
135             switch (style) {
136             case STYLE_INTERFACES:
137                 if (classes == null) {
138                     Route r = route(delegates);
139                     classes = r.classes;
140                     route = r.route;
141                 }
142                 break;
143             case STYLE_BEANS:
144                 // fall-through
145
case STYLE_EVERYTHING:
146                 if (classes == null) {
147                     classes = ReflectUtils.getClasses(delegates);
148                 } else {
149                     if (delegates != null) {
150                         Class JavaDoc[] temp = ReflectUtils.getClasses(delegates);
151                         if (classes.length != temp.length) {
152                             throw new IllegalStateException JavaDoc("Specified classes are incompatible with delegates");
153                         }
154                         for (int i = 0; i < classes.length; i++) {
155                             if (!classes[i].isAssignableFrom(temp[i])) {
156                                 throw new IllegalStateException JavaDoc("Specified class " + classes[i] + " is incompatible with delegate class " + temp[i] + " (index " + i + ")");
157                             }
158                         }
159                     }
160                 }
161             }
162             setNamePrefix(classes[ReflectUtils.findPackageProtected(classes)].getName());
163             
164             return (Mixin)super.create(KEY_FACTORY.newInstance(style, ReflectUtils.getNames( classes ), route));
165         }
166
167         public void generateClass(ClassVisitor v) {
168             switch (style) {
169             case STYLE_INTERFACES:
170                 new MixinEmitter(v, getClassName(), classes, route);
171                 break;
172             case STYLE_BEANS:
173                 new MixinBeanEmitter(v, getClassName(), classes);
174                 break;
175             case STYLE_EVERYTHING:
176                 new MixinEverythingEmitter(v, getClassName(), classes);
177                 break;
178             }
179         }
180
181         protected Object JavaDoc firstInstance(Class JavaDoc type) {
182             return ((Mixin)ReflectUtils.newInstance(type)).newInstance(delegates);
183         }
184
185         protected Object JavaDoc nextInstance(Object JavaDoc instance) {
186             return ((Mixin)instance).newInstance(delegates);
187         }
188     }
189
190     public static Class JavaDoc[] getClasses(Object JavaDoc[] delegates) {
191         return (Class JavaDoc[])route(delegates).classes.clone();
192     }
193
194 // public static int[] getRoute(Object[] delegates) {
195
// return (int[])route(delegates).route.clone();
196
// }
197

198     private static Route route(Object JavaDoc[] delegates) {
199         Object JavaDoc key = ClassesKey.create(delegates);
200         Route route = (Route)ROUTE_CACHE.get(key);
201         if (route == null) {
202             ROUTE_CACHE.put(key, route = new Route(delegates));
203         }
204         return route;
205     }
206
207     private static class Route
208     {
209         private Class JavaDoc[] classes;
210         private int[] route;
211
212         Route(Object JavaDoc[] delegates) {
213             Map map = new HashMap();
214             ArrayList collect = new ArrayList();
215             for (int i = 0; i < delegates.length; i++) {
216                 Class JavaDoc delegate = delegates[i].getClass();
217                 collect.clear();
218                 ReflectUtils.addAllInterfaces(delegate, collect);
219                 for (Iterator it = collect.iterator(); it.hasNext();) {
220                     Class JavaDoc iface = (Class JavaDoc)it.next();
221                     if (!map.containsKey(iface)) {
222                         map.put(iface, new Integer JavaDoc(i));
223                     }
224                 }
225             }
226             classes = new Class JavaDoc[map.size()];
227             route = new int[map.size()];
228             int index = 0;
229             for (Iterator it = map.keySet().iterator(); it.hasNext();) {
230                 Class JavaDoc key = (Class JavaDoc)it.next();
231                 classes[index] = key;
232                 route[index] = ((Integer JavaDoc)map.get(key)).intValue();
233                 index++;
234             }
235         }
236     }
237 }
238
Popular Tags