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.logging.log4j.core.appender.mom;
19  
20  import java.io.Serializable;
21  import javax.jms.Connection;
22  import javax.jms.ConnectionFactory;
23  import javax.jms.Destination;
24  import javax.jms.JMSException;
25  import javax.jms.Message;
26  import javax.jms.MessageConsumer;
27  import javax.jms.MessageProducer;
28  import javax.jms.Session;
29  import javax.naming.NamingException;
30  
31  import org.apache.logging.log4j.Logger;
32  import org.apache.logging.log4j.core.appender.AbstractManager;
33  import org.apache.logging.log4j.core.appender.ManagerFactory;
34  import org.apache.logging.log4j.core.net.JndiManager;
35  import org.apache.logging.log4j.status.StatusLogger;
36  
37  /**
38   * JMS connection and session manager. Can be used to access MessageProducer, MessageConsumer, and Message objects
39   * involving a configured ConnectionFactory and Destination.
40   */
41  public class JmsManager extends AbstractManager {
42  
43      private static final Logger LOGGER = StatusLogger.getLogger();
44  
45      private static final JmsManagerFactory FACTORY = new JmsManagerFactory();
46  
47      private final JndiManager jndiManager;
48      private final Connection connection;
49      private final Session session;
50      private final Destination destination;
51  
52      private JmsManager(final String name, final JndiManager jndiManager, final String connectionFactoryName,
53                         final String destinationName, final String username, final String password)
54          throws NamingException, JMSException {
55          super(name);
56          this.jndiManager = jndiManager;
57          final ConnectionFactory connectionFactory = this.jndiManager.lookup(connectionFactoryName);
58          if (username != null && password != null) {
59              this.connection = connectionFactory.createConnection(username, password);
60          } else {
61              this.connection = connectionFactory.createConnection();
62          }
63          this.session = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
64          this.destination = this.jndiManager.lookup(destinationName);
65          this.connection.start();
66      }
67  
68      /**
69       * Gets a JmsManager using the specified configuration parameters.
70       *
71       * @param name                  The name to use for this JmsManager.
72       * @param jndiManager           The JndiManager to look up JMS information through.
73       * @param connectionFactoryName The binding name for the {@link javax.jms.ConnectionFactory}.
74       * @param destinationName       The binding name for the {@link javax.jms.Destination}.
75       * @param username              The username to connect with or {@code null} for no authentication.
76       * @param password              The password to use with the given username or {@code null} for no authentication.
77       * @return The JmsManager as configured.
78       */
79      public static JmsManager getJmsManager(final String name, final JndiManager jndiManager,
80                                             final String connectionFactoryName, final String destinationName,
81                                             final String username, final String password) {
82          final JmsConfiguration configuration = new JmsConfiguration(jndiManager, connectionFactoryName, destinationName,
83              username, password);
84          return FACTORY.createManager(name, configuration);
85      }
86  
87      /**
88       * Creates a MessageConsumer on this Destination using the current Session.
89       *
90       * @return A MessageConsumer on this Destination.
91       * @throws JMSException
92       */
93      public MessageConsumer createMessageConsumer() throws JMSException {
94          return this.session.createConsumer(this.destination);
95      }
96  
97      /**
98       * Creates a MessageProducer on this Destination using the current Session.
99       *
100      * @return A MessageProducer on this Destination.
101      * @throws JMSException
102      */
103     public MessageProducer createMessageProducer() throws JMSException {
104         return this.session.createProducer(this.destination);
105     }
106 
107     /**
108      * Creates a TextMessage or ObjectMessage from a Serializable object. For instance, when using a text-based
109      * {@link org.apache.logging.log4j.core.Layout} such as {@link org.apache.logging.log4j.core.layout.PatternLayout},
110      * the {@link org.apache.logging.log4j.core.LogEvent} message will be serialized to a String. When using a
111      * layout such as {@link org.apache.logging.log4j.core.layout.SerializedLayout}, the LogEvent message will be
112      * serialized as a Java object.
113      *
114      * @param object The LogEvent or String message to wrap.
115      * @return A new JMS message containing the provided object.
116      * @throws JMSException
117      */
118     public Message createMessage(final Serializable object) throws JMSException {
119         if (object instanceof String) {
120             return this.session.createTextMessage((String) object);
121         }
122         return this.session.createObjectMessage(object);
123     }
124 
125     @Override
126     protected void releaseSub() {
127         try {
128             this.session.close();
129         } catch (final JMSException ignored) {
130         }
131         try {
132             this.connection.close();
133         } catch (final JMSException ignored) {
134         }
135         this.jndiManager.release();
136     }
137 
138     private static class JmsConfiguration {
139         private final JndiManager jndiManager;
140         private final String connectionFactoryName;
141         private final String destinationName;
142         private final String username;
143         private final String password;
144 
145         private JmsConfiguration(final JndiManager jndiManager, final String connectionFactoryName, final String destinationName,
146                                  final String username, final String password) {
147             this.jndiManager = jndiManager;
148             this.connectionFactoryName = connectionFactoryName;
149             this.destinationName = destinationName;
150             this.username = username;
151             this.password = password;
152         }
153     }
154 
155     private static class JmsManagerFactory implements ManagerFactory<JmsManager, JmsConfiguration> {
156 
157         @Override
158         public JmsManager createManager(final String name, final JmsConfiguration data) {
159             if (JndiManager.isJndiJmsEnabled()) {
160                 try {
161                     return new JmsManager(name, data.jndiManager, data.connectionFactoryName, data.destinationName,
162                         data.username, data.password);
163                 } catch (final Exception e) {
164                     LOGGER.error("Error creating JmsManager using ConnectionFactory [{}] and Destination [{}].",
165                         data.connectionFactoryName, data.destinationName, e);
166                     return null;
167                 }
168             } else {
169                 LOGGER.error("JNDI must be enabled by setting log4j2.enableJndiJms=true");
170                 return null;
171             }
172         }
173     }
174 
175 }