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.activemq.util;
018
019 import java.io.BufferedInputStream;
020 import java.io.IOException;
021 import java.io.InputStream;
022 import java.util.Properties;
023 import java.util.concurrent.ConcurrentHashMap;
024
025 /**
026 *
027 */
028 public class FactoryFinder {
029
030 /**
031 * The strategy that the FactoryFinder uses to find load and instantiate Objects
032 * can be changed out by calling the
033 * {@link org.apache.activemq.util.FactoryFinder#setObjectFactory(org.apache.activemq.util.FactoryFinder.ObjectFactory)}
034 * method with a custom implementation of ObjectFactory.
035 *
036 * The default ObjectFactory is typically changed out when running in a specialized container
037 * environment where service discovery needs to be done via the container system. For example,
038 * in an OSGi scenario.
039 */
040 public interface ObjectFactory {
041 /**
042 * @param path the full service path
043 * @return
044 */
045 public Object create(String path) throws IllegalAccessException, InstantiationException, IOException, ClassNotFoundException;
046
047 }
048
049 /**
050 * The default implementation of Object factory which works well in standalone applications.
051 */
052 protected static class StandaloneObjectFactory implements ObjectFactory {
053 final ConcurrentHashMap<String, Class> classMap = new ConcurrentHashMap<String, Class>();
054
055 public Object create(final String path) throws InstantiationException, IllegalAccessException, ClassNotFoundException, IOException {
056 Class clazz = classMap.get(path);
057 if (clazz == null) {
058 clazz = loadClass(loadProperties(path));
059 classMap.put(path, clazz);
060 }
061 return clazz.newInstance();
062 }
063
064 static public Class loadClass(Properties properties) throws ClassNotFoundException, IOException {
065
066 String className = properties.getProperty("class");
067 if (className == null) {
068 throw new IOException("Expected property is missing: class");
069 }
070 Class clazz = null;
071 ClassLoader loader = Thread.currentThread().getContextClassLoader();
072 if (loader != null) {
073 try {
074 clazz = loader.loadClass(className);
075 } catch (ClassNotFoundException e) {
076 // ignore
077 }
078 }
079 if (clazz == null) {
080 clazz = FactoryFinder.class.getClassLoader().loadClass(className);
081 }
082
083 return clazz;
084 }
085
086 static public Properties loadProperties(String uri) throws IOException {
087 // lets try the thread context class loader first
088 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
089 if (classLoader == null) {
090 classLoader = StandaloneObjectFactory.class.getClassLoader();
091 }
092 InputStream in = classLoader.getResourceAsStream(uri);
093 if (in == null) {
094 in = FactoryFinder.class.getClassLoader().getResourceAsStream(uri);
095 if (in == null) {
096 throw new IOException("Could not find factory class for resource: " + uri);
097 }
098 }
099
100 // lets load the file
101 BufferedInputStream reader = null;
102 try {
103 reader = new BufferedInputStream(in);
104 Properties properties = new Properties();
105 properties.load(reader);
106 return properties;
107 } finally {
108 try {
109 reader.close();
110 } catch (Exception e) {
111 }
112 }
113 }
114 }
115
116 // ================================================================
117 // Class methods and properties
118 // ================================================================
119 private static ObjectFactory objectFactory = new StandaloneObjectFactory();
120
121 public static ObjectFactory getObjectFactory() {
122 return objectFactory;
123 }
124
125 public static void setObjectFactory(ObjectFactory objectFactory) {
126 FactoryFinder.objectFactory = objectFactory;
127 }
128
129 // ================================================================
130 // Instance methods and properties
131 // ================================================================
132 private final String path;
133
134 public FactoryFinder(String path) {
135 this.path = path;
136 }
137
138 /**
139 * Creates a new instance of the given key
140 *
141 * @param key is the key to add to the path to find a text file containing
142 * the factory name
143 * @return a newly created instance
144 */
145 public Object newInstance(String key) throws IllegalAccessException, InstantiationException, IOException, ClassNotFoundException {
146 return objectFactory.create(path+key);
147 }
148
149
150 }