blob: 6ba2f3af63abee59be76a0d2d0ea91b9b0d36a11 [file] [log] [blame]
/**
* 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.transport;
import org.apache.activemq.broker.jmx.AnnotatedMBean;
import org.apache.activemq.broker.jmx.ManagementContext;
import org.apache.activemq.util.IOExceptionSupport;
import org.apache.activemq.util.LogWriterFinder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import javax.management.ObjectName;
/**
* Singleton class to create TransportLogger objects.
* When the method getInstance() is called for the first time,
* a TransportLoggerControlMBean is created and registered.
* This MBean permits enabling and disabling the logging for
* all TransportLogger objects at once.
*
* @author David Martin Clavo david(dot)martin(dot)clavo(at)gmail.com
*
* @see TransportLoggerControlMBean
*/
public class TransportLoggerFactory {
private static final Logger LOG = LoggerFactory.getLogger(TransportLoggerFactory.class);
private static TransportLoggerFactory instance;
private static int lastId=0;
private static final LogWriterFinder logWriterFinder = new LogWriterFinder("META-INF/services/org/apache/activemq/transport/logwriters/");
/**
* LogWriter that will be used if none is specified.
*/
public static String defaultLogWriterName = "default";
/**
* If transport logging is enabled, it will be possible to control
* the transport loggers or not based on this value
*/
private static boolean defaultDynamicManagement = false;
/**
* If transport logging is enabled, the transport loggers will initially
* output or not depending on this value.
* This setting only has a meaning if
*/
private static boolean defaultInitialBehavior = true;
/**
* Default port to control the transport loggers through JMX
*/
private static int defaultJmxPort = 1099;
private boolean transportLoggerControlCreated = false;
private ManagementContext managementContext;
private ObjectName objectName;
/**
* Private constructor.
*/
private TransportLoggerFactory() {
}
/**
* Returns a TransportLoggerFactory object which can be used to create TransportLogger objects.
* @return a TransportLoggerFactory object
*/
public static synchronized TransportLoggerFactory getInstance() {
if (instance == null) {
instance = new TransportLoggerFactory();
}
return instance;
}
public void stop() {
try {
if (this.transportLoggerControlCreated) {
this.managementContext.unregisterMBean(this.objectName);
this.managementContext.stop();
this.managementContext = null;
}
} catch (Exception e) {
LOG.error("TransportLoggerFactory could not be stopped, reason: " + e, e);
}
}
/**
* Creates a TransportLogger object, that will be inserted in the Transport Stack.
* Uses the default initial behavior, the default log writer, and creates a new
* log4j object to be used by the TransportLogger.
* @param next The next Transport layer in the Transport stack.
* @return A TransportLogger object.
* @throws IOException
*/
public TransportLogger createTransportLogger(Transport next) throws IOException {
int id = getNextId();
return createTransportLogger(next, id, createLog(id), defaultLogWriterName, defaultDynamicManagement, defaultInitialBehavior, defaultJmxPort);
}
/**
* Creates a TransportLogger object, that will be inserted in the Transport Stack.
* Uses the default initial behavior and the default log writer.
* @param next The next Transport layer in the Transport stack.
* @param log The log4j log that will be used by the TransportLogger.
* @return A TransportLogger object.
* @throws IOException
*/
public TransportLogger createTransportLogger(Transport next, Logger log) throws IOException {
return createTransportLogger(next, getNextId(), log, defaultLogWriterName, defaultDynamicManagement, defaultInitialBehavior, defaultJmxPort);
}
/**
* Creates a TransportLogger object, that will be inserted in the Transport Stack.
* Creates a new log4j object to be used by the TransportLogger.
* @param next The next Transport layer in the Transport stack.
* @param startLogging Specifies if this TransportLogger should be initially active or not.
* @param logWriterName The name or the LogWriter to be used. Different log writers can output
* logs with a different format.
* @return A TransportLogger object.
* @throws IOException
*/
public TransportLogger createTransportLogger(Transport next, String logWriterName,
boolean useJmx, boolean startLogging, int jmxport) throws IOException {
int id = getNextId();
return createTransportLogger(next, id, createLog(id), logWriterName, useJmx, startLogging, jmxport);
}
/**
* Creates a TransportLogger object, that will be inserted in the Transport Stack.
* @param next The next Transport layer in the Transport stack.
* @param id The id of the transport logger.
* @param log The log4j log that will be used by the TransportLogger.
* @param logWriterName The name or the LogWriter to be used. Different log writers can output
* @param dynamicManagement Specifies if JMX will be used to switch on/off the TransportLogger to be created.
* @param startLogging Specifies if this TransportLogger should be initially active or not. Only has a meaning if
* dynamicManagement = true.
* @param jmxPort the port to be used by the JMX server. It should only be different from 1099 (broker's default JMX port)
* when it's a client that is using Transport Logging. In a broker, if the port is different from 1099, 2 JMX servers will
* be created, both identical, with all the MBeans.
* @return A TransportLogger object.
* @throws IOException
*/
public TransportLogger createTransportLogger(Transport next, int id, Logger log,
String logWriterName, boolean dynamicManagement, boolean startLogging, int jmxport) throws IOException {
try {
LogWriter logWriter = logWriterFinder.newInstance(logWriterName);
TransportLogger tl = new TransportLogger (next, log, startLogging, logWriter);
if (dynamicManagement) {
synchronized (this) {
if (!this.transportLoggerControlCreated) {
this.createTransportLoggerControl(jmxport);
}
}
TransportLoggerView tlv = new TransportLoggerView(tl, next.toString(), id, this.managementContext);
tl.setView(tlv);
}
return tl;
} catch (Throwable e) {
throw IOExceptionSupport.create("Could not create log writer object for: " + logWriterName + ", reason: " + e, e);
}
}
synchronized private static int getNextId() {
return ++lastId;
}
private static Logger createLog(int id) {
return LoggerFactory.getLogger(TransportLogger.class.getName()+".Connection:" + id);
}
/**
* Starts the management context.
* Creates and registers a TransportLoggerControl MBean which enables the user
* to enable/disable logging for all transport loggers at once.
*/
private void createTransportLoggerControl(int port) {
try {
this.managementContext = new ManagementContext();
this.managementContext.setConnectorPort(port);
this.managementContext.start();
} catch (Exception e) {
LOG.error("Management context could not be started, reason: " + e, e);
}
try {
this.objectName = new ObjectName(this.managementContext.getJmxDomainName()+":"+ "Type=TransportLoggerControl");
AnnotatedMBean.registerMBean(this.managementContext, new TransportLoggerControl(this.managementContext),this.objectName);
this.transportLoggerControlCreated = true;
} catch (Exception e) {
LOG.error("TransportLoggerControlMBean could not be registered, reason: " + e, e);
}
}
}