/* * 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.log4j.receivers.net; import org.apache.log4j.component.plugins.Plugin; import org.apache.log4j.component.plugins.Receiver; import org.apache.log4j.spi.LoggingEvent; import javax.jms.*; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NameNotFoundException; import javax.naming.NamingException; import java.io.FileInputStream; import java.util.Properties; /** JMSReceiver receives a remote logging event on a configured JSM topic and "posts" it to a LoggerRepository as if the event was generated locally. This class is designed to receive events from the JMSAppender class (or classes that send compatible events). <p>Once the event has been "posted", it will be handled by the appenders currently configured in the LoggerRespository. <p>This implementation borrows heavily from the JMSSink implementation. @author Mark Womack @author Paul Smith @author Stephen Pain */ public class JMSReceiver extends Receiver implements MessageListener { private boolean active = false; protected String topicFactoryName; protected String topicName; protected String userId; protected String password; protected TopicConnection topicConnection; protected String jndiPath; private String remoteInfo; private String providerUrl; public JMSReceiver() { } public JMSReceiver(String _topicFactoryName, String _topicName, String _userId, String _password, String _jndiPath) { topicFactoryName = _topicFactoryName; topicName = _topicName; userId = _userId; password = _password; jndiPath = _jndiPath; } /** * Sets the path to a properties file containing * the initial context and jndi provider url */ public void setJndiPath(String _jndiPath) { jndiPath = _jndiPath; } /** * Gets the path to a properties file containing * the initial context and jndi provider url */ public String getJndiPath() { return jndiPath; } /** Sets the JMS topic factory name to use when creating the JMS connection. */ public void setTopicFactoryName(String _topicFactoryName) { topicFactoryName = _topicFactoryName; } /** Gets the curernt JMS topic factory name property. */ public String getTopicFactoryName() { return topicFactoryName; } /** * Sets the JMS topic name to use when creating the * JMS connection. */ public void setTopicName(String _topicName) { topicName = _topicName; } /** * Gets the curernt JMS topic name property. */ public String getTopicName() { return topicName; } /** Sets the user id to use when creating the JMS connection. */ public void setUserId(String _userId) { userId = _userId; } /** * Gets the current user id property. */ public String getUserId() { return userId; } /** * Sets the password to use when creating the * JMS connection. */ public void setPassword(String _password) { password = _password; } /** * Gets the curernt password property. */ public String getPassword() { return password; } /** * Returns true if the receiver is the same class and they are * configured for the same properties, and super class also considers * them to be equivalent. This is used by PluginRegistry when determining * if the a similarly configured receiver is being started. * * @param testPlugin The plugin to test equivalency against. * @return boolean True if the testPlugin is equivalent to this plugin. */ public boolean isEquivalent(Plugin testPlugin) { // only do full check if an instance of this class if (testPlugin instanceof JMSReceiver) { JMSReceiver receiver = (JMSReceiver)testPlugin; // check for same topic name and super class equivalency return ( topicFactoryName.equals(receiver.getTopicFactoryName()) && (jndiPath == null || jndiPath.equals(receiver.getJndiPath())) && super.isEquivalent(testPlugin) ); } return false; } /** Returns true if this receiver is active. */ public synchronized boolean isActive() { return active; } /** Sets the flag to indicate if receiver is active or not. */ protected synchronized void setActive(boolean _active) { active = _active; } /** Starts the JMSReceiver with the current options. */ public void activateOptions() { if (!isActive()) { try { remoteInfo = topicFactoryName + ":" + topicName; Context ctx = null; if (jndiPath == null || jndiPath.equals("")) { ctx = new InitialContext(); } else { FileInputStream is = new FileInputStream(jndiPath); Properties p = new Properties(); p.load(is); is.close(); ctx = new InitialContext(p); } // give some more flexibility about the choice of a tab name providerUrl = (String)ctx.getEnvironment().get(Context.PROVIDER_URL); TopicConnectionFactory topicConnectionFactory; topicConnectionFactory = (TopicConnectionFactory) lookup(ctx, topicFactoryName); if (userId != null && password != null) { topicConnection = topicConnectionFactory.createTopicConnection(userId, password); } else { topicConnection = topicConnectionFactory.createTopicConnection(); } TopicSession topicSession = topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); Topic topic = (Topic)ctx.lookup(topicName); TopicSubscriber topicSubscriber = topicSession.createSubscriber(topic); topicSubscriber.setMessageListener(this); topicConnection.start(); setActive(true); } catch(Exception e) { setActive(false); if (topicConnection != null) { try { topicConnection.close(); } catch (Exception e2) { // do nothing } topicConnection = null; } getLogger().error("Could not start JMSReceiver.", e); } } } /** Called when the receiver should be stopped. */ public synchronized void shutdown() { if (isActive()) { // mark this as no longer running setActive(false); if (topicConnection != null) { try { topicConnection.close(); } catch (Exception e) { // do nothing } topicConnection = null; } } } public void onMessage(Message message) { try { if(message instanceof ObjectMessage) { // get the logging event and post it to the repository ObjectMessage objectMessage = (ObjectMessage) message; LoggingEvent event = (LoggingEvent) objectMessage.getObject(); // store the known remote info in an event property event.setProperty("log4j.remoteSourceInfo", remoteInfo); event.setProperty("log4j.jmsProviderUrl", providerUrl); doPost(event); } else { getLogger().warn("Received message is of type "+message.getJMSType() +", was expecting ObjectMessage."); } } catch(Exception e) { getLogger().error("Exception thrown while processing incoming message.", e); } } protected Object lookup(Context ctx, String name) throws NamingException { try { return ctx.lookup(name); } catch(NameNotFoundException e) { getLogger().error("Could not find name ["+name+"]."); throw e; } } }