01: /**
02: * Copyright 2006 Webmedia Group Ltd.
03: *
04: * Licensed under the Apache License, Version 2.0 (the "License");
05: * you may not use this file except in compliance with the License.
06: * You may obtain a copy of the License at
07: *
08: * http://www.apache.org/licenses/LICENSE-2.0
09: *
10: * Unless required by applicable law or agreed to in writing, software
11: * distributed under the License is distributed on an "AS IS" BASIS,
12: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13: * See the License for the specific language governing permissions and
14: * limitations under the License.
15: **/package org.araneaframework.core.util;
16:
17: import org.apache.commons.lang.math.RandomUtils;
18: import org.araneaframework.Component;
19: import org.araneaframework.Environment;
20: import org.araneaframework.core.ApplicationComponent;
21: import org.araneaframework.core.Assert;
22: import org.araneaframework.core.NoSuchEnvironmentEntryException;
23: import org.araneaframework.core.StandardScope;
24:
25: /**
26: * This utility class contains methods for managing Aranea components.
27: *
28: * @author Jevgeni Kabanov (ekabanov <i>at</i> araneaframework <i>dot</i> org)
29: */
30: public abstract class ComponentUtil {
31: /**
32: * Prior to 1.0.2 this constant contained illegal characters (dots),
33: * thus using <code>addListenerComponent</code> broke component name
34: * scoping. */
35: public static final String LISTENER_KEY = "ComponentUtil_LISTENER";
36:
37: /**
38: * This method will attach the listener component to the target custom component, allowing it to receive
39: * all the lifecycle events (which exactly depends on the target component type).
40: * <p>
41: * This allows for instance to add a child component that will execute some action on destroy, thus
42: * essentially tying some action to the lifecycle of the target component. A typical application
43: * is to scope something (e.g. environment entry) with the target component.
44: */
45: public static void addListenerComponent(
46: ApplicationComponent target, Component listener) {
47: Assert.notNullParam(target, "target");
48: Assert.notNullParam(listener, "listener");
49:
50: String key = LISTENER_KEY;
51: while (target._getComposite().getChildren().get(key) != null) {
52: key = LISTENER_KEY + RandomUtils.nextLong();
53: }
54:
55: Environment env = target.isAlive() ? target
56: .getChildEnvironment()
57: : new LateBindingChildEnvironment(target);
58: listener._getComponent().init(
59: new StandardScope(key, target.getScope()), env);
60:
61: target._getComposite().attach(key, listener);
62: }
63:
64: // allows adding listener components to not yet initialized components by failing lazily
65: private static class LateBindingChildEnvironment implements
66: Environment {
67: private static final long serialVersionUID = 1L;
68: private ApplicationComponent component;
69:
70: public LateBindingChildEnvironment(
71: ApplicationComponent component) {
72: this .component = component;
73: }
74:
75: public Object getEntry(Object key) {
76: return getDelegateEnvironment().getEntry(key);
77: }
78:
79: public Object requireEntry(Object key)
80: throws NoSuchEnvironmentEntryException {
81: return getDelegateEnvironment().requireEntry(key);
82: }
83:
84: private Environment getDelegateEnvironment() {
85: Environment result = component.getChildEnvironment();
86: if (result == null) {
87: throw new IllegalStateException(getClass().getName()
88: + " does not yet have access to environment.");
89: }
90: return result;
91: }
92: }
93: }
|