1674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen/*
2674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Copyright 2003,2004 The Apache Software Foundation
3674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *
4674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *  Licensed under the Apache License, Version 2.0 (the "License");
5674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * you may not use this file except in compliance with the License.
6674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * You may obtain a copy of the License at
7674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *
8674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *      http://www.apache.org/licenses/LICENSE-2.0
9674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *
10674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen *  Unless required by applicable law or agreed to in writing, software
11674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * distributed under the License is distributed on an "AS IS" BASIS,
12674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * See the License for the specific language governing permissions and
14674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * limitations under the License.
15674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */
16674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenpackage org.mockito.cglib.proxy;
17674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
18674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport java.lang.reflect.Constructor;
19674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport java.lang.reflect.Modifier;
20674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport java.util.*;
21674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
22674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.ClassVisitor;
23674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.cglib.core.*;
24674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
25674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
26674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
27674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen/**
28674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * <code>Mixin</code> allows
29674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * multiple objects to be combined into a single larger object. The
30674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * methods in the generated object simply call the original methods in the
31674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * underlying "delegate" objects.
32674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @author Chris Nokleberg
33674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @version $Id: Mixin.java,v 1.7 2005/09/27 11:42:27 baliuka Exp $
34674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */
35674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenabstract public class Mixin {
36674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final MixinKey KEY_FACTORY =
37674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      (MixinKey)KeyFactory.create(MixinKey.class, KeyFactory.CLASS_BY_NAME);
38674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Map ROUTE_CACHE = Collections.synchronizedMap(new HashMap());
39674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
40674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static final int STYLE_INTERFACES = 0;
41674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static final int STYLE_BEANS = 1;
42674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static final int STYLE_EVERYTHING = 2;
43674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
44674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    interface MixinKey {
45674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        public Object newInstance(int style, String[] classes, int[] route);
46674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
47674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
48674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    abstract public Mixin newInstance(Object[] delegates);
49674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
50674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
51674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Helper method to create an interface mixin. For finer control over the
52674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * generated instance, use a new instance of <code>Mixin</code>
53674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * instead of this static method.
54674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * TODO
55674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
56674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static Mixin create(Object[] delegates) {
57674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Generator gen = new Generator();
58674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        gen.setDelegates(delegates);
59674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return gen.create();
60674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
61674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
62674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
63674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Helper method to create an interface mixin. For finer control over the
64674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * generated instance, use a new instance of <code>Mixin</code>
65674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * instead of this static method.
66674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * TODO
67674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
68674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static Mixin create(Class[] interfaces, Object[] delegates) {
69674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Generator gen = new Generator();
70674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        gen.setClasses(interfaces);
71674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        gen.setDelegates(delegates);
72674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return gen.create();
73674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
74674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
75674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
76674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static Mixin createBean(Object[] beans) {
77674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
78674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return createBean(null, beans);
79674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
80674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
81674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    /**
82674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * Helper method to create a bean mixin. For finer control over the
83674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * generated instance, use a new instance of <code>Mixin</code>
84674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * instead of this static method.
85674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     * TODO
86674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen     */
87674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static Mixin createBean(ClassLoader loader,Object[] beans) {
88674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Generator gen = new Generator();
89674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        gen.setStyle(STYLE_BEANS);
90674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        gen.setDelegates(beans);
91674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        gen.setClassLoader(loader);
92674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return gen.create();
93674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
94674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
95674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static class Generator extends AbstractClassGenerator {
96674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        private static final Source SOURCE = new Source(Mixin.class.getName());
97674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
98674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        private Class[] classes;
99674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        private Object[] delegates;
100674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        private int style = STYLE_INTERFACES;
101674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
102674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        private int[] route;
103674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
104674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        public Generator() {
105674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            super(SOURCE);
106674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
107674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
108674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        protected ClassLoader getDefaultClassLoader() {
109674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            return classes[0].getClassLoader(); // is this right?
110674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
111674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
112674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        public void setStyle(int style) {
113674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            switch (style) {
114674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            case STYLE_INTERFACES:
115674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            case STYLE_BEANS:
116674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            case STYLE_EVERYTHING:
117674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                this.style = style;
118674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                break;
119674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            default:
120674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                throw new IllegalArgumentException("Unknown mixin style: " + style);
121674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
122674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
123674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
124674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        public void setClasses(Class[] classes) {
125674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            this.classes = classes;
126674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
127674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
128674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        public void setDelegates(Object[] delegates) {
129674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            this.delegates = delegates;
130674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
131674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
132674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        public Mixin create() {
133674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (classes == null && delegates == null) {
134674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                throw new IllegalStateException("Either classes or delegates must be set");
135674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
136674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            switch (style) {
137674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            case STYLE_INTERFACES:
138674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                if (classes == null) {
139674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    Route r = route(delegates);
140674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    classes = r.classes;
141674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    route = r.route;
142674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
143674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                break;
144674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            case STYLE_BEANS:
145674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                // fall-through
146674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            case STYLE_EVERYTHING:
147674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                if (classes == null) {
148674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    classes = ReflectUtils.getClasses(delegates);
149674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                } else {
150674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    if (delegates != null) {
151674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        Class[] temp = ReflectUtils.getClasses(delegates);
152674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        if (classes.length != temp.length) {
153674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            throw new IllegalStateException("Specified classes are incompatible with delegates");
154674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        }
155674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        for (int i = 0; i < classes.length; i++) {
156674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            if (!classes[i].isAssignableFrom(temp[i])) {
157674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                throw new IllegalStateException("Specified class " + classes[i] + " is incompatible with delegate class " + temp[i] + " (index " + i + ")");
158674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                            }
159674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        }
160674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    }
161674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
162674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
163674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            setNamePrefix(classes[ReflectUtils.findPackageProtected(classes)].getName());
164674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
165674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            return (Mixin)super.create(KEY_FACTORY.newInstance(style, ReflectUtils.getNames( classes ), route));
166674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
167674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
168674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        public void generateClass(ClassVisitor v) {
169674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            switch (style) {
170674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            case STYLE_INTERFACES:
171674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                new MixinEmitter(v, getClassName(), classes, route);
172674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                break;
173674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            case STYLE_BEANS:
174674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                new MixinBeanEmitter(v, getClassName(), classes);
175674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                break;
176674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            case STYLE_EVERYTHING:
177674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                new MixinEverythingEmitter(v, getClassName(), classes);
178674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                break;
179674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
180674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
181674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
182674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        protected Object firstInstance(Class type) {
183674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            return ((Mixin)ReflectUtils.newInstance(type)).newInstance(delegates);
184674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
185674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
186674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        protected Object nextInstance(Object instance) {
187674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            return ((Mixin)instance).newInstance(delegates);
188674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
189674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
190674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
191674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static Class[] getClasses(Object[] delegates) {
192674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return (Class[])route(delegates).classes.clone();
193674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
194674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
195674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen//     public static int[] getRoute(Object[] delegates) {
196674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen//         return (int[])route(delegates).route.clone();
197674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen//     }
198674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
199674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static Route route(Object[] delegates) {
200674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Object key = ClassesKey.create(delegates);
201674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Route route = (Route)ROUTE_CACHE.get(key);
202674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (route == null) {
203674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            ROUTE_CACHE.put(key, route = new Route(delegates));
204674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
205674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return route;
206674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
207674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
208674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static class Route
209674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    {
210674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        private Class[] classes;
211674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        private int[] route;
212674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
213674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Route(Object[] delegates) {
214674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            Map map = new HashMap();
215674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            ArrayList collect = new ArrayList();
216674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            for (int i = 0; i < delegates.length; i++) {
217674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                Class delegate = delegates[i].getClass();
218674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                collect.clear();
219674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                ReflectUtils.addAllInterfaces(delegate, collect);
220674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                for (Iterator it = collect.iterator(); it.hasNext();) {
221674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    Class iface = (Class)it.next();
222674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    if (!map.containsKey(iface)) {
223674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        map.put(iface, new Integer(i));
224674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    }
225674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
226674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
227674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            classes = new Class[map.size()];
228674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            route = new int[map.size()];
229674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            int index = 0;
230674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            for (Iterator it = map.keySet().iterator(); it.hasNext();) {
231674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                Class key = (Class)it.next();
232674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                classes[index] = key;
233674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                route[index] = ((Integer)map.get(key)).intValue();
234674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                index++;
235674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
236674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
237674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
238674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen}
239