View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17
    18  package org.apache.log4j.net;
    19
    20  import org.apache.log4j.plugins.Plugin;
    21  import org.apache.log4j.plugins.Receiver;
    22  import org.apache.log4j.spi.LoggingEvent;
    23
    24  import javax.jms.*;
    25  import javax.naming.Context;
    26  import javax.naming.InitialContext;
    27  import javax.naming.NameNotFoundException;
    28  import javax.naming.NamingException;
    29  import java.io.FileInputStream;
    30  import java.util.Properties;
    31
    32  /**
    33   * JMSReceiver receives a remote logging event on a configured
    34   * JSM topic and "posts" it to a LoggerRepository as if the event was
    35   * generated locally. This class is designed to receive events from
    36   * the JMSAppender class (or classes that send compatible events).
    37   * <p>
    38   * <p>Once the event has been "posted", it will be handled by the
    39   * appenders currently configured in the LoggerRespository.
    40   * <p>
    41   * <p>This implementation borrows heavily from the JMSSink
    42   * implementation.
    43   *
    44   * @author Mark Womack
    45   * @author Paul Smith
    46   * @author Stephen Pain
    47   */
    48  public class JMSReceiver extends Receiver implements MessageListener {
    49
    50      private boolean active = false;
    51
    52      protected String topicFactoryName;
    53      protected String topicName;
    54      protected String userId;
    55      protected String password;
    56      protected TopicConnection topicConnection;
    57      protected String jndiPath;
    58
    59      private String remoteInfo;
    60      private String providerUrl;
    61
    62      public JMSReceiver() {
    63      }
    64
    65      public JMSReceiver(String _topicFactoryName, String _topicName,
    66                         String _userId, String _password, String _jndiPath) {
    67          topicFactoryName = _topicFactoryName;
    68          topicName = _topicName;
    69          userId = _userId;
    70          password = _password;
    71          jndiPath = _jndiPath;
    72      }
    73
    74      /**
    75       * Sets the path to a properties file containing
    76       * the initial context and jndi provider url
    77       */
    78      public void setJndiPath(String _jndiPath) {
    79          jndiPath = _jndiPath;
    80      }
    81
    82      /**
    83       * Gets the path to a properties file containing
    84       * the initial context and jndi provider url
    85       */
    86      public String getJndiPath() {
    87          return jndiPath;
    88      }
    89
    90      /**
    91       * Sets the JMS topic factory name to use when creating the
    92       * JMS connection.
    93       */
    94      public void setTopicFactoryName(String _topicFactoryName) {
    95          topicFactoryName = _topicFactoryName;
    96      }
    97
    98      /**
    99       * Gets the curernt JMS topic factory name property.
    100      */
    101     public String getTopicFactoryName() {
    102         return topicFactoryName;
    103     }
    104
    105     /**
    106      * Sets the JMS topic name to use when creating the
    107      * JMS connection.
    108      */
    109     public void setTopicName(String _topicName) {
    110         topicName = _topicName;
    111     }
    112
    113     /**
    114      * Gets the curernt JMS topic name property.
    115      */
    116     public String getTopicName() {
    117         return topicName;
    118     }
    119
    120     /**
    121      * Sets the user id to use when creating the
    122      * JMS connection.
    123      */
    124     public void setUserId(String _userId) {
    125         userId = _userId;
    126     }
    127
    128     /**
    129      * Gets the current user id property.
    130      */
    131     public String getUserId() {
    132         return userId;
    133     }
    134
    135     /**
    136      * Sets the password to use when creating the
    137      * JMS connection.
    138      */
    139     public void setPassword(String _password) {
    140         password = _password;
    141     }
    142
    143     /**
    144      * Gets the curernt password property.
    145      */
    146     public String getPassword() {
    147         return password;
    148     }
    149
    150     /**
    151      * Returns true if the receiver is the same class and they are
    152      * configured for the same properties, and super class also considers
    153      * them to be equivalent. This is used by PluginRegistry when determining
    154      * if the a similarly configured receiver is being started.
    155      *
    156      * @param testPlugin The plugin to test equivalency against.
    157      * @return boolean True if the testPlugin is equivalent to this plugin.
    158      */
    159     public boolean isEquivalent(Plugin testPlugin) {
    160         // only do full check if an instance of this class
    161         if (testPlugin instanceof JMSReceiver) {
    162
    163             JMSReceiver receiver = (JMSReceiver) testPlugin;
    164
    165             // check for same topic name and super class equivalency
    166             return (
    167                 topicFactoryName.equals(receiver.getTopicFactoryName()) &&
    168                     (jndiPath == null || jndiPath.equals(receiver.getJndiPath())) &&
    169                     super.isEquivalent(testPlugin)
    170             );
    171         }
    172
    173         return false;
    174     }
    175
    176     /**
    177      * Returns true if this receiver is active.
    178      */
    179     public synchronized boolean isActive() {
    180         return active;
    181     }
    182
    183     /**
    184      * Sets the flag to indicate if receiver is active or not.
    185      */
    186     protected synchronized void setActive(boolean _active) {
    187         active = _active;
    188     }
    189
    190     /**
    191      * Starts the JMSReceiver with the current options.
    192      */
    193     public void activateOptions() {
    194         if (!isActive()) {
    195             try {
    196                 remoteInfo = topicFactoryName + ":" + topicName;
    197
    198                 Context ctx;
    199                 if (jndiPath == null || jndiPath.equals("")) {
    200                     ctx = new InitialContext();
    201                 } else {
    202                     FileInputStream is = new FileInputStream(jndiPath);
    203                     Properties p = new Properties();
    204                     p.load(is);
    205                     is.close();
    206                     ctx = new InitialContext(p);
    207                 }
    208
    209                 // give some more flexibility about the choice of a tab name
    210                 providerUrl = (String) ctx.getEnvironment().get(Context.PROVIDER_URL);
    211                 TopicConnectionFactory topicConnectionFactory;
    212                 topicConnectionFactory =
    213                     (TopicConnectionFactory) lookup(ctx, topicFactoryName);
    214
    215                 if (userId != null && password != null) {
    216                     topicConnection =
    217                         topicConnectionFactory.createTopicConnection(userId, password);
    218                 } else {
    219                     topicConnection =
    220                         topicConnectionFactory.createTopicConnection();
    221                 }
    222
    223                 TopicSession topicSession =
    224                     topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
    225
    226                 Topic topic = (Topic) ctx.lookup(topicName);
    227
    228                 TopicSubscriber topicSubscriber = topicSession.createSubscriber(topic);
    229
    230                 topicSubscriber.setMessageListener(this);
    231
    232                 topicConnection.start();
    233
    234                 setActive(true);
    235             } catch (Exception e) {
    236                 setActive(false);
    237                 if (topicConnection != null) {
    238                     try {
    239                         topicConnection.close();
    240                     } catch (Exception e2) {
    241                         // do nothing
    242                     }
    243                     topicConnection = null;
    244                 }
    245                 getLogger().error("Could not start JMSReceiver.", e);
    246             }
    247         }
    248     }
    249
    250     /**
    251      * Called when the receiver should be stopped.
    252      */
    253     public synchronized void shutdown() {
    254         if (isActive()) {
    255             // mark this as no longer running
    256             setActive(false);
    257
    258             if (topicConnection != null) {
    259                 try {
    260                     topicConnection.close();
    261                 } catch (Exception e) {
    262                     // do nothing
    263                 }
    264                 topicConnection = null;
    265             }
    266         }
    267     }
    268
    269     public void onMessage(Message message) {
    270         try {
    271             if (message instanceof ObjectMessage) {
    272                 // get the logging event and post it to the repository
    273                 ObjectMessage objectMessage = (ObjectMessage) message;
    274                 LoggingEvent event = (LoggingEvent) objectMessage.getObject();
    275
    276                 // store the known remote info in an event property
    277                 event.setProperty("log4j.remoteSourceInfo", remoteInfo);
    278                 event.setProperty("log4j.jmsProviderUrl", providerUrl);
    279
    280                 doPost(event);
    281             } else {
    282                 getLogger().warn("Received message is of type " + message.getJMSType()
    283                     + ", was expecting ObjectMessage.");
    284             }
    285         } catch (Exception e) {
    286             getLogger().error("Exception thrown while processing incoming message.", e);
    287         }
    288     }
    289
    290     protected Object lookup(Context ctx, String name) throws NamingException {
    291         try {
    292             return ctx.lookup(name);
    293         } catch (NameNotFoundException e) {
    294             getLogger().error("Could not find name [" + name + "].");
    295             throw e;
    296         }
    297     }
    298
    299 }