1 package org.ocltf.common;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5
6 import org.apache.commons.collections.CollectionUtils;
7 import org.apache.commons.collections.Predicate;
8 import org.apache.commons.lang.StringUtils;
9 import org.apache.commons.logging.Log;
10 import org.apache.commons.logging.LogFactory;
11 import org.ocltf.utils.ClassUtils;
12 import org.ocltf.utils.ExceptionUtils;
13 import org.ocltf.utils.FileResourceUtils;
14 import org.picocontainer.MutablePicoContainer;
15 import org.picocontainer.defaults.DefaultPicoContainer;
16
17 /***
18 * This handles all registration and retrieval
19 * of components within the framework.
20 *
21 * @author Chad Brandon
22 * @version 1.0
23 */
24 public class ComponentContainer {
25
26 private static Log logger = LogFactory.getLog(ComponentContainer.class);
27
28 /***
29 * Where all component default implementations are found.
30 */
31 private static final String DEFAULTS_DIR = "META-INF/defaults/";
32
33 /***
34 * The container instance
35 */
36 private MutablePicoContainer container;
37
38 private static final ComponentContainer instance = new ComponentContainer();
39
40 /***
41 * Constructs an instance of ComponentContainer.
42 */
43 protected ComponentContainer() {
44 this.container = new DefaultPicoContainer();
45 }
46
47 /***
48 * Gets the shared instance of this ComponentContainer.
49 *
50 * @return PluginDiscoverer the static instance.
51 */
52 public static ComponentContainer instance() {
53 return instance;
54 }
55
56 /***
57 * Finds the component with the specified <code>key</code>.
58 *
59 * @param key the unique key of the component as an Object.
60 * @return Object the component instance.
61 */
62 public Object findComponent(Object key) {
63 return this.container.getComponentInstance(key);
64 }
65
66 /***
67 * Finds the component with the specified <code>key</code>.
68 *
69 * @param key the unique key as a Class.
70 * @return Object the component instance.
71 */
72 public Object findComponent(Class key) {
73 final String methodName = "ComponentContainer.findComponent";
74 ExceptionUtils.checkNull(methodName, "key", key);
75 return this.container.getComponentInstance(key.getName());
76 }
77
78 /***
79 * Attempts to find the component with the
80 * specified unique <code>key</code>, if it can't be found,
81 * the default of the specified <code>type</code> is
82 * returned, if no default is set, null is returned.
83 *
84 * @param key the unique key of the component.
85 * @return Object the component instance.
86 */
87 public Object findComponent(String key, Class type) {
88 String methodName = "findComponent";
89 ExceptionUtils.checkNull(methodName, "type", type);
90 try {
91
92 Object component = this.container.getComponentInstance(key);
93
94 if (component == null) {
95 String typeName = type.getName();
96 component = this.container.getComponentInstance(typeName);
97
98
99
100 if (component == null) {
101 String defaultImpl =
102 StringUtils.trimToEmpty(
103 FileResourceUtils.getResourceContentsAsString(
104 DEFAULTS_DIR + type.getName()));
105
106 if (StringUtils.isNotEmpty(defaultImpl)) {
107 component = this.registerDefaultComponent(
108 ClassUtils.loadClass(typeName),
109 ClassUtils.loadClass(defaultImpl));
110 } else {
111 if (logger.isWarnEnabled()) {
112 logger.warn("WARNING! No default implementation for '"
113 + type + "' found, check defaults directory --> '"
114 + DEFAULTS_DIR + "'");
115 }
116 }
117 }
118 }
119 return component;
120 } catch (Throwable th) {
121 String errMsg = "Error performing " + methodName;
122 logger.error(errMsg, th);
123 throw new ComponentContainerException(errMsg, th);
124 }
125 }
126
127 /***
128 * Finds all components having the given <code>type</code>.
129 *
130 * @param type the component type.
131 * @return Collection all components
132 */
133 public Collection findComponentsOfType(final Class type) {
134 class ClassMatcher implements Predicate {
135 public boolean evaluate(Object object) {
136 boolean match = false;
137 if (object != null) {
138 match = type.isAssignableFrom(object.getClass());
139 }
140 return match;
141 }
142 }
143 Collection components = new ArrayList(this.container.getComponentInstances());
144 CollectionUtils.filter(
145 components,
146 new ClassMatcher());
147 return components;
148 }
149
150 /***
151 * Registers the component in this container
152 * with a unique (within this container) <code>key</code>.
153 *
154 * @param key the unique key.
155 * @return Object the registered component.
156 */
157 public Object registerComponent(String key, Object component) {
158 String methodName = "registerComponent";
159 ExceptionUtils.checkNull(methodName, "component", component);
160 if (logger.isDebugEnabled()) {
161 logger.debug("registering component '"
162 + component + "' with key --> '" + key + "'");
163 }
164 return container.registerComponentInstance(
165 key, component).getComponentInstance();
166 }
167
168 /***
169 * Registers the "default" for the specified componentInterface.
170 *
171 * @param componentInterface the interface for the component.
172 * @param defaultType the "default" implementation to use for the
173 * componentInterface.
174 * @return Object the registered component.
175 */
176 public Object registerDefaultComponent(Class componentInterface, Class defaultType) {
177 String methodName = "registerDefaultComponent";
178 ExceptionUtils.checkNull(
179 methodName,
180 "componentInterface",
181 componentInterface);
182 ExceptionUtils.checkNull(
183 methodName,
184 "defaultType",
185 defaultType);
186 if (logger.isDebugEnabled()) {
187 logger.debug("registering default for component '"
188 + componentInterface + "' as type --> '" + defaultType + "'");
189 }
190 try {
191 return container.registerComponentInstance(
192 componentInterface.getName(),
193 defaultType.newInstance()).getComponentInstance();
194 } catch (Throwable th) {
195 String errMsg = "Error performing " + methodName;
196 logger.error(errMsg);
197 throw new ComponentContainerException(errMsg, th);
198 }
199 }
200
201 /***
202 * Registers the component of the specified <code>type</code>.
203 *
204 * @param type the type Class.
205 * @return Object an instance of the type registered.
206 */
207 public Object registerComponentType(Class type) {
208 String methodName = "registerComponent";
209 ExceptionUtils.checkNull(methodName, "type", type);
210 return this.container.registerComponentImplementation(
211 type).getComponentInstance();
212 }
213
214 /***
215 * Registers the components of the specified
216 * <code>type</code>.
217 * @param type the name of a type (must have be able
218 * to be instantiated into a Class instance)
219 * @return Object an instance of the type registered.
220 */
221 public Object registerComponentType(String type) {
222 String methodName = "registerComponent";
223 ExceptionUtils.checkNull(methodName, "type", type);
224 try {
225 Object component = ClassUtils.loadClass(type).newInstance();
226 return this.registerComponent(type, component);
227 } catch (Throwable th) {
228 String errMsg = "Error performing "
229 + methodName;
230 logger.error(errMsg, th);
231 throw new ComponentContainerException(errMsg, th);
232 }
233 }
234
235 }