KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > nanocontainer > script > xml > XMLContainerBuilder


1 /*****************************************************************************
2  * Copyright (C) NanoContainer Organization. All rights reserved. *
3  * ------------------------------------------------------------------------- *
4  * The software in this package is published under the terms of the BSD *
5  * style license a copy of which has been included with this distribution in *
6  * the LICENSE.txt file. *
7  * *
8  * Original code by Aslak Hellesoy and Paul Hammant *
9  *****************************************************************************/

10
11 package org.nanocontainer.script.xml;
12
13 import java.io.File JavaDoc;
14 import java.io.IOException JavaDoc;
15 import java.io.Reader JavaDoc;
16 import java.net.MalformedURLException JavaDoc;
17 import java.net.URL JavaDoc;
18 import java.security.Permission JavaDoc;
19 import java.util.ArrayList JavaDoc;
20 import java.util.List JavaDoc;
21
22 import javax.xml.parsers.DocumentBuilder JavaDoc;
23 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
24 import javax.xml.parsers.ParserConfigurationException JavaDoc;
25
26 import org.nanocontainer.ClassNameKey;
27 import org.nanocontainer.ClassPathElement;
28 import org.nanocontainer.DefaultNanoContainer;
29 import org.nanocontainer.NanoContainer;
30 import org.nanocontainer.reflection.DefaultNanoPicoContainer;
31 import org.nanocontainer.integrationkit.ContainerPopulator;
32 import org.nanocontainer.integrationkit.PicoCompositionException;
33 import org.nanocontainer.script.NanoContainerMarkupException;
34 import org.nanocontainer.script.ScriptedContainerBuilder;
35 import org.picocontainer.ComponentMonitor;
36 import org.picocontainer.MutablePicoContainer;
37 import org.picocontainer.Parameter;
38 import org.picocontainer.PicoContainer;
39 import org.picocontainer.defaults.ComponentAdapterFactory;
40 import org.picocontainer.defaults.ComponentMonitorStrategy;
41 import org.picocontainer.defaults.ComponentParameter;
42 import org.picocontainer.defaults.ConstantParameter;
43 import org.picocontainer.defaults.DefaultComponentAdapterFactory;
44 import org.picocontainer.defaults.DefaultPicoContainer;
45 import org.picocontainer.defaults.DelegatingComponentMonitor;
46 import org.w3c.dom.Element JavaDoc;
47 import org.w3c.dom.NodeList JavaDoc;
48 import org.xml.sax.EntityResolver JavaDoc;
49 import org.xml.sax.InputSource JavaDoc;
50 import org.xml.sax.SAXException JavaDoc;
51
52 /**
53  * This class builds up a hierarchy of PicoContainers from an XML configuration file.
54  *
55  * @author Paul Hammant
56  * @author Aslak Hellesøy
57  * @author Jeppe Cramon
58  * @author Mauro Talevi
59  * @version $Revision: 2953 $
60  */

