1
2
3
4
5
6
7
8
9
10
11 package org.mule.transport.jms.mulemq;
12
13 import org.mule.api.MuleContext;
14 import org.mule.api.lifecycle.InitialisationException;
15 import org.mule.config.ExceptionHelper;
16 import org.mule.transport.jms.JmsConnector;
17 import org.mule.transport.jms.JmsConstants;
18 import org.mule.transport.jms.i18n.JmsMessages;
19 import org.mule.util.ClassUtils;
20
21 import java.lang.reflect.Method;
22 import java.util.Hashtable;
23 import java.util.Map;
24
25 import javax.jms.ConnectionFactory;
26 import javax.jms.JMSException;
27
28 public class MuleMQJmsConnector extends JmsConnector
29 {
30 public static final String MULEMQ_CONNECTION_FACTORY_CLASS = "com.pcbsys.nirvana.nJMS.ConnectionFactoryImpl";
31
32
33 public static final String DEFAULT_REALM_URL = "nsp://localhost:9000";
34 public static final String DEFAULT_BUFFER_OUTPUT = "queued";
35 public static final boolean DEFAULT_SYNC_WRITES = false;
36 public static final int DEFAULT_SYNC_BATCH_SIZE = 50;
37 public static final int DEFAULT_SYNC_TIME = 20;
38 public static final int DEFAULT_GLOBAL_STORE_CAPACITY = 5000;
39 public static final int DEFAULT_MAX_UNACKED_SIZE = 100;
40 public static final boolean DEFAULT_USE_JMS_ENGINE = true;
41 public static final int DEFAULT_QUEUE_WINDOW_SIZE = 100;
42 public static final int DEFAULT_AUTO_ACK_COUNT = 50;
43 public static final boolean DEFAULT_ENABLE_SHARED_DURABLE = false;
44 public static final boolean DEFAULT_RANDOMISE_R_NAMES = false;
45 public static final int DEFAULT_MAX_REDELIVERY = 100;
46 public static final int DEFAULT_MESSAGE_THREAD_POOL_SIZE = 30;
47 public static final boolean DEFAULT_DISC_ON_CLUSTER_FAILURE = true;
48 public static final int DEFAULT_INITIAL_RETRY_COUNT = 2;
49 public static final boolean DEFAULT_RETRY_COMMIT = false;
50 public static final boolean DEFAULT_ENABLE_MULTIPLEXED_CONNECTIONS = false;
51
52
53
54 private String realmURL = DEFAULT_REALM_URL;
55 private String bufferOutput = DEFAULT_BUFFER_OUTPUT;
56 private boolean syncWrites = DEFAULT_SYNC_WRITES;
57 private int syncBatchSize = DEFAULT_SYNC_BATCH_SIZE;
58 private int syncTime = DEFAULT_SYNC_TIME;
59 private int globalStoreCapacity = DEFAULT_GLOBAL_STORE_CAPACITY;
60 private int maxUnackedSize = DEFAULT_MAX_UNACKED_SIZE;
61 private boolean useJMSEngine = DEFAULT_USE_JMS_ENGINE;
62 private int queueWindowSize = DEFAULT_QUEUE_WINDOW_SIZE;
63 private int autoAckCount = DEFAULT_AUTO_ACK_COUNT;
64 private boolean enableSharedDurable = DEFAULT_ENABLE_SHARED_DURABLE;
65 private boolean randomiseRNames = DEFAULT_RANDOMISE_R_NAMES;
66 private int muleMqMaxRedelivery = DEFAULT_MAX_REDELIVERY;
67 private int messageThreadPoolSize = DEFAULT_MESSAGE_THREAD_POOL_SIZE;
68 private boolean discOnClusterFailure = DEFAULT_DISC_ON_CLUSTER_FAILURE;
69 private int initialRetryCount = DEFAULT_INITIAL_RETRY_COUNT;
70 private boolean retryCommit = DEFAULT_RETRY_COMMIT;
71 private boolean enableMultiplexedConnections = DEFAULT_ENABLE_MULTIPLEXED_CONNECTIONS;
72
73
74 protected static final String BUFFER_OUTPUT = "BufferOutput";
75 protected static final String SYNC_WRITES = "nirvana.syncWrites";
76 protected static final String SYNC_BATCH_SIZE = "nirvana.syncBatchSize";
77 protected static final String SYNC_TIME = "nirvana.syncTime";
78 protected static final String GLOBAL_STORE_CAPACITY = "nirvana.globalStoreCapacity";
79 protected static final String MAX_UNACKED_SIZE = "nirvana.maxUnackedSize";
80 protected static final String USE_JMS_ENGINE = "nirvana.useJMSEngine";
81 protected static final String QUEUE_WINDOW_SIZE = "nirvana.queueWindowSize";
82 protected static final String AUTO_ACK_COUNT = "nirvana.autoAckCount";
83 protected static final String ENABLE_SHARED_DURABLE = "nirvana.enableSharedDurable";
84 protected static final String RANDOMISE_R_NAMES = "nirvana.randomiseRNames";
85 protected static final String MAX_REDELIVERY = "nirvana.maxRedelivery";
86 protected static final String MESSAGE_THREAD_POOL_SIZE = "nirvana.messageThreadPoolSize";
87 protected static final String DISC_ON_CLUSTER_FAILURE = "nirvana.discOnClusterFailure";
88 protected static final String INITIAL_RETRY_COUNT = "nirvana.initialRetryCount";
89 protected static final String RETRY_COMMIT = "nirvana.retryCommit";
90 protected static final String ENABLE_MULTIPLEXED_CONNECTIONS = "nirvana.enableMultiplexedConnections";
91
92 public boolean supportJms102bSpec = false;
93
94 private boolean inCluster = false;
95
96 public MuleMQJmsConnector(MuleContext context)
97 {
98 super(context);
99 super.setSpecification(JmsConstants.JMS_SPECIFICATION_11);
100 }
101
102 public boolean isSupportJms102bSpec()
103 {
104 return supportJms102bSpec;
105 }
106
107 public void setSupportJms102bSpec(boolean supportJms102bSpec)
108 {
109 this.supportJms102bSpec = supportJms102bSpec;
110 }
111
112
113
114
115
116
117 @Override
118 public void setSpecification(String specification)
119 {
120 if (!isSupportJms102bSpec() && specification.equals(JmsConstants.JMS_SPECIFICATION_102B))
121 {
122 logger.warn(JmsMessages.errorMuleMqJmsSpecification());
123 specification = JmsConstants.JMS_SPECIFICATION_11;
124 }
125 super.setSpecification(specification);
126 }
127
128 @Override
129 protected void doInitialise() throws InitialisationException
130 {
131 if (!isSupportJms102bSpec() && getSpecification().equals(JmsConstants.JMS_SPECIFICATION_102B))
132 {
133 throw new InitialisationException(JmsMessages.errorMuleMqJmsSpecification(), this);
134 }
135 super.doInitialise();
136 }
137
138 @Override
139 protected ConnectionFactory getDefaultConnectionFactory() throws Exception
140 {
141 ConnectionFactory connectionFactory = (ConnectionFactory) ClassUtils.instanciateClass(
142 getMuleMQFactoryClass(), getRealmURL());
143 applyVendorSpecificConnectionFactoryProperties(connectionFactory);
144 return connectionFactory;
145 }
146
147 private void applyVendorSpecificConnectionFactoryProperties(ConnectionFactory connectionFactory)
148 {
149
150 Hashtable<String, Object> props = new Hashtable<String, Object>();
151 props.put(BUFFER_OUTPUT, bufferOutput);
152 props.put(SYNC_WRITES, Boolean.toString(syncWrites));
153 props.put(SYNC_BATCH_SIZE, Integer.toString(syncBatchSize));
154 props.put(SYNC_TIME, Integer.toString(syncTime));
155 props.put(GLOBAL_STORE_CAPACITY, Integer.toString(globalStoreCapacity));
156 props.put(MAX_UNACKED_SIZE, Integer.toString(maxUnackedSize));
157 props.put(USE_JMS_ENGINE, Boolean.toString(useJMSEngine));
158 props.put(QUEUE_WINDOW_SIZE, Integer.toString(queueWindowSize));
159 props.put(AUTO_ACK_COUNT, Integer.toString(autoAckCount));
160 props.put(ENABLE_SHARED_DURABLE, Boolean.toString(enableSharedDurable));
161 props.put(RANDOMISE_R_NAMES, Boolean.toString(randomiseRNames));
162 props.put(MAX_REDELIVERY, Integer.toString(muleMqMaxRedelivery));
163 props.put(MESSAGE_THREAD_POOL_SIZE, Integer.toString(messageThreadPoolSize));
164 props.put(DISC_ON_CLUSTER_FAILURE, Boolean.toString(discOnClusterFailure));
165 props.put(INITIAL_RETRY_COUNT, Integer.toString(initialRetryCount));
166 props.put(RETRY_COMMIT, Boolean.toString(retryCommit));
167 props.put(ENABLE_MULTIPLEXED_CONNECTIONS, Boolean.toString(enableMultiplexedConnections));
168
169
170
171 Map<String, Object> connectionFactoryProperties = getConnectionFactoryProperties();
172 if (connectionFactoryProperties != null)
173 {
174 props.putAll(connectionFactoryProperties);
175 }
176
177 try
178 {
179
180 Method setPropertiesMethod = connectionFactory.getClass().getMethod("setProperties",
181 Hashtable.class);
182 setPropertiesMethod.invoke(connectionFactory, props);
183 }
184 catch (Exception e)
185 {
186 logger.error("Can not set properties on the MuleMQ connection factory " + e);
187 }
188 }
189
190
191
192
193 protected String getMuleMQFactoryClass()
194 {
195 return MULEMQ_CONNECTION_FACTORY_CLASS;
196 }
197
198 public String getRealmURL()
199 {
200 return realmURL;
201 }
202
203 public void setRealmURL(String realmURL)
204 {
205 this.realmURL = realmURL;
206 if (realmURL != null)
207 {
208 String[] realms = realmURL.split(",");
209 if (realms != null && realms.length > 1)
210 {
211 this.setInCluster(true);
212 }
213 }
214 }
215
216 public String getBufferOutput()
217 {
218 return bufferOutput;
219 }
220
221 public void setBufferOutput(String bufferOutput)
222 {
223 this.bufferOutput = bufferOutput;
224 }
225
226 public boolean isSyncWrites()
227 {
228 return syncWrites;
229 }
230
231 public void setSyncWrites(boolean syncWrites)
232 {
233 this.syncWrites = syncWrites;
234 }
235
236 public int getSyncBatchSize()
237 {
238 return syncBatchSize;
239 }
240
241 public void setSyncBatchSize(int syncBatchSize)
242 {
243 this.syncBatchSize = syncBatchSize;
244 }
245
246 public int getSyncTime()
247 {
248 return syncTime;
249 }
250
251 public void setSyncTime(int syncTime)
252 {
253 this.syncTime = syncTime;
254 }
255
256 public int getGlobalStoreCapacity()
257 {
258 return globalStoreCapacity;
259 }
260
261 public void setGlobalStoreCapacity(int globalStoreCapacity)
262 {
263 this.globalStoreCapacity = globalStoreCapacity;
264 }
265
266 public int getMaxUnackedSize()
267 {
268 return maxUnackedSize;
269 }
270
271 public void setMaxUnackedSize(int maxUnackedSize)
272 {
273 this.maxUnackedSize = maxUnackedSize;
274 }
275
276 public boolean isUseJMSEngine()
277 {
278 return useJMSEngine;
279 }
280
281 public void setUseJMSEngine(boolean useJMSEngine)
282 {
283 this.useJMSEngine = useJMSEngine;
284 }
285
286 public int getQueueWindowSize()
287 {
288 return queueWindowSize;
289 }
290
291 public void setQueueWindowSize(int queueWindowSize)
292 {
293 this.queueWindowSize = queueWindowSize;
294 }
295
296 public int getAutoAckCount()
297 {
298 return autoAckCount;
299 }
300
301 public void setAutoAckCount(int autoAckCount)
302 {
303 this.autoAckCount = autoAckCount;
304 }
305
306 public boolean isEnableSharedDurable()
307 {
308 return enableSharedDurable;
309 }
310
311 public void setEnableSharedDurable(boolean enableSharedDurable)
312 {
313 this.enableSharedDurable = enableSharedDurable;
314 }
315
316 public boolean isRandomiseRNames()
317 {
318 return randomiseRNames;
319 }
320
321 public void setRandomiseRNames(boolean randomiseRNames)
322 {
323 this.randomiseRNames = randomiseRNames;
324 }
325
326 public int getMessageThreadPoolSize()
327 {
328 return messageThreadPoolSize;
329 }
330
331 public void setMessageThreadPoolSize(int messageThreadPoolSize)
332 {
333 this.messageThreadPoolSize = messageThreadPoolSize;
334 }
335
336 public boolean isDiscOnClusterFailure()
337 {
338 return discOnClusterFailure;
339 }
340
341 public void setDiscOnClusterFailure(boolean discOnClusterFailure)
342 {
343 this.discOnClusterFailure = discOnClusterFailure;
344 }
345
346 public int getInitialRetryCount()
347 {
348 return initialRetryCount;
349 }
350
351 public void setInitialRetryCount(int initialRetryCount)
352 {
353 this.initialRetryCount = initialRetryCount;
354 }
355
356 public int getMuleMqMaxRedelivery()
357 {
358 return muleMqMaxRedelivery;
359 }
360
361 public void setMuleMqMaxRedelivery(int mulqMqMaxRedelivery)
362 {
363 this.muleMqMaxRedelivery = mulqMqMaxRedelivery;
364 }
365
366 public void setRetryCommit(boolean retryCommit)
367 {
368 this.retryCommit = retryCommit;
369 }
370
371 public boolean isRetryCommit()
372 {
373 return retryCommit;
374 }
375
376 public boolean isEnableMultiplexedConnections()
377 {
378 return enableMultiplexedConnections;
379 }
380
381 public void setEnableMultiplexedConnections(boolean enableMultiplexedConnections)
382 {
383 this.enableMultiplexedConnections = enableMultiplexedConnections;
384 }
385
386 public boolean isInCluster()
387 {
388 return inCluster;
389 }
390
391 public void setInCluster(boolean inCluster)
392 {
393 this.inCluster = inCluster;
394 }
395
396 public void onException(JMSException jmsException)
397 {
398 Throwable th = ExceptionHelper.getRootException(jmsException);
399 if (th == null) th = jmsException;
400 String errMsg = th.getMessage();
401
402 if (errMsg.contains("Channel is full :"))
403 {
404 if(logger.isWarnEnabled())
405 {
406
407 StringBuffer msg = new StringBuffer("MuleMQJmsConnector.onException() received exception: ");
408 msg.append(th.getMessage());
409 msg.append("Older Messages will be discarded by MULE MQ.To prevent message loss use transacted outbound-endpoint");
410 msg.append("Refer to 'Queue Capacity' at http://www.mulesoft.org/display/MQ/Configuring+Mule+MQ#ConfiguringMuleMQ-ConfiguringQueues");
411
412
413 logger.warn(msg.toString(),th);
414 }
415 }
416 else if (this.isInCluster() && errMsg.contains("Disconnected from :"))
417 {
418
419 StringBuffer msg = new StringBuffer("MuleMQJmsConnector.onException() received exception: ");
420 msg.append(th.getMessage());
421 msg.append("If using Mule MQ in a cluster Mule ESB will reconnect automatically in a few seconds");
422
423 logger.warn(msg.toString(),th);
424 }
425 else if (this.isInCluster() && errMsg.contains("Reconnected to :"))
426 {
427
428 StringBuffer msg = new StringBuffer("MuleMQJmsConnector.onException() received exception: ");
429 msg.append(th.getMessage());
430 msg.append("If using Mule MQ in a cluster Mule ESB will reconnect automatically in a few seconds");
431
432 logger.warn(msg.toString(),th);
433 }
434 else
435 {
436
437
438 super.onException(jmsException);
439 }
440 }
441 }