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    import org.apache.activemq.transport.LogWriter;
026    import org.apache.activemq.transport.TransportLoggerView;
027    import org.slf4j.Logger;
028    import org.slf4j.LoggerFactory;
029    
030    /**
031     * Class used to find a LogWriter implementation, and returning
032     * a LogWriter object, taking as argument the name of a log writer.
033     * The mapping between the log writer names and the classes
034     * implementing LogWriter is specified by the files in the
035     * resources/META-INF/services/org/apache/activemq/transport/logwriters
036     * directory.
037     * 
038     * @author David Martin Clavo david(dot)martin(dot)clavo(at)gmail.com
039     * 
040     */
041    public class LogWriterFinder {
042        
043        private static final Logger log = LoggerFactory.getLogger(TransportLoggerView.class);
044    
045        private final String path;
046        private final ConcurrentHashMap classMap = new ConcurrentHashMap();
047    
048        /**
049         * Builds a LogWriterFinder that will look for the mappings between
050         * LogWriter names and classes in the directory "path".
051         * @param path The directory where the files that map log writer names to
052         * LogWriter classes are. 
053         */
054        public LogWriterFinder(String path) {
055            this.path = path;
056        }
057    
058        /**
059         * Returns a LogWriter object, given a log writer name (for example "default", or "custom").
060         * Uses a ConcurrentHashMap to cache the Class objects that have already been loaded.
061         * @param logWriterName a log writer name (for example "default", or "custom").
062         * @return a LogWriter object to be used by the TransportLogger class.
063         * @throws IllegalAccessException
064         * @throws InstantiationException
065         * @throws IOException
066         * @throws ClassNotFoundException
067         */
068        public LogWriter newInstance(String logWriterName)
069        throws IllegalAccessException, InstantiationException, IOException, ClassNotFoundException
070        {
071            Class clazz = (Class) classMap.get(logWriterName);
072            if (clazz == null) {
073                clazz = newInstance(doFindLogWriterProperties(logWriterName));
074                classMap.put(logWriterName, clazz);
075            }
076            return (LogWriter)clazz.newInstance();
077        }
078        
079        /**
080         * Loads and returns a class given a Properties object with a "class" property.
081         * @param properties a Properties object with a "class" property.
082         * @return a Class object.
083         * @throws ClassNotFoundException
084         * @throws IOException
085         */
086        private Class newInstance(Properties properties) throws ClassNotFoundException, IOException {
087    
088            String className = properties.getProperty("class");
089            if (className == null) {
090                throw new IOException("Expected property is missing: " + "class");
091            }
092            Class clazz;
093            try {
094                clazz = Thread.currentThread().getContextClassLoader().loadClass(className);
095            } catch (ClassNotFoundException e) {
096                clazz = LogWriterFinder.class.getClassLoader().loadClass(className);
097            }
098    
099            return clazz;
100        }
101    
102        /**
103         * Given a log writer name, returns a Properties object with a "class" property
104         * whose value is a String with the name of the class to be loaded.
105         * @param logWriterName a log writer name.
106         * @return a Properties object with a "class" property
107         * @throws IOException
108         */
109        protected Properties doFindLogWriterProperties (String logWriterName) throws IOException {
110    
111            String uri = path + logWriterName;
112    
113            // lets try the thread context class loader first
114            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
115            if (classLoader == null) classLoader = getClass().getClassLoader();
116            InputStream in = classLoader.getResourceAsStream(uri);
117            if (in == null) {
118                in = LogWriterFinder.class.getClassLoader().getResourceAsStream(uri);
119                if (in == null) {
120                    log.error("Could not find log writer for resource: " + uri);
121                    throw new IOException("Could not find log writer for resource: " + uri);
122                }
123            }
124    
125            // lets load the file
126            BufferedInputStream reader = null;
127            Properties properties = new Properties();
128            try {
129                reader = new BufferedInputStream(in);
130                properties.load(reader);
131                return properties;
132            } finally {
133                try {
134                    reader.close();
135                } catch (Exception e) {
136                }
137            }
138        }
139    
140    
141    }