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.transport; 018 019 import org.apache.activemq.broker.jmx.AnnotatedMBean; 020 import org.apache.activemq.broker.jmx.ManagementContext; 021 import org.apache.activemq.util.IOExceptionSupport; 022 import org.apache.activemq.util.LogWriterFinder; 023 import org.slf4j.Logger; 024 import org.slf4j.LoggerFactory; 025 import java.io.IOException; 026 import javax.management.ObjectName; 027 028 /** 029 * Singleton class to create TransportLogger objects. 030 * When the method getInstance() is called for the first time, 031 * a TransportLoggerControlMBean is created and registered. 032 * This MBean permits enabling and disabling the logging for 033 * all TransportLogger objects at once. 034 * 035 * @author David Martin Clavo david(dot)martin(dot)clavo(at)gmail.com 036 * 037 * @see TransportLoggerControlMBean 038 */ 039 public class TransportLoggerFactory { 040 041 private static final Logger LOG = LoggerFactory.getLogger(TransportLoggerFactory.class); 042 043 private static TransportLoggerFactory instance; 044 private static int lastId=0; 045 private static final LogWriterFinder logWriterFinder = new LogWriterFinder("META-INF/services/org/apache/activemq/transport/logwriters/"); 046 047 /** 048 * LogWriter that will be used if none is specified. 049 */ 050 public static String defaultLogWriterName = "default"; 051 /** 052 * If transport logging is enabled, it will be possible to control 053 * the transport loggers or not based on this value 054 */ 055 private static boolean defaultDynamicManagement = false; 056 /** 057 * If transport logging is enabled, the transport loggers will initially 058 * output or not depending on this value. 059 * This setting only has a meaning if 060 */ 061 private static boolean defaultInitialBehavior = true; 062 /** 063 * Default port to control the transport loggers through JMX 064 */ 065 private static int defaultJmxPort = 1099; 066 067 private boolean transportLoggerControlCreated = false; 068 private ManagementContext managementContext; 069 private ObjectName objectName; 070 071 /** 072 * Private constructor. 073 */ 074 private TransportLoggerFactory() { 075 } 076 077 /** 078 * Returns a TransportLoggerFactory object which can be used to create TransportLogger objects. 079 * @return a TransportLoggerFactory object 080 */ 081 public static synchronized TransportLoggerFactory getInstance() { 082 if (instance == null) { 083 instance = new TransportLoggerFactory(); 084 } 085 return instance; 086 } 087 088 public void stop() { 089 try { 090 if (this.transportLoggerControlCreated) { 091 this.managementContext.unregisterMBean(this.objectName); 092 this.managementContext.stop(); 093 this.managementContext = null; 094 } 095 } catch (Exception e) { 096 LOG.error("TransportLoggerFactory could not be stopped, reason: " + e, e); 097 } 098 099 } 100 101 /** 102 * Creates a TransportLogger object, that will be inserted in the Transport Stack. 103 * Uses the default initial behavior, the default log writer, and creates a new 104 * log4j object to be used by the TransportLogger. 105 * @param next The next Transport layer in the Transport stack. 106 * @return A TransportLogger object. 107 * @throws IOException 108 */ 109 public TransportLogger createTransportLogger(Transport next) throws IOException { 110 int id = getNextId(); 111 return createTransportLogger(next, id, createLog(id), defaultLogWriterName, defaultDynamicManagement, defaultInitialBehavior, defaultJmxPort); 112 } 113 114 /** 115 * Creates a TransportLogger object, that will be inserted in the Transport Stack. 116 * Uses the default initial behavior and the default log writer. 117 * @param next The next Transport layer in the Transport stack. 118 * @param log The log4j log that will be used by the TransportLogger. 119 * @return A TransportLogger object. 120 * @throws IOException 121 */ 122 public TransportLogger createTransportLogger(Transport next, Logger log) throws IOException { 123 return createTransportLogger(next, getNextId(), log, defaultLogWriterName, defaultDynamicManagement, defaultInitialBehavior, defaultJmxPort); 124 } 125 126 /** 127 * Creates a TransportLogger object, that will be inserted in the Transport Stack. 128 * Creates a new log4j object to be used by the TransportLogger. 129 * @param next The next Transport layer in the Transport stack. 130 * @param startLogging Specifies if this TransportLogger should be initially active or not. 131 * @param logWriterName The name or the LogWriter to be used. Different log writers can output 132 * logs with a different format. 133 * @return A TransportLogger object. 134 * @throws IOException 135 */ 136 public TransportLogger createTransportLogger(Transport next, String logWriterName, 137 boolean useJmx, boolean startLogging, int jmxport) throws IOException { 138 int id = getNextId(); 139 return createTransportLogger(next, id, createLog(id), logWriterName, useJmx, startLogging, jmxport); 140 } 141 142 143 144 /** 145 * Creates a TransportLogger object, that will be inserted in the Transport Stack. 146 * @param next The next Transport layer in the Transport stack. 147 * @param id The id of the transport logger. 148 * @param log The log4j log that will be used by the TransportLogger. 149 * @param logWriterName The name or the LogWriter to be used. Different log writers can output 150 * @param dynamicManagement Specifies if JMX will be used to switch on/off the TransportLogger to be created. 151 * @param startLogging Specifies if this TransportLogger should be initially active or not. Only has a meaning if 152 * dynamicManagement = true. 153 * @param jmxPort the port to be used by the JMX server. It should only be different from 1099 (broker's default JMX port) 154 * when it's a client that is using Transport Logging. In a broker, if the port is different from 1099, 2 JMX servers will 155 * be created, both identical, with all the MBeans. 156 * @return A TransportLogger object. 157 * @throws IOException 158 */ 159 public TransportLogger createTransportLogger(Transport next, int id, Logger log, 160 String logWriterName, boolean dynamicManagement, boolean startLogging, int jmxport) throws IOException { 161 try { 162 LogWriter logWriter = logWriterFinder.newInstance(logWriterName); 163 TransportLogger tl = new TransportLogger (next, log, startLogging, logWriter); 164 if (dynamicManagement) { 165 synchronized (this) { 166 if (!this.transportLoggerControlCreated) { 167 this.createTransportLoggerControl(jmxport); 168 } 169 } 170 TransportLoggerView tlv = new TransportLoggerView(tl, next.toString(), id, this.managementContext); 171 tl.setView(tlv); 172 } 173 return tl; 174 } catch (Throwable e) { 175 throw IOExceptionSupport.create("Could not create log writer object for: " + logWriterName + ", reason: " + e, e); 176 } 177 } 178 179 synchronized private static int getNextId() { 180 return ++lastId; 181 } 182 183 private static Logger createLog(int id) { 184 return LoggerFactory.getLogger(TransportLogger.class.getName()+".Connection:" + id); 185 } 186 187 /** 188 * Starts the management context. 189 * Creates and registers a TransportLoggerControl MBean which enables the user 190 * to enable/disable logging for all transport loggers at once. 191 */ 192 private void createTransportLoggerControl(int port) { 193 try { 194 this.managementContext = new ManagementContext(); 195 this.managementContext.setConnectorPort(port); 196 this.managementContext.start(); 197 } catch (Exception e) { 198 LOG.error("Management context could not be started, reason: " + e, e); 199 } 200 201 try { 202 this.objectName = new ObjectName(this.managementContext.getJmxDomainName()+":"+ "Type=TransportLoggerControl"); 203 AnnotatedMBean.registerMBean(this.managementContext, new TransportLoggerControl(this.managementContext),this.objectName); 204 205 this.transportLoggerControlCreated = true; 206 207 } catch (Exception e) { 208 LOG.error("TransportLoggerControlMBean could not be registered, reason: " + e, e); 209 } 210 } 211 212 }