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.config;
8   
9   import org.mule.api.MuleContext;
10  import org.mule.api.config.MuleConfiguration;
11  import org.mule.api.config.MuleProperties;
12  import org.mule.api.context.MuleContextAware;
13  import org.mule.api.lifecycle.FatalException;
14  import org.mule.api.lifecycle.Initialisable;
15  import org.mule.api.lifecycle.Startable;
16  import org.mule.config.i18n.CoreMessages;
17  import org.mule.util.FileUtils;
18  import org.mule.util.NumberUtils;
19  import org.mule.util.StringUtils;
20  import org.mule.util.UUID;
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.net.InetAddress;
25  import java.net.UnknownHostException;
26  import java.nio.charset.Charset;
27  import java.util.HashMap;
28  import java.util.Map;
29  
30  import javax.xml.parsers.SAXParserFactory;
31  
32  import org.apache.commons.lang.BooleanUtils;
33  import org.apache.commons.logging.Log;
34  import org.apache.commons.logging.LogFactory;
35  
36  /**
37   * Configuration info. which can be set when creating the MuleContext but becomes
38   * immutable after starting the MuleContext.
39   */
40  public class DefaultMuleConfiguration implements MuleConfiguration, MuleContextAware
41  {
42  
43      public static final String[] DEFAULT_STACKTRACE_FILTER = (
44              "org.mule.processor.AbstractInterceptingMessageProcessor," +
45              "org.mule.processor.chain")
46              .split(",");
47  
48      /**
49       * When false (default), some internal Mule entries are removed from exception stacktraces for readability.
50       * @see #stackTraceFilter
51       */
52      public static boolean fullStackTraces = false;
53  
54      /**
55       * When false (default), only a summary of the root exception
56       * and trail is provided. If this flag is false, full exception information is reported.
57       * Switching on DEBUG level logging with automatically set this flag to true.
58       */
59      public static boolean verboseExceptions = false;
60  
61      /**
62       * A comma-separated list of internal packages/classes which are removed from sanitized stacktraces.
63       * Matching is done via string.startsWith().
64       * @see #fullStackTraces
65       */
66      public static String[] stackTraceFilter = DEFAULT_STACKTRACE_FILTER;
67  
68      private boolean synchronous = false;
69  
70      /**
71       * The type of model used for the internal system model where system created
72       * services are registered
73       */
74      private String systemModelType = "seda";
75  
76      private String encoding = "UTF-8";
77  
78      /**
79       * When running sychronously, return events can be received over transports that
80       * support ack or replyTo This property determines how long to wait for a receive
81       */
82      private int responseTimeout = 10000;
83  
84      /**
85       * The default transaction timeout value used if no specific transaction time out
86       * has been set on the transaction config
87       */
88      private int defaultTransactionTimeout = 30000;
89      
90      /**
91       * The default queue timeout value used when polling queues.
92       */
93      private int defaultQueueTimeout = 200;
94  
95      /**
96       * The default graceful shutdown timeout used when shutting stopping mule cleanly
97       * without message loss.
98       */
99      private int shutdownTimeout = 5000;
100 
101     /**
102      * Where Mule stores any runtime files to disk. Note that in container
103      * mode each app will have its working dir set one level under this dir
104      * (with app's name) in the {@link #setMuleContext} callback.
105      *
106      */
107     private String workingDirectory = "./.mule";
108 
109     /**
110      * Whether the server instance is running in client mode, which means that some
111      * services will not be started
112      */
113     private boolean clientMode = false;
114 
115     /** the unique id for this Mule instance */
116     private String id;
117 
118     /** If this node is part of a cluster then this is the shared cluster Id */
119     private String clusterId;
120 
121     /** The domain name that this instance belongs to. */
122     private String domainId;
123 
124     // Debug options
125     
126     private boolean cacheMessageAsBytes = true;
127 
128     private boolean cacheMessageOriginalPayload = true;
129 
130     private boolean enableStreaming = true;
131 
132     private boolean autoWrapMessageAwareTransform = true;
133     
134     protected transient Log logger = LogFactory.getLog(DefaultMuleConfiguration.class);
135 
136     private MuleContext muleContext;
137     private boolean containerMode;
138 
139     /**
140      * By default the Mule Expression parser will perform basic syntax checking on expressions in order to provide
141      * early feedback if an expression is malformed.  Part of the check is checking that all open braces are closed at
142      * some point. For some expressions such as groovy, there could be a scenario where a brace is deliberately used without
143      * being closed; this would cause the validation to fail.  Users can turn off validation using this flag.
144      */
145     private boolean validateExpressions = true;
146 
147     /**
148      * Generic string/string map of properties in addition to standard Mule props.
149      * Used as an extension point e.g. in MMC.
150      */
151     private Map<String, String> extendedProperties = new HashMap<String, String>();
152 
153     public DefaultMuleConfiguration()
154     {
155         this(false);
156     }
157 
158     public DefaultMuleConfiguration(boolean containerMode)  
159     {
160         this.containerMode = containerMode;
161         
162         // Apply any settings which come from the JVM system properties.
163         applySystemProperties();
164         
165         if (id == null)
166         {
167             id = UUID.getUUID();
168         }
169 
170         if (clusterId == null)
171         {
172             clusterId = CoreMessages.notClustered().getMessage();
173         }
174 
175         if (domainId == null)
176         {
177             try
178             {
179                 domainId = InetAddress.getLocalHost().getHostName();
180             }
181             catch (UnknownHostException e)
182             {
183                 logger.warn(e);
184                 domainId = "org.mule";
185             }
186         }
187         
188         try
189         {
190             validateEncoding();
191             validateXML();
192         }
193         catch (FatalException e)
194         {
195             throw new RuntimeException(e);
196         }
197     }
198 
199     public void setMuleContext(MuleContext context)
200     {
201         this.muleContext = context;
202         if (containerMode)
203         {
204             final String muleHome = System.getProperty("mule.home");
205             // in container mode the id is the app name, have each app isolate its work dir
206             if (!isStandalone()) {
207                 // fallback to current dir as a parent
208                 this.workingDirectory = String.format("%s/%s", getWorkingDirectory(), getId());
209             }
210             else
211             {
212                 this.workingDirectory = String.format("%s/%s/%s", muleHome.trim(), getWorkingDirectory(), getId());
213             }
214         }
215         else if (isStandalone())
216         {
217             this.workingDirectory = String.format("%s/%s", getWorkingDirectory(), getId());
218         }
219     }
220 
221     /**
222      * Apply any settings which come from the JVM system properties.
223      */
224     protected void applySystemProperties() 
225     {
226         String p;
227         
228         p = System.getProperty(MuleProperties.MULE_ENCODING_SYSTEM_PROPERTY);
229         if (p != null)
230         {
231             encoding = p;
232         }
233         else
234         {
235             System.setProperty(MuleProperties.MULE_ENCODING_SYSTEM_PROPERTY, encoding);
236         }
237         p = System.getProperty(MuleProperties.SYSTEM_PROPERTY_PREFIX + "endpoints.synchronous");
238         if (p != null)
239         {
240             synchronous = BooleanUtils.toBoolean(p);
241         }
242         p = System.getProperty(MuleProperties.SYSTEM_PROPERTY_PREFIX + "systemModelType");
243         if (p != null)
244         {
245             systemModelType = p;
246         }
247         p = System.getProperty(MuleProperties.SYSTEM_PROPERTY_PREFIX + "timeout.synchronous");
248         if (p != null)
249         {
250             responseTimeout = NumberUtils.toInt(p);
251         }
252         p = System.getProperty(MuleProperties.SYSTEM_PROPERTY_PREFIX + "timeout.transaction");
253         if (p != null)
254         {
255             defaultTransactionTimeout = NumberUtils.toInt(p);
256         }
257 
258         p = System.getProperty(MuleProperties.SYSTEM_PROPERTY_PREFIX + "workingDirectory");
259         if (p != null)
260         {
261             workingDirectory = p;
262         }
263         p = System.getProperty(MuleProperties.SYSTEM_PROPERTY_PREFIX + "clientMode");
264         if (p != null)
265         {
266             clientMode = BooleanUtils.toBoolean(p);
267         }
268         p = System.getProperty(MuleProperties.SYSTEM_PROPERTY_PREFIX + "serverId");
269         if (p != null)
270         {
271             id = p;
272         }
273         p = System.getProperty(MuleProperties.SYSTEM_PROPERTY_PREFIX + "clusterId");
274         if (p != null)
275         {
276             clusterId = p;
277         }
278         p = System.getProperty(MuleProperties.SYSTEM_PROPERTY_PREFIX + "domainId");
279         if (p != null)
280         {
281             domainId = p;
282         }
283         p = System.getProperty(MuleProperties.SYSTEM_PROPERTY_PREFIX + "message.cacheBytes");
284         if (p != null)
285         {
286             cacheMessageAsBytes = BooleanUtils.toBoolean(p);
287         }
288         p = System.getProperty(MuleProperties.SYSTEM_PROPERTY_PREFIX + "message.cacheOriginal");
289         if (p != null)
290         {
291             cacheMessageOriginalPayload = BooleanUtils.toBoolean(p);
292         }
293         p = System.getProperty(MuleProperties.SYSTEM_PROPERTY_PREFIX + "streaming.enable");
294         if (p != null)
295         {
296             enableStreaming = BooleanUtils.toBoolean(p);
297         }
298         p = System.getProperty(MuleProperties.SYSTEM_PROPERTY_PREFIX + "transform.autoWrap");
299         if (p != null)
300         {
301             autoWrapMessageAwareTransform = BooleanUtils.toBoolean(p);
302         }
303         p = System.getProperty(MuleProperties.SYSTEM_PROPERTY_PREFIX + "stacktrace.full");
304         if (p != null)
305         {
306             fullStackTraces = false;
307         }
308         p = System.getProperty(MuleProperties.SYSTEM_PROPERTY_PREFIX + "stacktrace.filter");
309         if (p != null)
310         {
311             stackTraceFilter = p.split(",");
312         }
313 
314         p = System.getProperty(MuleProperties.SYSTEM_PROPERTY_PREFIX + "verbose.exceptions");
315         if (p != null)
316         {
317             verboseExceptions = BooleanUtils.toBoolean(p);
318         }
319         else
320         {
321             verboseExceptions = logger.isDebugEnabled();
322         }
323 
324         p = System.getProperty(MuleProperties.SYSTEM_PROPERTY_PREFIX + "validate.expressions");
325         if (p != null)
326         {
327             validateExpressions = Boolean.valueOf(p);
328         }
329     }
330 
331     protected void validateEncoding() throws FatalException
332     {
333         //Check we have a valid and supported encoding
334         if (!Charset.isSupported(encoding))
335         {
336             throw new FatalException(CoreMessages.propertyHasInvalidValue("encoding", encoding), this);
337         }
338     }
339 
340     /**
341      * Mule needs a proper JAXP implementation and will complain when run with a plain JDK
342      * 1.4. Use the supplied launcher or specify a proper JAXP implementation via
343      * <code>-Djava.endorsed.dirs</code>. See the following URLs for more information:
344      * <ul>
345      * <li><a href="http://xerces.apache.org/xerces2-j/faq-general.html#faq-4">Xerces</a>
346      * <li><a href="http://xml.apache.org/xalan-j/faq.html#faq-N100D6">Xalan</a>
347      * <li><a href="http://java.sun.com/j2se/1.4.2/docs/guide/standards/">Endorsed Standards Override Mechanism</a>
348      * </ul>
349      */
350     protected void validateXML() throws FatalException
351     {
352         SAXParserFactory f = SAXParserFactory.newInstance();
353         if (f == null || f.getClass().getName().indexOf("crimson") != -1)
354         {
355             throw new FatalException(CoreMessages.valueIsInvalidFor(f.getClass().getName(),
356                 "javax.xml.parsers.SAXParserFactory"), this);
357         }
358     }
359 
360     public void setDefaultSynchronousEndpoints(boolean synchronous)
361     {
362         if (verifyContextNotStarted())
363         {
364             this.synchronous = synchronous;
365         }
366     }
367 
368     public int getDefaultResponseTimeout()
369     {
370         return responseTimeout;
371     }
372 
373     public void setDefaultResponseTimeout(int responseTimeout)
374     {
375         if (verifyContextNotStarted())
376         {
377             this.responseTimeout = responseTimeout;
378         }
379     }
380 
381     public String getWorkingDirectory()
382     {
383         return workingDirectory;
384     }
385 
386     public String getMuleHomeDirectory()
387     {
388         return System.getProperty(MuleProperties.MULE_HOME_DIRECTORY_PROPERTY);
389     }
390 
391     public void setWorkingDirectory(String workingDirectory)
392     {
393         if (verifyContextNotInitialized())
394         {
395             try
396             {
397                 File canonicalFile = FileUtils.openDirectory(workingDirectory);
398                 this.workingDirectory = canonicalFile.getCanonicalPath();
399             }
400             catch (IOException e)
401             {
402                 throw new IllegalArgumentException(CoreMessages.initialisationFailure(
403                     "Invalid working directory").getMessage(), e);
404             }
405         }
406     }
407 
408     public int getDefaultTransactionTimeout()
409     {
410         return defaultTransactionTimeout;
411     }
412 
413     public void setDefaultTransactionTimeout(int defaultTransactionTimeout)
414     {
415         if (verifyContextNotStarted())
416         {
417             this.defaultTransactionTimeout = defaultTransactionTimeout;
418         }
419     }
420 
421 
422     public boolean isValidateExpressions()
423     {
424         return validateExpressions;
425     }
426 
427     public boolean isClientMode()
428     {
429         return clientMode;
430     }
431 
432     public String getDefaultEncoding()
433     {
434         return encoding;
435     }
436 
437     public void setDefaultEncoding(String encoding)
438     {
439         if (verifyContextNotInitialized())
440         {
441             this.encoding = encoding;
442         }
443     }
444 
445     public String getId()
446     {
447         return id;
448     }
449 
450     public void setId(String id)
451     {
452         if (verifyContextNotInitialized())
453         {
454             if (StringUtils.isBlank(id))
455             {
456                 throw new IllegalArgumentException("Cannot set server id to null/blank");
457             }
458             this.id = id;
459         }
460     }
461 
462     public String getClusterId()
463     {
464         return clusterId;
465     }
466 
467     public void setClusterId(String clusterId)
468     {
469         if (verifyContextNotInitialized())
470         {
471             this.clusterId = clusterId;
472         }
473     }
474 
475     public String getDomainId()
476     {
477         return domainId;
478     }
479 
480     public void setDomainId(String domainId)
481     {
482         if (verifyContextNotInitialized())
483         {
484             this.domainId = domainId;
485         }
486     }
487 
488     public String getSystemModelType()
489     {
490         return systemModelType;
491     }
492 
493     public void setSystemModelType(String systemModelType)
494     {
495         if (verifyContextNotStarted())
496         {
497             this.systemModelType = systemModelType;
498         }
499     }
500 
501     public void setClientMode(boolean clientMode)
502     {
503         if (verifyContextNotStarted())
504         {
505             this.clientMode = clientMode;
506         }
507     }
508 
509     public String getSystemName()
510     {
511         return domainId + "." + clusterId + "." + id;
512     }
513     
514     public boolean isAutoWrapMessageAwareTransform()
515     {
516         return autoWrapMessageAwareTransform;
517     }
518 
519     public void setAutoWrapMessageAwareTransform(boolean autoWrapMessageAwareTransform)
520     {
521         if (verifyContextNotStarted())
522         {
523             this.autoWrapMessageAwareTransform = autoWrapMessageAwareTransform;
524         }
525     }
526 
527     public boolean isCacheMessageAsBytes()
528     {
529         return cacheMessageAsBytes;
530     }
531 
532     public void setCacheMessageAsBytes(boolean cacheMessageAsBytes)
533     {
534         if (verifyContextNotStarted())
535         {
536             this.cacheMessageAsBytes = cacheMessageAsBytes;
537         }
538     }
539 
540     public boolean isCacheMessageOriginalPayload()
541     {
542         return cacheMessageOriginalPayload;
543     }
544 
545     public void setCacheMessageOriginalPayload(boolean cacheMessageOriginalPayload)
546     {
547         if (verifyContextNotStarted())
548         {
549             this.cacheMessageOriginalPayload = cacheMessageOriginalPayload;
550         }
551     }
552 
553     public boolean isEnableStreaming()
554     {
555         return enableStreaming;
556     }
557 
558     public void setEnableStreaming(boolean enableStreaming)
559     {
560         if (verifyContextNotStarted())
561         {
562             this.enableStreaming = enableStreaming;
563         }
564     }
565 
566     protected boolean verifyContextNotInitialized()
567     {
568         if (muleContext != null && muleContext.getLifecycleManager().isPhaseComplete(Initialisable.PHASE_NAME))
569         {
570             logger.warn("Cannot modify MuleConfiguration once the MuleContext has been initialized.  Modification will be ignored.");
571             return false;
572         }
573         else
574         {
575             return true;
576         }
577     }
578     
579     protected boolean verifyContextNotStarted()
580     {
581         if (muleContext != null && muleContext.getLifecycleManager().isPhaseComplete(Startable.PHASE_NAME))
582         {
583             logger.warn("Cannot modify MuleConfiguration once the MuleContext has been started.  Modification will be ignored.");
584             return false;
585         }
586         else
587         {
588             return true;
589         }
590     }
591 
592     public int getDefaultQueueTimeout()
593     {
594         return defaultQueueTimeout;
595     }
596 
597     public void setDefaultQueueTimeout(int defaultQueueTimeout)
598     {
599         if (verifyContextNotStarted())
600         {
601             this.defaultQueueTimeout = defaultQueueTimeout;
602         }
603     }
604 
605     public int getShutdownTimeout()
606     {
607         return shutdownTimeout;
608     }
609 
610     public void setShutdownTimeout(int shutdownTimeout)
611     {
612         if (verifyContextNotStarted())
613         {
614             this.shutdownTimeout = shutdownTimeout;
615         }
616     }
617 
618     public boolean isContainerMode()
619     {
620         return this.containerMode;
621     }
622 
623     /**
624      * The setting is only editable before the context has been initialized, change requests ignored afterwards.
625      */
626     public void setContainerMode(boolean containerMode)
627     {
628         if (verifyContextNotInitialized())
629         {
630             this.containerMode = containerMode;
631         }
632     }
633 
634     public boolean isStandalone()
635     {
636         // this is our best guess
637         return getMuleHomeDirectory() != null;
638     }
639 
640     public Map<String, String> getExtendedProperties()
641     {
642         return extendedProperties;
643     }
644 
645     public void setExtendedProperties(Map<String, String> extendedProperties)
646     {
647         this.extendedProperties = extendedProperties;
648     }
649 
650     public void setExtendedProperty(String name, String value)
651     {
652         this.extendedProperties.put(name, value);
653     }
654 
655     public String getExtendedProperty(String name)
656     {
657         return this.extendedProperties.get(name);
658     }
659 
660     @Override
661     public int hashCode()
662     {
663         final int prime = 31;
664         int result = 1;
665         result = prime * result + (autoWrapMessageAwareTransform ? 1231 : 1237);
666         result = prime * result + (cacheMessageAsBytes ? 1231 : 1237);
667         result = prime * result + (cacheMessageOriginalPayload ? 1231 : 1237);
668         result = prime * result + (clientMode ? 1231 : 1237);
669         result = prime * result + ((clusterId == null) ? 0 : clusterId.hashCode());
670         result = prime * result + defaultQueueTimeout;
671         result = prime * result + defaultTransactionTimeout;
672         result = prime * result + ((domainId == null) ? 0 : domainId.hashCode());
673         result = prime * result + (enableStreaming ? 1231 : 1237);
674         result = prime * result + ((encoding == null) ? 0 : encoding.hashCode());
675         result = prime * result + ((id == null) ? 0 : id.hashCode());
676         result = prime * result + responseTimeout;
677         result = prime * result + shutdownTimeout;
678         result = prime * result + (synchronous ? 1231 : 1237);
679         result = prime * result + ((systemModelType == null) ? 0 : systemModelType.hashCode());
680         result = prime * result + ((workingDirectory == null) ? 0 : workingDirectory.hashCode());
681         result = prime * result + (containerMode ? 1231 : 1237);
682         return result;
683     }
684 
685     @Override
686     public boolean equals(Object obj)
687     {
688         if (this == obj) return true;
689         if (obj == null) return false;
690         if (getClass() != obj.getClass()) return false;
691         DefaultMuleConfiguration other = (DefaultMuleConfiguration) obj;
692         if (autoWrapMessageAwareTransform != other.autoWrapMessageAwareTransform) return false;
693         if (cacheMessageAsBytes != other.cacheMessageAsBytes) return false;
694         if (cacheMessageOriginalPayload != other.cacheMessageOriginalPayload) return false;
695         if (clientMode != other.clientMode) return false;
696         if (clusterId == null)
697         {
698             if (other.clusterId != null) return false;
699         }
700         else if (!clusterId.equals(other.clusterId)) return false;
701         if (defaultQueueTimeout != other.defaultQueueTimeout) return false;
702         if (defaultTransactionTimeout != other.defaultTransactionTimeout) return false;
703         if (domainId == null)
704         {
705             if (other.domainId != null) return false;
706         }
707         else if (!domainId.equals(other.domainId)) return false;
708         if (enableStreaming != other.enableStreaming) return false;
709         if (encoding == null)
710         {
711             if (other.encoding != null) return false;
712         }
713         else if (!encoding.equals(other.encoding)) return false;
714         if (id == null)
715         {
716             if (other.id != null) return false;
717         }
718         else if (!id.equals(other.id)) return false;
719         if (responseTimeout != other.responseTimeout) return false;
720         if (shutdownTimeout != other.shutdownTimeout) return false;
721         if (synchronous != other.synchronous) return false;
722         if (systemModelType == null)
723         {
724             if (other.systemModelType != null) return false;
725         }
726         else if (!systemModelType.equals(other.systemModelType)) return false;
727         if (workingDirectory == null)
728         {
729             if (other.workingDirectory != null) return false;
730         }
731         else if (!workingDirectory.equals(other.workingDirectory)) return false;
732 
733         if (containerMode != other.containerMode) return false;
734 
735         return true;
736     }
737 
738 }