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