View Javadoc

1   /*
2    * $Id: MulePropertiesRuleSet.java 7963 2007-08-21 08:53:15Z 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.MuleServer;
15  import org.mule.config.ConfigurationException;
16  import org.mule.config.MuleConfiguration;
17  import org.mule.config.PropertyFactory;
18  import org.mule.config.i18n.CoreMessages;
19  import org.mule.util.ClassUtils;
20  import org.mule.util.IOUtils;
21  import org.mule.util.StringUtils;
22  
23  import java.io.InputStream;
24  import java.util.ArrayList;
25  import java.util.HashMap;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Properties;
30  
31  import org.apache.commons.beanutils.MethodUtils;
32  import org.apache.commons.digester.CallMethodRule;
33  import org.apache.commons.digester.CallParamRule;
34  import org.apache.commons.digester.Digester;
35  import org.apache.commons.digester.ObjectCreateRule;
36  import org.apache.commons.digester.Rule;
37  import org.apache.commons.digester.RuleSetBase;
38  import org.xml.sax.Attributes;
39  
40  /**
41   * A digester rule set that loads rules for <properties> tags and its child tags.
42   */
43  public class MulePropertiesRuleSet extends RuleSetBase
44  {
45      private String path;
46      private PlaceholderProcessor processor;
47      private String propertiesSetterName;
48      private List objectRefs = null;
49      private String parentElement = "properties";
50  
51      public MulePropertiesRuleSet(String path, String propertiesSetterName, List objectRefs)
52      {
53          this(path, objectRefs);
54          this.propertiesSetterName = propertiesSetterName;
55      }
56  
57      public MulePropertiesRuleSet(String path,
58                                   String propertiesSetterName,
59                                   List objectRefs,
60                                   String parentElement)
61      {
62          this(path, objectRefs);
63          this.propertiesSetterName = propertiesSetterName;
64          this.parentElement = parentElement;
65      }
66  
67      public MulePropertiesRuleSet(String path, List objectRefs)
68      {
69          this.path = path;
70          processor = new PlaceholderProcessor();
71          this.objectRefs = objectRefs;
72      }
73  
74      public void addRuleInstances(Digester digester)
75      {
76  
77          path += "/" + parentElement;
78          // digester.addObjectCreate(path, HashMap.class);
79          digester.addRule(path, new ObjectCreateRule(path, HashMap.class)
80          {
81              // This will set the properties on the top object as bean setters if
82              // the flag is set
83              public void end(String string, String string1) throws Exception
84              {
85                  Map props = (Map)digester.peek();
86                  if (props.containsKey(MuleConfiguration.USE_MANAGER_PROPERTIES))
87                  {
88                      props.putAll(MuleManager.getInstance().getProperties());
89                      props.remove(MuleConfiguration.USE_MANAGER_PROPERTIES);
90                  }
91                  super.end(string, string1);
92  
93                  if (propertiesSetterName == null)
94                  {
95                      org.mule.util.BeanUtils.populateWithoutFail(digester.peek(), props, true);
96                  }
97                  else
98                  {
99                      MethodUtils.invokeMethod(digester.peek(), propertiesSetterName, props);
100                     // digester.addSetNext(path + "/properties", "setProperties");
101                 }
102                 // todo - is this needed?
103                 // support for setting transformers as properties
104                 // String trans = (String) props.remove("transformer");
105                 // if (trans != null) {
106                 // addTransformerReference("transformer", trans, digester.peek());
107                 // }
108             }
109         });
110         digester.addCallMethod(path + "/property", "put", 2);
111 
112         digester.addRule(path + "/property", new ProcessedCallParamRule(0, "name"));
113         digester.addRule(path + "/property", new ProcessedCallParamRule(1, "value"));
114 
115         addPropertyFactoryRule(digester, path + "/factory-property");
116         addSystemPropertyRule(digester, path + "/system-property");
117         addFilePropertiesRule(digester, path + "/file-properties");
118         addContainerPropertyRule(digester, path + "/container-property", propertiesSetterName == null);
119         addTextPropertyRule(digester, path + "/text-property");
120 
121         addMapPropertyRules(digester, path);
122         addListPropertyRules(digester, path);
123 
124         addMapPropertyRules(digester, path + "/map");
125         addListPropertyRules(digester, path + "/map");
126     }
127 
128     protected void addMapPropertyRules(Digester digester, String path)
129     {
130         digester.addObjectCreate(path + "/map", HashMap.class);
131         digester.addCallMethod(path + "/map/property", "put", 2);
132         digester.addRule(path + "/map/property", new ProcessedCallParamRule(0, "name"));
133         digester.addRule(path + "/map/property", new ProcessedCallParamRule(1, "value"));
134 
135         addPropertyFactoryRule(digester, path + "/map/factory-property");
136         addSystemPropertyRule(digester, path + "/map/system-property");
137         addFilePropertiesRule(digester, path + "/map/file-properties");
138         addContainerPropertyRule(digester, path + "/map/container-property", false);
139 
140         // call the put method on top -1 object
141         digester.addRule(path + "/map", new CallMethodOnIndexRule("put", 2, 1));
142         digester.addCallParam(path + "/map", 0, "name");
143         digester.addCallParam(path + "/map", 1, true);
144     }
145 
146     protected void addListPropertyRules(Digester digester, String path)
147     {
148         digester.addObjectCreate(path + "/list", ArrayList.class);
149 
150         // digester.addCallMethod(path + "/list/entry", "add", 1);
151         digester.addRule(path + "/list/entry", new CallMethodRule("add", 1)
152         {
153             public void begin(String endpointName, String endpointName1, Attributes attributes)
154                 throws Exception
155             {
156                 // Process template tokens
157                 attributes = processor.processAttributes(attributes, endpointName1);
158                 super.begin(endpointName, endpointName1, attributes);
159             }
160         });
161 
162         digester.addRule(path + "/list/entry", new ProcessedCallParamRule(0, "value"));
163 
164         addPropertyFactoryRule(digester, path + "/list/factory-entry");
165         addSystemPropertyRule(digester, path + "/list/system-entry");
166         addContainerPropertyRule(digester, path + "/list/container-entry", false);
167 
168         // A small hack to call a method on top -1
169         digester.addRule(path + "/list", new CallMethodOnIndexRule("put", 2, 1));
170         digester.addCallParam(path + "/list", 0, "name");
171         digester.addCallParam(path + "/list", 1, true);
172     }
173 
174     protected void addPropertyFactoryRule(Digester digester, String path)
175     {
176         digester.addRule(path, new Rule()
177         {
178 
179             public void begin(String s, String s1, Attributes attributes) throws Exception
180             {
181                 // Process template tokens
182                 attributes = processor.processAttributes(attributes, s1);
183 
184                 String clazz = attributes.getValue("factory");
185                 String name = attributes.getValue("name");
186                 Object props = digester.peek();
187                 Object obj = ClassUtils.instanciateClass(clazz, ClassUtils.NO_ARGS);
188                 if (obj instanceof PropertyFactory)
189                 {
190                     if (props instanceof Map)
191                     {
192                         obj = ((PropertyFactory)obj).create((Map)props);
193                     }
194                     else
195                     {
196                         // this must be a list so we'll get the containing
197                         // properties map
198                         obj = ((PropertyFactory)obj).create((Map)digester.peek(1));
199                     }
200                 }
201                 if (obj != null)
202                 {
203                     if (props instanceof Map)
204                     {
205                         ((Map)props).put(name, obj);
206                     }
207                     else
208                     {
209                         ((List)props).add(obj);
210                     }
211                 }
212             }
213         });
214     }
215 
216     protected void addSystemPropertyRule(Digester digester, String path)
217     {
218         digester.addRule(path, new Rule()
219         {
220             public void begin(String s, String s1, Attributes attributes) throws Exception
221             {
222                 // Process template tokens
223                 attributes = processor.processAttributes(attributes, s1);
224 
225                 String name = attributes.getValue("name");
226                 String key = attributes.getValue("key");
227                 String defaultValue = attributes.getValue("defaultValue");
228                 String value = System.getProperty(key, defaultValue);
229                 if (value != null)
230                 {
231                     Object props = digester.peek();
232                     if (props instanceof Map)
233                     {
234                         ((Map)props).put(name, value);
235                     }
236                     else
237                     {
238                         ((List)props).add(value);
239                     }
240                 }
241             }
242         });
243     }
244 
245     protected synchronized void addFilePropertiesRule(Digester digester, String path)
246     {
247         digester.addRule(path, new Rule()
248         {
249             public void begin(String s, String s1, Attributes attributes) throws Exception
250             {
251                 // Process template tokens
252                 attributes = processor.processAttributes(attributes, s1);
253 
254                 String location = attributes.getValue("location");
255                 String temp = attributes.getValue("override");
256                 boolean override = "true".equalsIgnoreCase(temp);
257                 InputStream is = IOUtils.getResourceAsStream(location, getClass());
258                 if (is == null)
259                 {
260                     throw new ConfigurationException(CoreMessages.cannotLoadFromClasspath(location));
261                 }
262 
263                 Properties fileProps = new Properties();
264                 fileProps.load(is);
265                 Map digesterProps = (Map)digester.peek();
266 
267                 if (override)
268                 {
269                     // Set all properties.
270                     digesterProps.putAll(fileProps);
271                 }
272                 else
273                 {
274                     // Set only those properties which have not yet been set.
275                     String key;
276                     for (Iterator iterator = fileProps.keySet().iterator(); iterator.hasNext();)
277                     {
278                         key = (String)iterator.next();
279                         if (!digesterProps.containsKey(key))
280                         {
281                             digesterProps.put(key, fileProps.getProperty(key));
282                         }
283                     }
284                 }
285 
286                 // If startup properties were given on the command line, they should
287                 // override the file properties.
288                 if (StringUtils.isNotBlank(MuleServer.getStartupPropertiesFile()))
289                 {
290                     is = IOUtils.getResourceAsStream(MuleServer.getStartupPropertiesFile(), getClass(),
291                     /* tryAsFile */true, /* tryAsUrl */false);
292                     if (is != null)
293                     {
294                         Properties startupProps = new Properties();
295                         startupProps.load(is);
296                         String key;
297                         // For each startup property, if the property has been set,
298                         // override its value.
299                         for (Iterator iterator = startupProps.keySet().iterator(); iterator.hasNext();)
300                         {
301                             key = (String)iterator.next();
302                             if (digesterProps.containsKey(key))
303                             {
304                                 digesterProps.put(key, startupProps.getProperty(key));
305                             }
306                         }
307                     }
308                 }
309             }
310         });
311     }
312 
313     protected void addContainerPropertyRule(Digester digester, String path, final boolean asBean)
314     {
315         digester.addRule(path, new Rule()
316         {
317             public void begin(String s, String s1, Attributes attributes) throws Exception
318             {
319                 attributes = processor.processAttributes(attributes, s1);
320 
321                 String name = attributes.getValue("name");
322                 String value = attributes.getValue("reference");
323                 String required = attributes.getValue("required");
324                 String container = attributes.getValue("container");
325                 if (required == null)
326                 {
327                     required = "true";
328                 }
329                 boolean req = Boolean.valueOf(required).booleanValue();
330                 // if we're not setting as bean properties we need get the
331                 // top-most object
332                 // which will be a list or Map
333                 Object obj = null;
334                 if (asBean)
335                 {
336                     obj = digester.peek(1);
337                 }
338                 else
339                 {
340                     obj = digester.peek();
341                 }
342                 objectRefs.add(new ContainerReference(name, value, obj, req, container));
343             }
344         });
345     }
346 
347     protected void addTextPropertyRule(Digester digester, String path)
348     {
349 
350         digester.addRule(path, new Rule()
351         {
352             private String name = null;
353 
354             public void begin(String s, String s1, Attributes attributes) throws Exception
355             {
356                 // Process template tokens
357                 attributes = processor.processAttributes(attributes, s1);
358                 name = attributes.getValue("name");
359             }
360 
361             public void body(String string, String string1, String string2) throws Exception
362             {
363                 Object props = digester.peek();
364                 if (props instanceof Map)
365                 {
366                     ((Map)props).put(name, string2);
367                 }
368                 else
369                 {
370                     ((List)props).add(string2);
371                 }
372             }
373         });
374     }
375 
376     private class ProcessedCallParamRule extends CallParamRule
377     {
378         public ProcessedCallParamRule(int i)
379         {
380             super(i);
381         }
382 
383         public ProcessedCallParamRule(int i, String s)
384         {
385             super(i, s);
386         }
387 
388         public ProcessedCallParamRule(int i, boolean b)
389         {
390             super(i, b);
391         }
392 
393         public ProcessedCallParamRule(int i, int i1)
394         {
395             super(i, i1);
396         }
397 
398         public void begin(String endpointName, String endpointName1, Attributes attributes) throws Exception
399         {
400             // Process template tokens
401             attributes = processor.processAttributes(attributes, endpointName1);
402             super.begin(endpointName, endpointName1, attributes);
403         }
404     }
405 
406     public static interface PropertiesCallback
407     {
408         public void setProperties(Map props, Digester digester) throws Exception;
409     }
410 }