View Javadoc

1   /*
2    * $Id: MuleXmlConfigurationBuilder.java 8039 2007-08-24 08:44:53Z dirk.olmes $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.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.config.builders;
12  
13  import org.mule.MuleManager;
14  import org.mule.config.ConfigurationBuilder;
15  import org.mule.config.ConfigurationException;
16  import org.mule.config.MuleConfiguration;
17  import org.mule.config.MuleDtdResolver;
18  import org.mule.config.MuleProperties;
19  import org.mule.config.PoolingProfile;
20  import org.mule.config.QueueProfile;
21  import org.mule.config.ReaderResource;
22  import org.mule.config.ThreadingProfile;
23  import org.mule.config.converters.ConnectorConverter;
24  import org.mule.config.converters.EndpointConverter;
25  import org.mule.config.converters.EndpointURIConverter;
26  import org.mule.config.converters.TransactionFactoryConverter;
27  import org.mule.config.converters.TransformerConverter;
28  import org.mule.config.i18n.CoreMessages;
29  import org.mule.config.pool.CommonsPoolFactory;
30  import org.mule.impl.DefaultLifecycleAdapter;
31  import org.mule.impl.MuleDescriptor;
32  import org.mule.impl.MuleTransactionConfig;
33  import org.mule.impl.endpoint.MuleEndpoint;
34  import org.mule.impl.model.ModelFactory;
35  import org.mule.impl.model.resolvers.DynamicEntryPointResolver;
36  import org.mule.impl.security.MuleSecurityManager;
37  import org.mule.interceptors.InterceptorStack;
38  import org.mule.providers.AbstractConnector;
39  import org.mule.providers.ConnectionStrategy;
40  import org.mule.routing.LoggingCatchAllStrategy;
41  import org.mule.routing.inbound.InboundRouterCollection;
42  import org.mule.routing.nested.NestedRouter;
43  import org.mule.routing.nested.NestedRouterCollection;
44  import org.mule.routing.outbound.OutboundRouterCollection;
45  import org.mule.routing.response.ResponseRouterCollection;
46  import org.mule.transaction.constraints.BatchConstraint;
47  import org.mule.umo.UMODescriptor;
48  import org.mule.umo.UMOEncryptionStrategy;
49  import org.mule.umo.UMOInterceptor;
50  import org.mule.umo.UMOInterceptorStack;
51  import org.mule.umo.UMOTransactionFactory;
52  import org.mule.umo.endpoint.UMOEndpoint;
53  import org.mule.umo.endpoint.UMOEndpointURI;
54  import org.mule.umo.lifecycle.InitialisationException;
55  import org.mule.umo.manager.ContainerException;
56  import org.mule.umo.manager.UMOAgent;
57  import org.mule.umo.manager.UMOContainerContext;
58  import org.mule.umo.manager.UMOManager;
59  import org.mule.umo.manager.UMOTransactionManagerFactory;
60  import org.mule.umo.model.UMOModel;
61  import org.mule.umo.provider.UMOConnector;
62  import org.mule.umo.routing.UMOInboundRouterCollection;
63  import org.mule.umo.routing.UMONestedRouterCollection;
64  import org.mule.umo.routing.UMOOutboundRouter;
65  import org.mule.umo.routing.UMOOutboundRouterCollection;
66  import org.mule.umo.routing.UMOResponseRouterCollection;
67  import org.mule.umo.security.UMOEndpointSecurityFilter;
68  import org.mule.umo.security.UMOSecurityManager;
69  import org.mule.umo.security.UMOSecurityProvider;
70  import org.mule.umo.transformer.UMOTransformer;
71  import org.mule.util.ArrayUtils;
72  import org.mule.util.ClassUtils;
73  import org.mule.util.IOUtils;
74  import org.mule.util.PropertiesUtils;
75  import org.mule.util.StringUtils;
76  import org.mule.util.queue.EventFilePersistenceStrategy;
77  
78  import java.beans.ExceptionListener;
79  import java.io.IOException;
80  import java.io.InputStream;
81  import java.io.InputStreamReader;
82  import java.util.ArrayList;
83  import java.util.HashMap;
84  import java.util.Iterator;
85  import java.util.List;
86  import java.util.Map;
87  import java.util.Properties;
88  
89  import org.apache.commons.beanutils.ConvertUtils;
90  import org.apache.commons.digester.AbstractObjectCreationFactory;
91  import org.apache.commons.digester.Digester;
92  import org.apache.commons.digester.ObjectCreateRule;
93  import org.apache.commons.digester.Rule;
94  import org.apache.commons.digester.SetNextRule;
95  import org.apache.commons.digester.SetPropertiesRule;
96  import org.xml.sax.Attributes;
97  
98  /**
99   * <code>MuleXmlConfigurationBuilder</code> is a configuration parser that builds a
100  * MuleManager instance based on a mule xml configration file defined in the
101  * mule-configuration.dtd.
102  */
103 public class MuleXmlConfigurationBuilder extends AbstractDigesterConfiguration
104     implements ConfigurationBuilder
105 {
106     public static final String DEFAULT_ENTRY_POINT_RESOLVER = DynamicEntryPointResolver.class.getName();
107     public static final String DEFAULT_LIFECYCLE_ADAPTER = DefaultLifecycleAdapter.class.getName();
108     public static final String DEFAULT_ENDPOINT = MuleEndpoint.class.getName();
109     public static final String DEFAULT_TRANSACTION_CONFIG = MuleTransactionConfig.class.getName();
110     public static final String DEFAULT_DESCRIPTOR = MuleDescriptor.class.getName();
111     public static final String DEFAULT_SECURITY_MANAGER = MuleSecurityManager.class.getName();
112     public static final String DEFAULT_OUTBOUND_ROUTER_COLLECTION = OutboundRouterCollection.class.getName();
113     public static final String DEFAULT_INBOUND_ROUTER_COLLECTION = InboundRouterCollection.class.getName();
114     public static final String DEFAULT_NESTED_ROUTER_COLLECTION = NestedRouterCollection.class.getName();
115     public static final String DEFAULT_RESPONSE_ROUTER_COLLECTION = ResponseRouterCollection.class.getName();
116     public static final String DEFAULT_NESTED_ROUTER = NestedRouter.class.getName();
117     public static final String DEFAULT_CATCH_ALL_STRATEGY = LoggingCatchAllStrategy.class.getName();
118     public static final String DEFAULT_POOL_FACTORY = CommonsPoolFactory.class.getName();
119     public static final String THREADING_PROFILE = ThreadingProfile.class.getName();
120     public static final String POOLING_PROFILE = PoolingProfile.class.getName();
121     public static final String QUEUE_PROFILE = QueueProfile.class.getName();
122 
123     public static final String PERSISTENCE_STRATEGY_INTERFACE = EventFilePersistenceStrategy.class.getName();
124     public static final String INBOUND_MESSAGE_ROUTER_INTERFACE = UMOInboundRouterCollection.class.getName();
125     public static final String NESTED_MESSAGE_ROUTER_INTERFACE = UMONestedRouterCollection.class.getName();
126     public static final String RESPONSE_MESSAGE_ROUTER_INTERFACE = UMOResponseRouterCollection.class.getName();
127     public static final String OUTBOUND_MESSAGE_ROUTER_INTERFACE = UMOOutboundRouterCollection.class.getName();
128     public static final String TRANSFORMER_INTERFACE = UMOTransformer.class.getName();
129     public static final String TRANSACTION_MANAGER_FACTORY_INTERFACE = UMOTransactionManagerFactory.class.getName();
130     public static final String SECURITY_PROVIDER_INTERFACE = UMOSecurityProvider.class.getName();
131     public static final String ENCRYPTION_STRATEGY_INTERFACE = UMOEncryptionStrategy.class.getName();
132     public static final String ENDPOINT_SECURITY_FILTER_INTERFACE = UMOEndpointSecurityFilter.class.getName();
133     public static final String AGENT_INTERFACE = UMOAgent.class.getName();
134     public static final String TRANSACTION_FACTORY_INTERFACE = UMOTransactionFactory.class.getName();
135     public static final String TRANSACTION_CONSTRAINT_INTERFACE = BatchConstraint.class.getName();
136     public static final String CONNECTOR_INTERFACE = UMOConnector.class.getName();
137     public static final String INTERCEPTOR_INTERFACE = UMOInterceptor.class.getName();
138     public static final String ROUTER_INTERFACE = UMOOutboundRouter.class.getName();
139     public static final String EXCEPTION_STRATEGY_INTERFACE = ExceptionListener.class.getName();
140     public static final String CONNECTION_STRATEGY_INTERFACE = ConnectionStrategy.class.getName();
141 
142     protected UMOManager manager;
143 
144     private final List transformerReferences = new ArrayList();
145     private final List endpointReferences = new ArrayList();
146 
147     public MuleXmlConfigurationBuilder() throws ConfigurationException
148     {
149         super(System.getProperty(MuleProperties.XML_VALIDATE_SYSTEM_PROPERTY, "true")
150             .equalsIgnoreCase("true"), System.getProperty(MuleProperties.XML_DTD_SYSTEM_PROPERTY,
151             MuleDtdResolver.DEFAULT_MULE_DTD));
152 
153         ConvertUtils.register(new EndpointConverter(), UMOEndpoint.class);
154         ConvertUtils.register(new TransformerConverter(), UMOTransformer.class);
155         ConvertUtils.register(new ConnectorConverter(), UMOConnector.class);
156         ConvertUtils.register(new TransactionFactoryConverter(), UMOTransactionFactory.class);
157         ConvertUtils.register(new EndpointURIConverter(), UMOEndpointURI.class);
158 
159         String path = getRootName();
160         addManagerRules(digester, path);
161         addServerPropertiesRules(path + "/environment-properties", "addProperties", 0);
162         addContainerContextRules(path + "/container-context", "setContainerContext", 0);
163 
164         addMuleConfigurationRules(digester, path);
165         addTransformerRules(digester, path);
166         addSecurityManagerRules(digester, path);
167         addTransactionManagerRules(digester, path);
168         addGlobalEndpointRules(digester, path);
169         addEndpointIdentifierRules(digester, path);
170         addInterceptorStackRules(digester, path);
171         addConnectorRules(digester, path);
172         addAgentRules(digester, path);
173 
174         addModelRules(digester, path);
175         // These rules allow for individual component configurations
176         //RM* this is no longer required since Mule supports Multiple models and can inherit existing models.
177         // This means that every mule-descriptor should be wrapped with a model element if its a stand alone
178         //component config
179         //addMuleDescriptorRules(digester, path);
180     }
181 
182     public String getRootName()
183     {
184         return "mule-configuration";
185     }
186 
187     public UMOManager configure(String configResources) throws ConfigurationException
188     {
189         return configure(configResources, null);
190     }
191 
192     public UMOManager configure(String configResources, String startupPropertiesFile)
193         throws ConfigurationException
194     {
195         try
196         {
197             String[] resources = StringUtils.splitAndTrim(configResources, ",");
198             if (logger.isDebugEnabled())
199             {
200                 logger.debug("There is/are " + resources.length + " configuration resource(s): " + ArrayUtils.toString(resources));
201             }
202             MuleManager.getConfiguration().setConfigResources(resources);
203             ReaderResource[] readers = new ReaderResource[resources.length];
204             String resource; 
205             for (int i = 0; i < resources.length; i++)
206             {
207                 resource = resources[i];
208                 readers[i] = new ReaderResource(resource, 
209                                             new InputStreamReader(loadResource(resource), configEncoding));
210             }
211 
212             // Load startup properties if any.
213             if (startupPropertiesFile != null)
214             {
215                 return configure(readers, PropertiesUtils.loadProperties(startupPropertiesFile, getClass()));
216             }
217             else
218                 return configure(readers, null);
219 
220         }
221         catch (Exception e)
222         {
223             throw new ConfigurationException(e);
224         }
225     }
226 
227     /**
228      * Override this method to provide alternative ways of loading a resource.
229      */
230     protected InputStream loadResource(String configResource) throws ConfigurationException
231     {
232         try
233         {
234             InputStream input = IOUtils.getResourceAsStream(configResource, getClass());
235             if (input == null)
236             {
237                 throw new ConfigurationException(CoreMessages.cannotLoadFromClasspath(configResource));
238             }
239             return input;
240         }
241         catch (IOException e)
242         {
243             throw new ConfigurationException(CoreMessages.cannotLoadFromClasspath(configResource), e);
244         }
245     }
246     
247     /**
248      * @deprecated Please use configure(ReaderResource[] configResources, Properties
249      *             startupProperties) instead.
250      */
251     public UMOManager configure(ReaderResource[] configResources) throws ConfigurationException
252     {
253         return configure(configResources, null);
254     }
255 
256     public UMOManager configure(ReaderResource[] configResources, Properties startupProperties)
257         throws ConfigurationException
258     {
259         if (startupProperties != null)
260         {
261             ((MuleManager)MuleManager.getInstance()).addProperties(startupProperties);
262         }
263         // Parse the config files with the Digester.
264         manager = (MuleManager)process(configResources);
265         if (manager == null)
266         {
267             throw new ConfigurationException(
268                 CoreMessages.failedToCreateManagerInstance("Are you using a correct configuration builder?"));
269         }
270         try
271         {
272             setContainerProperties();
273             setTransformers();
274             setGlobalEndpoints();
275             if (System.getProperty(MuleProperties.MULE_START_AFTER_CONFIG_SYSTEM_PROPERTY, "true")
276                 .equalsIgnoreCase("true"))
277             {
278                 manager.start();
279             }
280         }
281         catch (Exception e)
282         {
283             throw new ConfigurationException(CoreMessages.objectFailedToInitialise("MuleManager"), e);
284         }
285         return manager;
286     }
287 
288     /**
289      * Indicate whether this ConfigurationBulder has been configured yet
290      *
291      * @return <code>true</code> if this ConfigurationBulder has been configured
292      */
293     public boolean isConfigured()
294     {
295         return manager != null;
296     }
297 
298     protected void setContainerProperties() throws ContainerException
299     {
300         UMOContainerContext ctx = manager.getContainerContext();
301         try
302         {
303             for (Iterator iterator = containerReferences.iterator(); iterator.hasNext();)
304             {
305                 ContainerReference reference = (ContainerReference)iterator.next();
306                 reference.resolveReference(ctx);
307             }
308         }
309         finally
310         {
311             containerReferences.clear();
312         }
313     }
314 
315     protected void setTransformers() throws InitialisationException
316     {
317         try
318         {
319             for (Iterator iterator = transformerReferences.iterator(); iterator.hasNext();)
320             {
321                 TransformerReference reference = (TransformerReference)iterator.next();
322                 reference.resolveTransformer();
323             }
324         }
325         finally
326         {
327             transformerReferences.clear();
328         }
329     }
330 
331     protected void setGlobalEndpoints() throws InitialisationException
332     {
333         // because Mule Xml allows developers to overload global endpoints
334         // we need a way to initialise Global endpoints after the Xml has
335         // been processed but before the MuleManager is initialised. So we do
336         // it here.
337         UMOManager manager = MuleManager.getInstance();
338 
339         // we need to take a copy of the endpoints since we're going to modify them
340         // while iterating
341         Map endpoints = new HashMap(manager.getEndpoints());
342         for (Iterator iterator = endpoints.values().iterator(); iterator.hasNext();)
343         {
344             UMOEndpoint ep = (UMOEndpoint)iterator.next();
345             ep.initialise();
346             manager.unregisterEndpoint(ep.getName());
347             manager.registerEndpoint(ep);
348         }
349 
350         try
351         {
352             for (Iterator iterator = endpointReferences.iterator(); iterator.hasNext();)
353             {
354                 EndpointReference reference = (EndpointReference)iterator.next();
355                 reference.resolveEndpoint();
356             }
357         }
358         finally
359         {
360             endpointReferences.clear();
361         }
362     }
363 
364     protected void addManagerRules(Digester digester, String path)
365     {
366         digester.addFactoryCreate(path, new AbstractObjectCreationFactory()
367         {
368             public Object createObject(Attributes attributes) throws Exception
369             {
370                 manager = MuleManager.getInstance();
371                 return manager;
372             }
373         });
374         digester.addSetProperties(path);
375     }
376 
377     protected void addMuleConfigurationRules(Digester digester, String path)
378     {
379         digester.addSetProperties(path);
380         // Create mule system properties and defaults
381         path += "/mule-environment-properties";
382         digester.addObjectCreate(path, MuleConfiguration.class);
383         addSetPropertiesRule(path, digester);
384 
385         // Add pooling profile rules
386         addPoolingProfileRules(digester, path);
387 
388         // Add Queue Profile rules
389         addQueueProfileRules(digester, path);
390 
391         // set threading profile
392         digester.addObjectCreate(path + "/threading-profile", THREADING_PROFILE);
393         SetPropertiesRule threadingRule = new SetPropertiesRule();
394         threadingRule.addAlias("poolExhaustedAction", "poolExhaustedActionString");
395         digester.addRule(path + "/threading-profile", threadingRule);
396         digester.addRule(path + "/threading-profile", new Rule()
397         {
398             private String id;
399 
400             public void begin(String s, String s1, Attributes attributes) throws Exception
401             {
402                 id = attributes.getValue("id");
403             }
404 
405             public void end(String s, String s1) throws Exception
406             {
407                 ThreadingProfile tp = (ThreadingProfile)digester.peek();
408                 MuleConfiguration cfg = (MuleConfiguration)digester.peek(1);
409 
410                 if ("default".equals(id))
411                 {
412                     cfg.setDefaultThreadingProfile(tp);
413                     cfg.setMessageDispatcherThreadingProfile(tp);
414                     cfg.setMessageReceiverThreadingProfile(tp);
415                     cfg.setComponentThreadingProfile(tp);
416                 }
417                 else if ("messageReceiver".equals(id) || "receiver".equals(id))
418                 {
419                     cfg.setMessageReceiverThreadingProfile(tp);
420                 }
421                 else if ("messageDispatcher".equals(id) || "dispatcher".equals(id))
422                 {
423                     cfg.setMessageDispatcherThreadingProfile(tp);
424                 }
425                 else if ("component".equals(id))
426                 {
427                     cfg.setComponentThreadingProfile(tp);
428                 }
429             }
430         });
431 
432         // add persistence strategy
433         digester.addObjectCreate(path + "/persistence-strategy", PERSISTENCE_STRATEGY_INTERFACE, "className");
434         addMulePropertiesRule(path + "/persistence-strategy", digester);
435         digester.addSetNext(path + "/persistence-strategy", "setPersistenceStrategy");
436 
437         // Connection strategy
438         digester.addObjectCreate(path + "/connection-strategy", CONNECTION_STRATEGY_INTERFACE, "className");
439         addMulePropertiesRule(path + "/connection-strategy", digester);
440         // digester.addSetNext(path + "/connection-strategy",
441         // "setConnectionStrategy");
442         digester.addRule(path + "/connection-strategy", new SetNextRule("setConnectionStrategy")
443         {
444             public void end(String s, String s1) throws Exception
445             {
446                 super.end(s, s1);
447             }
448         });
449 
450         digester.addRule(path, new Rule()
451         {
452             public void end(String s, String s1) throws Exception
453             {
454                 MuleManager.setConfiguration((MuleConfiguration)digester.peek());
455             }
456         });
457     }
458 
459     protected void addSecurityManagerRules(Digester digester, String path) throws ConfigurationException
460     {
461         // Create container Context
462         path += "/security-manager";
463         addObjectCreateOrGetFromContainer(path, DEFAULT_SECURITY_MANAGER, "className", "ref", false);
464 
465         // Add propviders
466         digester.addObjectCreate(path + "/security-provider", SECURITY_PROVIDER_INTERFACE, "className");
467         addSetPropertiesRule(path + "/security-provider", digester);
468         addMulePropertiesRule(path + "/security-provider", digester);
469         digester.addSetNext(path + "/security-provider", "addProvider");
470 
471         // Add encryption strategies
472         digester.addObjectCreate(path + "/encryption-strategy", ENCRYPTION_STRATEGY_INTERFACE, "className");
473         addSetPropertiesRule(path + "/encryption-strategy", digester);
474         addMulePropertiesRule(path + "/encryption-strategy", digester);
475         digester.addRule(path + "/encryption-strategy", new Rule()
476         {
477             private String name;
478 
479             public void begin(String endpointName, String endpointName1, Attributes attributes)
480                 throws Exception
481             {
482                 name = attributes.getValue("name");
483             }
484 
485             public void end(String endpointName, String endpointName1) throws Exception
486             {
487                 UMOEncryptionStrategy s = (UMOEncryptionStrategy)digester.peek();
488                 ((UMOSecurityManager)digester.peek(1)).addEncryptionStrategy(name, s);
489             }
490         });
491         digester.addSetNext(path, "setSecurityManager");
492 
493     }
494 
495     protected void addTransformerRules(Digester digester, String path) throws ConfigurationException
496     {
497         // Create Transformers
498         path += "/transformers/transformer";
499         addObjectCreateOrGetFromContainer(path, TRANSFORMER_INTERFACE, "className", "ref", true);
500 
501         addSetPropertiesRule(path, digester);
502 
503         addMulePropertiesRule(path, digester);
504         digester.addSetRoot(path, "registerTransformer");
505     }
506 
507     protected void addGlobalEndpointRules(Digester digester, String path) throws ConfigurationException
508     {
509         // Create global message endpoints
510         path += "/global-endpoints";
511         addEndpointRules(digester, path, "registerEndpoint");
512     }
513 
514     protected void addEndpointIdentifierRules(Digester digester, String path) throws ConfigurationException
515     {
516         // Create and reqister endpoints
517         path += "/endpoint-identifiers/endpoint-identifier";
518         digester.addRule(path, new Rule()
519         {
520             private PlaceholderProcessor processor = new PlaceholderProcessor();
521 
522             public void begin(String s, String s1, Attributes attributes) throws Exception
523             {
524                 attributes = processor.processAttributes(attributes, s1);
525                 String name = attributes.getValue("name");
526                 String value = attributes.getValue("value");
527                 ((UMOManager)digester.getRoot()).registerEndpointIdentifier(name, value);
528             }
529         });
530     }
531 
532     protected void addTransactionManagerRules(Digester digester, String path) throws ConfigurationException
533     {
534         // Create transactionManager
535         path += "/transaction-manager";
536         addObjectCreateOrGetFromContainer(path, TRANSACTION_MANAGER_FACTORY_INTERFACE, "factory", "ref", true);
537         addMulePropertiesRule(path, digester);
538 
539         digester.addSetRoot(path, "setTransactionManager");
540         digester.addRule(path, new Rule()
541         {
542             public void end(String s, String s1) throws Exception
543             {
544                 UMOTransactionManagerFactory txFactory = (UMOTransactionManagerFactory)digester.pop();
545                 digester.push(txFactory.create());
546             }
547         });
548     }
549 
550     protected void addAgentRules(Digester digester, String path) throws ConfigurationException
551     {
552         // Create Agents
553         path += "/agents/agent";
554         addObjectCreateOrGetFromContainer(path, AGENT_INTERFACE, "className", "ref", true);
555         addSetPropertiesRule(path, digester);
556 
557         addMulePropertiesRule(path, digester);
558 
559         digester.addSetRoot(path, "registerAgent");
560     }
561 
562     protected void addConnectorRules(Digester digester, String path) throws ConfigurationException
563     {
564         // Create connectors
565         path += "/connector";
566         addObjectCreateOrGetFromContainer(path, CONNECTOR_INTERFACE, "className", "ref", true);
567 
568         addSetPropertiesRule(path, digester);
569 
570         addMulePropertiesRule(path, digester);
571 
572         digester.addRule(path + "/threading-profile", new Rule()
573         {
574             private String id;
575 
576             public void begin(String s, String s1, Attributes attributes) throws Exception
577             {
578                 // use the global tp as a template
579                 MuleConfiguration cfg = MuleManager.getConfiguration();
580                 id = attributes.getValue("id");
581                 if ("default".equals(id))
582                 {
583                     digester.push(cfg.getDefaultThreadingProfile());
584                 }
585                 else if ("receiver".equals(id))
586                 {
587                     digester.push(cfg.getMessageReceiverThreadingProfile());
588                 }
589                 else if ("dispatcher".equals(id))
590                 {
591                     digester.push(cfg.getMessageDispatcherThreadingProfile());
592                 }
593 
594             }
595 
596             public void end(String s, String s1) throws Exception
597             {
598                 ThreadingProfile tp = (ThreadingProfile)digester.pop();
599                 AbstractConnector cnn = (AbstractConnector)digester.peek();
600 
601                 if ("default".equals(id))
602                 {
603                     cnn.setReceiverThreadingProfile(tp);
604                     cnn.setDispatcherThreadingProfile(tp);
605                 }
606                 else if ("receiver".equals(id))
607                 {
608                     cnn.setReceiverThreadingProfile(tp);
609                 }
610                 else if ("dispatcher".equals(id))
611                 {
612                     cnn.setDispatcherThreadingProfile(tp);
613                 }
614             }
615         });
616 
617         SetPropertiesRule threadingRule = new SetPropertiesRule();
618         threadingRule.addAlias("setPoolExhaustedAction", "setPoolExhaustedActionString");
619         digester.addRule(path + "/threading-profile", threadingRule);
620 
621         // Connection strategy
622         digester.addObjectCreate(path + "/connection-strategy", CONNECTION_STRATEGY_INTERFACE, "className");
623         addMulePropertiesRule(path + "/connection-strategy", digester);
624         digester.addSetNext(path + "/connection-strategy", "setConnectionStrategy");
625 
626         addExceptionStrategyRules(digester, path);
627 
628         // register conntector
629         digester.addSetRoot(path, "registerConnector");
630     }
631 
632     protected void addInterceptorStackRules(Digester digester, String path) throws ConfigurationException
633     {
634         // Create Inteceptor stacks
635         path += "/interceptor-stack";
636         digester.addRule(path + "/interceptor", new ObjectCreateRule(INTERCEPTOR_INTERFACE, "className")
637         {
638             public void end(String s, String s1) throws Exception
639             {
640                 /* do not pop the result */
641             }
642         });
643 
644         digester.addRule(path, new Rule()
645         {
646             public void begin(String s, String s1, Attributes attributes) throws Exception
647             {
648                 digester.push(attributes.getValue("name"));
649             }
650 
651             public void end(String s, String s1) throws Exception
652             {
653                 List list = new ArrayList();
654                 Object obj = digester.peek();
655                 while (obj instanceof UMOInterceptor)
656                 {
657                     list.add(0, digester.pop());
658                     obj = digester.peek();
659                 }
660                 InterceptorStack stack = new InterceptorStack();
661                 stack.setInterceptors(list);
662                 manager.registerInterceptorStack(digester.pop().toString(), stack);
663             }
664         });
665 
666         addMulePropertiesRule(path + "/interceptor", digester);
667     }
668 
669     protected void addModelRules(Digester digester, String path) throws ConfigurationException
670     {
671         // Create Model
672         path += "/model";
673 
674         digester.addRule(path, new Rule()
675         {
676             public void begin(String string, String string1, Attributes attributes) throws Exception
677             {
678                 UMOModel model;
679                 String modelType = attributes.getValue("type");
680                 String modelName = attributes.getValue("name");
681                 if (modelType == null)
682                 {
683                     modelType = MuleManager.getConfiguration().getModelType();
684                 }
685                 if (modelType.equalsIgnoreCase("custom"))
686                 {
687                     String className = attributes.getValue("className");
688                     if (className == null)
689                     {
690                         throw new IllegalArgumentException(
691                             "Cannot use 'custom' model type without setting the 'className' for the model");
692                     }
693                     else
694                     {
695                         model = (UMOModel)ClassUtils.instanciateClass(className, ClassUtils.NO_ARGS,
696                             getClass());
697                     }
698                 }
699                 else if (modelType.equalsIgnoreCase("inherited"))
700                 {
701                     Map models = MuleManager.getInstance().getModels();
702                     if(models.size()==0)
703                     {
704                         throw new IllegalArgumentException("When using model inheritance there must be one model registered with Mule");
705                     }
706                     model = (UMOModel)models.get(modelName);
707                     if(model == null)
708                     {
709                         throw new IllegalArgumentException("Cannot inherit from model '" + modelName + "'. No such model registered");
710                     }
711                 }
712                 else
713                 {
714                     model = ModelFactory.createModel(modelType);
715                 }
716 
717                 digester.push(model);
718             }
719         });
720 
721         addSetPropertiesRule(path, digester);
722 
723         digester.addSetRoot(path, "registerModel");
724 
725         // Create endpointUri resolver
726         digester.addObjectCreate(path + "/entry-point-resolver", DEFAULT_ENTRY_POINT_RESOLVER, "className");
727         addSetPropertiesRule(path + "/entry-point-resolver", digester);
728 
729         digester.addSetNext(path + "/entry-point-resolver", "setEntryPointResolver");
730 
731         // Create lifecycle adapter
732         digester.addObjectCreate(path + "/component-lifecycle-adapter-factory", DEFAULT_LIFECYCLE_ADAPTER,
733             "className");
734         addSetPropertiesRule(path, digester);
735         digester.addSetNext(path + "/component-lifecycle-adapter-factory", "setLifecycleAdapterFactory");
736 
737         // Pool factory
738         addPoolingProfileRules(digester, path);
739 
740         // Exception strategy
741         addExceptionStrategyRules(digester, path);
742 
743         // Add Components
744         addMuleDescriptorRules(digester, path);
745     }
746 
747     protected void addMuleDescriptorRules(Digester digester, String path) throws ConfigurationException
748     {
749         // Create Mule UMOs
750         path += "/mule-descriptor";
751         addObjectCreateOrGetFromContainer(path, DEFAULT_DESCRIPTOR, "className", "ref", "container", false);
752 
753         addSetPropertiesRule(path, digester);
754 
755         // Create Message Routers
756         addMessageRouterRules(digester, path, "inbound");
757         addMessageRouterRules(digester, path, "outbound");
758         addMessageRouterRules(digester, path, "nested");
759         addMessageRouterRules(digester, path, "response");
760 
761         // Add threading profile rules
762         addThreadingProfileRules(digester, path, "component");
763 
764         // Add pooling profile rules
765         addPoolingProfileRules(digester, path);
766 
767         // queue profile rules
768         addQueueProfileRules(digester, path);
769 
770         // Create interceptors
771         digester.addRule(path + "/interceptor", new Rule()
772         {
773             public void begin(String string, String string1, Attributes attributes) throws Exception
774             {
775                 String value = attributes.getValue("name");
776                 if (value == null)
777                 {
778                     value = attributes.getValue("className");
779                 }
780                 UMOManager man = (UMOManager)digester.getRoot();
781                 UMOInterceptorStack interceptorStack = man.lookupInterceptorStack(value);
782                 MuleDescriptor temp = (MuleDescriptor)digester.peek();
783                 if (interceptorStack != null)
784                 {
785                     temp.addInterceptor(interceptorStack);
786                 }
787                 else
788                 {
789                     // Instantiate the new object and push it on the context
790                     // stack
791                     Class clazz = digester.getClassLoader().loadClass(value);
792                     Object instance = clazz.newInstance();
793                     temp.addInterceptor((UMOInterceptor)instance);
794                     digester.push(instance);
795                 }
796             }
797 
798             public void end(String s, String s1) throws Exception
799             {
800                 if (digester.peek() instanceof UMOInterceptor)
801                 {
802                     digester.pop();
803                 }
804             }
805         });
806 
807         addMulePropertiesRule(path + "/interceptor", digester);
808 
809         // Set exception strategy
810         addExceptionStrategyRules(digester, path);
811 
812         addMulePropertiesRule(path, digester, "setProperties");
813         digester.addSetNext(path + "/properties", "setProperties");
814 
815         // register the component
816         digester.addRule(path, new Rule()
817         {
818             public void end(String s, String s1) throws Exception
819             {
820                 UMODescriptor descriptor = (UMODescriptor)digester.peek();
821                 Object obj = digester.peek(1);
822                 final UMOModel model = (UMOModel)obj;
823                 descriptor.setModelName(model.getName());
824                 model.registerComponent(descriptor);
825             }
826         });
827     }
828 
829     protected void addThreadingProfileRules(Digester digester, String path, final String type)
830     {
831         // set threading profile
832         digester.addRule(path + "/threading-profile", new Rule()
833         {
834             public void begin(String s, String s1, Attributes attributes) throws Exception
835             {
836                 // use the default as a template
837                 MuleConfiguration cfg = MuleManager.getConfiguration();
838                 if ("component".equals(type))
839                 {
840                     digester.push(cfg.getComponentThreadingProfile());
841                 }
842                 else if ("messageReceiver".equals(type))
843                 {
844                     digester.push(cfg.getComponentThreadingProfile());
845                 }
846                 else if ("messageDispatcher".equals(type))
847                 {
848                     digester.push(cfg.getComponentThreadingProfile());
849                 }
850                 else
851                 {
852                     digester.push(cfg.getDefaultThreadingProfile());
853                 }
854             }
855 
856             public void end(String s, String s1) throws Exception
857             {
858                 digester.pop();
859             }
860         });
861         // set threading profile
862         SetPropertiesRule threadingRule = new SetPropertiesRule();
863         threadingRule.addAlias("setPoolExhaustedAction", "setPoolExhaustedActionString");
864         digester.addRule(path + "/threading-profile", threadingRule);
865         digester.addSetNext(path + "/threading-profile", "setThreadingProfile");
866     }
867 
868     protected void addPoolingProfileRules(Digester digester, String path)
869     {
870         // set pooling profile
871         digester.addRule(path + "/pooling-profile", new Rule()
872         {
873             public void begin(String s, String s1, Attributes attributes) throws Exception
874             {
875                 // use the default as a template
876                 MuleConfiguration cfg = MuleManager.getConfiguration();
877                 digester.push(cfg.getPoolingProfile());
878             }
879 
880             public void end(String s, String s1) throws Exception
881             {
882                 digester.pop();
883             }
884         });
885 
886         SetPropertiesRule rule = new SetPropertiesRule();
887         rule.addAlias("exhaustedAction", "exhaustedActionString");
888         rule.addAlias("initialisationPolicy", "initialisationPolicyString");
889         digester.addRule(path + "/pooling-profile", rule);
890         digester.addSetNext(path + "/pooling-profile", "setPoolingProfile");
891     }
892 
893     protected void addQueueProfileRules(Digester digester, String path)
894     {
895         digester.addObjectCreate(path + "/queue-profile", QUEUE_PROFILE);
896         addSetPropertiesRule(path + "/queue-profile", digester);
897         digester.addSetNext(path + "/queue-profile", "setQueueProfile");
898     }
899 
900     protected void addMessageRouterRules(Digester digester, String path, String type)
901         throws ConfigurationException
902     {
903         String defaultRouter;
904         String setMethod;
905         if ("inbound".equals(type))
906         {
907             defaultRouter = DEFAULT_INBOUND_ROUTER_COLLECTION;
908             setMethod = "setInboundRouter";
909             path += "/inbound-router";
910             // Add endpoints for multiple inbound endpoints
911             addEndpointRules(digester, path, "addEndpoint");
912             addGlobalReferenceEndpointRules(digester, path, "addEndpoint");
913         }
914         else if ("response".equals(type))
915         {
916             defaultRouter = DEFAULT_RESPONSE_ROUTER_COLLECTION;
917             setMethod = "setResponseRouter";
918             path += "/response-router";
919             // Add endpoints for multiple response endpoints i.e. replyTo
920             // addresses
921             addEndpointRules(digester, path, "addEndpoint");
922             addGlobalReferenceEndpointRules(digester, path, "addEndpoint");
923         }
924         else if ("nested".equals(type)) {
925 			defaultRouter = DEFAULT_NESTED_ROUTER_COLLECTION;
926 			setMethod = "setNestedRouter";
927 			path += "/nested-router";
928 
929     	}
930         else
931         {
932             defaultRouter = DEFAULT_OUTBOUND_ROUTER_COLLECTION;
933             setMethod = "setOutboundRouter";
934             path += "/outbound-router";
935         }
936         digester.addObjectCreate(path, defaultRouter, "className");
937         addSetPropertiesRule(path, digester);
938 
939         // Add Catch All strategy
940         digester.addObjectCreate(path + "/catch-all-strategy", DEFAULT_CATCH_ALL_STRATEGY, "className");
941         addSetPropertiesRule(path + "/catch-all-strategy", digester);
942 
943         // Add endpointUri for catch-all strategy
944         addEndpointRules(digester, path + "/catch-all-strategy", "setEndpoint");
945         addGlobalReferenceEndpointRules(digester, path + "/catch-all-strategy", "setEndpoint");
946 
947         addMulePropertiesRule(path + "/catch-all-strategy", digester);
948         digester.addSetNext(path + "/catch-all-strategy", "setCatchAllStrategy");
949 
950         // Add router rules
951         addRouterRules(digester, path, type);
952 
953         // add the router to the descriptor
954         digester.addSetNext(path, setMethod);
955     }
956 
957     protected void addRouterRules(Digester digester, String path, final String type)
958         throws ConfigurationException
959     {
960         if("nested".equals(type))
961         {
962             path += "/binding";
963             digester.addObjectCreate(path, DEFAULT_NESTED_ROUTER);
964 
965 
966         } else if ("inbound".equals(type))
967         {
968             path += "/router";
969             digester.addObjectCreate(path, INBOUND_MESSAGE_ROUTER_INTERFACE, "className");
970         }
971         else if ("response".equals(type))
972         {
973             path += "/router";
974             digester.addObjectCreate(path, RESPONSE_MESSAGE_ROUTER_INTERFACE, "className");
975         }
976         else
977         {
978             path += "/router";
979             digester.addObjectCreate(path, OUTBOUND_MESSAGE_ROUTER_INTERFACE, "className");
980         }
981 
982         addSetPropertiesRule(path, digester, new String[]{"enableCorrelation", "propertyExtractor"},
983             new String[]{"enableCorrelationAsString", "propertyExtractorAsString"});
984         addMulePropertiesRule(path, digester);
985         if ("outbound".equals(type))
986         {
987             addEndpointRules(digester, path, "addEndpoint");
988             addReplyToRules(digester, path);
989             addGlobalReferenceEndpointRules(digester, path, "addEndpoint");
990             addTransactionConfigRules(path, digester);
991         }
992         else if("nested".equals(type))
993         {
994             //Right now only one endpoint can be set on a nested Router so call
995             //setEndpoint not addEndpoint
996             addEndpointRules(digester, path, "setEndpoint");
997 			addGlobalReferenceEndpointRules(digester, path, "setEndpoint");
998         }
999         addFilterRules(digester, path);
1000 
1001         // Set the router on the to the message router
1002         digester.addSetNext(path, "addRouter");
1003     }
1004 
1005     protected void addReplyToRules(Digester digester, String path) throws ConfigurationException
1006     {
1007         // Set message endpoint
1008         path += "/reply-to";
1009         digester.addRule(path, new Rule()
1010         {
1011             public void begin(String s, String s1, Attributes attributes) throws Exception
1012             {
1013                 String replyTo = attributes.getValue("address");
1014                 ((UMOOutboundRouter)digester.peek()).setReplyTo(replyTo);
1015             }
1016         });
1017     }
1018 
1019     protected void addEndpointRules(Digester digester, String path, String method)
1020         throws ConfigurationException
1021     {
1022         // Set message endpoint
1023         path += "/endpoint";
1024         addObjectCreateOrGetFromContainer(path, DEFAULT_ENDPOINT, "className", "ref", false);
1025         addCommonEndpointRules(digester, path, method);
1026     }
1027 
1028     protected void addGlobalReferenceEndpointRules(Digester digester, String path, final String method)
1029         throws ConfigurationException
1030     {
1031         // Set message endpoint
1032         path += "/global-endpoint";
1033         digester.addRule(path, new Rule()
1034         {
1035             public void begin(String s, String s1, Attributes attributes) throws Exception
1036             {
1037                 String name = attributes.getValue("name");
1038                 String address = attributes.getValue("address");
1039                 String trans = attributes.getValue("transformers");
1040                 String responseTrans = attributes.getValue("responseTransformers");
1041                 String createConnector = attributes.getValue("createConnector");
1042                 EndpointReference ref = new EndpointReference(method, name, address, trans, responseTrans,
1043                     createConnector, digester.peek());
1044                 // TODO encoding
1045                 // String encoding = attributes.getValue("encoding");
1046                 digester.push(ref);
1047             }
1048 
1049             public void end(String endpointName, String endpointName1) throws Exception
1050             {
1051                 endpointReferences.add(digester.pop());
1052             }
1053         });
1054         addCommonEndpointRules(digester, path, null);
1055     }
1056 
1057     protected void addCommonEndpointRules(Digester digester, String path, String method)
1058         throws ConfigurationException
1059     {
1060         addSetPropertiesRule(path, digester, new String[]{"address", "transformers", "responseTransformers",
1061             "createConnector"}, new String[]{"endpointURI", "transformer", "responseTransformer",
1062             "createConnectorAsString"});
1063         // todo test
1064         addMulePropertiesRule(path, digester, "setProperties");
1065         addTransactionConfigRules(path, digester);
1066 
1067         addFilterRules(digester, path);
1068         if (method != null)
1069         {
1070             digester.addSetNext(path, method);
1071         }
1072 
1073         // Add security filter rules
1074         digester.addObjectCreate(path + "/security-filter", ENDPOINT_SECURITY_FILTER_INTERFACE, "className");
1075 
1076         addMulePropertiesRule(path + "/security-filter", digester);
1077         digester.addSetNext(path + "/security-filter", "setSecurityFilter");
1078     }
1079 
1080     protected void addTransactionConfigRules(String path, Digester digester)
1081     {
1082         digester.addObjectCreate(path + "/transaction", DEFAULT_TRANSACTION_CONFIG);
1083         addSetPropertiesRule(path + "/transaction", digester, new String[]{"action"},
1084             new String[]{"actionAsString"});
1085 
1086         digester.addObjectCreate(path + "/transaction/constraint", TRANSACTION_CONSTRAINT_INTERFACE,
1087             "className");
1088         addSetPropertiesRule(path + "/transaction/constraint", digester);
1089 
1090         digester.addSetNext(path + "/transaction/constraint", "setConstraint");
1091         digester.addSetNext(path + "/transaction", "setTransactionConfig");
1092     }
1093 
1094     protected void addExceptionStrategyRules(Digester digester, String path) throws ConfigurationException
1095     {
1096         path += "/exception-strategy";
1097         digester.addObjectCreate(path, EXCEPTION_STRATEGY_INTERFACE, "className");
1098         addMulePropertiesRule(path, digester);
1099 
1100         // Add endpoint rules
1101         addEndpointRules(digester, path, "addEndpoint");
1102         addGlobalReferenceEndpointRules(digester, path, "addEndpoint");
1103         digester.addSetNext(path, "setExceptionListener");
1104     }
1105 
1106     protected void addSetPropertiesRule(String path, Digester digester, String[] s1, String[] s2)
1107     {
1108         digester.addRule(path, new ExtendedMuleSetPropertiesRule(s1, s2));
1109     }
1110 
1111     protected void addSetPropertiesRule(String path, Digester digester)
1112     {
1113         digester.addRule(path, new ExtendedMuleSetPropertiesRule());
1114     }
1115 
1116     private void addTransformerReference(String propName, String transName, Object object)
1117     {
1118         transformerReferences.add(new TransformerReference(propName, transName, object));
1119     }
1120 
1121     private void addEndpointReference(String propName, String endpointName, Object object)
1122     {
1123         endpointReferences.add(new EndpointReference(propName, endpointName, null, null, null, null, object));
1124     }
1125 
1126     /**
1127      * this rule serves 2 functions - 1. Allows for late binding of certain types of
1128      * object, namely Transformers and endpoints that need to be set on objects once
1129      * the Manager configuration has been processed 2. Allows for template parameters
1130      * to be parse on the configuration file in the form of ${param-name}. These will
1131      * get resolved against properties set in the mule-properites element
1132      */
1133     public class ExtendedMuleSetPropertiesRule extends MuleSetPropertiesRule
1134     {
1135         public ExtendedMuleSetPropertiesRule()
1136         {
1137             super();
1138         }
1139 
1140         public ExtendedMuleSetPropertiesRule(PlaceholderProcessor processor)
1141         {
1142             super(processor);
1143         }
1144 
1145         public ExtendedMuleSetPropertiesRule(String[] strings, String[] strings1)
1146         {
1147             super(strings, strings1);
1148         }
1149 
1150         public ExtendedMuleSetPropertiesRule(String[] strings,
1151                                              String[] strings1,
1152                                              PlaceholderProcessor processor)
1153         {
1154             super(strings, strings1, processor);
1155         }
1156 
1157         public void begin(String s1, String s2, Attributes attributes) throws Exception
1158         {
1159             attributes = processor.processAttributes(attributes, s2);
1160             // Add transformer references that will be bound to their objects
1161             // once all configuration has bean read
1162             String transformerNames = attributes.getValue("transformer");
1163             if (transformerNames != null)
1164             {
1165                 addTransformerReference("transformer", transformerNames, digester.peek());
1166             }
1167             transformerNames = attributes.getValue("transformers");
1168             if (transformerNames != null)
1169             {
1170                 addTransformerReference("transformer", transformerNames, digester.peek());
1171             }
1172 
1173             transformerNames = attributes.getValue("responseTransformers");
1174             if (transformerNames != null)
1175             {
1176                 addTransformerReference("responseTransformer", transformerNames, digester.peek());
1177             }
1178 
1179             // transformerNames = attributes.getValue("responseTransformer");
1180             // if (transformerNames != null) {
1181             // addTransformerReference("responseTransformer", transformerNames,
1182             // digester.peek());
1183             // }
1184 
1185             transformerNames = attributes.getValue("inboundTransformer");
1186             if (transformerNames != null)
1187             {
1188                 addTransformerReference("inboundTransformer", transformerNames, digester.peek());
1189             }
1190 
1191             transformerNames = attributes.getValue("outboundTransformer");
1192             if (transformerNames != null)
1193             {
1194                 addTransformerReference("outboundTransformer", transformerNames, digester.peek());
1195             }
1196 
1197             transformerNames = attributes.getValue("responseTransformer");
1198             if (transformerNames != null)
1199             {
1200                 addTransformerReference("responseTransformer", transformerNames, digester.peek());
1201             }
1202 
1203             // Special case handling of global endpoint refs on the
1204             // inboundEndpoint/
1205             // outboundendpoint attributes of the descriptor
1206             String endpoint = attributes.getValue("inboundEndpoint");
1207             if (endpoint != null)
1208             {
1209                 Object o = manager.getEndpoints().get(endpoint);
1210                 if (o != null)
1211                 {
1212                     addEndpointReference("setInboundEndpoint", endpoint, digester.peek());
1213                 }
1214             }
1215 
1216             endpoint = attributes.getValue("outboundEndpoint");
1217             if (endpoint != null)
1218             {
1219                 Object o = manager.getEndpoints().get(endpoint);
1220                 if (o != null)
1221                 {
1222                     addEndpointReference("setOutboundEndpoint", endpoint, digester.peek());
1223                 }
1224             }
1225             super.begin(attributes);
1226         }
1227     }
1228 
1229     protected void addObjectCreateOrGetFromContainer(final String path,
1230                                                      String defaultImpl,
1231                                                      final String classAttrib,
1232                                                      final String refAttrib,
1233                                                      final boolean classRefRequired)
1234     {
1235         digester.addRule(path, new ObjectGetOrCreateRule(defaultImpl, classAttrib, refAttrib, classAttrib,
1236             classRefRequired, "getContainerContext"));
1237     }
1238 
1239     protected void addObjectCreateOrGetFromContainer(final String path,
1240                                                      String defaultImpl,
1241                                                      final String classAttrib,
1242                                                      final String refAttrib,
1243                                                      final String containerAttrib,
1244                                                      final boolean classRefRequired)
1245     {
1246         digester.addRule(path, new ObjectGetOrCreateRule(defaultImpl, classAttrib, refAttrib,
1247             containerAttrib, classAttrib, classRefRequired, "getContainerContext"));
1248     }
1249 }