001 /***************************************************************************** 002 * Copyright (C) NanoContainer Organization. All rights reserved. * 003 * ------------------------------------------------------------------------- * 004 * The software in this package is published under the terms of the BSD * 005 * style license a copy of which has been included with this distribution in * 006 * the LICENSE.txt file. * 007 * * 008 * Original code by James Strachan * 009 *****************************************************************************/ 010 011 package org.nanocontainer.script.groovy.buildernodes; 012 013 import java.util.Map; 014 import org.nanocontainer.NanoContainer; 015 import org.nanocontainer.script.NanoContainerMarkupException; 016 import org.picocontainer.defaults.DefaultPicoContainer; 017 import java.security.PrivilegedAction; 018 import org.picocontainer.defaults.ComponentAdapterFactory; 019 import java.security.AccessController; 020 import org.picocontainer.defaults.DefaultComponentAdapterFactory; 021 import org.picocontainer.MutablePicoContainer; 022 import org.picocontainer.PicoContainer; 023 import org.nanocontainer.DefaultNanoContainer; 024 import org.nanocontainer.script.NodeBuilderDecorationDelegate; 025 import org.picocontainer.ComponentMonitor; 026 import org.picocontainer.defaults.DelegatingComponentMonitor; 027 import org.picocontainer.defaults.ComponentMonitorStrategy; 028 029 /** 030 * Creates a new NanoContainer node. There may or may not be a parent 031 * container involved. 032 * @author James Strachan 033 * @author Paul Hammant 034 * @author Aslak Hellesøy 035 * @author Michael Rimov 036 * @author Mauro Talevi 037 * @version $Revision: 2695 $ 038 */ 039 public class ChildContainerNode extends AbstractBuilderNode { 040 041 /** 042 * Node name. 043 */ 044 public static final String NODE_NAME = "container"; 045 046 /** 047 * Supported Attribute: 'class' Reference to a classname of the container 048 * to use. 049 */ 050 private static final String CLASS = "class"; 051 052 /** 053 * The node decoration delegate. 054 */ 055 private final NodeBuilderDecorationDelegate decorationDelegate; 056 057 /** 058 * Attribute: 'componentAdapterFactory' a reference to an instance of a 059 * component adapter factory. 060 */ 061 private static final String COMPONENT_ADAPTER_FACTORY = "componentAdapterFactory"; 062 063 /** 064 * Attribute: 'componentMonitor' a reference to an instance of a component monitor. 065 */ 066 private static final String COMPONENT_MONITOR = "componentMonitor"; 067 068 069 /** 070 * Attribute that exists in test cases, but not necessarily used? 071 * 072 */ 073 private static final String SCOPE = "scope"; 074 075 076 /** 077 * Attribute: 'parent' a reference to the parent for this new container. 078 */ 079 private static final String PARENT = "parent"; 080 081 082 /** 083 * Constructs a child container node. It requires a <tt>NodeBuilderDecorationDelegate</tt> 084 * for construction. 085 * @param delegate NodeBuilderDecorationDelegate 086 */ 087 public ChildContainerNode(NodeBuilderDecorationDelegate delegate) { 088 super(NODE_NAME); 089 decorationDelegate = delegate; 090 091 this.addAttribute(CLASS) 092 .addAttribute(COMPONENT_ADAPTER_FACTORY) 093 .addAttribute(COMPONENT_MONITOR) 094 .addAttribute(PARENT) 095 .addAttribute(SCOPE); 096 097 098 } 099 100 /** 101 * Creates a new container. There may or may not be a parent to this container. 102 * Supported attributes are 103 * <p>{@inheritDoc}</p> 104 * @param current NanoContainer 105 * @param attributes Map 106 * @return Object 107 * @throws NanoContainerMarkupException 108 */ 109 public Object createNewNode(Object current, Map attributes) throws 110 NanoContainerMarkupException { 111 112 return createChildContainer(attributes,(NanoContainer) current); 113 } 114 115 /** 116 * Retrieve the decoration delegate. 117 * @return NodeBuilderDecorationDelegate 118 */ 119 private NodeBuilderDecorationDelegate getDecorationDelegate() { 120 return decorationDelegate; 121 } 122 123 124 125 /** 126 * Creates a new container. There may or may not be a parent to this container. 127 * Supported attributes are: 128 * <ul> 129 * <li><tt>componentAdapterFactory</tt>: The ComponentAdapterFactory used for new container</li> 130 * <li><tt>componentMonitor</tt>: The ComponentMonitor used for new container</li> 131 * </ul> 132 * @param attributes Map Attributes defined by the builder in the script. 133 * @param parent The parent container 134 * @return The NanoContainer 135 */ 136 protected NanoContainer createChildContainer(Map attributes, NanoContainer parent) { 137 138 ClassLoader parentClassLoader = null; 139 MutablePicoContainer childContainer = null; 140 if (parent != null) { 141 parentClassLoader = parent.getComponentClassLoader(); 142 if ( isAttribute(attributes, COMPONENT_ADAPTER_FACTORY) ) { 143 ComponentAdapterFactory componentAdapterFactory = createComponentAdapterFactory(attributes); 144 childContainer = new DefaultPicoContainer( 145 getDecorationDelegate().decorate(componentAdapterFactory, attributes), parent.getPico()); 146 if ( isAttribute(attributes, COMPONENT_MONITOR) ) { 147 changeComponentMonitor(childContainer, createComponentMonitor(attributes)); 148 } 149 parent.getPico().addChildContainer(childContainer); 150 } else if ( isAttribute(attributes, COMPONENT_MONITOR) ) { 151 ComponentAdapterFactory componentAdapterFactory = new DefaultComponentAdapterFactory( 152 createComponentMonitor(attributes)); 153 childContainer = new DefaultPicoContainer( 154 getDecorationDelegate().decorate(componentAdapterFactory, attributes), parent.getPico()); 155 } else { 156 childContainer = parent.getPico().makeChildContainer(); 157 } 158 } else { 159 parentClassLoader = (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() { 160 public Object run() { 161 return PicoContainer.class.getClassLoader(); 162 } 163 }); 164 ComponentAdapterFactory componentAdapterFactory = createComponentAdapterFactory(attributes); 165 childContainer = new DefaultPicoContainer( 166 getDecorationDelegate().decorate(componentAdapterFactory, attributes)); 167 if ( isAttribute(attributes, COMPONENT_MONITOR) ) { 168 changeComponentMonitor(childContainer, createComponentMonitor(attributes)); 169 } 170 } 171 172 MutablePicoContainer decoratedPico = getDecorationDelegate().decorate(childContainer); 173 if ( isAttribute(attributes, CLASS) ) { 174 Class clazz = (Class) attributes.get(CLASS); 175 return createNanoContainer(clazz, decoratedPico, parentClassLoader); 176 } else { 177 return new DefaultNanoContainer(parentClassLoader, decoratedPico); 178 } 179 } 180 181 private void changeComponentMonitor(MutablePicoContainer childContainer, ComponentMonitor monitor) { 182 if ( childContainer instanceof ComponentMonitorStrategy ){ 183 ((ComponentMonitorStrategy)childContainer).changeMonitor(monitor); 184 } 185 } 186 187 private NanoContainer createNanoContainer(Class clazz, MutablePicoContainer decoratedPico, ClassLoader parentClassLoader) { 188 DefaultPicoContainer instantiatingContainer = new DefaultPicoContainer(); 189 instantiatingContainer.registerComponentInstance(ClassLoader.class, parentClassLoader); 190 instantiatingContainer.registerComponentInstance(MutablePicoContainer.class, decoratedPico); 191 instantiatingContainer.registerComponentImplementation(NanoContainer.class, clazz); 192 Object componentInstance = instantiatingContainer.getComponentInstance(NanoContainer.class); 193 return (NanoContainer) componentInstance; 194 } 195 196 private ComponentAdapterFactory createComponentAdapterFactory(Map attributes) { 197 final ComponentAdapterFactory factory = (ComponentAdapterFactory) attributes.remove(COMPONENT_ADAPTER_FACTORY); 198 if ( factory == null ){ 199 return new DefaultComponentAdapterFactory(); 200 } 201 return factory; 202 } 203 204 private ComponentMonitor createComponentMonitor(Map attributes) { 205 final ComponentMonitor monitor = (ComponentMonitor) attributes.remove(COMPONENT_MONITOR); 206 if ( monitor == null ){ 207 return new DelegatingComponentMonitor(); 208 } 209 return monitor; 210 } 211 212 213 }