View Javadoc
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 net.sf.cglib.proxy; 55 56 import java.lang.reflect.Constructor; 57 import java.lang.reflect.Modifier; 58 import java.util.*; 59 import net.sf.cglib.core.*; 60 import org.objectweb.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.4 2004/01/25 22:28:02 herbyderby 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 public static final int STYLE_INTERFACES = 0; 76 public static final int STYLE_BEANS = 1; 77 public static final int STYLE_EVERYTHING = 2; 78 79 interface MixinKey { 80 public Object newInstance(int style, Class[] classes, int[] route); 81 } 82 83 abstract public Mixin newInstance(Object[] delegates); 84 85 /*** 86 * Helper method to create an interface mixin. For finer control over the 87 * generated instance, use a new instance of <code>Mixin</code> 88 * instead of this static method. 89 * TODO 90 */ 91 public static Mixin create(Object[] delegates) { 92 Generator gen = new Generator(); 93 gen.setDelegates(delegates); 94 return gen.create(); 95 } 96 97 /*** 98 * Helper method to create an interface mixin. For finer control over the 99 * generated instance, use a new instance of <code>Mixin</code> 100 * instead of this static method. 101 * TODO 102 */ 103 public static Mixin create(Class[] interfaces, Object[] delegates) { 104 Generator gen = new Generator(); 105 gen.setClasses(interfaces); 106 gen.setDelegates(delegates); 107 return gen.create(); 108 } 109 110 /*** 111 * Helper method to create a bean mixin. For finer control over the 112 * generated instance, use a new instance of <code>Mixin</code> 113 * instead of this static method. 114 * TODO 115 */ 116 public static Mixin createBean(Object[] beans) { 117 Generator gen = new Generator(); 118 gen.setStyle(STYLE_BEANS); 119 gen.setDelegates(beans); 120 return gen.create(); 121 } 122 123 public static class Generator extends AbstractClassGenerator { 124 private static final Source SOURCE = new Source(Mixin.class.getName()); 125 126 private Class[] classes; 127 private Object[] delegates; 128 private int style = STYLE_INTERFACES; 129 130 private int[] route; 131 132 public Generator() { 133 super(SOURCE); 134 } 135 136 protected ClassLoader getDefaultClassLoader() { 137 return classes[0].getClassLoader(); // is this right? 138 } 139 140 public void setStyle(int style) { 141 switch (style) { 142 case STYLE_INTERFACES: 143 case STYLE_BEANS: 144 case STYLE_EVERYTHING: 145 this.style = style; 146 break; 147 default: 148 throw new IllegalArgumentException("Unknown mixin style: " + style); 149 } 150 } 151 152 public void setClasses(Class[] classes) { 153 this.classes = classes; 154 } 155 156 public void setDelegates(Object[] delegates) { 157 this.delegates = delegates; 158 } 159 160 public Mixin create() { 161 if (classes == null && delegates == null) { 162 throw new IllegalStateException("Either classes or delegates must be set"); 163 } 164 switch (style) { 165 case STYLE_INTERFACES: 166 if (classes == null) { 167 Route r = route(delegates); 168 classes = r.classes; 169 route = r.route; 170 } 171 break; 172 case STYLE_BEANS: 173 // fall-through 174 case STYLE_EVERYTHING: 175 if (classes == null) { 176 classes = ReflectUtils.getClasses(delegates); 177 } else { 178 if (delegates != null) { 179 Class[] temp = ReflectUtils.getClasses(delegates); 180 if (classes.length != temp.length) { 181 throw new IllegalStateException("Specified classes are incompatible with delegates"); 182 } 183 for (int i = 0; i < classes.length; i++) { 184 if (!classes[i].isAssignableFrom(temp[i])) { 185 throw new IllegalStateException("Specified class " + classes[i] + " is incompatible with delegate class " + temp[i] + " (index " + i + ")"); 186 } 187 } 188 } 189 } 190 } 191 setNamePrefix(classes[ReflectUtils.findPackageProtected(classes)].getName()); 192 return (Mixin)super.create(KEY_FACTORY.newInstance(style, classes, route)); 193 } 194 195 public void generateClass(ClassVisitor v) { 196 switch (style) { 197 case STYLE_INTERFACES: 198 new MixinEmitter(v, getClassName(), classes, route); 199 break; 200 case STYLE_BEANS: 201 new MixinBeanEmitter(v, getClassName(), classes); 202 break; 203 case STYLE_EVERYTHING: 204 new MixinEverythingEmitter(v, getClassName(), classes); 205 break; 206 } 207 } 208 209 protected Object firstInstance(Class type) { 210 return ((Mixin)ReflectUtils.newInstance(type)).newInstance(delegates); 211 } 212 213 protected Object nextInstance(Object instance) { 214 return ((Mixin)instance).newInstance(delegates); 215 } 216 } 217 218 public static Class[] getClasses(Object[] delegates) { 219 return (Class[])route(delegates).classes.clone(); 220 } 221 222 // public static int[] getRoute(Object[] delegates) { 223 // return (int[])route(delegates).route.clone(); 224 // } 225 226 private static Route route(Object[] delegates) { 227 Object key = ClassesKey.create(delegates); 228 Route route = (Route)ROUTE_CACHE.get(key); 229 if (route == null) { 230 ROUTE_CACHE.put(key, route = new Route(delegates)); 231 } 232 return route; 233 } 234 235 private static class Route 236 { 237 private Class[] classes; 238 private int[] route; 239 240 Route(Object[] delegates) { 241 Map map = new HashMap(); 242 ArrayList collect = new ArrayList(); 243 for (int i = 0; i < delegates.length; i++) { 244 Class delegate = delegates[i].getClass(); 245 collect.clear(); 246 ReflectUtils.addAllInterfaces(delegate, collect); 247 for (Iterator it = collect.iterator(); it.hasNext();) { 248 Class iface = (Class)it.next(); 249 if (!map.containsKey(iface)) { 250 map.put(iface, new Integer(i)); 251 } 252 } 253 } 254 classes = new Class[map.size()]; 255 route = new int[map.size()]; 256 int index = 0; 257 for (Iterator it = map.keySet().iterator(); it.hasNext();) { 258 Class key = (Class)it.next(); 259 classes[index] = key; 260 route[index] = ((Integer)map.get(key)).intValue(); 261 index++; 262 } 263 } 264 } 265 }

This page was automatically generated by Maven