[CVS nano] provisional comp from konstantin

Paul Hammant <paul-yCVjj/[email protected]> Thu, 5 Feb 2004 17:51:25 -0600
Newsgroups gmane.comp.java.nanocontainer.cvs
Message-ID <[email protected]>
Commit in nano/src on MAIN

java/org/nanocontainer/script/xml/XStreamContainerBuilder.java +239 added 1.1

test/org/nanocontainer/script/xml/XStreamContainerBuilderTestCase.java +79 added 1.1

+318

2 added files

provisional comp from konstantin

----------

nano /src /java /org /nanocontainer /script /xml

XStreamContainerBuilder.java added at 1.1

diff -N XStreamContainerBuilder.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ XStreamContainerBuilder.java 5 Feb 2004 23:51:25 -0000 1.1
@@ -0,0 +1,239 @@

+/*****************************************************************************
+ * Copyright (C) NanoContainer Organization. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * The software in this package is published under the terms of the BSD *
+ * style license a copy of which has been included with this distribution in *
+ * the LICENSE.txt file. *
+ * *
+ * *
+ *****************************************************************************/
+
+package org.nanocontainer.script.xml;
+
+import org.picocontainer.ComponentAdapter;
+import org.picocontainer.MutablePicoContainer;
+import org.picocontainer.PicoContainer;
+import org.picocontainer.Parameter;
+import org.picocontainer.defaults.DefaultComponentAdapterFactory;
+import org.picocontainer.defaults.ComponentAdapterFactory;
+import org.picocontainer.defaults.DefaultPicoContainer;
+import org.picocontainer.defaults.ObjectReference;
+import org.picocontainer.defaults.ConstantParameter;
+import org.picocontainer.defaults.ComponentParameter;
+import org.picoextras.integrationkit.PicoAssemblyException;
+import org.picoextras.reflection.DefaultReflectionContainerAdapter;
+import org.picoextras.reflection.ReflectionContainerAdapter;
+import org.nanocontainer.script.ScriptedComposingLifecycleContainerBuilder;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.File;
+import java.io.IOException;
+import java.io.Reader;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.thoughtworks.xstream.XStream;
+import com.thoughtworks.xstream.xml.dom.DomXMLReader;
+
+/**
+ * This class builds up a hierarchy of PicoContainers from an XML configuration file.
+ * @author Konstantin Pribluda
+ * @version $Revision: 1.1 $
+ */
+public class XStreamContainerBuilder extends ScriptedComposingLifecycleContainerBuilder {
+ private final Element rootElement;
+
+ private final static String IMPLEMENTATION = "implementation";
+ private final static String INSTANCE = "instance";
+ private final static String CLASS = "class";
+ private final static String KEY = "key";
+ private final static String CONSTANT = "constant";
+ private final static String DEPENDENCY = "dependency";
+
+ private XStream xstream;
+
+ public XStreamContainerBuilder(Reader script, ClassLoader classLoader) {
+ super(script, classLoader);
+ xstream = new XStream();
+ InputSource inputSource = new InputSource(script);
+ try {
+ rootElement = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(inputSource).getDocumentElement();
+ } catch (SAXException e) {
+ throw new PicoAssemblyException(e);
+ } catch (IOException e) {
+ throw new PicoAssemblyException(e);
+ } catch (ParserConfigurationException e) {
+ throw new PicoAssemblyException(e);
+ }
+ }
+
+ public void buildContainer(ObjectReference containerRef, ObjectReference parentContainerRef, Object assemblyScope) {
+
+ MutablePicoContainer container = createContainer();
+ try {
+ containerRef.set(container);
+ populateContainer(container, rootElement);
+
+ } catch (ClassNotFoundException e) {
+ throw new PicoAssemblyException(e);
+ //} catch (IOException e) {
+ // throw new PicoAssemblyException(e);
+ } catch (SAXException e) {
+ throw new PicoAssemblyException(e);
+ }
+ }
+
+ /**
+ * populate contaiber off root element. we process instance &amp; implementation
+ * nodes here
+ */
+ protected void populateContainer(MutablePicoContainer container, Element rootElement) throws SAXException, ClassNotFoundException
+ {
+ NodeList children = rootElement.getChildNodes();
+ Node child;
+ String name;
+ short type;
+ for (int i = 0; i < children.getLength(); i++) {
+ child = children.item(i);
+ type = child.getNodeType();
+
+ if (type == Document.ELEMENT_NODE) {
+ name = child.getNodeName();
+ if (IMPLEMENTATION.equals(name)) {
+ insertImplementation(container,(Element)child);
+ } else if( INSTANCE.equals(name)) {
+ insertInstance(container,(Element)child);
+ } else {
+ throw new PicoAssemblyException("Unsupported element:" + name);
+ }
+ }
+ }
+ }
+ /**
+ * process implementation node
+ */
+ protected void insertImplementation(MutablePicoContainer container, Element rootElement) throws SAXException, ClassNotFoundException
+ {
+ String key = rootElement.getAttribute(KEY);
+ String klass = rootElement.getAttribute(CLASS);
+ if(klass == null || "".equals(klass)) {
+ throw new PicoAssemblyException("class specification is required for component implementation");
+ }
+
+ Class clazz = classLoader.loadClass(klass);
+
+ ArrayList parameters = new ArrayList();
+
+ NodeList children = rootElement.getChildNodes();
+ Node child;
+ String name;
+ String dependencyKey;
+ String dependencyClass;
+ Object parseResult;
+
+ for(int i = 0; i < children.getLength(); i++) {
+ child = children.item(i);
+ if(child.getNodeType() == Document.ELEMENT_NODE ) {
+ name = child.getNodeName();
+ // constant parameter. it does not have any attributes.
+ if(CONSTANT.equals(name)) {
+ // create constant with xstream
+ parseResult = parseElementChild((Element)child);
+ if(parseResult == null) {
+ throw new PicoAssemblyException("could not parse constant parameter");
+ }
+ parameters.add(new ConstantParameter(parseResult));
+ } else if(DEPENDENCY.equals(name)) {
+ // either key or class must be present. not both
+ // key has prececence
+ dependencyKey = ((Element)child).getAttribute(KEY);
+ if(dependencyKey == null || "".equals(dependencyKey)) {
+ dependencyClass = ((Element)child).getAttribute(CLASS);
+ if(dependencyClass == null || "".equals(dependencyClass)) {
+ throw new PicoAssemblyException("either key or class must be present for dependecy");
+ } else {
+ parameters.add(new ComponentParameter(classLoader.loadClass(dependencyClass)));
+ }
+ } else {
+ parameters.add(new ComponentParameter(dependencyKey));
+ }
+ }
+ }
+ }
+
+ // ok , we processed our children. insert implementation
+ Parameter[] parameterArray = (Parameter[])parameters.toArray(new Parameter[parameters.size()]);
+
+ if(key == null || "".equals(key)) {
+ // without key. clazz is our key
+ container.registerComponentImplementation(clazz,clazz,parameterArray);
+ } else {
+ // with key
+ container.registerComponentImplementation(key,clazz,parameterArray);
+ }
+ }
+
+ /**
+ * process instance node. we get key from atributes ( if any ) and leave content
+ * to xstream. we allow only one child node inside. ( first one wins )
+ */
+ protected void insertInstance(MutablePicoContainer container, Element rootElement) throws SAXException, ClassNotFoundException
+ {
+ String key = rootElement.getAttribute(KEY);
+ Object result = parseElementChild(rootElement);
+ if(result == null) {
+ throw new PicoAssemblyException("no content could be parsed in instance");
+ }
+ if(key != null && !"".equals(key)) {
+ // insert with key
+ container.registerComponentInstance(key,result);
+ } else {
+ // or without
+ container.registerComponentInstance(result);
+ }
+ }
+
+ /**
+ * parse element child with xstream and provide object
+ */
+ protected Object parseElementChild( Element rootElement ) throws SAXException, ClassNotFoundException
+ {
+ NodeList children = rootElement.getChildNodes();
+ Node child;
+ for(int i = 0; i < children.getLength(); i++) {
+ child = children.item(i);
+ if(child.getNodeType() == Document.ELEMENT_NODE ) {
+ return (new XStream()).fromXML(new DomXMLReader((Element)child));
+ }
+ }
+ return null;
+ }
+
+
+ protected MutablePicoContainer createContainer() {
+ try {
+ String cafName = rootElement.getAttribute("componentadapterfactory");
+ if ("".equals(cafName) || cafName == null) {
+ cafName = DefaultComponentAdapterFactory.class.getName();
+ }
+ Class cfaClass = classLoader.loadClass(cafName);
+ ComponentAdapterFactory componentAdapterFactory = (ComponentAdapterFactory) cfaClass.newInstance();
+ return new DefaultPicoContainer(componentAdapterFactory);
+ } catch (ClassNotFoundException e) {
+ throw new PicoAssemblyException(e);
+ } catch (InstantiationException e) {
+ throw new PicoAssemblyException(e);
+ } catch (IllegalAccessException e) {
+ throw new PicoAssemblyException(e);
+ }
+ }
+
+}

