001    /**
002     * Copyright (C) 2009 Erik Putrycz <erik.putrycz@gmail.com>
003     * 
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     * 
008     *         http://www.apache.org/licenses/LICENSE-2.0
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package net.ep.db4o.factories;
018    
019    import java.lang.reflect.Constructor;
020    import java.lang.reflect.InvocationHandler;
021    import java.lang.reflect.Method;
022    import java.util.HashMap;
023    import java.util.Map;
024    
025    public class FactoryInvocationHandler implements InvocationHandler {
026    
027            private Map<Method, Constructor<?>> _constructors = new HashMap<Method, Constructor<?>>();
028            private Factories _factories;
029    
030            public FactoryInvocationHandler(Class<?> factory, Class<?> targetType, Class<?> realType, Factories basicFactories) {
031                    for (Method method:factory.getDeclaredMethods()) {
032                            Constructor<?> cons = findConstructor(method, realType);
033                            if (cons == null)
034                                    throw new InvalidFactoryException("No matching constructor found in " + targetType.getName() + " for method " + method.getName());                      
035                            _constructors.put(method, cons);
036                    }
037                    _factories = basicFactories;
038            }
039    
040            private Constructor<?> findConstructor(Method main, Class<?> targetType) {
041                    for (Constructor<?> cons:targetType.getDeclaredConstructors()) {
042                            cons.setAccessible(true);
043                            if (cons.getParameterTypes() != null && main.getParameterTypes() != null) {
044                                    if (cons.getParameterTypes().length == main.getParameterTypes().length) {
045                                            boolean found = true;
046                                            for (int il = 0;il < cons.getParameterTypes().length;il++) {
047                                                    found = found && cons.getParameterTypes()[il] == main.getParameterTypes()[il];
048                                            }
049                                            if (found)
050                                                    return cons;
051                                    }
052                            } else {
053                                    if (main.getParameterTypes() == null)
054                                            return cons;
055                            }
056                    }
057                    return null;
058            }
059    
060            public Object invoke(Object proxy, Method method, Object[] args)
061                            throws Throwable {
062                    Object inst = _constructors.get(method).newInstance(args);
063                    _factories.onNewInstance(inst);
064                    return inst;
065            }
066    
067    }