1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.net.jms;
18
19 import java.io.Serializable;
20
21 import javax.jms.JMSException;
22 import javax.jms.Session;
23 import javax.jms.Topic;
24 import javax.jms.TopicConnection;
25 import javax.jms.TopicConnectionFactory;
26 import javax.jms.TopicPublisher;
27 import javax.jms.TopicSession;
28 import javax.naming.Context;
29 import javax.naming.NamingException;
30
31 import org.apache.logging.log4j.core.appender.ManagerFactory;
32
33
34
35
36 public class JmsTopicManager extends AbstractJmsManager {
37
38 private static final JMSTopicManagerFactory FACTORY = new JMSTopicManagerFactory();
39
40 private TopicInfo info;
41 private final String factoryBindingName;
42 private final String topicBindingName;
43 private final String userName;
44 private final String password;
45 private final Context context;
46
47
48
49
50
51
52
53
54
55
56 protected JmsTopicManager(final String name, final Context context, final String factoryBindingName,
57 final String topicBindingName, final String userName, final String password,
58 final TopicInfo info) {
59 super(name);
60 this.context = context;
61 this.factoryBindingName = factoryBindingName;
62 this.topicBindingName = topicBindingName;
63 this.userName = userName;
64 this.password = password;
65 this.info = info;
66 }
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82 public static JmsTopicManager getJmsTopicManager(final String factoryName, final String providerURL,
83 final String urlPkgPrefixes, final String securityPrincipalName,
84 final String securityCredentials, final String factoryBindingName,
85 final String topicBindingName, final String userName,
86 final String password) {
87
88 if (factoryBindingName == null) {
89 LOGGER.error("No factory name provided for JmsTopicManager");
90 return null;
91 }
92 if (topicBindingName == null) {
93 LOGGER.error("No topic name provided for JmsTopicManager");
94 return null;
95 }
96
97 final String name = "JMSTopic:" + factoryBindingName + '.' + topicBindingName;
98 return getManager(name, FACTORY, new FactoryData(factoryName, providerURL, urlPkgPrefixes,
99 securityPrincipalName, securityCredentials, factoryBindingName, topicBindingName, userName, password));
100 }
101
102
103 @Override
104 public void send(final Serializable object) throws Exception {
105 if (info == null) {
106 info = connect(context, factoryBindingName, topicBindingName, userName, password, false);
107 }
108 try {
109 super.send(object, info.session, info.publisher);
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
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 topicBindingName;
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 topicBindingName,
158 final String userName, 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.topicBindingName = topicBindingName;
166 this.userName = userName;
167 this.password = password;
168 }
169 }
170
171 private static TopicInfo 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 TopicConnectionFactory factory = (TopicConnectionFactory) lookup(context, factoryBindingName);
176 TopicConnection conn;
177 if (userName != null) {
178 conn = factory.createTopicConnection(userName, password);
179 } else {
180 conn = factory.createTopicConnection();
181 }
182 final TopicSession sess = conn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
183 final Topic topic = (Topic) lookup(context, queueBindingName);
184 final TopicPublisher publisher = sess.createPublisher(topic);
185 conn.start();
186 return new TopicInfo(conn, sess, publisher);
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
202 private static class TopicInfo {
203 private final TopicConnection conn;
204 private final TopicSession session;
205 private final TopicPublisher publisher;
206
207 public TopicInfo(final TopicConnection conn, final TopicSession session, final TopicPublisher publisher) {
208 this.conn = conn;
209 this.session = session;
210 this.publisher = publisher;
211 }
212 }
213
214
215
216
217 private static class JMSTopicManagerFactory implements ManagerFactory<JmsTopicManager, FactoryData> {
218
219 @Override
220 public JmsTopicManager 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 TopicInfo info = connect(ctx, data.factoryBindingName, data.topicBindingName, data.userName,
225 data.password, true);
226 return new JmsTopicManager(name, ctx, data.factoryBindingName, data.topicBindingName,
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 }