001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.components;
018:
019: import java.io.IOException;
020: import java.net.MalformedURLException;
021: import java.util.ArrayList;
022: import java.util.HashMap;
023: import java.util.Iterator;
024: import java.util.List;
025: import java.util.Map;
026:
027: import org.apache.avalon.excalibur.component.ExcaliburComponentManager;
028: import org.apache.avalon.framework.component.Component;
029: import org.apache.avalon.framework.component.ComponentException;
030: import org.apache.avalon.framework.component.ComponentManager;
031: import org.apache.avalon.framework.component.ComponentSelector;
032: import org.apache.avalon.framework.component.Recomposable;
033: import org.apache.avalon.framework.configuration.Configuration;
034: import org.apache.avalon.framework.configuration.ConfigurationException;
035: import org.apache.avalon.framework.logger.Logger;
036: import org.apache.cocoon.ProcessingException;
037: import org.apache.cocoon.Processor;
038: import org.apache.cocoon.environment.Environment;
039: import org.apache.cocoon.xml.XMLConsumer;
040: import org.apache.excalibur.instrument.InstrumentManager;
041: import org.apache.excalibur.source.Source;
042: import org.apache.excalibur.source.SourceException;
043: import org.apache.excalibur.source.SourceResolver;
044:
045: /**
046: * Cocoon Component Manager.
047: * This manager extends the {@link ExcaliburComponentManager}
048: * by a special lifecycle handling for a {@link RequestLifecycleComponent}
049: * and by handling the lookup of the {@link SourceResolver}.
050: * WARNING: This is a "private" Cocoon core class - do NOT use this class
051: * directly - and do not assume that a {@link ComponentManager} you get
052: * via the compose() method is an instance of CocoonComponentManager.
053: *
054: * @author <a href="mailto:bluetkemeier@s-und-n.de">Björn Lütkemeier</a>
055: * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
056: * @version CVS $Id: CocoonComponentManager.java 540711 2007-05-22 19:36:07Z cziegeler $
057: */
058: public final class CocoonComponentManager extends
059: ExcaliburComponentManager implements SourceResolver, Component {
060:
061: /** The key used to store the current process environment */
062: private static final String PROCESS_KEY = CocoonComponentManager.class
063: .getName();
064:
065: /** The environment attribute used to keep track of the actual environment in which the pipeline was built. */
066: private static final String PROCESSOR_ATTR = "CocoonComponentManager.processor";
067:
068: /** The environment information */
069: protected static final ThreadLocal environmentStack = new ThreadLocal();
070:
071: /** The configured {@link SourceResolver} */
072: private SourceResolver sourceResolver;
073:
074: /** The {@link SitemapConfigurationHolder}s */
075: private Map sitemapConfigurationHolders = new HashMap(15);
076:
077: /** The parent component manager for implementing parent aware components */
078: private ComponentManager parentManager;
079:
080: /** Temporary list of parent-aware components. Will be null for most of
081: * our lifecycle. */
082: private ArrayList parentAwareComponents = new ArrayList();
083:
084: /** has this been disposed? */
085: private boolean wasDisposed;
086:
087: /** The instrument manager (if any). */
088: private InstrumentManager instrumentManager;
089:
090: /** Create the ComponentManager */
091: public CocoonComponentManager() {
092: super (null, Thread.currentThread().getContextClassLoader());
093: }
094:
095: /** Create the ComponentManager with a Classloader */
096: public CocoonComponentManager(final ClassLoader loader) {
097: super (null, loader);
098: }
099:
100: /** Create the ComponentManager with a Classloader and parent ComponentManager */
101: public CocoonComponentManager(final ComponentManager manager,
102: final ClassLoader loader) {
103: super (manager, loader);
104: this .setParentManager(manager);
105: }
106:
107: /** Create the ComponentManager with a parent ComponentManager */
108: public CocoonComponentManager(final ComponentManager manager) {
109: super (manager);
110: this .setParentManager(manager);
111: }
112:
113: protected void setParentManager(final ComponentManager manager) {
114: this .parentManager = manager;
115: if (manager instanceof CocoonComponentManager) {
116: this
117: .setInstrumentManager(((CocoonComponentManager) manager).instrumentManager);
118: }
119: }
120:
121: /**
122: * @see org.apache.avalon.excalibur.component.ExcaliburComponentManager#setInstrumentManager(org.apache.excalibur.instrument.InstrumentManager)
123: */
124: public void setInstrumentManager(InstrumentManager iManager) {
125: this .instrumentManager = iManager;
126: super .setInstrumentManager(iManager);
127: }
128:
129: /**
130: * This hook must be called by the sitemap each time a sitemap is entered
131: * This method should never raise an exception, except when the
132: * parameters are not set!
133: */
134: public static void enterEnvironment(Environment env,
135: ComponentManager manager, Processor processor) {
136: if (null == env || null == manager || null == processor) {
137: throw new RuntimeException(
138: "CocoonComponentManager.enterEnvironment: "
139: + "All parameters must be set: " + env
140: + " - " + manager + " - " + processor);
141: }
142:
143: EnvironmentStack stack = (EnvironmentStack) environmentStack
144: .get();
145: if (stack == null) {
146: stack = new EnvironmentStack();
147: environmentStack.set(stack);
148: }
149: stack.push(new EnvironmentStack.Item(env, processor, manager,
150: stack.getOffset()));
151: stack.setOffset(stack.size() - 1);
152:
153: env.setAttribute(PROCESSOR_ATTR, processor);
154: }
155:
156: /**
157: * This hook must be called by the sitemap each time a sitemap is left.
158: * It's the counterpart to {@link #enterEnvironment(Environment, ComponentManager, Processor)}.
159: */
160: public static void leaveEnvironment() {
161: // Calling with true will avoid any change on the active processor
162: leaveEnvironment(true);
163: }
164:
165: /**
166: * This hook must be called by the sitemap each time a sitemap is left.
167: * It's the counterpart to {@link #enterEnvironment(Environment, ComponentManager, Processor)}.
168: *
169: * @param success indicates if the request was successfully handled by the environment that's being left
170: */
171: public static void leaveEnvironment(boolean success) {
172: final EnvironmentStack stack = (EnvironmentStack) environmentStack
173: .get();
174: final EnvironmentStack.Item objs = (EnvironmentStack.Item) stack
175: .pop();
176: stack.setOffset(objs.offset);
177:
178: if (stack.isEmpty()) {
179: final Environment env = objs.env;
180: final Map globalComponents = (Map) env
181: .getAttribute(GlobalRequestLifecycleComponent.class
182: .getName());
183: if (globalComponents != null) {
184:
185: final Iterator iter = globalComponents.values()
186: .iterator();
187: while (iter.hasNext()) {
188: final Object[] o = (Object[]) iter.next();
189: final Component c = (Component) o[0];
190: ((CocoonComponentManager) o[1])
191: .releaseRLComponent(c);
192: }
193: }
194: env.removeAttribute(GlobalRequestLifecycleComponent.class
195: .getName());
196:
197: // Setting this ThreadLocal to null allows it to be garbage collected
198: CocoonComponentManager.environmentStack.set(null);
199: } else {
200: if (!success) {
201: // Restore the current processor as being the active one
202: getCurrentEnvironment().setAttribute(PROCESSOR_ATTR,
203: getCurrentProcessor());
204: }
205: }
206: }
207:
208: /**
209: * INTERNAL METHOD. Do not use, can be removed without warning or deprecation cycle.
210: */
211: public static int markEnvironment() {
212: // TODO (CZ): This is only for testing - remove it later on. See also Cocoon.java.
213: final EnvironmentStack stack = (EnvironmentStack) environmentStack
214: .get();
215: if (stack != null) {
216: return stack.size();
217: }
218:
219: return 0;
220: }
221:
222: /**
223: * INTERNAL METHOD. Do not use, can be removed without warning or deprecation cycle.
224: */
225: public static void checkEnvironment(int depth, Logger logger)
226: throws Exception {
227: // TODO (CZ): This is only for testing - remove it later on. See also Cocoon.java.
228: final EnvironmentStack stack = (EnvironmentStack) environmentStack
229: .get();
230: int currentDepth = stack != null ? stack.size() : 0;
231: if (currentDepth != depth) {
232: logger
233: .error("ENVIRONMENT STACK HAS NOT BEEN CLEANED PROPERLY!");
234: throw new ProcessingException(
235: "Environment stack has not been cleaned up properly. "
236: + "Please report this (and if possible, together with a test case) "
237: + "to the Cocoon developers.");
238: }
239: }
240:
241: /**
242: * Create an environment aware xml consumer for the cocoon
243: * protocol
244: */
245: public static XMLConsumer createEnvironmentAwareConsumer(
246: XMLConsumer consumer) {
247: final EnvironmentStack stack = (EnvironmentStack) environmentStack
248: .get();
249: final EnvironmentStack.Item objs = stack.getCurrent();
250: return stack.getEnvironmentAwareConsumerWrapper(consumer,
251: objs.offset);
252: }
253:
254: /**
255: * This hook has to be called before a request is processed.
256: * The hook is called by the Cocoon component and by the
257: * cocoon protocol implementation.
258: * This method should never raise an exception, except when
259: * the environment is not set.
260: *
261: * @return A unique key within this thread.
262: */
263: public static Object startProcessing(Environment env) {
264: if (null == env) {
265: throw new RuntimeException(
266: "CocoonComponentManager.startProcessing: environment must be set.");
267: }
268: final EnvironmentDescription desc = new EnvironmentDescription(
269: env);
270: env.getObjectModel().put(PROCESS_KEY, desc);
271: env.startingProcessing();
272: return desc;
273: }
274:
275: /**
276: * This hook has to be called before a request is processed.
277: * The hook is called by the Cocoon component and by the
278: * cocoon protocol implementation.
279: * @param key A unique key within this thread return by
280: * {@link #startProcessing(Environment)}.
281: */
282: public static void endProcessing(Environment env, Object key) {
283: env.finishingProcessing();
284: final EnvironmentDescription desc = (EnvironmentDescription) key;
285: desc.release();
286: env.getObjectModel().remove(PROCESS_KEY);
287: }
288:
289: /**
290: * Return the current environment (for the cocoon: protocol)
291: */
292: public static Environment getCurrentEnvironment() {
293: final EnvironmentStack stack = (EnvironmentStack) environmentStack
294: .get();
295: if (null != stack && !stack.isEmpty()) {
296: return stack.getCurrent().env;
297: }
298: return null;
299: }
300:
301: /**
302: * Return the current processor (for the cocoon: protocol)
303: */
304: public static Processor getCurrentProcessor() {
305: final EnvironmentStack stack = (EnvironmentStack) environmentStack
306: .get();
307: if (null != stack && !stack.isEmpty()) {
308: return stack.getCurrent().processor;
309: }
310: return null;
311: }
312:
313: /**
314: * Return the processor that has actually processed the request
315: */
316: public static Processor getActiveProcessor(Environment env) {
317: return (Processor) env.getAttribute(PROCESSOR_ATTR);
318: }
319:
320: /**
321: * Get the current sitemap component manager.
322: * This method return the current sitemap component manager. This
323: * is the manager that holds all the components of the currently
324: * processed (sub)sitemap.
325: */
326: static public ComponentManager getSitemapComponentManager() {
327: final EnvironmentStack stack = (EnvironmentStack) environmentStack
328: .get();
329: if (null != stack && !stack.isEmpty()) {
330: EnvironmentStack.Item o = (EnvironmentStack.Item) stack
331: .peek();
332: return o.manager;
333: }
334:
335: // If we don't have an environment yet, just return null
336: return null;
337: }
338:
339: /**
340: * Return an instance of a component based on a Role. The Role is usually the Interface's
341: * Fully Qualified Name(FQN)--unless there are multiple Components for the same Role. In that
342: * case, the Role's FQN is appended with "Selector", and we return a ComponentSelector.
343: */
344: public Component lookup(final String role)
345: throws ComponentException {
346: if (null == role) {
347: final String message = "ComponentLocator Attempted to retrieve component with null role.";
348: throw new ComponentException(role, message);
349: }
350:
351: if (role.equals(SourceResolver.ROLE)) {
352: if (null == this .sourceResolver) {
353: if (this .wasDisposed) {
354: // (BD) working on bug 27249: I think we could throw an Exception here, as
355: // the following call fails anyway, but I'm not sure enough ;-)
356: this
357: .getLogger()
358: .warn(
359: "Trying to lookup SourceResolver on disposed CocoonComponentManager");
360: }
361: this .sourceResolver = (SourceResolver) super
362: .lookup(role);
363: }
364: return this ;
365: }
366:
367: final EnvironmentStack stack = (EnvironmentStack) environmentStack
368: .get();
369: if (null != stack && !stack.isEmpty()) {
370: final EnvironmentStack.Item objects = stack.getCurrent();
371: final Map objectModel = objects.env.getObjectModel();
372: EnvironmentDescription desc = (EnvironmentDescription) objectModel
373: .get(PROCESS_KEY);
374: if (null != desc) {
375: Component component = desc
376: .getRequestLifecycleComponent(role);
377: if (null != component) {
378: return component;
379: }
380: component = desc
381: .getGlobalRequestLifecycleComponent(role);
382: if (null != component) {
383: return component;
384: }
385: }
386: }
387:
388: final Component component = super .lookup(role);
389:
390: if (component != null
391: && component instanceof RequestLifecycleComponent) {
392: if (stack == null || stack.isEmpty()) {
393: throw new ComponentException(role,
394: "ComponentManager has no Environment Stack.");
395: }
396:
397: final EnvironmentStack.Item objects = stack.getCurrent();
398: final Map objectModel = objects.env.getObjectModel();
399: EnvironmentDescription desc = (EnvironmentDescription) objectModel
400: .get(PROCESS_KEY);
401: if (null != desc) {
402: // first test if the parent CM has already initialized this component
403: if (!desc.containsRequestLifecycleComponent(role)) {
404: try {
405: if (component instanceof Recomposable) {
406: ((Recomposable) component).recompose(this );
407: }
408: ((RequestLifecycleComponent) component).setup(
409: objects.env, objectModel);
410: } catch (Exception local) {
411: throw new ComponentException(
412: role,
413: "Exception during setup of RequestLifecycleComponent.",
414: local);
415: }
416: desc.addRequestLifecycleComponent(role, component,
417: this );
418: }
419: }
420: }
421:
422: if (component != null
423: && component instanceof GlobalRequestLifecycleComponent) {
424: if (stack == null || stack.isEmpty()) {
425: throw new ComponentException(role,
426: "ComponentManager has no Environment Stack.");
427: }
428:
429: final EnvironmentStack.Item objects = stack.getCurrent();
430: final Map objectModel = objects.env.getObjectModel();
431: EnvironmentDescription desc = (EnvironmentDescription) objectModel
432: .get(PROCESS_KEY);
433: if (null != desc) {
434: // first test if the parent CM has already initialized this component
435: if (!desc.containsGlobalRequestLifecycleComponent(role)) {
436: try {
437: if (component instanceof Recomposable) {
438: ((Recomposable) component).recompose(this );
439: }
440: ((GlobalRequestLifecycleComponent) component)
441: .setup(objects.env, objectModel);
442: } catch (Exception local) {
443: throw new ComponentException(
444: role,
445: "Exception during setup of RequestLifecycleComponent.",
446: local);
447: }
448: desc.addGlobalRequestLifecycleComponent(role,
449: component, this );
450: }
451: }
452: }
453:
454: if (component != null
455: && component instanceof SitemapConfigurable) {
456: // FIXME: how can we prevent that this is called over and over again?
457: SitemapConfigurationHolder holder;
458:
459: holder = (SitemapConfigurationHolder) this .sitemapConfigurationHolders
460: .get(role);
461: if (null == holder) {
462: // create new holder
463: holder = new DefaultSitemapConfigurationHolder(role);
464: this .sitemapConfigurationHolders.put(role, holder);
465: }
466:
467: try {
468: ((SitemapConfigurable) component).configure(holder);
469: } catch (ConfigurationException ce) {
470: throw new ComponentException(
471: role,
472: "Exception during setup of SitemapConfigurable.",
473: ce);
474: }
475: }
476:
477: return component;
478: }
479:
480: /**
481: * Release a Component. This implementation makes sure it has a handle on the propper
482: * ComponentHandler, and let's the ComponentHandler take care of the actual work.
483: */
484: public void release(final Component component) {
485: if (null == component) {
486: return;
487: }
488:
489: if (component instanceof RequestLifecycleComponent
490: || component instanceof GlobalRequestLifecycleComponent) {
491: return;
492: }
493:
494: if (component == this ) {
495: return;
496: }
497:
498: super .release(component);
499: }
500:
501: /**
502: * Release a RequestLifecycleComponent
503: */
504: protected void releaseRLComponent(final Component component) {
505: super .release(component);
506: }
507:
508: /**
509: * Add an automatically released component
510: */
511: public static void addComponentForAutomaticRelease(
512: final ComponentSelector selector,
513: final Component component, final ComponentManager manager)
514: throws ProcessingException {
515: final EnvironmentStack stack = (EnvironmentStack) environmentStack
516: .get();
517: if (null != stack && !stack.isEmpty()) {
518: final EnvironmentStack.Item objects = (EnvironmentStack.Item) stack
519: .get(0);
520: final Map objectModel = objects.env.getObjectModel();
521: EnvironmentDescription desc = (EnvironmentDescription) objectModel
522: .get(PROCESS_KEY);
523: if (null != desc) {
524: desc.addToAutoRelease(selector, component, manager);
525: }
526: } else {
527: throw new ProcessingException(
528: "Unable to add component for automatic release: no environment available.");
529: }
530: }
531:
532: /**
533: * Add an automatically released component
534: */
535: public static void addComponentForAutomaticRelease(
536: final ComponentManager manager, final Component component)
537: throws ProcessingException {
538: final EnvironmentStack stack = (EnvironmentStack) environmentStack
539: .get();
540: if (null != stack && !stack.isEmpty()) {
541: final EnvironmentStack.Item objects = (EnvironmentStack.Item) stack
542: .get(0);
543: final Map objectModel = objects.env.getObjectModel();
544: EnvironmentDescription desc = (EnvironmentDescription) objectModel
545: .get(PROCESS_KEY);
546: if (null != desc) {
547: desc.addToAutoRelease(manager, component);
548: }
549: } else {
550: throw new ProcessingException(
551: "Unable to add component for automatic release: no environment available.");
552: }
553: }
554:
555: /**
556: * Remove from automatically released components
557: */
558: public static void removeFromAutomaticRelease(
559: final Component component) throws ProcessingException {
560: final EnvironmentStack stack = (EnvironmentStack) environmentStack
561: .get();
562: if (null != stack && !stack.isEmpty()) {
563: final EnvironmentStack.Item objects = (EnvironmentStack.Item) stack
564: .get(0);
565: final Map objectModel = objects.env.getObjectModel();
566: EnvironmentDescription desc = (EnvironmentDescription) objectModel
567: .get(PROCESS_KEY);
568: if (null != desc) {
569: desc.removeFromAutoRelease(component);
570: }
571: } else {
572: throw new ProcessingException(
573: "Unable to remove component from automatic release: no environment available.");
574: }
575: }
576:
577: /**
578: * Dispose
579: */
580: public void dispose() {
581: if (this .getLogger().isDebugEnabled()) {
582: this .getLogger().debug(
583: "CocoonComponentManager.dispose() called");
584: }
585:
586: if (null != this .sourceResolver) {
587: super .release((Component) this .sourceResolver);
588: // We cannot null out sourceResolver here yet as some other not
589: // disposed yet components might still have unreleased sources,
590: // and they will call {@link #release(Source)} during their
591: // dispose().
592: }
593:
594: super .dispose();
595:
596: // All components now are released so sourceResolver should be not
597: // needed anymore.
598: this .sourceResolver = null;
599:
600: // This is used to track bug 27249
601: this .wasDisposed = true;
602: }
603:
604: /**
605: * Get a <code>Source</code> object.
606: */
607: public Source resolveURI(final String location)
608: throws MalformedURLException, IOException, SourceException {
609: return this .resolveURI(location, null, null);
610: }
611:
612: /**
613: * Get a <code>Source</code> object.
614: */
615: public Source resolveURI(final String location, String baseURI,
616: final Map parameters) throws MalformedURLException,
617: IOException, SourceException {
618: if (baseURI == null) {
619: final EnvironmentStack stack = (EnvironmentStack) environmentStack
620: .get();
621: if (null != stack && !stack.isEmpty()) {
622: final EnvironmentStack.Item objects = stack
623: .getCurrent();
624: baseURI = objects.env.getContext();
625: }
626: }
627: return this .sourceResolver.resolveURI(location, baseURI,
628: parameters);
629: }
630:
631: /**
632: * Releases a resolved resource
633: */
634: public void release(final Source source) {
635: this .sourceResolver.release(source);
636: }
637:
638: /* (non-Javadoc)
639: * @see org.apache.avalon.excalibur.component.ExcaliburComponentManager#addComponent(java.lang.String, java.lang.Class, org.apache.avalon.framework.configuration.Configuration)
640: */
641: public void addComponent(String role, Class clazz,
642: Configuration conf) throws ComponentException {
643: super .addComponent(role, clazz, conf);
644: // Note that at this point, we're not initialized and cannot do
645: // lookups, so defer parental introductions to initialize().
646: if (ParentAware.class.isAssignableFrom(clazz)) {
647: this .parentAwareComponents.add(role);
648: }
649: }
650:
651: public void initialize() throws Exception {
652: super .initialize();
653: if (this .parentAwareComponents == null) {
654: throw new ComponentException(null,
655: "CocoonComponentManager already initialized");
656: }
657: // Set parents for parentAware components
658: Iterator iter = this .parentAwareComponents.iterator();
659: while (iter.hasNext()) {
660: String role = (String) iter.next();
661: this .getLogger().debug(".. " + role);
662: if (this .parentManager != null
663: && this .parentManager.hasComponent(role)) {
664: // lookup new component
665: Component component = null;
666: try {
667: component = this .lookup(role);
668: ((ParentAware) component)
669: .setParentLocator(new ComponentLocatorImpl(
670: this .parentManager, role));
671: } catch (ComponentException ignore) {
672: // we don't set the parent then
673: } finally {
674: this .release(component);
675: }
676: }
677: }
678: this .parentAwareComponents = null; // null to save memory, and catch logic bugs.
679: }
680:
681: /**
682: * A runnable wrapper that inherits the environment stack of the thread it is
683: * created in.
684: * <p>
685: * It's defined as an abstract class here to use some internals of EnvironmentHelper, and
686: * should only be used through its public counterpart, {@link org.apache.cocoon.environment.CocoonRunnable}
687: */
688: public static abstract class AbstractCocoonRunnable implements
689: Runnable {
690: private Object parentStack = null;
691:
692: public AbstractCocoonRunnable() {
693: // Clone the environment stack of the calling thread.
694: // We'll use it in run() below
695: Object stack = CocoonComponentManager.environmentStack
696: .get();
697: if (stack != null) {
698: this .parentStack = ((EnvironmentStack) stack).clone();
699: }
700: }
701:
702: /**
703: * Calls {@link #doRun()} within the environment context of the creating thread.
704: */
705: public final void run() {
706: // Install the stack from the parent thread and run the Runnable
707: Object oldStack = environmentStack.get();
708: CocoonComponentManager.environmentStack
709: .set(this .parentStack);
710: try {
711: this .doRun();
712: } finally {
713: // Restore the previous stack
714: CocoonComponentManager.environmentStack.set(oldStack);
715: }
716: // FIXME: Check the lifetime of this run compared to the parent thread.
717: // A CocoonThread is meant to start and die within the execution period of the parent request,
718: // and it is an error if it lives longer as the parent environment is no more valid.
719: }
720:
721: abstract protected void doRun();
722: }
723: }
724:
725: final class EnvironmentDescription {
726:
727: Environment environment;
728: Map objectModel;
729: Map requestLifecycleComponents;
730: List autoreleaseComponents = new ArrayList(4);
731:
732: /**
733: * Constructor
734: */
735: EnvironmentDescription(Environment env) {
736: this .environment = env;
737: this .objectModel = env.getObjectModel();
738: }
739:
740: Map getGlobalRequestLifcecycleComponents() {
741: Map m = (Map) this .environment
742: .getAttribute(GlobalRequestLifecycleComponent.class
743: .getName());
744: if (m == null) {
745: m = new HashMap();
746: this .environment.setAttribute(
747: GlobalRequestLifecycleComponent.class.getName(), m);
748: }
749: return m;
750: }
751:
752: /**
753: * Release all components of this environment
754: * All RequestLifecycleComponents and autoreleaseComponents are
755: * released.
756: */
757: synchronized void release() {
758: if (this .requestLifecycleComponents != null) {
759: final Iterator iter = this .requestLifecycleComponents
760: .values().iterator();
761: while (iter.hasNext()) {
762: final Object[] o = (Object[]) iter.next();
763: final Component component = (Component) o[0];
764: ((CocoonComponentManager) o[1])
765: .releaseRLComponent(component);
766: }
767: this .requestLifecycleComponents.clear();
768: }
769:
770: for (int i = 0; i < this .autoreleaseComponents.size(); i++) {
771: final Object[] o = (Object[]) this .autoreleaseComponents
772: .get(i);
773: final Component component = (Component) o[0];
774: if (o[1] instanceof ComponentManager) {
775: ((ComponentManager) o[1]).release(component);
776: } else {
777: ((ComponentSelector) o[1]).release(component);
778: if (o[2] != null) {
779: ((ComponentManager) o[2]).release((Component) o[1]);
780: }
781: }
782: }
783: this .autoreleaseComponents.clear();
784: this .environment = null;
785: this .objectModel = null;
786: }
787:
788: /**
789: * Add a RequestLifecycleComponent to the environment
790: */
791: void addRequestLifecycleComponent(final String role,
792: final Component co, final ComponentManager manager) {
793: if (this .requestLifecycleComponents == null) {
794: this .requestLifecycleComponents = new HashMap();
795: }
796: this .requestLifecycleComponents.put(role, new Object[] { co,
797: manager });
798: }
799:
800: /**
801: * Add a GlobalRequestLifecycleComponent to the environment
802: */
803: void addGlobalRequestLifecycleComponent(final String role,
804: final Component co, final ComponentManager manager) {
805: this .getGlobalRequestLifcecycleComponents().put(role,
806: new Object[] { co, manager });
807: }
808:
809: /**
810: * Do we already have a request lifecycle component
811: */
812: boolean containsRequestLifecycleComponent(final String role) {
813: if (this .requestLifecycleComponents == null) {
814: return false;
815: }
816: return this .requestLifecycleComponents.containsKey(role);
817: }
818:
819: /**
820: * Do we already have a global request lifecycle component
821: */
822: boolean containsGlobalRequestLifecycleComponent(final String role) {
823: return this .getGlobalRequestLifcecycleComponents().containsKey(
824: role);
825: }
826:
827: /**
828: * Search a RequestLifecycleComponent
829: */
830: Component getRequestLifecycleComponent(final String role) {
831: if (this .requestLifecycleComponents == null) {
832: return null;
833: }
834: final Object[] o = (Object[]) this .requestLifecycleComponents
835: .get(role);
836: if (null != o) {
837: return (Component) o[0];
838: }
839: return null;
840: }
841:
842: /**
843: * Search a GlobalRequestLifecycleComponent
844: */
845: Component getGlobalRequestLifecycleComponent(final String role) {
846: final Object[] o = (Object[]) this
847: .getGlobalRequestLifcecycleComponents().get(role);
848: if (null != o) {
849: return (Component) o[0];
850: }
851: return null;
852: }
853:
854: /**
855: * Add an automatically released component
856: */
857: synchronized void addToAutoRelease(
858: final ComponentSelector selector,
859: final Component component, final ComponentManager manager) {
860: this .autoreleaseComponents.add(new Object[] { component,
861: selector, manager });
862: }
863:
864: /**
865: * Add an automatically released component
866: */
867: synchronized void addToAutoRelease(final ComponentManager manager,
868: final Component component) {
869: this .autoreleaseComponents.add(new Object[] { component,
870: manager });
871: }
872:
873: /**
874: * Remove from automatically released components
875: */
876: synchronized void removeFromAutoRelease(final Component component)
877: throws ProcessingException {
878: int i = 0;
879: boolean found = false;
880: while (i < this .autoreleaseComponents.size() && !found) {
881: final Object[] o = (Object[]) this .autoreleaseComponents
882: .get(i);
883: if (o[0] == component) {
884: found = true;
885: if (o[1] instanceof ComponentManager) {
886: ((ComponentManager) o[1]).release(component);
887: } else {
888: ((ComponentSelector) o[1]).release(component);
889: if (o[2] != null) {
890: ((ComponentManager) o[2])
891: .release((Component) o[1]);
892: }
893: }
894: this .autoreleaseComponents.remove(i);
895: } else {
896: i++;
897: }
898: }
899: if (!found) {
900: throw new ProcessingException(
901: "Unable to remove component from automatic release: component not found.");
902: }
903: }
904: }
|