/** 
 * 
 * Copyright 2004 Protique Ltd
 * 
 * Licensed 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.activemq.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

/**
 * A helper class to discover protocols dynamically to ensure
 * that the system is extensible and has minimum runtime dependencies
 *
 * @version $Revision: 1.1.1.1 $
 */
public class FactoryFinder {
    private String path;
    private Map classes = new HashMap();

    public FactoryFinder(String path) {
        this.path = path;
    }

    /**
     * Creates a new instance of the given key
     *
     * @param key is the key to add to the path to find a text file containing the factory name
     * @return a newly created instance
     */
    public Object newInstance(String key) throws IllegalAccessException, InstantiationException, IOException, ClassNotFoundException {
        Class type = findClass(key);
        return type.newInstance();
    }

    /**
     * Loads the class for the given key
     *
     * @param key is the key to add to the path to find a text file containing the factory name
     * @return the class for the given key
     */
    public Class findClass(String key) throws IOException, ClassNotFoundException {
        Class answer = (Class) classes.get(key);
        if (answer == null) {
            answer = doFindClass(key);
            classes.put(key, answer);
        }
        return answer;

    }

    private Class doFindClass(String key) throws IOException, ClassNotFoundException {
        String uri = path + key;

        // lets try the thread context class loader first
        InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(uri);
        if (in == null) {
            in = getClass().getClassLoader().getResourceAsStream(uri);
            if (in == null) {
                throw new IOException("Could not find class for resource: " + uri);
            }
        }

        // lets load the file
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(in));
            String line = reader.readLine();
            if (line == null) {
                throw new IOException("Empty file found for: " + uri);
            }
            line = line.trim();
            Class answer = loadClass(line);
            if (answer == null) {
                throw new ClassNotFoundException("Could not find class: " + line);
            }
            return answer;
        }
        finally {
            try {
                reader.close();
            }
            catch (Exception e) {
                // ignore
            }
        }
    }

    protected Class loadClass(String name) throws ClassNotFoundException {
        try {
            return Thread.currentThread().getContextClassLoader().loadClass(name);
        }
        catch (ClassNotFoundException e) {
            return getClass().getClassLoader().loadClass(name);
        }
    }
}