/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.activemq.util; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.activemq.transport.LogWriter; import org.apache.activemq.transport.TransportLoggerView; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Class used to find a LogWriter implementation, and returning * a LogWriter object, taking as argument the name of a log writer. * The mapping between the log writer names and the classes * implementing LogWriter is specified by the files in the * resources/META-INF/services/org/apache/activemq/transport/logwriters * directory. * * @author David Martin Clavo david(dot)martin(dot)clavo(at)gmail.com * */ public class LogWriterFinder { private static final Logger log = LoggerFactory.getLogger(TransportLoggerView.class); private final String path; private final ConcurrentMap classMap = new ConcurrentHashMap(); /** * Builds a LogWriterFinder that will look for the mappings between * LogWriter names and classes in the directory "path". * @param path The directory where the files that map log writer names to * LogWriter classes are. */ public LogWriterFinder(String path) { this.path = path; } /** * Returns a LogWriter object, given a log writer name (for example "default", or "custom"). * Uses a ConcurrentHashMap to cache the Class objects that have already been loaded. * @param logWriterName a log writer name (for example "default", or "custom"). * @return a LogWriter object to be used by the TransportLogger class. * @throws IllegalAccessException * @throws InstantiationException * @throws IOException * @throws ClassNotFoundException */ public LogWriter newInstance(String logWriterName) throws IllegalAccessException, InstantiationException, IOException, ClassNotFoundException { Class clazz = (Class) classMap.get(logWriterName); if (clazz == null) { clazz = newInstance(doFindLogWriterProperties(logWriterName)); classMap.put(logWriterName, clazz); } return (LogWriter)clazz.newInstance(); } /** * Loads and returns a class given a Properties object with a "class" property. * @param properties a Properties object with a "class" property. * @return a Class object. * @throws ClassNotFoundException * @throws IOException */ private Class newInstance(Properties properties) throws ClassNotFoundException, IOException { String className = properties.getProperty("class"); if (className == null) { throw new IOException("Expected property is missing: " + "class"); } Class clazz; try { clazz = Thread.currentThread().getContextClassLoader().loadClass(className); } catch (ClassNotFoundException e) { clazz = LogWriterFinder.class.getClassLoader().loadClass(className); } return clazz; } /** * Given a log writer name, returns a Properties object with a "class" property * whose value is a String with the name of the class to be loaded. * @param logWriterName a log writer name. * @return a Properties object with a "class" property * @throws IOException */ protected Properties doFindLogWriterProperties (String logWriterName) throws IOException { String uri = path + logWriterName; // lets try the thread context class loader first ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); if (classLoader == null) classLoader = getClass().getClassLoader(); InputStream in = classLoader.getResourceAsStream(uri); if (in == null) { in = LogWriterFinder.class.getClassLoader().getResourceAsStream(uri); if (in == null) { log.error("Could not find log writer for resource: " + uri); throw new IOException("Could not find log writer for resource: " + uri); } } // lets load the file BufferedInputStream reader = null; Properties properties = new Properties(); try { reader = new BufferedInputStream(in); properties.load(reader); return properties; } finally { try { reader.close(); } catch (Exception e) { } } } }