KickJava   Java API By Example, From Geeks To Geeks.

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


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  * *
9  *****************************************************************************/

10
11 package org.nanocontainer.script.xml;
12
13 import java.io.IOException JavaDoc;
14 import java.io.Reader JavaDoc;
15 import java.net.URL JavaDoc;
16 import java.util.ArrayList JavaDoc;
17 import java.util.List JavaDoc;
18
19 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
20 import javax.xml.parsers.ParserConfigurationException JavaDoc;
21
22 import org.nanocontainer.DefaultNanoContainer;
23 import org.nanocontainer.NanoContainer;
24 import org.nanocontainer.integrationkit.ContainerPopulator;
25 import org.nanocontainer.script.NanoContainerMarkupException;
26 import org.nanocontainer.script.ScriptedContainerBuilder;
27 import org.picocontainer.ComponentAdapter;
28 import org.picocontainer.MutablePicoContainer;
29 import org.picocontainer.Parameter;
30 import org.picocontainer.PicoContainer;
31 import org.picocontainer.defaults.ComponentAdapterFactory;
32 import org.picocontainer.defaults.ComponentParameter;
33 import org.picocontainer.defaults.ConstantParameter;
34 import org.picocontainer.defaults.DefaultComponentAdapterFactory;
35 import org.picocontainer.defaults.DefaultPicoContainer;
36 import org.w3c.dom.Document JavaDoc;
37 import org.w3c.dom.Element JavaDoc;
38 import org.w3c.dom.Node JavaDoc;
39 import org.w3c.dom.NodeList JavaDoc;
40 import org.xml.sax.InputSource JavaDoc;
41 import org.xml.sax.SAXException JavaDoc;
42
43 import com.thoughtworks.xstream.XStream;
44 import com.thoughtworks.xstream.io.HierarchicalStreamDriver;
45 import com.thoughtworks.xstream.io.xml.DomDriver;
46 import com.thoughtworks.xstream.io.xml.DomReader;
47
48 /**
49  * This class builds up a hierarchy of PicoContainers from an XML configuration file.
50  *
51  * @author Konstantin Pribluda
52  * @version $Revision: 2164 $
53  */

