001    // Copyright 2005 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.hivemind.service.impl;
016    
017    import java.lang.reflect.Method;
018    import java.lang.reflect.Modifier;
019    import java.util.ArrayList;
020    import java.util.HashSet;
021    import java.util.Iterator;
022    import java.util.List;
023    import java.util.Set;
024    
025    import org.apache.hivemind.service.ClassFabUtils;
026    import org.apache.hivemind.service.ClassFactory;
027    import org.apache.hivemind.service.InterfaceFab;
028    import org.apache.hivemind.service.InterfaceSynthesizer;
029    import org.apache.hivemind.service.MethodSignature;
030    
031    /**
032     * @author Howard M. Lewis Ship
033     */
034    public class InterfaceSynthesizerImpl implements InterfaceSynthesizer
035    {
036        private ClassFactory _classFactory;
037    
038        private static class Operation
039        {
040            private Set _interfaces = new HashSet();
041    
042            private Set _interfaceMethods = new HashSet();
043    
044            private Set _allMethods = new HashSet();
045    
046            private List _interfaceQueue = new ArrayList();
047    
048            public Set getInterfaces()
049            {
050                return _interfaces;
051            }
052    
053            public Set getNonInterfaceMethodSignatures()
054            {
055                Set result = new HashSet(_allMethods);
056    
057                result.removeAll(_interfaceMethods);
058    
059                return result;
060            }
061    
062            public void processInterfaceQueue()
063            {
064                while (!_interfaceQueue.isEmpty())
065                {
066                    Class interfaceClass = (Class) _interfaceQueue.remove(0);
067    
068                    processInterface(interfaceClass);
069                }
070            }
071    
072            private void processInterface(Class interfaceClass)
073            {
074                Class[] interfaces = interfaceClass.getInterfaces();
075    
076                for (int i = 0; i < interfaces.length; i++)
077                    addInterfaceToQueue(interfaces[i]);
078    
079                Method[] methods = interfaceClass.getDeclaredMethods();
080    
081                for (int i = 0; i < methods.length; i++)
082                {
083                    MethodSignature sig = new MethodSignature(methods[i]);
084    
085                    _interfaceMethods.add(sig);
086                }
087            }
088    
089            private void addInterfaceToQueue(Class interfaceClass)
090            {
091                if (_interfaces.contains(interfaceClass))
092                    return;
093    
094                _interfaces.add(interfaceClass);
095                _interfaceQueue.add(interfaceClass);
096            }
097    
098            public void processClass(Class beanClass)
099            {
100                Class[] interfaces = beanClass.getInterfaces();
101    
102                for (int i = 0; i < interfaces.length; i++)
103                    addInterfaceToQueue(interfaces[i]);
104    
105                Method[] methods = beanClass.getDeclaredMethods();
106    
107                for (int i = 0; i < methods.length; i++)
108                {
109                    Method m = methods[i];
110                    int modifiers = m.getModifiers();
111    
112                    if (Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers))
113                        continue;
114    
115                    MethodSignature sig = new MethodSignature(m);
116    
117                    _allMethods.add(sig);
118                }
119            }
120    
121        }
122    
123        public Class synthesizeInterface(Class beanClass)
124        {
125            Operation op = new Operation();
126    
127            explodeClass(beanClass, op);
128    
129            return createInterface(beanClass, op);
130        }
131    
132        void explodeClass(Class beanClass, Operation op)
133        {
134            Class current = beanClass;
135    
136            while (current != Object.class)
137            {
138                op.processClass(current);
139    
140                current = current.getSuperclass();
141            }
142    
143            op.processInterfaceQueue();
144        }
145    
146        Class createInterface(Class beanClass, Operation op)
147        {
148            String name = ClassFabUtils.generateClassName(beanClass);
149    
150            return createInterface(name, op);
151        }
152    
153        private Class createInterface(String name, Operation op)
154        {
155            InterfaceFab fab = _classFactory.newInterface(name);
156    
157            Iterator i = op.getInterfaces().iterator();
158            while (i.hasNext())
159            {
160                Class interfaceClass = (Class) i.next();
161    
162                fab.addInterface(interfaceClass);
163            }
164    
165            i = op.getNonInterfaceMethodSignatures().iterator();
166            while (i.hasNext())
167            {
168                MethodSignature sig = (MethodSignature) i.next();
169    
170                fab.addMethod(sig);
171            }
172    
173            return fab.createInterface();
174        }
175    
176        public void setClassFactory(ClassFactory classFactory)
177        {
178            _classFactory = classFactory;
179        }
180    }