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