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; 018 019 import org.apache.logging.log4j.core.appender.ManagerFactory; 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 import java.io.Serializable; 031 032 /** 033 * Manager for a JMS Queue. 034 */ 035 public class JMSQueueManager extends AbstractJMSManager { 036 037 private static final JMSQueueManagerFactory FACTORY = new JMSQueueManagerFactory(); 038 039 private QueueInfo info; 040 private final String factoryBindingName; 041 private final String queueBindingName; 042 private final String userName; 043 private final String password; 044 private final Context context; 045 046 /** 047 * The Constructor. 048 * @param name The unique name of the connection. 049 * @param context The context. 050 * @param factoryBindingName The factory binding name. 051 * @param queueBindingName The queue binding name. 052 * @param userName The user name. 053 * @param password The credentials for the user. 054 * @param info The Queue connection info. 055 */ 056 protected JMSQueueManager(final String name, final Context context, final String factoryBindingName, 057 final String queueBindingName, final String userName, final String password, 058 final QueueInfo info) { 059 super(name); 060 this.context = context; 061 this.factoryBindingName = factoryBindingName; 062 this.queueBindingName = queueBindingName; 063 this.userName = userName; 064 this.password = password; 065 this.info = info; 066 } 067 068 /** 069 * Obtain a JMSQueueManager. 070 * @param factoryName The fully qualified class name of the InitialContextFactory. 071 * @param providerURL The URL of the provider to use. 072 * @param urlPkgPrefixes A colon-separated list of package prefixes for the class name of the factory class that 073 * will create a URL context factory 074 * @param securityPrincipalName The name of the identity of the Principal. 075 * @param securityCredentials The security credentials of the Principal. 076 * @param factoryBindingName The name to locate in the Context that provides the QueueConnectionFactory. 077 * @param queueBindingName The name to use to locate the Queue. 078 * @param userName The userid to use to create the Queue Connection. 079 * @param password The password to use to create the Queue Connection. 080 * @return The JMSQueueManager. 081 */ 082 public static JMSQueueManager getJMSQueueManager(final String factoryName, final String providerURL, 083 final String urlPkgPrefixes, final String securityPrincipalName, 084 final String securityCredentials, final String factoryBindingName, 085 final String queueBindingName, final String userName, 086 final String password) { 087 088 if (factoryBindingName == null) { 089 LOGGER.error("No factory name provided for JMSQueueManager"); 090 return null; 091 } 092 if (queueBindingName == null) { 093 LOGGER.error("No topic name provided for JMSQueueManager"); 094 return null; 095 } 096 097 final String name = "JMSQueue:" + factoryBindingName + '.' + queueBindingName; 098 return getManager(name, FACTORY, new FactoryData(factoryName, providerURL, urlPkgPrefixes, 099 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 }