View Javadoc

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