1
2
3
4
5
6
7
8
9
10
11 package org.mule.model.seda;
12
13 import org.mule.DefaultMuleEvent;
14 import org.mule.DefaultMuleMessage;
15 import org.mule.FailedToQueueEventException;
16 import org.mule.OptimizedRequestContext;
17 import org.mule.RequestContext;
18 import org.mule.api.ExceptionPayload;
19 import org.mule.api.MessagingException;
20 import org.mule.api.MuleEvent;
21 import org.mule.api.MuleException;
22 import org.mule.api.MuleMessage;
23 import org.mule.api.MuleRuntimeException;
24 import org.mule.api.config.ThreadingProfile;
25 import org.mule.api.context.WorkManager;
26 import org.mule.api.endpoint.InboundEndpoint;
27 import org.mule.api.lifecycle.InitialisationException;
28 import org.mule.api.lifecycle.LifecycleException;
29 import org.mule.api.service.ServiceException;
30 import org.mule.api.transport.ReplyToHandler;
31 import org.mule.config.QueueProfile;
32 import org.mule.config.i18n.CoreMessages;
33 import org.mule.config.i18n.MessageFactory;
34 import org.mule.management.stats.ServiceStatistics;
35 import org.mule.message.DefaultExceptionPayload;
36 import org.mule.service.AbstractService;
37 import org.mule.transport.NullPayload;
38 import org.mule.util.queue.Queue;
39 import org.mule.util.queue.QueueSession;
40
41 import java.util.NoSuchElementException;
42
43 import javax.resource.spi.work.Work;
44 import javax.resource.spi.work.WorkEvent;
45 import javax.resource.spi.work.WorkException;
46 import javax.resource.spi.work.WorkListener;
47
48
49
50
51
52
53 public class SedaService extends AbstractService implements Work, WorkListener
54 {
55
56
57
58 private static final long serialVersionUID = 7711976708670893015L;
59
60 private static final String QUEUE_NAME_SUFFIX = ".component";
61
62 protected WorkManager workManager;
63
64
65
66
67 protected Integer queueTimeout;
68
69
70
71
72
73 protected ThreadingProfile threadingProfile;
74
75
76
77
78
79 protected QueueProfile queueProfile;
80
81 protected Queue queue;
82
83
84 public SedaService()
85 {
86 super();
87 }
88
89
90
91
92
93
94
95
96
97
98 protected synchronized void doInitialise() throws InitialisationException
99 {
100 if (threadingProfile == null)
101 {
102
103 threadingProfile = muleContext.getDefaultComponentThreadingProfile();
104 }
105
106 workManager = threadingProfile.createWorkManager(getName());
107
108 if (queueProfile == null)
109 {
110
111 queueProfile = ((SedaModel) model).getQueueProfile();
112 }
113
114 if (queueTimeout == null)
115 {
116
117 setQueueTimeout(new Integer(((SedaModel) model).getQueueTimeout()));
118 }
119
120 try
121 {
122 if (name == null)
123 {
124 throw new InitialisationException(MessageFactory.createStaticMessage("Service has no name to identify it"), this);
125 }
126
127 queueProfile.configureQueue(name, muleContext.getQueueManager());
128 queue = muleContext.getQueueManager().getQueueSession().getQueue(name + QUEUE_NAME_SUFFIX);
129 if (queue == null)
130 {
131 throw new InitialisationException(MessageFactory.createStaticMessage("Queue not created for service " + name), this);
132 }
133 }
134 catch (InitialisationException e)
135 {
136 throw e;
137 }
138 catch (Throwable e)
139 {
140 throw new InitialisationException(
141 CoreMessages.objectFailedToInitialise("Service Queue"), e, this);
142 }
143 }
144
145 protected void doForceStop() throws MuleException
146 {
147 doStop();
148 }
149
150 protected void doStop() throws MuleException
151 {
152 if (queue != null && queue.size() > 0)
153 {
154 try
155 {
156 stopping.whenFalse(null);
157 }
158 catch (InterruptedException e)
159 {
160
161
162 }
163 }
164 workManager.dispose();
165 }
166
167 protected void doStart() throws MuleException
168 {
169 try
170 {
171 workManager.start();
172 workManager.scheduleWork(this, WorkManager.INDEFINITE, null, this);
173 }
174 catch (Exception e)
175 {
176 throw new LifecycleException(
177 CoreMessages.failedToStart("Service: " + name), e, this);
178 }
179 }
180
181 protected void doDispose()
182 {
183 queue = null;
184
185 if (workManager != null)
186 {
187 workManager.dispose();
188 }
189 }
190
191 protected void doDispatch(MuleEvent event) throws MuleException
192 {
193
194 if (stats.isEnabled())
195 {
196 stats.incReceivedEventASync();
197 }
198 if (logger.isDebugEnabled())
199 {
200 logger.debug("Service: " + name + " has received asynchronous event on: "
201 + event.getEndpoint().getEndpointURI());
202 }
203
204
205 try
206 {
207 enqueue(event);
208 if (stats.isEnabled())
209 {
210 stats.incQueuedEvent();
211 }
212 }
213 catch (Exception e)
214 {
215 FailedToQueueEventException e1 = new FailedToQueueEventException(
216 CoreMessages.interruptedQueuingEventFor(this.getName()), event.getMessage(), this, e);
217 handleException(e1);
218 }
219
220 if (logger.isTraceEnabled())
221 {
222 logger.trace("MuleEvent added to queue for: " + name);
223 }
224 }
225
226 protected MuleMessage doSend(MuleEvent event) throws MuleException
227 {
228 MuleMessage result = null;
229 try
230 {
231 if (logger.isDebugEnabled())
232 {
233 logger.debug(this + " : got proxy for " + event.getId() + " = " + component);
234 }
235 Object replyTo = event.getMessage().getReplyTo();
236 ReplyToHandler replyToHandler = getReplyToHandler(event.getMessage(), (InboundEndpoint) event.getEndpoint());
237 result = component.onCall(event);
238 result = sendToOutboundRouter(event, result);
239 result = processAsyncReplyRouter(result);
240 processReplyTo(event, result, replyToHandler, replyTo);
241
242 if (stats.isEnabled())
243 {
244 stats.incSentEventSync();
245 }
246 }
247 catch (Exception e)
248 {
249 event.getSession().setValid(false);
250 if (e instanceof MessagingException)
251 {
252 handleException(e);
253 }
254 else
255 {
256 handleException(new MessagingException(CoreMessages.eventProcessingFailedFor(getName()),
257 event.getMessage(), e));
258 }
259 if (result == null)
260 {
261
262
263
264 result = new DefaultMuleMessage(NullPayload.getInstance(), RequestContext.getEvent().getMessage());
265 }
266 ExceptionPayload exceptionPayload = result.getExceptionPayload();
267 if (exceptionPayload == null)
268 {
269 exceptionPayload = new DefaultExceptionPayload(e);
270 }
271 result.setExceptionPayload(exceptionPayload);
272 }
273 return result;
274 }
275
276 public int getQueueSize()
277 {
278 if (queue == null)
279 {
280 logger.warn(new InitialisationException(MessageFactory.createStaticMessage("Queue not created for service " + name), this));
281 return -1;
282 }
283 return queue.size();
284 }
285
286
287
288
289
290 public void run()
291 {
292 DefaultMuleEvent event = null;
293 QueueSession queueSession = muleContext.getQueueManager().getQueueSession();
294
295 while (!stopped.get())
296 {
297 try
298 {
299
300 paused.whenFalse(null);
301
302
303
304 if (stopping.get())
305 {
306 if (queueSession == null || getQueueSize() <= 0)
307 {
308 stopping.set(false);
309 break;
310 }
311 }
312
313 event = (DefaultMuleEvent) dequeue();
314 if (event != null)
315 {
316 if (stats.isEnabled())
317 {
318 stats.decQueuedEvent();
319 }
320
321 if (logger.isDebugEnabled())
322 {
323 logger.debug("Service: " + name + " dequeued event on: "
324 + event.getEndpoint().getEndpointURI());
325 }
326 workManager.scheduleWork(new ComponentStageWorker(event), WorkManager.INDEFINITE, null, this);
327 }
328 }
329 catch (Exception e)
330 {
331 if (isStopped() || isStopping())
332 {
333 break;
334 }
335
336 if (e instanceof InterruptedException)
337 {
338 stopping.set(false);
339 break;
340 }
341 else if (e instanceof NoSuchElementException)
342 {
343 handleException(new ServiceException(CoreMessages.proxyPoolTimedOut(),
344 (event == null ? null : event.getMessage()), this, e));
345 }
346 else if (e instanceof MuleException)
347 {
348 handleException(e);
349 }
350 else if (e instanceof WorkException)
351 {
352 handleException(
353 new ServiceException(
354 CoreMessages.eventProcessingFailedFor(name),
355 (event == null ? null : event.getMessage()), this, e));
356 }
357 else
358 {
359 handleException(
360 new ServiceException(
361 CoreMessages.failedToGetPooledObject(),
362 (event == null ? null : event.getMessage()), this, e));
363 }
364 }
365 finally
366 {
367 stopping.set(false);
368 }
369 }
370 }
371
372 public void release()
373 {
374 stopping.set(false);
375 }
376
377 protected void enqueue(MuleEvent event) throws Exception
378 {
379 if (queue == null)
380 {
381 throw new InitialisationException(MessageFactory.createStaticMessage("Queue not created for service " + name), this);
382 }
383 if (logger.isDebugEnabled())
384 {
385 logger.debug("Service " + name + " putting event on queue " + queue.getName() + ": " + event);
386 }
387 queue.put(event);
388 }
389
390 protected MuleEvent dequeue() throws Exception
391 {
392 if (queue == null)
393 {
394 throw new InitialisationException(MessageFactory.createStaticMessage("Queue not created for service " + name), this);
395 }
396 if (logger.isDebugEnabled())
397 {
398 logger.debug("Service " + name + " polling queue " + queue.getName() + ", timeout = " + queueTimeout);
399 }
400 if (getQueueTimeout() == null)
401 {
402 throw new InitialisationException(CoreMessages.noServiceQueueTimeoutSet(this), this);
403 }
404 else
405 {
406 return (MuleEvent) queue.poll(getQueueTimeout().intValue());
407 }
408 }
409
410 public void workAccepted(WorkEvent event)
411 {
412 handleWorkException(event, "workAccepted");
413 }
414
415 public void workRejected(WorkEvent event)
416 {
417 handleWorkException(event, "workRejected");
418 }
419
420 public void workStarted(WorkEvent event)
421 {
422 handleWorkException(event, "workStarted");
423 }
424
425 public void workCompleted(WorkEvent event)
426 {
427 handleWorkException(event, "workCompleted");
428 }
429
430 protected void handleWorkException(WorkEvent event, String type)
431 {
432 Throwable e;
433
434 if (event != null && event.getException() != null)
435 {
436 e = event.getException();
437 }
438 else
439 {
440 return;
441 }
442
443 if (event.getException().getCause() != null)
444 {
445 e = event.getException().getCause();
446 }
447
448 logger.error("Work caused exception on '" + type + "'. Work being executed was: "
449 + event.getWork().toString());
450
451 if (e instanceof Exception)
452 {
453 handleException((Exception) e);
454 }
455 else
456 {
457 throw new MuleRuntimeException(
458 CoreMessages.componentCausedErrorIs(this.getName()), e);
459 }
460 }
461
462 protected ServiceStatistics createStatistics()
463 {
464 return new ServiceStatistics(getName(), threadingProfile.getMaxThreadsActive());
465 }
466
467 public Object getInstance() throws MuleException
468 {
469 throw new UnsupportedOperationException("Direct access to underlying service object is not allowed in the SedaModel. If this is for a unit test, make sure you are using the TestSedaModel ('seda-test')");
470 }
471
472 public QueueProfile getQueueProfile()
473 {
474 return queueProfile;
475 }
476
477 public void setQueueProfile(QueueProfile queueProfile)
478 {
479 this.queueProfile = queueProfile;
480 }
481
482 public Integer getQueueTimeout()
483 {
484 return queueTimeout;
485 }
486
487 public void setQueueTimeout(Integer queueTimeout)
488 {
489 this.queueTimeout = queueTimeout;
490 }
491
492 public ThreadingProfile getThreadingProfile()
493 {
494 return threadingProfile;
495 }
496
497 public void setThreadingProfile(ThreadingProfile threadingProfile)
498 {
499 this.threadingProfile = threadingProfile;
500 }
501
502 public WorkManager getWorkManager()
503 {
504 return workManager;
505 }
506
507 public void setWorkManager(WorkManager workManager)
508 {
509 this.workManager = workManager;
510 }
511
512 protected void dispatchToOutboundRouter(MuleEvent event, MuleMessage result) throws MessagingException
513 {
514 super.dispatchToOutboundRouter(event, result);
515
516
517 }
518
519 private class ComponentStageWorker implements Work
520 {
521 private MuleEvent event;
522
523 public ComponentStageWorker(MuleEvent event)
524 {
525 this.event = event;
526 }
527
528 public void run()
529 {
530 try
531 {
532 event = OptimizedRequestContext.criticalSetEvent(event);
533 Object replyTo = event.getMessage().getReplyTo();
534 ReplyToHandler replyToHandler = getReplyToHandler(event.getMessage(),
535 (InboundEndpoint) event.getEndpoint());
536 MuleMessage result = component.onCall(event);
537 dispatchToOutboundRouter(event, result);
538 processReplyTo(event, result, replyToHandler, replyTo);
539 }
540 catch (Exception e)
541 {
542 event.getSession().setValid(false);
543 if (e instanceof MessagingException)
544 {
545 handleException(e);
546 }
547 else
548 {
549 handleException(new MessagingException(CoreMessages.eventProcessingFailedFor(getName()),
550 event.getMessage(), e));
551 }
552 }
553 }
554
555 public void release()
556 {
557
558 }
559 }
560 }