KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > cache > factories > XmlConfigurationParser


1 /*
2  * JBoss, Home of Professional Open Source
3  *
4  * Distributable under LGPL license.
5  * See terms of license at gnu.org.
6  */

7 package org.jboss.cache.factories;
8
9 import org.apache.commons.logging.Log;
10 import org.apache.commons.logging.LogFactory;
11 import org.jboss.cache.buddyreplication.NextMemberBuddyLocator;
12 import org.jboss.cache.config.BuddyReplicationConfig;
13 import org.jboss.cache.config.BuddyReplicationConfig.BuddyLocatorConfig;
14 import org.jboss.cache.config.CacheLoaderConfig;
15 import org.jboss.cache.config.Configuration;
16 import org.jboss.cache.config.ConfigurationException;
17 import org.jboss.cache.config.EvictionConfig;
18 import org.jboss.cache.config.EvictionRegionConfig;
19 import org.jboss.cache.config.MissingPolicyException;
20 import org.jboss.cache.eviction.EvictionPolicy;
21 import org.jboss.cache.eviction.EvictionPolicyConfig;
22 import org.jboss.cache.util.Util;
23 import org.jboss.cache.xml.XmlHelper;
24 import org.w3c.dom.Attr JavaDoc;
25 import org.w3c.dom.Element JavaDoc;
26 import org.w3c.dom.NamedNodeMap JavaDoc;
27 import org.w3c.dom.Node JavaDoc;
28 import org.w3c.dom.NodeList JavaDoc;
29
30 import java.beans.PropertyEditor JavaDoc;
31 import java.beans.PropertyEditorManager JavaDoc;
32 import java.io.IOException JavaDoc;
33 import java.io.InputStream JavaDoc;
34 import java.lang.reflect.Method JavaDoc;
35 import java.util.ArrayList JavaDoc;
36 import java.util.HashMap JavaDoc;
37 import java.util.Iterator JavaDoc;
38 import java.util.List JavaDoc;
39 import java.util.Map JavaDoc;
40 import java.util.Map.Entry;
41 import java.util.Properties JavaDoc;
42
43 /**
44  * Reads in XMLconfiguration files and spits out a {@link org.jboss.cache.config.Configuration} object. When deployed as a
45  * JBoss MBean, this role is performed by the JBoss Microcontainer. This class is only used internally in unit tests
46  * or within {@link CacheFactory} implementations for standalone JBoss Cache usage.
47  *
48  * @author <a HREF="mailto:manik@jboss.org">Manik Surtani (manik@jboss.org)</a>
49  */

