View Javadoc

1   /*
2    * $Id: MuleEventMulticaster.java 19191 2010-08-25 21:05:23Z tcarlson $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.module.spring.events;
12  
13  import org.mule.DefaultMuleEvent;
14  import org.mule.DefaultMuleMessage;
15  import org.mule.MessageExchangePattern;
16  import org.mule.RequestContext;
17  import org.mule.api.MuleContext;
18  import org.mule.api.MuleEventContext;
19  import org.mule.api.MuleException;
20  import org.mule.api.MuleRuntimeException;
21  import org.mule.api.MuleSession;
22  import org.mule.api.config.MuleProperties;
23  import org.mule.api.config.ThreadingProfile;
24  import org.mule.api.context.MuleContextAware;
25  import org.mule.api.endpoint.EndpointBuilder;
26  import org.mule.api.endpoint.EndpointFactory;
27  import org.mule.api.endpoint.EndpointURI;
28  import org.mule.api.endpoint.InboundEndpoint;
29  import org.mule.api.endpoint.MalformedEndpointException;
30  import org.mule.api.endpoint.OutboundEndpoint;
31  import org.mule.api.lifecycle.Callable;
32  import org.mule.api.lifecycle.Initialisable;
33  import org.mule.api.lifecycle.InitialisationException;
34  import org.mule.api.model.Model;
35  import org.mule.api.routing.filter.ObjectFilter;
36  import org.mule.api.service.Service;
37  import org.mule.api.source.CompositeMessageSource;
38  import org.mule.api.transformer.Transformer;
39  import org.mule.api.transformer.TransformerException;
40  import org.mule.api.transport.Connector;
41  import org.mule.component.DefaultJavaComponent;
42  import org.mule.config.QueueProfile;
43  import org.mule.endpoint.MuleEndpointURI;
44  import org.mule.model.seda.SedaModel;
45  import org.mule.model.seda.SedaService;
46  import org.mule.module.spring.i18n.SpringMessages;
47  import org.mule.object.SingletonObjectFactory;
48  import org.mule.routing.filters.WildcardFilter;
49  import org.mule.service.ServiceCompositeMessageSource;
50  import org.mule.session.DefaultMuleSession;
51  import org.mule.util.ClassUtils;
52  
53  import java.beans.ExceptionListener;
54  import java.util.ArrayList;
55  import java.util.Iterator;
56  import java.util.List;
57  import java.util.Map;
58  import java.util.Set;
59  
60  import edu.emory.mathcs.backport.java.util.concurrent.CopyOnWriteArraySet;
61  import edu.emory.mathcs.backport.java.util.concurrent.ExecutorService;
62  
63  import org.apache.commons.logging.Log;
64  import org.apache.commons.logging.LogFactory;
65  import org.springframework.beans.BeansException;
66  import org.springframework.context.ApplicationContext;
67  import org.springframework.context.ApplicationContextAware;
68  import org.springframework.context.ApplicationEvent;
69  import org.springframework.context.ApplicationListener;
70  import org.springframework.context.event.ApplicationEventMulticaster;
71  import org.springframework.context.event.ContextClosedEvent;
72  import org.springframework.context.event.ContextRefreshedEvent;
73  
74  /**
75   * <code>MuleEventMulticaster</code> is an implementation of a Spring
76   * ApplicationeventMulticaster. This implementation allows Mule event to be sent and
77   * received through the Spring ApplicationContext. This allows any Spring bean to
78   * receive and send events from any transport that Mule supports such as Jms, Http,
79   * Tcp, Pop3, Smtp, File, etc. All a bean needs to do to receive and send events is
80   * to implement MuleEventListener. Beans can also have subscriptions to certain
81   * events by implementing MuleSubscriptionEventListener, where the bean can provide a
82   * list of endpoints on which to receive events i.e. <code>
83   * &lt;bean id="myListener" class="com.foo.MyListener"&gt;
84   * &lt;property name="subscriptions"&gt;
85   * &lt;list&gt;
86   * &lt;value&gt;jms://customer.support&lt;/value&gt;
87   * &lt;value&gt;pop3://support:123456@mail.mycompany.com&lt;/value&gt;
88   * &lt;/list&gt;
89   * &lt;/property&gt;
90   * &lt;/bean&gt;
91   * </code>
92   * <p/> Endpoints are specified as a Mule Url which is used to register a listener
93   * for the subscription In the previous version of the MuleEventMulticaster it was
94   * possible to specify wildcard endpoints. This is still possible but you need to
95   * tell the multicaster which specific endpoints to listen on and then your
96   * subscription listeners can use wildcards. To register the specific endpoints on
97   * the MuleEvent Multicaster you use the <i>subscriptions</i> property. <p/> <code>
98   * &lt;bean id="applicationEventMulticaster" class="org.mule.module.spring.events.MuleEventMulticaster"&gt;
99   * &lt;property name="subscriptions"&gt;
100  * &lt;list&gt;
101  * &lt;value&gt;jms://orders.queue&lt;/value&gt;
102  * &lt;value&gt;jms://another.orders.queue&lt;/value&gt;
103  * &lt;/list&gt;
104  * &lt;/property&gt;
105  * &lt;/bean&gt;
106  * <p/>
107  * &lt;bean id="myListener" class="com.foo.MyListener"&gt;
108  * &lt;property name="subscriptions"&gt;
109  * &lt;list&gt;
110  * &lt;value&gt;jms://*.orders.*.&lt;/value&gt;
111  * &lt;/list&gt;
112  * &lt;/property&gt;
113  * &lt;/bean&gt;
114  * <p/>
115  * </code>
116  * 
117  * @see MuleEventListener
118  * @see MuleSubscriptionEventListener
119  * @see ApplicationEventMulticaster
120  */
121 public class MuleEventMulticaster
122     implements ApplicationEventMulticaster, ApplicationContextAware, MuleContextAware, Callable, Initialisable
123 {
124     public static final String EVENT_MULTICASTER_DESCRIPTOR_NAME = "muleEventMulticasterDescriptor";
125 
126     /**
127      * logger used by this class
128      */
129     protected static final Log logger = LogFactory.getLog(MuleEventMulticaster.class);
130 
131     /**
132      * The set of listeners for this Multicaster
133      */
134     protected final Set listeners = new CopyOnWriteArraySet();
135 
136     /**
137      * Determines whether events will be processed asynchronously
138      */
139     protected boolean asynchronous = false;
140 
141     /**
142      * An ExecutorService for handling asynchronous events
143      */
144     protected ExecutorService asyncPool = null;
145 
146     /**
147      * A list of endpoints the eventMulticaster will receive events on Note that if
148      * this eventMulticaster has a Mule Descriptor associated with it, these
149      * endpoints are ignored and the ones on the Mule Descriptor are used. These are
150      * here for convenience, the event multicaster will use these to create a default
151      * MuleDescriptor for itself at runtime
152      */
153     protected String[] subscriptions = null;
154 
155     /**
156      * The Spring acpplication context
157      */
158     protected ApplicationContext applicationContext;
159 
160     /**
161      * The mule instance compoennt for the Multicaster
162      */
163     protected Service service;
164 
165     /**
166      * The filter used to match subscriptions
167      */
168     protected Class subscriptionFilter = WildcardFilter.class;
169 
170     /**
171      * Used to store parsed endpoints
172      */
173     protected ExceptionListener exceptionListener = new LoggingExceptionListener();
174 
175     protected MuleContext muleContext;
176 
177     public void setMuleContext(MuleContext context)
178     {
179         this.muleContext = context;
180     }
181 
182     public void initialise() throws InitialisationException
183     {
184         if (asynchronous)
185         {
186             if (asyncPool == null)
187             {
188                 asyncPool = muleContext.getDefaultThreadingProfile().createPool("spring-events");
189             }
190         }
191         else
192         {
193             if (asyncPool != null)
194             {
195                 asyncPool.shutdown();
196                 asyncPool = null;
197             }
198         }
199     }
200 
201     /**
202      * Adds a listener to the the Multicaster. If asynchronous is set to true, an
203      * <code>AsynchronousMessageListener</code> is used to wrap the listener. This
204      * listener will be initialised with a threadpool. The configuration for the
205      * threadpool can be set on this multicaster or inherited from the MuleManager
206      * configuration, which is good for most cases.
207      * 
208      * @param listener the ApplicationListener to register with this Multicaster
209      * @see AsynchronousEventListener
210      * @see ThreadingProfile
211      */
212     public void addApplicationListener(ApplicationListener listener)
213     {
214         Object listenerToAdd = listener;
215 
216         if (asynchronous)
217         {
218             listenerToAdd = new AsynchronousEventListener(asyncPool, listener);
219         }
220 
221         listeners.add(listenerToAdd);
222     }
223 
224     /**
225      * Removes a listener from the multicaster
226      * 
227      * @param listener the listener to remove
228      */
229     public void removeApplicationListener(ApplicationListener listener)
230     {
231         for (Iterator iterator = listeners.iterator(); iterator.hasNext();)
232         {
233             ApplicationListener applicationListener = (ApplicationListener) iterator.next();
234             if (applicationListener instanceof AsynchronousEventListener)
235             {
236                 if (((AsynchronousEventListener) applicationListener).getListener().equals(listener))
237                 {
238                     listeners.remove(applicationListener);
239                     return;
240                 }
241             }
242             else
243             {
244                 if (applicationListener.equals(listener))
245                 {
246                     listeners.remove(applicationListener);
247                     return;
248                 }
249             }
250         }
251         listeners.remove(listener);
252     }
253 
254 
255     public void addApplicationListenerBean(String s)
256        {
257            Object listener = applicationContext.getBean(s);
258            if(listener instanceof ApplicationListener)
259            {
260                addApplicationListener((ApplicationListener)listener);
261            }
262            else
263            {
264                throw new IllegalArgumentException(SpringMessages.beanNotInstanceOfApplicationListener(s).getMessage());
265            }
266        }
267 
268        public void removeApplicationListenerBean(String s)
269        {
270            Object listener = applicationContext.getBean(s);
271            if(listener instanceof ApplicationListener)
272            {
273                removeApplicationListener((ApplicationListener)listener);
274            }
275            else
276            {
277                throw new IllegalArgumentException(SpringMessages.beanNotInstanceOfApplicationListener(s).getMessage());
278            }
279        }
280 
281     /**
282      * Removes all the listeners from the multicaster
283      */
284     public void removeAllListeners()
285     {
286         listeners.clear();
287     }
288 
289     /**
290      * Method is used to dispatch events to listeners registered with the
291      * EventManager or dispatches events to Mule depending on the type and state of
292      * the event received. If the event is not a Mule event it will be dispatched to
293      * any listeners registered that are NOT MuleEventListeners. If the event is a
294      * Mule event and there is no source event attached to it, it is assumed that the
295      * event was dispatched by an object in the context using context.publishEvent()
296      * and will be dispatched by Mule. If the event does have a source event attached
297      * to it, it is assumed that the event was dispatched by Mule and will be
298      * delivered to any listeners subscribed to the event.
299      * 
300      * @param e the application event received by the context
301      */
302     public void multicastEvent(ApplicationEvent e)
303     {
304         MuleApplicationEvent muleEvent = null;
305         // if the context gets refreshed we need to reinitialise
306         if (e instanceof ContextRefreshedEvent)
307         {
308             try
309             {
310                 registerMulticasterComponent();
311             }
312             catch (MuleException ex)
313             {
314                 throw new MuleRuntimeException(SpringMessages.failedToReinitMule(), ex);
315             }
316         }
317         else if (e instanceof ContextClosedEvent)
318         {
319             if (!muleContext.isDisposing() && !muleContext.isDisposed())
320             {
321                 muleContext.dispose();
322             }
323             return;
324         }
325         else if (e instanceof MuleApplicationEvent)
326         {
327             muleEvent = (MuleApplicationEvent) e;
328             // If there is no Mule event the event didn't originate from Mule
329             // so its an outbound event
330             if (muleEvent.getMuleEventContext() == null)
331             {
332                 try
333                 {
334                     dispatchEvent(muleEvent);
335                 }
336                 catch (ApplicationEventException e1)
337                 {
338                     exceptionListener.exceptionThrown(e1);
339                 }
340                 return;
341             }
342         }
343 
344         for (Iterator iterator = listeners.iterator(); iterator.hasNext();)
345         {
346             ApplicationListener listener = (ApplicationListener) iterator.next();
347             if (muleEvent != null)
348             {
349                 // As the asynchronous listener wraps the real listener we need
350                 // to check the type of the wrapped listener, but invoke the Async
351                 // listener
352                 if (listener instanceof AsynchronousEventListener)
353                 {
354                     AsynchronousEventListener asyncListener = (AsynchronousEventListener) listener;
355                     if (asyncListener.getListener() instanceof MuleSubscriptionEventListener)
356                     {
357                         if (isSubscriptionMatch(muleEvent.getEndpoint(),
358                             ((MuleSubscriptionEventListener) asyncListener.getListener()).getSubscriptions()))
359                         {
360                             asyncListener.onApplicationEvent(muleEvent);
361                         }
362                     }
363                     else if (asyncListener.getListener() instanceof MuleEventListener)
364                     {
365                         asyncListener.onApplicationEvent(muleEvent);
366                     }
367                     else if (!(asyncListener.getListener() instanceof MuleEventListener))
368                     {
369                         asyncListener.onApplicationEvent(e);
370                     }
371                     // Synchronous MuleEvent listener Checks
372                 }
373                 else if (listener instanceof MuleSubscriptionEventListener)
374                 {
375                     if (isSubscriptionMatch(muleEvent.getEndpoint(),
376                         ((MuleSubscriptionEventListener) listener).getSubscriptions()))
377                     {
378                         listener.onApplicationEvent(muleEvent);
379                     }
380                 }
381                 else if (listener instanceof MuleEventListener)
382                 {
383                     listener.onApplicationEvent(muleEvent);
384                 }
385             }
386             else if (listener instanceof AsynchronousEventListener
387                      && !(((AsynchronousEventListener) listener).getListener() instanceof MuleEventListener))
388             {
389                 listener.onApplicationEvent(e);
390             }
391             else if (!(listener instanceof MuleEventListener))
392             {
393                 listener.onApplicationEvent(e);
394             }
395             else
396             {
397                 // Finally only propagate the Application event if the
398                 // ApplicationEvent interface is explicitly implemented
399                 for (int i = 0; i < listener.getClass().getInterfaces().length; i++)
400                 {
401                     if (listener.getClass().getInterfaces()[i].equals(ApplicationListener.class))
402                     {
403                         listener.onApplicationEvent(e);
404                         break;
405                     }
406                 }
407 
408             }
409         }
410     }
411 
412     /**
413      * Matches a subscription to the current event endpointUri
414      * 
415      * @param endpoint endpoint
416      * @param subscriptions subscriptions
417      * @return true if there's a match
418      */
419     private boolean isSubscriptionMatch(String endpoint, String[] subscriptions)
420     {
421         for (int i = 0; i < subscriptions.length; i++)
422         {
423             String subscription = subscriptions[i];
424 
425             // Subscriptions can be full Mule Urls or resource specific such as
426             // my.queue
427             // if it is a MuleEndpointURI we need to extract the Resource
428             // specific part
429             // if (MuleEndpointURI.isMuleUri(subscription)) {
430             // EndpointURI ep = (EndpointURI) endpointsCache.get(subscription);
431             // if (ep == null) {
432             // try {
433             // ep = new MuleEndpointURI(subscription);
434             // } catch (MalformedEndpointException e) {
435             // throw new IllegalArgumentException(e.getMessage());
436             // }
437             // endpointsCache.put(subscription, ep);
438             // }
439             // subscription = ep.getAddress();
440             // }
441 
442             ObjectFilter filter = createFilter(subscription);
443             if (filter.accept(endpoint))
444             {
445                 return true;
446             }
447         }
448         return false;
449     }
450 
451     /**
452      * Determines whether events will be processed asynchronously
453      * 
454      * @return tru if asynchronous. The default is false
455      */
456     public boolean isAsynchronous()
457     {
458         return asynchronous;
459     }
460 
461     /**
462      * Determines whether events will be processed asynchronously
463      * 
464      * @param asynchronous true if aysnchronous
465      */
466     public void setAsynchronous(boolean asynchronous)
467     {
468         this.asynchronous = asynchronous;
469     }
470 
471     /**
472      * This is the callback method used by Mule to give Mule events to this
473      * Multicaster
474      * 
475      * @param context the context received by Mule
476      */
477     public Object onCall(MuleEventContext context) throws TransformerException, MalformedEndpointException
478     {
479         multicastEvent(new MuleApplicationEvent(context.getMessage().getPayload(), context, applicationContext));
480         context.setStopFurtherProcessing(true);
481         return null;
482     }
483 
484     /**
485      * Will dispatch an application event through Mule
486      * 
487      * @param applicationEvent the Spring event to be dispatched
488      * @throws ApplicationEventException if the event cannot be dispatched i.e. if
489      *             the underlying transport throws an exception
490      */
491     protected void dispatchEvent(MuleApplicationEvent applicationEvent) throws ApplicationEventException
492     {
493         OutboundEndpoint endpoint;
494         try
495         {
496             endpoint = muleContext.getRegistry().lookupEndpointFactory().getOutboundEndpoint(
497                 applicationEvent.getEndpoint());
498         }
499         catch (MuleException e)
500         {
501             throw new ApplicationEventException("Failed to get endpoint for endpointUri: "
502                                                 + applicationEvent.getEndpoint(), e);
503         }
504         if (endpoint != null)
505         {
506             try
507             {
508                 // if (applicationEvent.getEndpoint() != null) {
509                 // endpoint.setEndpointURI(applicationEvent.getEndpoint());
510                 // }
511 
512                 DefaultMuleMessage message = new DefaultMuleMessage(applicationEvent.getSource(),
513                     applicationEvent.getProperties(), muleContext);
514                 // has dispatch been triggered using beanFactory.publish()
515                 // without a current event
516                 if (applicationEvent.getMuleEventContext() != null)
517                 {
518                     // tell mule not to try and route this event itself
519                     applicationEvent.getMuleEventContext().setStopFurtherProcessing(true);
520                     applicationEvent.getMuleEventContext().dispatchEvent(message, endpoint);
521                 }
522                 else
523                 {
524                     MuleSession session = new DefaultMuleSession(service, muleContext);
525                     DefaultMuleEvent event = new DefaultMuleEvent(message, endpoint, session);
526                     RequestContext.setEvent(event);
527                     // transform if necessary
528                     if (endpoint.getTransformers() != null)
529                     {
530                         message = new DefaultMuleMessage(applicationEvent.getSource(),
531                             applicationEvent.getProperties(), muleContext);
532                         message.applyTransformers(event, endpoint.getTransformers());
533                     }
534                     endpoint.process(new DefaultMuleEvent(message, endpoint, session));
535                 }
536             }
537             catch (Exception e1)
538             {
539                 throw new ApplicationEventException("Failed to dispatch event: " + e1.getMessage(), e1);
540             }
541         }
542         else
543         {
544             throw new ApplicationEventException("Failed endpoint using name: "
545                                                 + applicationEvent.getEndpoint());
546         }
547     }
548 
549     /**
550      * Set the current Spring application context
551      * 
552      * @param applicationContext application context
553      * @throws BeansException
554      */
555     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
556     {
557         this.applicationContext = applicationContext;
558     }
559 
560     protected void registerMulticasterComponent() throws MuleException
561     {
562         // A discriptor hasn't been explicitly configured, so create a default
563         if (service == null)
564         {
565             service = getDefaultService();
566             setSubscriptionsOnService(service);
567             muleContext.getRegistry().registerService(service);
568         }
569     }
570 
571     protected void setSubscriptionsOnService(Service service) throws MuleException
572     {
573         String[] subscriptions;
574         List endpoints = new ArrayList();
575         for (Iterator iterator = listeners.iterator(); iterator.hasNext();)
576         {
577             ApplicationListener listener = (ApplicationListener) iterator.next();
578             if (listener instanceof AsynchronousEventListener)
579             {
580                 listener = ((AsynchronousEventListener) listener).getListener();
581             }
582             if (listener instanceof MuleSubscriptionEventListener)
583             {
584                 subscriptions = ((MuleSubscriptionEventListener) listener).getSubscriptions();
585                 for (int i = 0; i < subscriptions.length; i++)
586                 {
587                     if (subscriptions[i].indexOf("*") == -1 && MuleEndpointURI.isMuleUri(subscriptions[i]))
588                     {
589                         boolean isSoap = registerAsSoap(subscriptions[i], listener);
590 
591                         if (!isSoap)
592                         {
593                             endpoints.add(subscriptions[i]);
594                         }
595                     }
596                 }
597             }
598         }
599         if (endpoints.size() > 0)
600         {
601             String endpoint;
602             for (Iterator iterator = endpoints.iterator(); iterator.hasNext();)
603             {
604                 endpoint = (String) iterator.next();
605 
606                 InboundEndpoint ep = muleContext.getRegistry().lookupEndpointFactory().getInboundEndpoint(
607                     endpoint);
608 
609                 // check whether the endpoint has already been set on the
610                 // MuleEventMulticastor
611                 if (((ServiceCompositeMessageSource) service.getMessageSource()).getEndpoint(ep.getName()) == null)
612                 {
613                     ((ServiceCompositeMessageSource) service.getMessageSource()).addSource(ep);
614                 }
615             }
616         }
617     }
618 
619     private boolean registerAsSoap(String endpoint, Object listener) throws MuleException
620     {
621         if (endpoint.startsWith("soap") || endpoint.startsWith("axis") || endpoint.startsWith("cxf"))
622         {
623             EndpointURI ep = new MuleEndpointURI(endpoint, muleContext);
624 
625             // get the service name from the URI path
626             String serviceName = null;
627             if (ep.getPath() != null)
628             {
629                 String path = ep.getPath();
630                 if (path.endsWith("/"))
631                 {
632                     path = path.substring(0, path.length() - 1);
633                 }
634                 int i = path.lastIndexOf("/");
635                 if (i > -1)
636                 {
637                     serviceName = path.substring(i + 1);
638                 }
639             }
640             else
641             {
642                 serviceName = service.getName();
643             }
644             // now strip off the service name
645             String newEndpoint = endpoint;
646             int i = newEndpoint.indexOf(serviceName);
647             newEndpoint = newEndpoint.substring(0, i - 1);
648             SedaService s = new SedaService(muleContext);
649             s.setName(serviceName);
650             s.setModel(muleContext.getRegistry().lookupSystemModel());
651             s.setQueueProfile(new QueueProfile());
652             ((CompositeMessageSource) s.getMessageSource()).addSource(
653                 muleContext.getRegistry().lookupEndpointFactory().getInboundEndpoint(newEndpoint));
654             s.setComponent(new DefaultJavaComponent(new SingletonObjectFactory(listener)));
655             muleContext.getRegistry().registerService(s);
656             return true;
657         }
658         else
659         {
660             return false;
661         }
662     }
663 
664     protected void registerConnectors() throws MuleException
665     {
666         if (!muleContext.isInitialised())
667         {
668             // Next see if there are any Connectors to register
669             Map connectors = applicationContext.getBeansOfType(Connector.class, true, true);
670             if (connectors.size() > 0)
671             {
672                 Map.Entry entry;
673                 Connector c;
674                 for (Iterator iterator = connectors.entrySet().iterator(); iterator.hasNext();)
675                 {
676                     entry = (Map.Entry) iterator.next();
677                     c = (Connector) entry.getValue();
678                     if (c.getName() == null)
679                     {
680                         c.setName(entry.getKey().toString());
681                     }
682                     muleContext.getRegistry().registerConnector(c);
683                 }
684             }
685         }
686     }
687 
688     protected void registerTransformers() throws MuleException
689     {
690         if (!muleContext.isInitialised())
691         {
692             // Next see if there are any Connectors to register
693             Map transformers = applicationContext.getBeansOfType(Transformer.class, true, true);
694             if (transformers.size() > 0)
695             {
696                 Map.Entry entry;
697                 Transformer t;
698                 for (Iterator iterator = transformers.entrySet().iterator(); iterator.hasNext();)
699                 {
700                     entry = (Map.Entry) iterator.next();
701                     t = (Transformer) entry.getValue();
702                     if (t.getName() == null)
703                     {
704                         t.setName(entry.getKey().toString());
705                     }
706                     muleContext.getRegistry().registerTransformer(t);
707                 }
708             }
709         }
710     }
711 
712     protected Service getDefaultService() throws MuleException
713     {
714         // When the the beanFactory is refreshed all the beans get
715         // reloaded so we need to unregister the service from Mule
716         Model model = muleContext.getRegistry().lookupModel(MuleProperties.OBJECT_SYSTEM_MODEL);
717         if (model == null)
718         {
719             model = new SedaModel();
720             model.setName(MuleProperties.OBJECT_SYSTEM_MODEL);
721             muleContext.getRegistry().registerModel(model);
722         }
723         Service service = muleContext.getRegistry().lookupService(EVENT_MULTICASTER_DESCRIPTOR_NAME);
724         if (service != null)
725         {
726             muleContext.getRegistry().unregisterService(service.getName());
727         }
728         service = new SedaService(muleContext);
729         service.setName(EVENT_MULTICASTER_DESCRIPTOR_NAME);
730         service.setModel(model);
731         if (subscriptions == null)
732         {
733             logger.info("No receive endpoints have been set, using default '*'");
734             ((CompositeMessageSource) service.getMessageSource()).addSource(
735                 muleContext.getRegistry().lookupEndpointFactory().getInboundEndpoint("vm://*"));
736         }
737         else
738         {
739             // Set multiple inbound subscriptions on the descriptor
740             ServiceCompositeMessageSource messageRouter = (ServiceCompositeMessageSource) service.getMessageSource();
741 
742             for (int i = 0; i < subscriptions.length; i++)
743             {
744                 String subscription = subscriptions[i];
745 
746                 EndpointFactory endpointFactory = muleContext.getRegistry().lookupEndpointFactory();
747                 EndpointBuilder endpointBuilder = endpointFactory.getEndpointBuilder(subscription);
748                 endpointBuilder.setExchangePattern(MessageExchangePattern.fromSyncFlag(!asynchronous));
749                 InboundEndpoint endpoint = endpointFactory.getInboundEndpoint(endpointBuilder);
750 
751                 messageRouter.addSource(endpoint);
752             }
753         }
754         DefaultJavaComponent component = new DefaultJavaComponent(new SingletonObjectFactory(this));
755         component.setMuleContext(muleContext);
756         service.setComponent(component);
757         return service;
758     }
759 
760     protected ObjectFilter createFilter(String pattern)
761     {
762         try
763         {
764             if (getSubscriptionFilter() == null)
765             {
766                 setSubscriptionFilter(WildcardFilter.class);
767             }
768             return (ObjectFilter) ClassUtils.instanciateClass(getSubscriptionFilter(), pattern);
769         }
770         catch (Exception e)
771         {
772             exceptionListener.exceptionThrown(e);
773             return new WildcardFilter(pattern);
774         }
775     }
776 
777     /**
778      * the type of filter used to filter subscriptions
779      * 
780      * @return the class of the filter to use. The default is WildcardFilter
781      * @see WildcardFilter
782      */
783     public Class getSubscriptionFilter()
784     {
785         return subscriptionFilter;
786     }
787 
788     /**
789      * sets the type of filter used to filter subscriptions
790      * 
791      * @param subscriptionFilter the class of the filter to use.
792      */
793     public void setSubscriptionFilter(Class subscriptionFilter)
794     {
795         this.subscriptionFilter = subscriptionFilter;
796     }
797 
798     /**
799      * A list of endpoints the eventMulticaster will receive events on Note that if
800      * this eventMulticaster has a Mule Descriptor associated with it, these
801      * endpoints are ignored and the ones on the Mule Descriptor are used. These are
802      * here for convenience, the event multicaster will use these to create a default
803      * MuleDescriptor for itself at runtime
804      * 
805      * @return endpoints List being listened on
806      */
807     public String[] getSubscriptions()
808     {
809         return subscriptions;
810     }
811 
812     /**
813      * A list of endpoints the eventMulticaster will receive events on Note that if
814      * this eventMulticaster has a Mule Descriptor associated with it, these
815      * endpoints are ignored and the ones on the Mule Descriptor are used. These are
816      * here for convenience, the event multicaster will use these to create a default
817      * MuleDescriptor for itself at runtime
818      * 
819      * @param subscriptions a list of enpoints to listen on
820      */
821     public void setSubscriptions(String[] subscriptions)
822     {
823         this.subscriptions = subscriptions;
824     }
825 
826     protected void setExceptionListener(ExceptionListener listener)
827     {
828         if (listener != null)
829         {
830             this.exceptionListener = listener;
831         }
832         else
833         {
834             throw new IllegalArgumentException("exceptionListener may not be null");
835         }
836     }
837 
838     private static class LoggingExceptionListener implements ExceptionListener
839     {
840         public LoggingExceptionListener()
841         {
842             super();
843         }
844         
845         public void exceptionThrown(Exception e)
846         {
847             logger.error(e.getMessage(), e);
848         }
849     }
850 }