001    /**
002     *
003     * Licensed to the Apache Software Foundation (ASF) under one or more
004     * contributor license agreements.  See the NOTICE file distributed with
005     * this work for additional information regarding copyright ownership.
006     * The ASF licenses this file to You under the Apache License, Version 2.0
007     * (the "License"); you may not use this file except in compliance with
008     * the License.  You may obtain a copy of the License at
009     *
010     * http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    package org.apache.camel.util;
019    
020    import org.apache.camel.spi.Injector;
021    
022    import java.io.BufferedInputStream;
023    import java.io.IOException;
024    import java.io.InputStream;
025    import java.util.Properties;
026    import java.util.concurrent.ConcurrentHashMap;
027    
028    public class FactoryFinder {
029        private final String path;
030        private final ConcurrentHashMap classMap = new ConcurrentHashMap();
031    
032        public FactoryFinder() {
033            this("META-INF/services/org/apache/camel/");
034        }
035    
036        public FactoryFinder(String path) {
037            this.path = path;
038        }
039    
040        /**
041         * Creates a new instance of the given key
042         *
043         * @param key is the key to add to the path to find a text file
044         *            containing the factory name
045         * @return a newly created instance
046         */
047        public Object newInstance(String key)
048                throws IllegalAccessException, InstantiationException, IOException, ClassNotFoundException {
049            return newInstance(key, (String) null);
050        }
051    
052        public Object newInstance(String key, String propertyPrefix)
053                throws IllegalAccessException, InstantiationException, IOException, ClassNotFoundException {
054            Class clazz = findClass(key, propertyPrefix);
055            return clazz.newInstance();
056        }
057    
058        public Object newInstance(String key, Injector injector) throws IOException, ClassNotFoundException {
059            return newInstance(key, injector, null);
060        }
061    
062        public Object newInstance(String key, Injector injector, String propertyPrefix) throws IOException, ClassNotFoundException {
063            Class type = findClass(key, propertyPrefix);
064            return injector.newInstance(type);
065        }
066    
067        public Class findClass(String key) throws ClassNotFoundException, IOException {
068            return findClass(key, null);
069        }
070    
071        public Class findClass(String key, String propertyPrefix) throws ClassNotFoundException, IOException {
072            if (propertyPrefix == null) {
073                propertyPrefix = "";
074            }
075    
076            Class clazz = (Class) classMap.get(propertyPrefix + key);
077            if (clazz == null) {
078                clazz = newInstance(doFindFactoryProperies(key), propertyPrefix);
079                classMap.put(propertyPrefix + key, clazz);
080            }
081            return clazz;
082        }
083    
084        private Class newInstance(Properties properties, String propertyPrefix) throws ClassNotFoundException, IOException {
085    
086            String className = properties.getProperty(propertyPrefix + "class");
087            if (className == null) {
088                throw new IOException("Expected property is missing: " + propertyPrefix + "class");
089            }
090            Class clazz = null;
091            ClassLoader loader = Thread.currentThread().getContextClassLoader();
092            if (loader != null) {
093                try {
094                    clazz = loader.loadClass(className);
095                }
096                catch (ClassNotFoundException e) {
097                    // ignore
098                }
099            }
100            if (clazz == null) {
101                clazz = FactoryFinder.class.getClassLoader().loadClass(className);
102            }
103            return clazz;
104        }
105    
106        private Properties doFindFactoryProperies(String key) throws IOException {
107            String uri = path + key;
108    
109            // lets try the thread context class loader first
110            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
111            if (classLoader == null) {
112                classLoader = getClass().getClassLoader();
113            }
114            InputStream in = classLoader.getResourceAsStream(uri);
115            if (in == null) {
116                in = FactoryFinder.class.getClassLoader().getResourceAsStream(uri);
117                if (in == null) {
118                    throw new NoFactoryAvailableException(uri);
119                }
120            }
121    
122            // lets load the file
123            BufferedInputStream reader = null;
124            try {
125                reader = new BufferedInputStream(in);
126                Properties properties = new Properties();
127                properties.load(reader);
128                return properties;
129            }
130            finally {
131                try {
132                    reader.close();
133                }
134                catch (Exception e) {
135                }
136            }
137        }
138    }