001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017 package org.apache.logging.log4j.core.net.jms; 018 019 import java.io.Serializable; 020 021 import javax.jms.JMSException; 022 import javax.jms.Queue; 023 import javax.jms.QueueConnection; 024 import javax.jms.QueueConnectionFactory; 025 import javax.jms.QueueSender; 026 import javax.jms.QueueSession; 027 import javax.jms.Session; 028 import javax.naming.Context; 029 import javax.naming.NamingException; 030 031 import org.apache.logging.log4j.core.appender.ManagerFactory; 032 033 /** 034 * Manager for a JMS Queue. 035 */ 036 public class JmsQueueManager extends AbstractJmsManager { 037 038 private static final JMSQueueManagerFactory FACTORY = new JMSQueueManagerFactory(); 039 040 private QueueInfo info; 041 private final String factoryBindingName; 042 private final String queueBindingName; 043 private final String userName; 044 private final String password; 045 private final Context context; 046 047 /** 048 * The Constructor. 049 * @param name The unique name of the connection. 050 * @param context The context. 051 * @param factoryBindingName The factory binding name. 052 * @param queueBindingName The queue binding name. 053 * @param userName The user name. 054 * @param password The credentials for the user. 055 * @param info The Queue connection info. 056 */ 057 protected JmsQueueManager(final String name, final Context context, final String factoryBindingName, 058 final String queueBindingName, final String userName, final String password, 059 final QueueInfo info) { 060 super(name); 061 this.context = context; 062 this.factoryBindingName = factoryBindingName; 063 this.queueBindingName = queueBindingName; 064 this.userName = userName; 065 this.password = password; 066 this.info = info; 067 } 068 069 /** 070 * Obtain a JmsQueueManager. 071 * @param factoryName The fully qualified class name of the InitialContextFactory. 072 * @param providerURL The URL of the provider to use. 073 * @param urlPkgPrefixes A colon-separated list of package prefixes for the class name of the factory class that 074 * will create a URL context factory 075 * @param securityPrincipalName The name of the identity of the Principal. 076 * @param securityCredentials The security credentials of the Principal. 077 * @param factoryBindingName The name to locate in the Context that provides the QueueConnectionFactory. 078 * @param queueBindingName The name to use to locate the Queue. 079 * @param userName The userid to use to create the Queue Connection. 080 * @param password The password to use to create the Queue Connection. 081 * @return The JmsQueueManager. 082 */ 083 public static JmsQueueManager getJmsQueueManager(final String factoryName, final String providerURL, 084 final String urlPkgPrefixes, final String securityPrincipalName, 085 final String securityCredentials, final String factoryBindingName, 086 final String queueBindingName, final String userName, 087 final String password) { 088 089 if (factoryBindingName == null) { 090 LOGGER.error("No factory name provided for JmsQueueManager"); 091 return null; 092 } 093 if (queueBindingName == null) { 094 LOGGER.error("No topic name provided for JmsQueueManager"); 095 return null; 096 } 097 098 final String name = "JMSQueue:" + factoryBindingName + '.' + queueBindingName; 099 return getManager(name, FACTORY, new FactoryData(factoryName, providerURL, urlPkgPrefixes, 100 securityPrincipalName, securityCredentials, factoryBindingName, queueBindingName, userName, password)); 101 } 102 103 @Override 104 public synchronized void send(final Serializable object) throws Exception { 105 if (info == null) { 106 info = connect(context, factoryBindingName, queueBindingName, userName, password, false); 107 } 108 try { 109 super.send(object, info.session, info.sender); 110 } catch (final Exception ex) { 111 cleanup(true); 112 throw ex; 113 } 114 } 115 116 @Override 117 public void releaseSub() { 118 if (info != null) { 119 cleanup(false); 120 } 121 } 122 123 private void cleanup(final boolean quiet) { 124 try { 125 info.session.close(); 126 } catch (final Exception e) { 127 if (!quiet) { 128 LOGGER.error("Error closing session for " + getName(), e); 129 } 130 } 131 try { 132 info.conn.close(); 133 } catch (final Exception e) { 134 if (!quiet) { 135 LOGGER.error("Error closing connection for " + getName(), e); 136 } 137 } 138 info = null; 139 } 140 141 /** 142 * Data for the factory. 143 */ 144 private static class FactoryData { 145 private final String factoryName; 146 private final String providerURL; 147 private final String urlPkgPrefixes; 148 private final String securityPrincipalName; 149 private final String securityCredentials; 150 private final String factoryBindingName; 151 private final String queueBindingName; 152 private final String userName; 153 private final String password; 154 155 public FactoryData(final String factoryName, final String providerURL, final String urlPkgPrefixes, 156 final String securityPrincipalName, final String securityCredentials, 157 final String factoryBindingName, final String queueBindingName, final String userName, 158 final String password) { 159 this.factoryName = factoryName; 160 this.providerURL = providerURL; 161 this.urlPkgPrefixes = urlPkgPrefixes; 162 this.securityPrincipalName = securityPrincipalName; 163 this.securityCredentials = securityCredentials; 164 this.factoryBindingName = factoryBindingName; 165 this.queueBindingName = queueBindingName; 166 this.userName = userName; 167 this.password = password; 168 } 169 } 170 171 private static QueueInfo connect(final Context context, final String factoryBindingName, 172 final String queueBindingName, final String userName, final String password, 173 final boolean suppress) throws Exception { 174 try { 175 final QueueConnectionFactory factory = (QueueConnectionFactory) lookup(context, factoryBindingName); 176 QueueConnection conn; 177 if (userName != null) { 178 conn = factory.createQueueConnection(userName, password); 179 } else { 180 conn = factory.createQueueConnection(); 181 } 182 final QueueSession sess = conn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); 183 final Queue queue = (Queue) lookup(context, queueBindingName); 184 final QueueSender sender = sess.createSender(queue); 185 conn.start(); 186 return new QueueInfo(conn, sess, sender); 187 } catch (final NamingException ex) { 188 LOGGER.warn("Unable to locate connection factory " + factoryBindingName, ex); 189 if (!suppress) { 190 throw ex; 191 } 192 } catch (final JMSException ex) { 193 LOGGER.warn("Unable to create connection to queue " + queueBindingName, ex); 194 if (!suppress) { 195 throw ex; 196 } 197 } 198 return null; 199 } 200 201 /** Queue connection information */ 202 private static class QueueInfo { 203 private final QueueConnection conn; 204 private final QueueSession session; 205 private final QueueSender sender; 206 207 public QueueInfo(final QueueConnection conn, final QueueSession session, final QueueSender sender) { 208 this.conn = conn; 209 this.session = session; 210 this.sender = sender; 211 } 212 } 213 214 /** 215 * Factory to create the JmsQueueManager. 216 */ 217 private static class JMSQueueManagerFactory implements ManagerFactory<JmsQueueManager, FactoryData> { 218 219 @Override 220 public JmsQueueManager createManager(final String name, final FactoryData data) { 221 try { 222 final Context ctx = createContext(data.factoryName, data.providerURL, data.urlPkgPrefixes, 223 data.securityPrincipalName, data.securityCredentials); 224 final QueueInfo info = connect(ctx, data.factoryBindingName, data.queueBindingName, data.userName, 225 data.password, true); 226 return new JmsQueueManager(name, ctx, data.factoryBindingName, data.queueBindingName, 227 data.userName, data.password, info); 228 } catch (final NamingException ex) { 229 LOGGER.error("Unable to locate resource", ex); 230 } catch (final Exception ex) { 231 LOGGER.error("Unable to connect", ex); 232 } 233 234 return null; 235 } 236 } 237 }