----------

nano /src /test /org /nanocontainer /script /xml

XStreamContainerBuilderTestCase.java added at 1.1

diff -N XStreamContainerBuilderTestCase.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ XStreamContainerBuilderTestCase.java 5 Feb 2004 23:51:25 -0000 1.1
@@ -0,0 +1,79 @@

+/*****************************************************************************
+ * Copyright (C) NanoContainer Organization. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * The software in this package is published under the terms of the BSD *
+ * style license a copy of which has been included with this distribution in *
+ * the LICENSE.txt file. *
+ * *
+ * Original code by Aslak Hellesoy and Paul Hammant *
+ *****************************************************************************/
+package org.nanocontainer.script.xml;
+
+import org.picocontainer.PicoContainer;
+import org.picocontainer.defaults.ImplementationHidingComponentAdapterFactory;
+import org.picoextras.integrationkit.PicoAssemblyException;
+import org.nanocontainer.script.AbstractScriptedComposingLifecycleContainerBuilderTestCase;
+
+
+import org.picoextras.testmodel.DefaultWebServerConfig;
+import org.picoextras.testmodel.ThingThatTakesParamsInConstructor;
+import org.picoextras.testmodel.WebServer;
+import org.picoextras.testmodel.WebServerConfig;
+import org.picoextras.testmodel.WebServerConfigComp;
+import org.picoextras.testmodel.WebServerImpl;
+
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.File;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+/**
+ * test case for container creation off xml via xstream
+ */
+public class XStreamContainerBuilderTestCase extends AbstractScriptedComposingLifecycleContainerBuilderTestCase {
+
+
+ public void testContainerBuilding() throws ParserConfigurationException, SAXException, IOException, ClassNotFoundException, PicoAssemblyException {
+ Reader script = new StringReader("<container>" +
+ " <instance key='foo'>" +
+ " <string>foo bar</string>" +
+ " </instance>" +
+ " <instance key='bar'>" +
+ " <int>239</int>" +
+ " </instance>" +
+ " <instance>" +
+ " <org.picoextras.testmodel.DefaultWebServerConfig>" +
+ " <port>555</port>" +
+ " </org.picoextras.testmodel.DefaultWebServerConfig>" +
+ " </instance>" +
+ " <implementation class='org.picoextras.testmodel.WebServerImpl'>" +
+ " <dependency class='org.picoextras.testmodel.DefaultWebServerConfig'/>" +
+ " </implementation>" +
+ " <implementation key='konstantin needs beer' class='org.picoextras.testmodel.ThingThatTakesParamsInConstructor'>" +
+ " <constant>" +
+ " <string>it's really late</string>" +
+ " </constant>" +
+ " <constant>" +
+ " <int>239</int>" +
+ " </constant>" +
+ " </implementation>" +
+ "</container>");
+
+ PicoContainer pico = buildContainer(new XStreamContainerBuilder(script, getClass().getClassLoader()));
+ assertEquals(5, pico.getComponentInstances().size());
+ assertEquals("foo bar",pico.getComponentInstance("foo"));
+ assertEquals(new Integer(239),pico.getComponentInstance("bar"));
+ assertEquals(555,((DefaultWebServerConfig)pico.getComponentInstance(DefaultWebServerConfig.class)).getPort());
+
+ assertNotNull(pico.getComponentInstanceOfType(WebServerImpl.class));
+ assertNotNull(pico.getComponentInstanceOfType(ThingThatTakesParamsInConstructor.class));
+ assertSame(pico.getComponentInstance("konstantin needs beer"),pico.getComponentInstanceOfType(ThingThatTakesParamsInConstructor.class));
+ assertEquals("it's really late239",((ThingThatTakesParamsInConstructor)pico.getComponentInstance("konstantin needs beer")).getValue());
+ }
+
+
+}
+