61 public class XMLContainerBuilder extends ScriptedContainerBuilder implements ContainerPopulator {
62
63     private final static String JavaDoc DEFAULT_COMPONENT_ADAPTER_FACTORY = DefaultComponentAdapterFactory.class.getName();
64     private final static String JavaDoc DEFAULT_COMPONENT_INSTANCE_FACTORY = BeanComponentInstanceFactory.class.getName();
65     private final static String JavaDoc DEFAULT_COMPONENT_MONITOR = DelegatingComponentMonitor.class.getName();
66
67     private final static String JavaDoc CONTAINER = "container";
68     private final static String JavaDoc CLASSPATH = "classpath";
69     private final static String JavaDoc CLASSLOADER = "classloader";
70     private static final String JavaDoc CLASS_NAME_KEY = "class-name-key";
71     private final static String JavaDoc COMPONENT = "component";
72     private final static String JavaDoc COMPONENT_IMPLEMENTATION = "component-implementation";
73     private final static String JavaDoc COMPONENT_INSTANCE = "component-instance";
74     private final static String JavaDoc COMPONENT_ADAPTER = "component-adapter";
75     private final static String JavaDoc COMPONENT_ADAPTER_FACTORY = "component-adapter-factory";
76     private final static String JavaDoc COMPONENT_INSTANCE_FACTORY = "component-instance-factory";
77     private final static String JavaDoc COMPONENT_MONITOR = "component-monitor";
78     private final static String JavaDoc DECORATING_PICOCONTAINER = "decorating-picocontainer";
79     private final static String JavaDoc CLASS = "class";
80     private final static String JavaDoc FACTORY = "factory";
81     private final static String JavaDoc FILE = "file";
82     private final static String JavaDoc KEY = "key";
83     private final static String JavaDoc PARAMETER = "parameter";
84     private final static String JavaDoc URL = "url";
85
86     private final static String JavaDoc CLASSNAME = "classname";
87     private final static String JavaDoc CONTEXT = "context";
88     private final static String JavaDoc VALUE = "value";
89
90     private static final String JavaDoc EMPTY = "";
91
92     private Element rootElement;
93     /**
94      * The XMLComponentInstanceFactory globally defined for the container.
95      * It may be overridden at node level.
96      */

97     private XMLComponentInstanceFactory componentInstanceFactory;
98
99     public XMLContainerBuilder(Reader JavaDoc script, ClassLoader JavaDoc classLoader) {
100         super(script, classLoader);
101         try {
102             DocumentBuilder JavaDoc documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
103             parse(documentBuilder, new InputSource JavaDoc(script));
104         } catch (ParserConfigurationException JavaDoc e) {
105             throw new NanoContainerMarkupException(e);
106         }
107     }
108
109     public XMLContainerBuilder(final URL JavaDoc script, ClassLoader JavaDoc classLoader) {
110         super(script, classLoader);
111         try {
112             DocumentBuilder JavaDoc documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
113             documentBuilder.setEntityResolver(new EntityResolver JavaDoc() {
114                 public InputSource JavaDoc resolveEntity(String JavaDoc publicId, String JavaDoc systemId) throws IOException JavaDoc {
115                     URL JavaDoc url = new URL JavaDoc(script, systemId);
116                     return new InputSource JavaDoc(url.openStream());
117                 }
118             });
119             parse(documentBuilder, new InputSource JavaDoc(script.toString()));
120         } catch (ParserConfigurationException JavaDoc e) {
121             throw new NanoContainerMarkupException(e);
122         }
123     }
124
125     private void parse(DocumentBuilder JavaDoc documentBuilder, InputSource JavaDoc inputSource) {
126         try {
127             rootElement = documentBuilder.parse(inputSource).getDocumentElement();
128         } catch (SAXException JavaDoc e) {
129             throw new NanoContainerMarkupException(e);
130         } catch (IOException JavaDoc e) {
131             throw new NanoContainerMarkupException(e);
132         }
133     }
134
135     protected PicoContainer createContainerFromScript(PicoContainer parentContainer, Object JavaDoc assemblyScope) {
136         try {
137             // create ComponentInstanceFactory for the container
138
componentInstanceFactory = createComponentInstanceFactory(rootElement.getAttribute(COMPONENT_INSTANCE_FACTORY));
139             MutablePicoContainer childContainer = createMutablePicoContainer(rootElement.getAttribute(COMPONENT_ADAPTER_FACTORY),
140                     rootElement.getAttribute(COMPONENT_MONITOR), parentContainer);
141             populateContainer(childContainer);
142             return childContainer;
143         } catch (ClassNotFoundException JavaDoc e) {
144             throw new NanoContainerMarkupException("Class not found:" + e.getMessage(), e);
145         }
146     }
147
148     private MutablePicoContainer createMutablePicoContainer(String JavaDoc cafName, String JavaDoc monitorName, PicoContainer parentContainer) throws PicoCompositionException, ClassNotFoundException JavaDoc {
149         MutablePicoContainer container = new DefaultNanoPicoContainer(getClassLoader(),createComponentAdapterFactory(cafName, new DefaultNanoContainer(getClassLoader())), parentContainer);
150         if ( !notSet(monitorName) ){
151             ComponentMonitor monitor = createComponentMonitor(monitorName);
152             ((ComponentMonitorStrategy)container).changeMonitor(monitor);
153         }
154         return container;
155     }
156
157     public void populateContainer(MutablePicoContainer container) {
158         try {
159             String JavaDoc parentClass = rootElement.getAttribute("parentclassloader");
160             ClassLoader JavaDoc classLoader = getClassLoader();
161             if (parentClass != null && !EMPTY.equals(parentClass)) {
162                 classLoader = classLoader.loadClass(parentClass).getClassLoader();
163             }
164             NanoContainer nanoContainer = new DefaultNanoContainer(classLoader, container);
165             registerComponentsAndChildContainers(nanoContainer, rootElement, new DefaultNanoContainer(getClassLoader()));
166         } catch (ClassNotFoundException JavaDoc e) {
167             throw new NanoContainerMarkupException("Class not found: " + e.getMessage(), e);
168         } catch (IOException JavaDoc e) {
169             throw new NanoContainerMarkupException(e);
170         } catch (SAXException JavaDoc e) {
171             throw new NanoContainerMarkupException(e);
172         }
173     }
174
175     private void registerComponentsAndChildContainers(NanoContainer parentContainer, Element containerElement, NanoContainer knownComponentAdapterFactories) throws ClassNotFoundException JavaDoc, IOException JavaDoc, SAXException JavaDoc {
176
177         NanoContainer metaContainer = new DefaultNanoContainer(getClassLoader(), knownComponentAdapterFactories.getPico());
178         NodeList JavaDoc children = containerElement.getChildNodes();
179         // register classpath first, regardless of order in the document.
180
for (int i = 0; i < children.getLength(); i++) {
181             if (children.item(i) instanceof Element) {
182                 Element childElement = (Element) children.item(i);
183                 String JavaDoc name = childElement.getNodeName();
184                 if (CLASSPATH.equals(name)) {
185                     registerClasspath(parentContainer, childElement);
186                 }
187             }
188         }
189         for (int i = 0; i < children.getLength(); i++) {
190             if (children.item(i) instanceof Element) {
191                 Element childElement = (Element) children.item(i);
192                 String JavaDoc name = childElement.getNodeName();
193                 if (CONTAINER.equals(name)) {
194                     MutablePicoContainer childContainer = parentContainer.getPico().makeChildContainer();
195                     NanoContainer childNanoContainer = new DefaultNanoContainer(parentContainer.getComponentClassLoader(), childContainer);
196                     registerComponentsAndChildContainers(childNanoContainer, childElement, metaContainer);
197                 } else if (COMPONENT_IMPLEMENTATION.equals(name)
198                         || COMPONENT.equals(name)) {
199                     registerComponentImplementation(parentContainer, childElement);
200                 } else if (COMPONENT_INSTANCE.equals(name)) {
201                     registerComponentInstance(parentContainer, childElement);
202                 } else if (COMPONENT_ADAPTER.equals(name)) {
203                     registerComponentAdapter(parentContainer, childElement, metaContainer);
204                 } else if (COMPONENT_ADAPTER_FACTORY.equals(name)) {
205                     addComponentAdapterFactory(childElement, metaContainer);
206                 } else if (CLASSLOADER.equals(name)) {
207                     registerClassLoader(parentContainer, childElement, metaContainer);
208                 } else if (DECORATING_PICOCONTAINER.equals(name)) {
209                     addDecoratingPicoContainer(parentContainer, childElement);
210                 } else if (CLASSPATH.equals(name) != true) {
211                     throw new NanoContainerMarkupException("Unsupported element:" + name);
212                 }
213             }
214         }
215     }
216
217
218     private void addComponentAdapterFactory(Element element, NanoContainer metaContainer) throws MalformedURLException JavaDoc, ClassNotFoundException JavaDoc {
219         if (notSet(element.getAttribute(KEY))) {
220             throw new NanoContainerMarkupException("'" + KEY + "' attribute not specified for " + element.getNodeName());
221         }
222         Element node = (Element)element.cloneNode(false);
223         NodeList JavaDoc children = element.getChildNodes();
224         for (int i = 0; i < children.getLength(); i++) {
225             if (children.item(i) instanceof Element) {
226                 Element childElement = (Element) children.item(i);
227                 String JavaDoc name = childElement.getNodeName();
228                 if (COMPONENT_ADAPTER_FACTORY.equals(name)) {
229                     if (!"".equals(childElement.getAttribute(KEY))) {
230                         throw new NanoContainerMarkupException("'" + KEY + "' attribute must not be specified for nested " + element.getNodeName());
231                     }
232                     childElement = (Element)childElement.cloneNode(true);
233                     String JavaDoc key = String.valueOf(System.identityHashCode(childElement));
234                     childElement.setAttribute(KEY, key);
235                     addComponentAdapterFactory(childElement, metaContainer);
236                     // replace nested CAF with a ComponentParameter using an internally generated key
237
Element parameter = node.getOwnerDocument().createElement(PARAMETER);
238                     parameter.setAttribute(KEY, key);
239                     node.appendChild(parameter);
240                 } else if (PARAMETER.equals(name)) {
241                     node.appendChild(childElement.cloneNode(true));
242                 }
243             }
244         }
245         // handle CAF now as standard component in the metaContainer
246
registerComponentImplementation(metaContainer, node);
247     }
248
249     private void registerClassLoader(NanoContainer parentContainer, Element childElement, NanoContainer metaContainer) throws IOException JavaDoc, SAXException JavaDoc, ClassNotFoundException JavaDoc {
250         String JavaDoc parentClass = childElement.getAttribute("parentclassloader");
251         ClassLoader JavaDoc parentClassLoader = parentContainer.getComponentClassLoader();
252         if (parentClass != null && !EMPTY.equals(parentClass)) {
253             parentClassLoader = parentClassLoader.loadClass(parentClass).getClassLoader();
254         }
255         NanoContainer nano = new DefaultNanoContainer(parentClassLoader, parentContainer.getPico());
256         registerComponentsAndChildContainers(nano, childElement, metaContainer);
257     }
258
259     private void registerClasspath(NanoContainer container, Element classpathElement) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
260         NodeList JavaDoc children = classpathElement.getChildNodes();
261         for (int i = 0; i < children.getLength(); i++) {
262             if (children.item(i) instanceof Element) {
263                 Element childElement = (Element) children.item(i);
264
265                 String JavaDoc fileName = childElement.getAttribute(FILE);
266                 String JavaDoc urlSpec = childElement.getAttribute(URL);
267                 URL JavaDoc url = null;
268                 if (urlSpec != null && !EMPTY.equals(urlSpec)) {
269                     url = new URL JavaDoc(urlSpec);
270                 } else {
271                     File JavaDoc file = new File JavaDoc(fileName);
272                     if (!file.exists()) {
273                         throw new IOException JavaDoc(file.getAbsolutePath() + " doesn't exist");
274                     }
275                     url = file.toURL();
276                 }
277                 ClassPathElement cpe = container.addClassLoaderURL(url);
278                 registerPermissions(cpe, childElement);
279             }
280         }
281     }
282
283     private void registerPermissions(ClassPathElement classPathElement, Element classPathXmlElement) throws ClassNotFoundException JavaDoc {
284         NodeList JavaDoc children = classPathXmlElement.getChildNodes();
285         for (int i = 0; i < children.getLength(); i++) {
286             if (children.item(i) instanceof Element) {
287                 Element childElement = (Element) children.item(i);
288
289                 String JavaDoc permissionClassName = childElement.getAttribute(CLASSNAME);
290                 String JavaDoc action = childElement.getAttribute(CONTEXT);
291                 String JavaDoc value = childElement.getAttribute(VALUE);
292                 MutablePicoContainer mpc = new DefaultPicoContainer();
293                 mpc.registerComponentImplementation(Permission JavaDoc.class, Class.forName(permissionClassName),new Parameter[] {new ConstantParameter(action), new ConstantParameter(value)});
294
295                 Permission JavaDoc permission = (Permission JavaDoc) mpc.getComponentInstanceOfType(Permission JavaDoc.class);
296                 classPathElement.grantPermission(permission);
297             }
298         }
299
300     }
301
302     private void registerComponentImplementation(NanoContainer container, Element element) throws ClassNotFoundException JavaDoc, MalformedURLException JavaDoc {
303         String JavaDoc className = element.getAttribute(CLASS);
304         if (notSet(className)) {
305             throw new NanoContainerMarkupException("'" + CLASS + "' attribute not specified for " + element.getNodeName());
306         }
307
308         Parameter[] parameters = createChildParameters(container, element);
309         Class JavaDoc clazz = container.getComponentClassLoader().loadClass(className);
310         Object JavaDoc key = element.getAttribute(KEY);
311         String JavaDoc classKey = element.getAttribute(CLASS_NAME_KEY);
312         if (notSet(key)) {
313             if (!notSet(classKey)) {
314                 key = getClassLoader().loadClass(classKey);
315             } else {
316                 key = clazz;
317             }
318         }
319         if (parameters == null) {
320             container.getPico().registerComponentImplementation(key, clazz);
321         } else {
322             container.getPico().registerComponentImplementation(key, clazz, parameters);
323         }
324     }
325
326     private void addDecoratingPicoContainer(NanoContainer parentContainer, Element childElement) throws ClassNotFoundException JavaDoc {
327         String JavaDoc className = childElement.getAttribute("class");
328
329         parentContainer.addDecoratingPicoContainer(getClassLoader().loadClass(className));
330
331     }
332
333
334
335     private Parameter[] createChildParameters(NanoContainer container, Element element) throws ClassNotFoundException JavaDoc, MalformedURLException JavaDoc {
336         List JavaDoc parametersList = new ArrayList JavaDoc();
337         NodeList JavaDoc children = element.getChildNodes();
338         for (int i = 0; i < children.getLength(); i++) {
339             if (children.item(i) instanceof Element) {
340                 Element childElement = (Element) children.item(i);
341                 if (PARAMETER.equals(childElement.getNodeName())) {
342                     parametersList.add(createParameter(container.getPico(), childElement));
343                 }
344             }
345         }
346
347         Parameter[] parameters = null;
348         if (!parametersList.isEmpty()) {
349             parameters = (Parameter[]) parametersList.toArray(new Parameter[parametersList.size()]);
350         }
351         return parameters;
352     }
353
354     private Parameter createParameter(PicoContainer pico, Element element) throws ClassNotFoundException JavaDoc, MalformedURLException JavaDoc {
355         final Parameter parameter;
356         String JavaDoc key = element.getAttribute(KEY);
357         if (key != null && !EMPTY.equals(key)) {
358             parameter = new ComponentParameter(key);
359         } else if (getFirstChildElement(element, false) == null) {
360             parameter = new ComponentParameter();
361         } else {
362             Object JavaDoc instance = createInstance(pico, element);
363             parameter = new ConstantParameter(instance);
364         }
365         return parameter;
366     }
367
368     private void registerComponentInstance(NanoContainer container, Element element) throws ClassNotFoundException JavaDoc, PicoCompositionException, MalformedURLException JavaDoc {
369         Object JavaDoc instance = createInstance(container.getPico(), element);
370         String JavaDoc key = element.getAttribute(KEY);
371         String JavaDoc classKey = element.getAttribute(CLASS_NAME_KEY);
372         if (notSet(key)) {
373             if (!notSet(classKey)) {
374                 container.getPico().registerComponentInstance(getClassLoader().loadClass(classKey), instance);
375             } else {
376                 container.getPico().registerComponentInstance(instance);
377             }
378         } else {
379             container.getPico().registerComponentInstance(key, instance);
380         }
381     }
382
383     private Object JavaDoc createInstance(PicoContainer pico, Element element) throws ClassNotFoundException JavaDoc, MalformedURLException JavaDoc {
384         XMLComponentInstanceFactory factory = createComponentInstanceFactory(element.getAttribute(FACTORY));
385         Element instanceElement = getFirstChildElement(element, true);
386         return factory.makeInstance(pico, instanceElement, getClassLoader());
387     }
388
389     private Element getFirstChildElement(Element parent, boolean fail) {
390         NodeList JavaDoc children = parent.getChildNodes();
391         Element child = null;
392         for (int i = 0; i < children.getLength(); i++) {
393             if (children.item(i) instanceof Element) {
394                 child = (Element) children.item(i);
395                 break;
396             }
397         }
398         if (child == null && fail) {
399             throw new NanoContainerMarkupException(parent.getNodeName() + " needs a child element");
400         }
401         return child;
402     }
403
404     private XMLComponentInstanceFactory createComponentInstanceFactory(String JavaDoc factoryClass) throws ClassNotFoundException JavaDoc {
405         if ( notSet(factoryClass)) {
406             // no factory has been specified for the node
407
// return globally defined factory for the container - if there is one
408
if (componentInstanceFactory != null) {
409                 return componentInstanceFactory;
410             }
411             factoryClass = DEFAULT_COMPONENT_INSTANCE_FACTORY;
412         }
413
414         NanoContainer adapter = new DefaultNanoContainer(getClassLoader());
415         adapter.registerComponentImplementation(XMLComponentInstanceFactory.class.getName(), factoryClass);
416         return (XMLComponentInstanceFactory) adapter.getPico().getComponentInstances().get(0);
417     }
418
419     private void registerComponentAdapter(NanoContainer container, Element element, NanoContainer metaContainer) throws ClassNotFoundException JavaDoc, PicoCompositionException, MalformedURLException JavaDoc {
420         String JavaDoc className = element.getAttribute(CLASS);
421         if (notSet(className)) {
422             throw new NanoContainerMarkupException("'" + CLASS + "' attribute not specified for " + element.getNodeName());
423         }
424         Class JavaDoc implementationClass = getClassLoader().loadClass(className);
425         Object JavaDoc key = element.getAttribute(KEY);
426         String JavaDoc classKey = element.getAttribute(CLASS_NAME_KEY);
427         if (notSet(key)) {
428             if (!notSet(classKey)) {
429                 key = getClassLoader().loadClass(classKey);
430             } else {
431                 key = implementationClass;
432             }
433         }
434         Parameter[] parameters = createChildParameters(container, element);
435         ComponentAdapterFactory componentAdapterFactory = createComponentAdapterFactory(element.getAttribute(FACTORY), metaContainer);
436         container.getPico().registerComponent(componentAdapterFactory.createComponentAdapter(key, implementationClass, parameters));
437     }
438
439     private ComponentAdapterFactory createComponentAdapterFactory(String JavaDoc factoryName, NanoContainer metaContainer) throws ClassNotFoundException JavaDoc, PicoCompositionException {
440         if ( notSet(factoryName)) {
441             factoryName = DEFAULT_COMPONENT_ADAPTER_FACTORY;
442         }
443         final Object JavaDoc key;
444         if (metaContainer.getPico().getComponentAdapter(factoryName) != null) {
445             key = factoryName;
446         } else {
447             metaContainer.registerComponentImplementation(new ClassNameKey(ComponentAdapterFactory.class.getName()), factoryName);
448             key = ComponentAdapterFactory.class;
449         }
450         return (ComponentAdapterFactory) metaContainer.getPico().getComponentInstance(key);
451     }
452
453     private ComponentMonitor createComponentMonitor(String JavaDoc monitorName) throws ClassNotFoundException JavaDoc, PicoCompositionException {
454         if (notSet(monitorName)) {
455             monitorName = DEFAULT_COMPONENT_MONITOR;
456         }
457         Class JavaDoc monitorClass = getClassLoader().loadClass(monitorName);
458         try {
459             return (ComponentMonitor) monitorClass.newInstance();
460         } catch (InstantiationException JavaDoc e) {
461             throw new NanoContainerMarkupException(e);
462         } catch (IllegalAccessException JavaDoc e) {
463             throw new NanoContainerMarkupException(e);
464         }
465     }
466
467     private boolean notSet(Object JavaDoc string) {
468         return string == null || string.equals(EMPTY);
469     }
470
471 }
472
Popular Tags