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