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