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 }