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 }