All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nanocontainer.script.groovy.OldGroovyNodeBuilder Maven / Gradle / Ivy

The newest version!
/*****************************************************************************
 * 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 James Strachan                                           *
 *****************************************************************************/

package org.nanocontainer.script.groovy;

import groovy.lang.Closure;
import groovy.lang.GroovyObject;
import groovy.util.BuilderSupport;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.AccessController;
import java.security.Permission;
import java.security.PrivilegedAction;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.codehaus.groovy.runtime.InvokerHelper;
import org.nanocontainer.ClassNameKey;
import org.nanocontainer.ClassPathElement;
import org.nanocontainer.DefaultNanoContainer;
import org.nanocontainer.NanoContainer;
import org.nanocontainer.script.NanoContainerMarkupException;
import org.nanocontainer.script.NodeBuilderDecorationDelegate;
import org.nanocontainer.script.NullNodeBuilderDecorationDelegate;
import org.picocontainer.ComponentMonitor;
import org.picocontainer.MutablePicoContainer;
import org.picocontainer.Parameter;
import org.picocontainer.PicoContainer;
import org.picocontainer.ComponentAdapter;
import org.picocontainer.defaults.ComponentAdapterFactory;
import org.picocontainer.defaults.ComponentMonitorStrategy;
import org.picocontainer.defaults.ConstantParameter;
import org.picocontainer.defaults.DefaultComponentAdapterFactory;
import org.picocontainer.defaults.DefaultPicoContainer;
import org.picocontainer.defaults.DelegatingComponentMonitor;

