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