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.impl; 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.NoFactoryAvailableException; 029 import org.apache.camel.spi.ClassResolver; 030 import org.apache.camel.spi.FactoryFinder; 031 import org.apache.camel.spi.Injector; 032 import org.apache.camel.util.ObjectHelper; 033 034 /** 035 * Default factory finder. 036 */ 037 public class DefaultFactoryFinder implements FactoryFinder { 038 039 protected final ConcurrentHashMap<String, Class> classMap = new ConcurrentHashMap<String, Class>(); 040 private final ClassResolver classResolver; 041 private final String path; 042 043 public DefaultFactoryFinder(ClassResolver classResolver, String resourcePath) { 044 this.classResolver = classResolver; 045 this.path = resourcePath; 046 } 047 048 public String getResourcePath() { 049 return path; 050 } 051 052 public Object newInstance(String key) throws NoFactoryAvailableException { 053 try { 054 return newInstance(key, null); 055 } catch (Exception e) { 056 throw new NoFactoryAvailableException(key, e); 057 } 058 } 059 060 public <T> List<T> newInstances(String key, Injector injector, Class<T> type) throws ClassNotFoundException, IOException { 061 List<Class> list = findClasses(key); 062 List<T> answer = new ArrayList<T>(list.size()); 063 answer.add(newInstance(key, injector, type)); 064 return answer; 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 String prefix = propertyPrefix != null ? propertyPrefix : ""; 073 074 Class clazz = classMap.get(prefix + key); 075 if (clazz == null) { 076 clazz = newInstance(doFindFactoryProperties(key), prefix); 077 if (clazz != null) { 078 classMap.put(prefix + key, clazz); 079 } 080 } 081 return clazz; 082 } 083 084 private Object newInstance(String key, String propertyPrefix) throws IllegalAccessException, 085 InstantiationException, IOException, ClassNotFoundException { 086 Class clazz = findClass(key, propertyPrefix); 087 return clazz.newInstance(); 088 } 089 090 private <T> T newInstance(String key, Injector injector, Class<T> expectedType) throws IOException, 091 ClassNotFoundException { 092 return newInstance(key, injector, null, expectedType); 093 } 094 095 private <T> T newInstance(String key, Injector injector, String propertyPrefix, Class<T> expectedType) 096 throws IOException, ClassNotFoundException { 097 Class<?> type = findClass(key, propertyPrefix); 098 Object value = injector.newInstance(type); 099 if (expectedType.isInstance(value)) { 100 return expectedType.cast(value); 101 } else { 102 throw new ClassCastException("Not instanceof " + expectedType.getName() + " value: " + value); 103 } 104 } 105 106 private List<Class> findClasses(String key) throws ClassNotFoundException, IOException { 107 return findClasses(key, null); 108 } 109 110 private List<Class> findClasses(String key, String propertyPrefix) throws ClassNotFoundException, IOException { 111 // TODO change to support finding multiple classes on the classpath! 112 Class type = findClass(key, propertyPrefix); 113 return Collections.singletonList(type); 114 } 115 116 private Class newInstance(Properties properties, String propertyPrefix) throws ClassNotFoundException, IOException { 117 String className = properties.getProperty(propertyPrefix + "class"); 118 if (className == null) { 119 throw new IOException("Expected property is missing: " + propertyPrefix + "class"); 120 } 121 122 Class clazz = classResolver.resolveClass(className); 123 if (clazz == null) { 124 throw new ClassNotFoundException(className); 125 } 126 return clazz; 127 } 128 129 private Properties doFindFactoryProperties(String key) throws IOException { 130 String uri = path + key; 131 132 InputStream in = classResolver.loadResourceAsStream(uri); 133 if (in == null) { 134 throw new NoFactoryAvailableException(uri); 135 } 136 137 // lets load the file 138 BufferedInputStream reader = null; 139 try { 140 reader = new BufferedInputStream(in); 141 Properties properties = new Properties(); 142 properties.load(reader); 143 return properties; 144 } finally { 145 ObjectHelper.close(reader, key, null); 146 ObjectHelper.close(in, key, null); 147 } 148 } 149 150 151 }