54 public class XStreamContainerBuilder extends ScriptedContainerBuilder implements ContainerPopulator {
55     private final Element JavaDoc rootElement;
56
57     private final static String JavaDoc IMPLEMENTATION = "implementation";
58     private final static String JavaDoc INSTANCE = "instance";
59     private final static String JavaDoc ADAPTER = "adapter";
60     private final static String JavaDoc CLASS = "class";
61     private final static String JavaDoc KEY = "key";
62     private final static String JavaDoc CONSTANT = "constant";
63     private final static String JavaDoc DEPENDENCY = "dependency";
64     private final static String JavaDoc CONSTRUCTOR = "constructor";
65
66     private final HierarchicalStreamDriver xsdriver;
67
68     /**
69     * construct with just reader, use context classloader
70     */

71     public XStreamContainerBuilder(Reader JavaDoc script) {
72         this(script,Thread.currentThread().getContextClassLoader());
73     }
74     
75     /**
76      * construct with given script and specified classloader
77      */

78     public XStreamContainerBuilder(Reader JavaDoc script, ClassLoader JavaDoc classLoader) {
79         this(script, classLoader, new DomDriver());
80     }
81
82     public XStreamContainerBuilder(Reader JavaDoc script, ClassLoader JavaDoc classLoader, HierarchicalStreamDriver driver) {
83         super(script, classLoader);
84         xsdriver = driver;
85         InputSource JavaDoc inputSource = new InputSource JavaDoc(script);
86         try {
87             rootElement = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(inputSource).getDocumentElement();
88         } catch (SAXException JavaDoc e) {
89             throw new NanoContainerMarkupException(e);
90         } catch (IOException JavaDoc e) {
91             throw new NanoContainerMarkupException(e);
92         } catch (ParserConfigurationException JavaDoc e) {
93             throw new NanoContainerMarkupException(e);
94         }
95     }
96
97     public XStreamContainerBuilder(URL JavaDoc script, ClassLoader JavaDoc classLoader, HierarchicalStreamDriver driver) {
98         super(script, classLoader);
99         xsdriver = driver;
100         try {
101             InputSource JavaDoc inputSource = new InputSource JavaDoc(getScriptReader());
102             rootElement = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(inputSource).getDocumentElement();
103         } catch (SAXException JavaDoc e) {
104             throw new NanoContainerMarkupException(e);
105         } catch (IOException JavaDoc e) {
106             throw new NanoContainerMarkupException(e);
107         } catch (ParserConfigurationException JavaDoc e) {
108             throw new NanoContainerMarkupException(e);
109         }
110     }
111
112     public void populateContainer(MutablePicoContainer container) {
113         populateContainer(container, rootElement);
114     }
115
116     /**
117      * just a convenience method, so we can work recursively with subcontainers
118      * for whatever puproses we see cool.
119      */

120     private void populateContainer(MutablePicoContainer container, Element JavaDoc rootElement) {
121         NodeList JavaDoc children = rootElement.getChildNodes();
122         Node JavaDoc child;
123         String JavaDoc name;
124         short type;
125         for (int i = 0; i < children.getLength(); i++) {
126             child = children.item(i);
127             type = child.getNodeType();
128
129             if (type == Document.ELEMENT_NODE) {
130                 name = child.getNodeName();
131                 if (IMPLEMENTATION.equals(name)) {
132                     try {
133                         insertImplementation(container, (Element JavaDoc) child);
134                     } catch (ClassNotFoundException JavaDoc e) {
135                         throw new NanoContainerMarkupException(e);
136                     }
137                 } else if (INSTANCE.equals(name)) {
138                     insertInstance(container, (Element JavaDoc) child);
139                 } else if (ADAPTER.equals(name)) {
140                     insertAdapter(container, (Element JavaDoc) child);
141                 } else {
142                     throw new NanoContainerMarkupException("Unsupported element:" + name);
143                 }
144             }
145         }
146
147     }
148
149     /**
150      * process adapter node
151      */

152     protected void insertAdapter(MutablePicoContainer container, Element JavaDoc rootElement) {
153         String JavaDoc key = rootElement.getAttribute(KEY);
154         String JavaDoc klass = rootElement.getAttribute(CLASS);
155         try {
156             DefaultPicoContainer nested = new DefaultPicoContainer();
157             populateContainer(nested, rootElement);
158
159             if (key != null) {
160                 container.registerComponent((ComponentAdapter) nested.getComponentInstance(key));
161             } else if (klass != null) {
162                 Class JavaDoc clazz = getClassLoader().loadClass(klass);
163                 container.registerComponent((ComponentAdapter) nested.getComponentInstanceOfType(clazz));
164             } else {
165                 container.registerComponent((ComponentAdapter) nested.getComponentInstanceOfType(ComponentAdapter.class));
166             }
167         } catch (ClassNotFoundException JavaDoc ex) {
168             throw new NanoContainerMarkupException(ex);
169         }
170
171     }
172
173     /**
174      * process implementation node
175      */

176     protected void insertImplementation(MutablePicoContainer container, Element JavaDoc rootElement) throws ClassNotFoundException JavaDoc {
177         String JavaDoc key = rootElement.getAttribute(KEY);
178         String JavaDoc klass = rootElement.getAttribute(CLASS);
179         String JavaDoc constructor = rootElement.getAttribute(CONSTRUCTOR);
180         if (klass == null || "".equals(klass)) {
181             throw new NanoContainerMarkupException("class specification is required for component implementation");
182         }
183
184         Class JavaDoc clazz = getClassLoader().loadClass(klass);
185
186         List JavaDoc parameters = new ArrayList JavaDoc();
187
188         NodeList JavaDoc children = rootElement.getChildNodes();
189         Node JavaDoc child;
190         String JavaDoc name;
191         String JavaDoc dependencyKey;
192         String JavaDoc dependencyClass;
193         Object JavaDoc parseResult;
194
195         for (int i = 0; i < children.getLength(); i++) {
196             child = children.item(i);
197             if (child.getNodeType() == Document.ELEMENT_NODE) {
198                 name = child.getNodeName();
199                 // constant parameter. it does not have any attributes.
200
if (CONSTANT.equals(name)) {
201                     // create constant with xstream
202
parseResult = parseElementChild((Element JavaDoc) child);
203                     if (parseResult == null) {
204                         throw new NanoContainerMarkupException("could not parse constant parameter");
205                     }
206                     parameters.add(new ConstantParameter(parseResult));
207                 } else if (DEPENDENCY.equals(name)) {
208                     // either key or class must be present. not both
209
// key has prececence
210
dependencyKey = ((Element JavaDoc) child).getAttribute(KEY);
211                     if (dependencyKey == null || "".equals(dependencyKey)) {
212                         dependencyClass = ((Element JavaDoc) child).getAttribute(CLASS);
213                         if (dependencyClass == null || "".equals(dependencyClass)) {
214                             throw new NanoContainerMarkupException("either key or class must be present for dependency");
215                         } else {
216                             parameters.add(new ComponentParameter(getClassLoader().loadClass(dependencyClass)));
217                         }
218                     } else {
219                         parameters.add(new ComponentParameter(dependencyKey));
220                     }
221                 }
222             }
223         }
224
225         // ok , we processed our children. insert implementation
226
Parameter[] parameterArray = (Parameter[]) parameters.toArray(new Parameter[parameters.size()]);
227         if (parameters.size() > 0 || "default".equals(constructor)) {
228             if (key == null || "".equals(key)) {
229                 // without key. clazz is our key
230
container.registerComponentImplementation(clazz, clazz, parameterArray);
231             } else {
232                 // with key
233
container.registerComponentImplementation(key, clazz, parameterArray);
234             }
235         } else {
236             if (key == null || "".equals(key)) {
237                 // without key. clazz is our key
238
container.registerComponentImplementation(clazz, clazz);
239             } else {
240                 // with key
241
container.registerComponentImplementation(key, clazz);
242             }
243
244         }
245     }
246
247     /**
248      * process instance node. we get key from atributes ( if any ) and leave content
249      * to xstream. we allow only one child node inside. ( first one wins )
250      */

251     protected void insertInstance(MutablePicoContainer container, Element JavaDoc rootElement) {
252         String JavaDoc key = rootElement.getAttribute(KEY);
253         Object JavaDoc result = parseElementChild(rootElement);
254         if (result == null) {
255             throw new NanoContainerMarkupException("no content could be parsed in instance");
256         }
257         if (key != null && !"".equals(key)) {
258             // insert with key
259
container.registerComponentInstance(key, result);
260         } else {
261             // or without
262
container.registerComponentInstance(result);
263         }
264     }
265
266     /**
267      * parse element child with xstream and provide object
268      */

269     protected Object JavaDoc parseElementChild(Element JavaDoc rootElement) {
270         NodeList JavaDoc children = rootElement.getChildNodes();
271         Node JavaDoc child;
272         for (int i = 0; i < children.getLength(); i++) {
273             child = children.item(i);
274             if (child.getNodeType() == Document.ELEMENT_NODE) {
275                 return (new XStream(xsdriver)).unmarshal(new DomReader((Element JavaDoc) child));
276             }
277         }
278         return null;
279     }
280
281     protected PicoContainer createContainerFromScript(PicoContainer parentContainer, Object JavaDoc assemblyScope) {
282         try {
283             String JavaDoc cafName = rootElement.getAttribute("componentadapterfactory");
284             if ("".equals(cafName) || cafName == null) {
285                 cafName = DefaultComponentAdapterFactory.class.getName();
286             }
287             Class JavaDoc cafClass = getClassLoader().loadClass(cafName);
288             ComponentAdapterFactory componentAdapterFactory = (ComponentAdapterFactory) cafClass.newInstance();
289             MutablePicoContainer picoContainer = new DefaultPicoContainer(componentAdapterFactory);
290             NanoContainer nano = new DefaultNanoContainer(getClassLoader(), picoContainer);
291             populateContainer(nano.getPico());
292             return nano.getPico();
293         } catch (ClassNotFoundException JavaDoc e) {
294             throw new NanoContainerMarkupException(e);
295         } catch (InstantiationException JavaDoc e) {
296             throw new NanoContainerMarkupException(e);
297         } catch (IllegalAccessException JavaDoc e) {
298             throw new NanoContainerMarkupException(e);
299         }
300     }
301 }
302
Popular Tags