All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.openjpa.persistence.jest.PrototypeFactory Maven / Gradle / Ivy

There is a newer version: 4.0.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.    
 */

package org.apache.openjpa.persistence.jest;

import java.lang.reflect.Constructor;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import org.apache.openjpa.kernel.Filters;

/**
 * A factory for a specific type of objects registered by a key.
 * The client registers a type indexed by name. 
 * The client can get a new instance of the registered type. 
 * The requested registered type not necessarily have to have a no-arg
 * constructor. The constructor arguments can be passed during 
 * {@link #newInstance(Class, Object...) new instance} request. Based on the
 * arguments, a matching constructor, if any, is located and invoked.
 * 
 *  type of key for this registry
 *  base type of the objects to construct 
 * 
 * @author Pinaki Poddar
 *
 */
public class PrototypeFactory {
    private Map> _registry = new TreeMap>();
    
    /**
     * Register the given class with the given key.
     * 
     * @param key a non-null key.
     * @param prototype a type.
     */
    public void register(K key, Class prototype) {
        _registry.put(key, prototype);
    }
    
    /**
     * Create a new instance of the type {@linkplain #register(Object, Class) registered} before
     * with the given key, if any.
     * The given arguments are used to identify a constructor of the registered type and 
     * passed to the constructor of the registered type.
     * 
     * @param key a key to identify a registered type.
     * @param args arguments to pass to the constructor of the type.
     * 
     * @return null if no type has been registered against the given key.  
     */
    public T newInstance(K key, Object... args) {
        return _registry.containsKey(key) ? newInstance(_registry.get(key), args) : null;
    }
    
    /**
     * Gets the keys registered in this factory.
     * 
     * @return immutable set of registered keys.
     */
    public Set getRegisteredKeys() {
        return Collections.unmodifiableSet(_registry.keySet());
    }
    
    private T newInstance(Class type, Object... args) {
        try {
            return findConstructor(type, getConstructorParameterTypes(args)).newInstance(args);
        } catch (Exception e) {
            throw new RuntimeException();
        }
    }
    
    Class[] getConstructorParameterTypes(Object... args) {
        if (args == null || args.length == 0) {
            return new Class[0];
        }
        Class[] types = new Class[args.length];
        for (int i = 0; i < args.length; i++) {
            types[i] = args[i] == null ? Object.class : args[i].getClass();
        }
        return types;
    }
    
    /**
     * Finds a constructor of the given class with given argument types.
     */
    Constructor findConstructor(Class cls, Class[] types) {
        try {
            return cls.getConstructor(types);
        } catch (Exception e) {
            Constructor[] constructors = cls.getConstructors();
            for (Constructor cons : constructors) {
                Class[] paramTypes = cons.getParameterTypes();
                boolean match = false;
                if (paramTypes.length == types.length) {
                    for (int i = 0; i < paramTypes.length; i++) {
                        match = paramTypes[i].isAssignableFrom(Filters.wrap(types[i]));
                        if (!match)
                            break;
                        }
                    }
                    if (match) {
                        return (Constructor)cons;
                    }
            }
        }
        throw new RuntimeException();//_loc.get("fill-ctor-none", cls, Arrays.toString(types)).getMessage());
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy