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 /** 031 * Finder to find factories from the resource classpath, usually <b>META-INF/services/org/apache/camel/</b>. 032 */ 033 public class FactoryFinder { 034 private final String path; 035 private final ConcurrentHashMap classMap = new ConcurrentHashMap(); 036 037 public FactoryFinder() { 038 this("META-INF/services/org/apache/camel/"); 039 } 040 041 public FactoryFinder(String path) { 042 this.path = path; 043 } 044 045 /** 046 * Creates a new instance of the given key 047 * 048 * @param key is the key to add to the path to find a text file containing 049 * the factory name 050 * @return a newly created instance 051 */ 052 public Object newInstance(String key) throws IllegalAccessException, InstantiationException, IOException, 053 ClassNotFoundException { 054 return newInstance(key, (String)null); 055 } 056 057 public Object newInstance(String key, String propertyPrefix) throws IllegalAccessException, 058 InstantiationException, IOException, ClassNotFoundException { 059 Class clazz = findClass(key, propertyPrefix); 060 return clazz.newInstance(); 061 } 062 063 public Object newInstance(String key, Injector injector) throws IOException, ClassNotFoundException { 064 return newInstance(key, injector, (String)null); 065 } 066 067 public Object newInstance(String key, Injector injector, String propertyPrefix) throws IOException, 068 ClassNotFoundException { 069 Class type = findClass(key, propertyPrefix); 070 return injector.newInstance(type); 071 } 072 073 public <T> T newInstance(String key, Injector injector, Class<T> expectedType) throws IOException, 074 ClassNotFoundException { 075 return newInstance(key, injector, null, expectedType); 076 } 077 078 public <T> T newInstance(String key, Injector injector, String propertyPrefix, Class<T> expectedType) 079 throws IOException, ClassNotFoundException { 080 Class type = findClass(key, propertyPrefix); 081 Object value = injector.newInstance(type); 082 if (expectedType.isInstance(value)) { 083 return expectedType.cast(value); 084 } else { 085 throw new ClassCastException("Not instanceof " + expectedType.getName() + " value: " + value); 086 } 087 } 088 089 public <T> List<T> newInstances(String key, Injector injector, Class<T> type) throws IOException, 090 ClassNotFoundException { 091 List<Class> list = findClasses(key); 092 List<T> answer = new ArrayList<T>(list.size()); 093 answer.add(newInstance(key, injector, type)); 094 return answer; 095 } 096 097 public Class findClass(String key) throws ClassNotFoundException, IOException { 098 return findClass(key, null); 099 } 100 101 public Class findClass(String key, String propertyPrefix) throws ClassNotFoundException, IOException { 102 if (propertyPrefix == null) { 103 propertyPrefix = ""; 104 } 105 106 Class clazz = (Class)classMap.get(propertyPrefix + key); 107 if (clazz == null) { 108 clazz = newInstance(doFindFactoryProperties(key), propertyPrefix); 109 classMap.put(propertyPrefix + key, clazz); 110 } 111 return clazz; 112 } 113 114 public List<Class> findClasses(String key) throws ClassNotFoundException, IOException { 115 return findClasses(key, null); 116 } 117 118 public List<Class> findClasses(String key, String propertyPrefix) throws ClassNotFoundException, 119 IOException { 120 // TODO change to support finding multiple classes on the classpath! 121 Class type = findClass(key, propertyPrefix); 122 return Collections.singletonList(type); 123 } 124 125 public String getPath() { 126 return path; 127 } 128 129 private Class newInstance(Properties properties, String propertyPrefix) throws ClassNotFoundException, 130 IOException { 131 132 String className = properties.getProperty(propertyPrefix + "class"); 133 if (className == null) { 134 throw new IOException("Expected property is missing: " + propertyPrefix + "class"); 135 } 136 137 return ObjectHelper.loadClass(className); 138 } 139 140 private Properties doFindFactoryProperties(String key) throws IOException { 141 String uri = path + key; 142 143 InputStream in = ObjectHelper.loadResourceAsStream(uri); 144 if (in == null) { 145 throw new NoFactoryAvailableException(uri); 146 } 147 148 // lets load the file 149 BufferedInputStream reader = null; 150 try { 151 reader = new BufferedInputStream(in); 152 Properties properties = new Properties(); 153 properties.load(reader); 154 return properties; 155 } finally { 156 ObjectHelper.close(reader, key, null); 157 ObjectHelper.close(in, key, null); 158 } 159 } 160 161 }