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  package org.apache.logging.log4j.core.net;
18  
19  import org.apache.logging.log4j.core.appender.ManagerFactory;
20  
21  import javax.jms.JMSException;
22  import javax.jms.Queue;
23  import javax.jms.QueueConnection;
24  import javax.jms.QueueConnectionFactory;
25  import javax.jms.QueueSender;
26  import javax.jms.QueueSession;
27  import javax.jms.Session;
28  import javax.naming.Context;
29  import javax.naming.NamingException;
30  import java.io.Serializable;
31  
32  /**
33   * Manager for a JMS Queue.
34   */
35  public class JMSQueueManager extends AbstractJMSManager {
36  
37      private static final JMSQueueManagerFactory FACTORY = new JMSQueueManagerFactory();
38  
39      private QueueInfo info;
40      private final String factoryBindingName;
41      private final String queueBindingName;
42      private final String userName;
43      private final String password;
44      private final Context context;
45  
46      /**
47       * The Constructor.
48       * @param name The unique name of the connection.
49       * @param context The context.
50       * @param factoryBindingName The factory binding name.
51       * @param queueBindingName The queue binding name.
52       * @param userName The user name.
53       * @param password The credentials for the user.
54       * @param info The Queue connection info.
55       */
56      protected JMSQueueManager(final String name, final Context context, final String factoryBindingName,
57                                final String queueBindingName, final String userName, final String password,
58                                final QueueInfo info) {
59          super(name);
60          this.context = context;
61          this.factoryBindingName = factoryBindingName;
62          this.queueBindingName = queueBindingName;
63          this.userName = userName;
64          this.password = password;
65          this.info = info;
66      }
67  
68      /**
69       * Obtain a JMSQueueManager.
70       * @param factoryName The fully qualified class name of the InitialContextFactory.
71       * @param providerURL The URL of the provider to use.
72       * @param urlPkgPrefixes A colon-separated list of package prefixes for the class name of the factory class that
73       * will create a URL context factory
74       * @param securityPrincipalName The name of the identity of the Principal.
75       * @param securityCredentials The security credentials of the Principal.
76       * @param factoryBindingName The name to locate in the Context that provides the QueueConnectionFactory.
77       * @param queueBindingName The name to use to locate the Queue.
78       * @param userName The userid to use to create the Queue Connection.
79       * @param password The password to use to create the Queue Connection.
80       * @return The JMSQueueManager.
81       */
82      public static JMSQueueManager getJMSQueueManager(final String factoryName, final String providerURL,
83                                                       final String urlPkgPrefixes, final String securityPrincipalName,
84                                                       final String securityCredentials, final String factoryBindingName,
85                                                       final String queueBindingName, final String userName,
86                                                       final String password) {
87  
88          if (factoryBindingName == null) {
89              LOGGER.error("No factory name provided for JMSQueueManager");
90              return null;
91          }
92          if (queueBindingName == null) {
93              LOGGER.error("No topic name provided for JMSQueueManager");
94              return null;
95          }
96  
97          final String name = "JMSQueue:" + factoryBindingName + '.' + queueBindingName;
98          return getManager(name, FACTORY, new FactoryData(factoryName, providerURL, urlPkgPrefixes,
99              securityPrincipalName, securityCredentials, factoryBindingName, queueBindingName, userName, password));
100     }
101 
102     @Override
103     public synchronized void send(final Serializable object) throws Exception {
104         if (info == null) {
105             info = connect(context, factoryBindingName, queueBindingName, userName, password, false);
106         }
107         try {
108             super.send(object, info.session, info.sender);
109         } catch (final Exception ex) {
110             cleanup(true);
111             throw ex;
112         }
113     }
114 
115     @Override
116     public void releaseSub() {
117         if (info != null) {
118             cleanup(false);
119         }
120     }
121 
122     private void cleanup(final boolean quiet) {
123         try {
124             info.session.close();
125         } catch (final Exception e) {
126             if (!quiet) {
127                 LOGGER.error("Error closing session for " + getName(), e);
128             }
129         }
130         try {
131             info.conn.close();
132         } catch (final Exception e) {
133             if (!quiet) {
134                 LOGGER.error("Error closing connection for " + getName(), e);
135             }
136         }
137         info = null;
138     }
139 
140     /**
141      * Data for the factory.
142      */
143     private static class FactoryData {
144         private final String factoryName;
145         private final String providerURL;
146         private final String urlPkgPrefixes;
147         private final String securityPrincipalName;
148         private final String securityCredentials;
149         private final String factoryBindingName;
150         private final String queueBindingName;
151         private final String userName;
152         private final String password;
153 
154         public FactoryData(final String factoryName, final String providerURL, final String urlPkgPrefixes,
155                            final String securityPrincipalName, final String securityCredentials,
156                            final String factoryBindingName, final String queueBindingName, final String userName,
157                            final String password) {
158             this.factoryName = factoryName;
159             this.providerURL = providerURL;
160             this.urlPkgPrefixes = urlPkgPrefixes;
161             this.securityPrincipalName = securityPrincipalName;
162             this.securityCredentials = securityCredentials;
163             this.factoryBindingName = factoryBindingName;
164             this.queueBindingName = queueBindingName;
165             this.userName = userName;
166             this.password = password;
167         }
168     }
169 
170     private static QueueInfo connect(final Context context, final String factoryBindingName,
171                                      final String queueBindingName, final String userName, final String password,
172                                      final boolean suppress) throws Exception {
173         try {
174             final QueueConnectionFactory factory = (QueueConnectionFactory) lookup(context, factoryBindingName);
175             QueueConnection conn;
176             if (userName != null) {
177                 conn = factory.createQueueConnection(userName, password);
178             } else {
179                 conn = factory.createQueueConnection();
180             }
181             final QueueSession sess = conn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
182             final Queue queue = (Queue) lookup(context, queueBindingName);
183             final QueueSender sender = sess.createSender(queue);
184             conn.start();
185             return new QueueInfo(conn, sess, sender);
186         } catch (final NamingException ex) {
187             LOGGER.warn("Unable to locate connection factory " + factoryBindingName, ex);
188             if (!suppress) {
189                 throw ex;
190             }
191         } catch (final JMSException ex) {
192             LOGGER.warn("Unable to create connection to queue " + queueBindingName, ex);
193             if (!suppress) {
194                 throw ex;
195             }
196         }
197         return null;
198     }
199 
200     /** Queue connection information */
201     private static class QueueInfo {
202         private final QueueConnection conn;
203         private final QueueSession session;
204         private final QueueSender sender;
205 
206         public QueueInfo(final QueueConnection conn, final QueueSession session, final QueueSender sender) {
207             this.conn = conn;
208             this.session = session;
209             this.sender = sender;
210         }
211     }
212 
213     /**
214      * Factory to create the JMSQueueManager.
215      */
216     private static class JMSQueueManagerFactory implements ManagerFactory<JMSQueueManager, FactoryData> {
217 
218         public JMSQueueManager createManager(final String name, final FactoryData data) {
219             try {
220                 final Context ctx = createContext(data.factoryName, data.providerURL, data.urlPkgPrefixes,
221                                             data.securityPrincipalName, data.securityCredentials);
222                 final QueueInfo info = connect(ctx, data.factoryBindingName, data.queueBindingName, data.userName,
223                     data.password, true);
224                 return new JMSQueueManager(name, ctx, data.factoryBindingName, data.queueBindingName,
225                     data.userName, data.password, info);
226             } catch (final NamingException ex) {
227                 LOGGER.error("Unable to locate resource", ex);
228             } catch (final Exception ex) {
229                 LOGGER.error("Unable to connect", ex);
230             }
231 
232             return null;
233         }
234     }
235 }