/**
 * 

* Builds node trees of PicoContainers and Pico components using GroovyMarkup. *

*

Simple example usage in your groovy script: *

 * builder = new org.nanocontainer.script.groovy.OldGroovyNodeBuilder()
 * pico = builder.container(parent:parent) {
 *   component(class:org.nanocontainer.testmodel.DefaultWebServerConfig)
 *   component(class:org.nanocontainer.testmodel.WebServerImpl)
 * }
 * 
*

* @author James Strachan * @author Paul Hammant * @author Aslak Hellesøy * @author Michael Rimov * @author Mauro Talevi * @version $Revision: 3144 $ * @deprecated Since version 1.0-RC-3, use GroovyNodeBuilder instead. */ public class OldGroovyNodeBuilder extends BuilderSupport { private static final String NEW_BUILDER = "newBuilder"; private static final String CONTAINER = "container"; private static final String COMPONENT = "component"; private static final String INSTANCE = "instance"; private static final String KEY = "key"; private static final String PARAMETERS = "parameters"; private static final String BEAN = "bean"; private static final String BEAN_CLASS = "beanClass"; private static final String CLASS = "class"; private static final String CLASS_NAME_KEY = "classNameKey"; private static final String CLASSPATH_ELEMENT = "classPathElement"; private static final String CLASSLOADER = "classLoader"; private static final String PATH = "path"; private static final String GRANT = "grant"; private static final String HTTP = "http://"; private static final String PARENT = "parent"; private static final String COMPONENT_ADAPTER_FACTORY = "componentAdapterFactory"; private static final String COMPONENT_MONITOR = "componentMonitor"; private static final String EMPTY = ""; private static final String DO_CALL = "doCall"; private final NodeBuilderDecorationDelegate decorationDelegate; public OldGroovyNodeBuilder(NodeBuilderDecorationDelegate decorationDelegate) { this.decorationDelegate = decorationDelegate; } public OldGroovyNodeBuilder() { this(new NullNodeBuilderDecorationDelegate()); } protected void setParent(Object parent, Object child) { } protected Object doInvokeMethod(String s, Object name, Object args) { //TODO use setClosureDelegate() from Groovy JSR Object answer = super.doInvokeMethod(s, name, args); List list = InvokerHelper.asList(args); if (!list.isEmpty()) { Object o = list.get(list.size() - 1); if (o instanceof Closure) { Closure closure = (Closure) o; closure.setDelegate(answer); } } return answer; } protected void setClosureDelegate(Closure closure, Object o) { super.setClosureDelegate(closure, o); } protected Object createNode(Object name) { return createNode(name, Collections.EMPTY_MAP); } protected Object createNode(Object name, Object value) { Map attributes = new HashMap(); attributes.put(CLASS, value); return createNode(name, attributes); } /** * Override of create node. Called by BuilderSupport. It examines the * current state of the builder and the given parameters and dispatches the * code to one of the create private functions in this object. * @param name The name of the groovy node we're building. Examples are * 'container', and 'grant', * @param attributes Map attributes of the current invocation. * @return Object the created object. */ protected Object createNode(Object name, Map attributes, Object value) { Object current = getCurrent(); if (current != null && current instanceof GroovyObject) { return createChildBuilder(current, name, attributes); } else if (current == null || current instanceof NanoContainer) { NanoContainer parent = (NanoContainer) current; Object parentAttribute = attributes.get(PARENT); if (parent != null && parentAttribute != null) { throw new NanoContainerMarkupException("You can't explicitly specify a parent in a child element."); } if (parent == null && (parentAttribute instanceof MutablePicoContainer)) { // we're not in an enclosing scope - look at parent attribute instead parent = new DefaultNanoContainer((MutablePicoContainer) parentAttribute); } if (parent == null && (parentAttribute instanceof NanoContainer)) { // we're not in an enclosing scope - look at parent attribute instead parent = (NanoContainer) parentAttribute; } if (name.equals(CONTAINER)) { return createChildContainer(attributes, parent); } else { try { return createChildOfContainerNode(parent, name, attributes, current); } catch (ClassNotFoundException e) { throw new NanoContainerMarkupException("ClassNotFoundException: " + e.getMessage(), e); } } } else if (current instanceof ClassPathElement) { if (name.equals(GRANT)) { return createGrantPermission(attributes, (ClassPathElement) current); } return EMPTY; } else if (current instanceof ComponentAdapter && name.equals("instance")) { // TODO - Michael. // Michael, we could implement key() implementation() and possibly (with many limits on use) instance() here. // Not what you outline in NANO-138 as is though. return decorationDelegate.createNode(name, attributes, current); } else { // we don't know how to handle it - delegate to the decorator. return decorationDelegate.createNode(name, attributes, current); } } private Object createChildBuilder(Object current, Object name, Map attributes) { GroovyObject groovyObject = (GroovyObject) current; return groovyObject.invokeMethod(name.toString(), attributes); } private Object createGrantPermission(Map attributes, ClassPathElement cpe) { Permission perm = (Permission) attributes.remove(CLASS); return cpe.grantPermission(perm); } private Object createChildOfContainerNode(NanoContainer parentContainer, Object name, Map attributes, Object current) throws ClassNotFoundException { if (name.equals(COMPONENT)) { decorationDelegate.rememberComponentKey(attributes); return createComponentNode(attributes, parentContainer, name); } else if (name.equals(BEAN)) { return createBeanNode(attributes, parentContainer.getPico()); } else if (name.equals(CLASSPATH_ELEMENT)) { return createClassPathElementNode(attributes, parentContainer); } else if (name.equals(DO_CALL)) { // TODO does this node need to be handled? return null; } else if (name.equals(NEW_BUILDER)) { return createNewBuilderNode(attributes, parentContainer); } else if (name.equals(CLASSLOADER)) { return createComponentClassLoader(parentContainer); } else { // we don't know how to handle it - delegate to the decorator. return decorationDelegate.createNode(name, attributes, current); } } private Object createNewBuilderNode(Map attributes, NanoContainer parentContainer) { String builderClass = (String) attributes.remove(CLASS); NanoContainer factory = new DefaultNanoContainer(); MutablePicoContainer parentPico = parentContainer.getPico(); factory.getPico().registerComponentInstance(MutablePicoContainer.class, parentPico); try { factory.registerComponentImplementation(GroovyObject.class, builderClass); } catch (ClassNotFoundException e) { throw new NanoContainerMarkupException("ClassNotFoundException " + builderClass); } Object componentInstance = factory.getPico().getComponentInstance(GroovyObject.class); return componentInstance; } private ClassPathElement createClassPathElementNode(Map attributes, NanoContainer nanoContainer) { final String path = (String) attributes.remove(PATH); URL pathURL = null; try { if (path.toLowerCase().startsWith(HTTP)) { pathURL = new URL(path); } else { Object rVal = AccessController.doPrivileged(new PrivilegedAction() { public Object run() { try { File file = new File(path); if (!file.exists()) { return new NanoContainerMarkupException("classpath '" + path + "' does not exist "); } return file.toURL(); } catch (MalformedURLException e) { return e; } } }); if (rVal instanceof MalformedURLException) { throw (MalformedURLException) rVal; } if (rVal instanceof NanoContainerMarkupException) { throw (NanoContainerMarkupException) rVal; } pathURL = (URL) rVal; } } catch (MalformedURLException e) { throw new NanoContainerMarkupException("classpath '" + path + "' malformed ", e); } return nanoContainer.addClassLoaderURL(pathURL); } private Object createBeanNode(Map attributes, MutablePicoContainer pico) { Object bean = createBean(attributes); pico.registerComponentInstance(bean); return bean; } private Object createComponentNode(Map attributes, NanoContainer nano, Object name) throws ClassNotFoundException { Object key = attributes.remove(KEY); Object cnkey = attributes.remove(CLASS_NAME_KEY); Object classValue = attributes.remove(CLASS); Object instance = attributes.remove(INSTANCE); Object retval = null; List parameters = (List) attributes.remove(PARAMETERS); MutablePicoContainer pico = nano.getPico(); if (cnkey != null) { key = new ClassNameKey((String)cnkey); } Parameter[] parameterArray = getParameters(parameters); if (classValue instanceof Class) { Class clazz = (Class) classValue; key = key == null ? clazz : key; retval = pico.registerComponentImplementation(key, clazz, parameterArray); } else if (classValue instanceof String) { String className = (String) classValue; key = key == null ? className : key; retval = nano.registerComponentImplementation(key, className, parameterArray); } else if (instance != null) { key = key == null ? instance.getClass() : key; retval = pico.registerComponentInstance(key, instance); } else { throw new NanoContainerMarkupException("Must specify a class attribute for a component as a class name (string) or Class. Attributes:" + attributes); } return retval; } protected Object createNode(Object name, Map attributes) { return createNode(name, attributes, null); } /** * Creates a new container. There may or may not be a parent to this container. * Supported attributes are: *
    *
  • componentAdapterFactory: The ComponentAdapterFactory used for new container
  • *
  • componentMonitor: The ComponentMonitor used for new container
  • *
* @param attributes Map Attributes defined by the builder in the script. * @param parent The parent container * @return The NanoContainer */ protected NanoContainer createChildContainer(Map attributes, NanoContainer parent) { ClassLoader parentClassLoader = null; MutablePicoContainer childContainer = null; if (parent != null) { parentClassLoader = parent.getComponentClassLoader(); if ( isAttribute(attributes, COMPONENT_ADAPTER_FACTORY) ) { ComponentAdapterFactory componentAdapterFactory = createComponentAdapterFactory(attributes); childContainer = new DefaultPicoContainer( decorationDelegate.decorate(componentAdapterFactory, attributes), parent.getPico()); if ( isAttribute(attributes, COMPONENT_MONITOR) ) { changeComponentMonitor(childContainer, createComponentMonitor(attributes)); } parent.getPico().addChildContainer(childContainer); } else if ( isAttribute(attributes, COMPONENT_MONITOR) ) { ComponentAdapterFactory componentAdapterFactory = new DefaultComponentAdapterFactory( createComponentMonitor(attributes)); childContainer = new DefaultPicoContainer( decorationDelegate.decorate(componentAdapterFactory, attributes), parent.getPico()); } else { childContainer = parent.getPico().makeChildContainer(); } } else { parentClassLoader = (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { return PicoContainer.class.getClassLoader(); } }); ComponentAdapterFactory componentAdapterFactory = createComponentAdapterFactory(attributes); childContainer = new DefaultPicoContainer( decorationDelegate.decorate(componentAdapterFactory, attributes)); if ( isAttribute(attributes, COMPONENT_MONITOR) ) { changeComponentMonitor(childContainer, createComponentMonitor(attributes)); } } MutablePicoContainer decoratedPico = decorationDelegate.decorate(childContainer); if ( isAttribute(attributes, CLASS) ) { Class clazz = (Class) attributes.get(CLASS); return createNanoContainer(clazz, decoratedPico, parentClassLoader); } else { return new DefaultNanoContainer(parentClassLoader, decoratedPico); } } private void changeComponentMonitor(MutablePicoContainer childContainer, ComponentMonitor monitor) { if ( childContainer instanceof ComponentMonitorStrategy ){ ((ComponentMonitorStrategy)childContainer).changeMonitor(monitor); } } private NanoContainer createNanoContainer(Class clazz, MutablePicoContainer decoratedPico, ClassLoader parentClassLoader) { DefaultPicoContainer instantiatingContainer = new DefaultPicoContainer(); instantiatingContainer.registerComponentInstance(ClassLoader.class, parentClassLoader); instantiatingContainer.registerComponentInstance(MutablePicoContainer.class, decoratedPico); instantiatingContainer.registerComponentImplementation(NanoContainer.class, clazz); Object componentInstance = instantiatingContainer.getComponentInstance(NanoContainer.class); return (NanoContainer) componentInstance; } private boolean isAttribute(Map attributes, String key) { return attributes.containsKey(key) && attributes.get(key) != null; } private ComponentAdapterFactory createComponentAdapterFactory(Map attributes) { final ComponentAdapterFactory factory = (ComponentAdapterFactory) attributes.remove(COMPONENT_ADAPTER_FACTORY); if ( factory == null ){ return new DefaultComponentAdapterFactory(); } return factory; } private ComponentMonitor createComponentMonitor(Map attributes) { final ComponentMonitor monitor = (ComponentMonitor) attributes.remove(COMPONENT_MONITOR); if ( monitor == null ){ return new DelegatingComponentMonitor(); } return monitor; } protected NanoContainer createComponentClassLoader(NanoContainer parent) { return new DefaultNanoContainer(parent.getComponentClassLoader(), parent.getPico()); } protected Object createBean(Map attributes) { Class type = (Class) attributes.remove(BEAN_CLASS); if (type == null) { throw new NanoContainerMarkupException("Bean must have a beanClass attribute"); } try { Object bean = type.newInstance(); // now let's set the properties on the bean for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();) { Map.Entry entry = (Map.Entry) iter.next(); String name = entry.getKey().toString(); Object value = entry.getValue(); InvokerHelper.setProperty(bean, name, value); } return bean; } catch (IllegalAccessException e) { throw new NanoContainerMarkupException("Failed to create bean of type '" + type + "'. Reason: " + e, e); } catch (InstantiationException e) { throw new NanoContainerMarkupException("Failed to create bean of type " + type + "'. Reason: " + e, e); } } private Parameter[] getParameters(List paramsList) { if (paramsList == null) { return null; } int n = paramsList.size(); Parameter[] parameters = new Parameter[n]; for (int i = 0; i < n; ++i) { parameters[i] = toParameter(paramsList.get(i)); } return parameters; } private Parameter toParameter(Object obj) { return obj instanceof Parameter ? (Parameter) obj : new ConstantParameter(obj); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy