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