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