50 public class XmlConfigurationParser
51 {
52    private static Log log = LogFactory.getLog(XmlConfigurationParser.class);
53
54    public static final String JavaDoc ATTR = "attribute";
55    public static final String JavaDoc NAME = "name";
56
57    public Configuration parseFile(String JavaDoc filename)
58    {
59       return parseStream(getAsInputStreamFromClassLoader(filename));
60    }
61
62    public Configuration parseStream(InputStream JavaDoc stream)
63    {
64       // loop through all elements in XML.
65
if (stream == null) throw new ConfigurationException("Input stream for configuration xml is null!");
66
67       Element JavaDoc root = XmlHelper.getDocumentRoot(stream);
68       Element JavaDoc mbeanElement = getMBeanElement(root);
69
70       ParsedAttributes attributes = extractAttributes(mbeanElement);
71
72       // Special handling for the old separate property for
73
// eviction policy -- just cache it and use with the eviction XML
74
String JavaDoc defaultEvictionClass = attributes.stringAttribs.remove("EvictionPolicyClass");
75
76       // Deal with rename of the old property that controlled MBean registration
77
String JavaDoc keepStats = attributes.stringAttribs.remove("UseMbean");
78       if (keepStats != null && attributes.stringAttribs.get("ExposeManagementStatistics") == null)
79       {
80          attributes.stringAttribs.put("ExposeManagementStatistics", keepStats);
81       }
82
83       Configuration c = new Configuration();
84       setValues(c, attributes.stringAttribs, false);
85       // Special handling for XML elements -- we hard code the parsing
86
setXmlValues(c, attributes.xmlAttribs, defaultEvictionClass);
87
88       return c;
89    }
90
91    protected InputStream JavaDoc getAsInputStreamFromClassLoader(String JavaDoc filename)
92    {
93       return Thread.currentThread().getContextClassLoader().getResourceAsStream(filename);
94    }
95
96    protected Element JavaDoc getMBeanElement(Element JavaDoc root)
97    {
98       // This is following JBoss convention.
99
NodeList JavaDoc list = root.getElementsByTagName(XmlHelper.ROOT);
100       if (list == null) throw new ConfigurationException("Can't find " + XmlHelper.ROOT + " tag");
101
102       if (list.getLength() > 1) throw new ConfigurationException("Has multiple " + XmlHelper.ROOT + " tag");
103
104       Node JavaDoc node = list.item(0);
105       Element JavaDoc element = null;
106       if (node.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE)
107       {
108          element = (Element JavaDoc) node;
109       }
110       else
111       {
112          throw new ConfigurationException("Can't find " + XmlHelper.ROOT + " element");
113       }
114       return element;
115    }
116
117
118    protected static void setValues(Object JavaDoc target, Map JavaDoc attribs, boolean isXmlAttribs)
119    {
120       Class JavaDoc objectClass = target.getClass();
121
122       // go thru simple string setters first.
123
for (Iterator JavaDoc iter = attribs.entrySet().iterator(); iter.hasNext();)
124       {
125          Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iter.next();
126          String JavaDoc propName = (String JavaDoc) entry.getKey();
127          String JavaDoc setter = getSetterName(propName);
128          Method JavaDoc method = null;
129
130          try
131          {
132             if (isXmlAttribs)
133             {
134                method = objectClass.getMethod(setter, new Class JavaDoc[]{Element JavaDoc.class});
135                method.invoke(target, new Object JavaDoc[]{entry.getValue()});
136             }
137             else
138             {
139                method = objectClass.getMethod(setter, new Class JavaDoc[]{String JavaDoc.class});
140                method.invoke(target, new Object JavaDoc[]{entry.getValue()});
141             }
142
143             continue;
144          }
145          catch (NoSuchMethodException JavaDoc me)
146          {
147             // this is ok
148
//log.debug("Unable to find String setter for " + setter);
149
}
150          catch (Exception JavaDoc e)
151          {
152             throw new ConfigurationException("Unable to invoke setter " + setter + " on " + objectClass, e);
153          }
154
155          // if we get here, we could not find a String or Element setter.
156
for (Method JavaDoc m : objectClass.getMethods())
157          {
158             if (setter.equals(m.getName()))
159             {
160                Class JavaDoc paramTypes[] = m.getParameterTypes();
161                if (paramTypes.length != 1)
162                {
163                   throw new ConfigurationException("Setter " + setter + " does not contain the expected number of params. Has " + paramTypes.length + " instead of just 1.");
164                }
165
166                Class JavaDoc parameterType = paramTypes[0];
167                PropertyEditor JavaDoc editor = PropertyEditorManager.findEditor(parameterType);
168                if (editor == null)
169                {
170                   throw new ConfigurationException("Couldn't find a property editor for parameter type " + parameterType);
171                }
172
173                editor.setAsText((String JavaDoc) attribs.get(propName));
174
175                Object JavaDoc parameter = editor.getValue();
176                //if (log.isDebugEnabled()) log.debug("Invoking setter method: " + setter + " with parameter \"" + parameter + "\" of type " + parameter.getClass());
177

178                try
179                {
180                   m.invoke(target, new Object JavaDoc[]{parameter});
181                }
182                catch (Exception JavaDoc e)
183                {
184                   throw new ConfigurationException("Unable to invoke setter " + setter + " on " + objectClass, e);
185                }
186             }
187          }
188       }
189    }
190
191    protected void setXmlValues(Configuration conf, Map JavaDoc<String JavaDoc, Element JavaDoc> attribs, String JavaDoc defaultEvictionClass)
192    {
193       for (Iterator JavaDoc it = attribs.entrySet().iterator(); it.hasNext();)
194       {
195          Map.Entry JavaDoc entry = (Entry) it.next();
196          String JavaDoc propname = (String JavaDoc) entry.getKey();
197          if ("BuddyReplicationConfiguration".equals(propname)
198                  || "BuddyReplicationConfig".equals(propname))
199          {
200             BuddyReplicationConfig brc = parseBuddyReplicationConfig((Element JavaDoc) entry.getValue());
201             conf.setBuddyReplicationConfig(brc);
202          }
203          else if ("CacheLoaderConfiguration".equals(propname)
204                  || "CacheLoaderConfig".equals(propname))
205          {
206             CacheLoaderConfig clc = parseCacheLoaderConfig((Element JavaDoc) entry.getValue());
207             conf.setCacheLoaderConfig(clc);
208          }
209          else if ("EvictionPolicyConfiguration".equals(propname)
210                  || "EvictionPolicyConfig".equals(propname))
211          {
212             EvictionConfig ec = parseEvictionConfig((Element JavaDoc) entry.getValue(),
213                     defaultEvictionClass);
214             conf.setEvictionConfig(ec);
215          }
216          else if ("ClusterConfig".equals(propname))
217          {
218             String JavaDoc jgc = parseClusterConfigXml((Element JavaDoc) entry.getValue());
219             conf.setClusterConfig(jgc);
220          }
221          else
222          {
223             throw new ConfigurationException("Unknown configuration element " + propname);
224          }
225       }
226    }
227
228    public static BuddyReplicationConfig parseBuddyReplicationConfig(Element JavaDoc element)
229    {
230       BuddyReplicationConfig brc = new BuddyReplicationConfig();
231       brc.setEnabled(XmlHelper.readBooleanContents(element, "buddyReplicationEnabled"));
232       brc.setDataGravitationRemoveOnFind(XmlHelper.readBooleanContents(element, "dataGravitationRemoveOnFind", true));
233       brc.setDataGravitationSearchBackupTrees(XmlHelper.readBooleanContents(element, "dataGravitationSearchBackupTrees", true));
234       brc.setAutoDataGravitation(brc.isEnabled() && XmlHelper.readBooleanContents(element, "autoDataGravitation", false));
235
236       String JavaDoc strBuddyCommunicationTimeout = XmlHelper.readStringContents(element, "buddyCommunicationTimeout");
237       try
238       {
239          brc.setBuddyCommunicationTimeout(Integer.parseInt(strBuddyCommunicationTimeout));
240       }
241       catch (Exception JavaDoc e)
242       {
243       }
244       finally
245       {
246          if (log.isDebugEnabled())
247          {
248             log.debug("Using buddy communication timeout of " + brc.getBuddyCommunicationTimeout() + " millis");
249          }
250       }
251       String JavaDoc buddyPoolName = XmlHelper.readStringContents(element, "buddyPoolName");
252       if ("".equals(buddyPoolName))
253       {
254          buddyPoolName = null;
255       }
256
257       brc.setBuddyPoolName(buddyPoolName);
258
259       // now read the buddy locator details
260

261       String JavaDoc buddyLocatorClass = XmlHelper.readStringContents(element, "buddyLocatorClass");
262       if (buddyLocatorClass == null || buddyLocatorClass.length() == 0)
263       {
264          buddyLocatorClass = NextMemberBuddyLocator.class.getName();
265       }
266       Properties JavaDoc props = null;
267       try
268       {
269          props = XmlHelper.readPropertiesContents(element, "buddyLocatorProperties");
270       }
271       catch (IOException JavaDoc e)
272       {
273          log.warn("Caught exception reading buddyLocatorProperties", e);
274          log.error("Unable to read buddyLocatorProperties specified! Using defaults for [" + buddyLocatorClass + "]");
275       }
276       BuddyLocatorConfig blc = new BuddyLocatorConfig();
277       blc.setBuddyLocatorClass(buddyLocatorClass);
278       blc.setBuddyLocatorProperties(props);
279       brc.setBuddyLocatorConfig(blc);
280
281       return brc;
282    }
283
284    public static CacheLoaderConfig parseCacheLoaderConfig(Element JavaDoc element)
285    {
286       CacheLoaderConfig clc = new CacheLoaderConfig();
287       clc.setPassivation(XmlHelper.readBooleanContents(element, "passivation"));
288       clc.setPreload(XmlHelper.readStringContents(element, "preload"));
289       clc.setShared(XmlHelper.readBooleanContents(element, "shared"));
290
291       NodeList JavaDoc cacheLoaderNodes = element.getElementsByTagName("cacheloader");
292       for (int i = 0; i < cacheLoaderNodes.getLength(); i++)
293       {
294          Node JavaDoc node = cacheLoaderNodes.item(i);
295          if (node.getNodeType() == Node.ELEMENT_NODE)
296          {
297             Element JavaDoc indivElement = (Element JavaDoc) node;
298             CacheLoaderConfig.IndividualCacheLoaderConfig iclc = new CacheLoaderConfig.IndividualCacheLoaderConfig();
299             iclc.setAsync(XmlHelper.readBooleanContents(indivElement, "async", false));
300             iclc.setIgnoreModifications(XmlHelper.readBooleanContents(indivElement, "ignoreModifications", false));
301             iclc.setFetchPersistentState(XmlHelper.readBooleanContents(indivElement, "fetchPersistentState", false));
302             iclc.setPurgeOnStartup(XmlHelper.readBooleanContents(indivElement, "purgeOnStartup", false));
303             iclc.setClassName(XmlHelper.readStringContents(indivElement, "class"));
304             try
305             {
306                iclc.setProperties(XmlHelper.readPropertiesContents(indivElement, "properties"));
307             }
308             catch (IOException JavaDoc e)
309             {
310                throw new ConfigurationException("Problem loader cache loader properties", e);
311             }
312             iclc.setSingletonStore(XmlHelper.readBooleanContents(indivElement, "singletonStore", false));
313             iclc.setPushStateWhenCoordinator(XmlHelper.readBooleanAttribute(indivElement, "singletonStore", "pushStateWhenCoordinator", false));
314             clc.addIndividualCacheLoaderConfig(iclc);
315          }
316       }
317
318       return clc;
319    }
320
321    public static EvictionConfig parseEvictionConfig(Element JavaDoc element, String JavaDoc defaultEvictionClass)
322    {
323       EvictionConfig ec = new EvictionConfig();
324
325       ec.setDefaultEvictionPolicyClass(defaultEvictionClass);
326
327       if (element != null)
328       {
329          // If they set the default eviction policy in the element, use that
330
// in preference to the external attribute
331
String JavaDoc temp = XmlHelper.getTagContents(element,
332                  EvictionConfig.EVICTION_POLICY_CLASS, ATTR, NAME);
333          if (temp != null && temp.length() > 0)
334          {
335             defaultEvictionClass = temp;
336             ec.setDefaultEvictionPolicyClass(defaultEvictionClass);
337          }
338
339          temp = XmlHelper.getTagContents(element,
340                  EvictionConfig.WAKEUP_INTERVAL_SECONDS, ATTR, NAME);
341
342          int wakeupIntervalSeconds = 0;
343          if (temp != null)
344          {
345             wakeupIntervalSeconds = Integer.parseInt(temp);
346          }
347
348          if (wakeupIntervalSeconds <= 0)
349          {
350             wakeupIntervalSeconds = EvictionConfig.WAKEUP_DEFAULT;
351          }
352
353          ec.setWakeupIntervalSeconds(wakeupIntervalSeconds);
354
355          int eventQueueSize = 0;
356          temp = XmlHelper.getTagContents(element,
357                  EvictionConfig.EVENT_QUEUE_SIZE, ATTR, NAME);
358
359          if (temp != null)
360          {
361             eventQueueSize = Integer.parseInt(temp);
362          }
363
364          if (eventQueueSize <= 0)
365          {
366             eventQueueSize = EvictionConfig.EVENT_QUEUE_SIZE_DEFAULT;
367          }
368
369          ec.setDefaultEventQueueSize(eventQueueSize);
370
371          NodeList JavaDoc list = element.getElementsByTagName(EvictionRegionConfig.REGION);
372          if (list != null && list.getLength() > 0)
373          {
374             List JavaDoc regionConfigs = new ArrayList JavaDoc(list.getLength());
375             for (int i = 0; i < list.getLength(); i++)
376             {
377                org.w3c.dom.Node JavaDoc node = list.item(i);
378                if (node.getNodeType() != org.w3c.dom.Node.ELEMENT_NODE)
379                {
380                   continue;
381                }
382                try
383                {
384                   regionConfigs.add(parseEvictionRegionConfig((Element JavaDoc) node, defaultEvictionClass, eventQueueSize));
385                }
386                catch (MissingPolicyException ignored)
387                {
388                   // Just log a warning and continue
389
// TODO (BES Oct-2006) I did it this way as that is how it worked
390
// before, but why not just throw the exception?
391
LogFactory.getLog(EvictionConfig.class).warn(ignored.getLocalizedMessage());
392                }
393             }
394
395             ec.setEvictionRegionConfigs(regionConfigs);
396          }
397       }
398
399       return ec;
400
401    }
402
403    public static EvictionRegionConfig parseEvictionRegionConfig(Element JavaDoc element,
404                                                                 String JavaDoc defaultEvictionClass,
405                                                                 int defaultQueueCapacity)
406    {
407       EvictionRegionConfig erc = new EvictionRegionConfig();
408
409       erc.setRegionName(element.getAttribute(EvictionRegionConfig.NAME));
410
411       String JavaDoc temp = element.getAttribute(EvictionRegionConfig.EVENT_QUEUE_SIZE);
412       if (temp != null && temp.length() > 0)
413       {
414          erc.setEventQueueSize(Integer.parseInt(temp));
415       }
416       else
417       {
418          erc.setEventQueueSize(defaultQueueCapacity);
419       }
420
421       String JavaDoc evictionClass = element.getAttribute(EvictionRegionConfig.REGION_POLICY_CLASS);
422       if (evictionClass == null || evictionClass.length() == 0)
423       {
424          evictionClass = defaultEvictionClass;
425          // if it's still null... what do we configure?
426
if (evictionClass == null || evictionClass.length() == 0)
427          {
428             throw new MissingPolicyException(
429                     "There is no Eviction Policy Class specified on the region or for the entire cache!");
430          }
431       }
432
433       EvictionPolicy policy = null;
434       try
435       {
436          policy = (EvictionPolicy) Util.loadClass(evictionClass).newInstance();
437       }
438       catch (RuntimeException JavaDoc e)
439       {
440          throw e;
441       }
442       catch (Exception JavaDoc e)
443       {
444          throw new RuntimeException JavaDoc("Eviction class is not properly loaded in classloader", e);
445       }
446
447       EvictionPolicyConfig epc = null;
448       try
449       {
450          epc = policy.getEvictionConfigurationClass().newInstance();
451       }
452       catch (RuntimeException JavaDoc e)
453       {
454          throw e;
455       }
456       catch (Exception JavaDoc e)
457       {
458          throw new RuntimeException JavaDoc("Failed to instantiate eviction configuration of class " +
459                  policy.getEvictionConfigurationClass(), e);
460       }
461
462       parseEvictionPolicyConfig(element, epc);
463
464       erc.setEvictionPolicyConfig(epc);
465
466       return erc;
467    }
468
469    public static void parseEvictionPolicyConfig(Element JavaDoc element, EvictionPolicyConfig target)
470    {
471       target.reset();
472       ParsedAttributes attributes = extractAttributes(element);
473       setValues(target, attributes.stringAttribs, false);
474       setValues(target, attributes.xmlAttribs, true);
475       target.validate();
476    }
477
478    /**
479     * Parses the cluster config which is used to start a JGroups channel
480     *
481     * @param config an old-style JGroups protocol config String
482     */

483    public static String JavaDoc parseClusterConfigXml(Element JavaDoc config)
484    {
485       StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
486       NodeList JavaDoc stack = config.getChildNodes();
487       int length = stack.getLength();
488
489       for (int s = 0; s < length; s++)
490       {
491          org.w3c.dom.Node JavaDoc node = stack.item(s);
492          if (node.getNodeType() != org.w3c.dom.Node.ELEMENT_NODE)
493          {
494             continue;
495          }
496
497          Element JavaDoc tag = (Element JavaDoc) node;
498          String JavaDoc protocol = tag.getTagName();
499          buffer.append(protocol);
500          NamedNodeMap JavaDoc attrs = tag.getAttributes();
501          int attrLength = attrs.getLength();
502          if (attrLength > 0)
503          {
504             buffer.append('(');
505          }
506          for (int a = 0; a < attrLength; a++)
507          {
508             Attr JavaDoc attr = (Attr JavaDoc) attrs.item(a);
509             String JavaDoc name = attr.getName();
510             String JavaDoc value = attr.getValue();
511             buffer.append(name);
512             buffer.append('=');
513             buffer.append(value);
514             if (a < attrLength - 1)
515             {
516                buffer.append(';');
517             }
518          }
519          if (attrLength > 0)
520          {
521             buffer.append(')');
522          }
523          buffer.append(':');
524       }
525       // Remove the trailing ':'
526
buffer.setLength(buffer.length() - 1);
527       return buffer.toString();
528    }
529
530    protected static ParsedAttributes extractAttributes(Element JavaDoc source)
531    {
532       Map JavaDoc<String JavaDoc, String JavaDoc> stringAttribs = new HashMap JavaDoc<String JavaDoc, String JavaDoc>();
533       Map JavaDoc<String JavaDoc, Element JavaDoc> xmlAttribs = new HashMap JavaDoc<String JavaDoc, Element JavaDoc>();
534       NodeList JavaDoc list = source.getElementsByTagName(XmlHelper.ATTR);
535       if (log.isDebugEnabled()) log.debug("Attribute size: " + list.getLength());
536
537
538       // loop through attributes
539
for (int loop = 0; loop < list.getLength(); loop++)
540       {
541          Node JavaDoc node = list.item(loop);
542          if (node.getNodeType() != org.w3c.dom.Node.ELEMENT_NODE) continue;
543
544          // for each element (attribute) ...
545
Element JavaDoc element = (Element JavaDoc) node;
546          String JavaDoc name = element.getAttribute(XmlHelper.NAME);
547          String JavaDoc valueStr = XmlHelper.getElementContent(element, true);
548
549          Element JavaDoc valueXml = null;
550          if (valueStr.length() == 0)
551          {
552             // This may be an XML element ...
553
valueXml = XmlHelper.getConfigSubElement(element);
554          }
555
556          // add these to the maps.
557

558          if (valueStr.length() > 0) stringAttribs.put(name, valueStr);
559          if (valueXml != null) xmlAttribs.put(name, valueXml);
560       }
561
562       return new ParsedAttributes(stringAttribs, xmlAttribs);
563    }
564
565    private static String JavaDoc getSetterName(String JavaDoc propName)
566    {
567       StringBuffer JavaDoc sb = new StringBuffer JavaDoc("set");
568       if (propName != null && propName.length() > 0)
569       {
570          sb.append(propName.substring(0, 1).toUpperCase());
571          if (propName.length() > 1)
572          {
573             sb.append(propName.substring(1));
574          }
575       }
576       return sb.toString();
577    }
578
579    static class ParsedAttributes
580    {
581       Map JavaDoc<String JavaDoc, String JavaDoc> stringAttribs;
582       Map JavaDoc<String JavaDoc, Element JavaDoc> xmlAttribs;
583
584       ParsedAttributes(Map JavaDoc strings, Map JavaDoc elements)
585       {
586          this.stringAttribs = strings;
587          this.xmlAttribs = elements;
588       }
589    }
590 }
591
Popular Tags