001 /*******************************************************************************
002 * Copyright (C) PicoContainer Organization. All rights reserved.
003 * ---------------------------------------------------------------------------
004 * The software in this package is published under the terms of the BSD style
005 * license a copy of which has been included with this distribution in the
006 * LICENSE.txt file.
007 ******************************************************************************/
008 package org.picocontainer.classname;
009
010 import org.picocontainer.ComponentAdapter;
011 import org.picocontainer.ComponentFactory;
012 import org.picocontainer.ComponentMonitor;
013 import org.picocontainer.ComponentMonitorStrategy;
014 import org.picocontainer.LifecycleStrategy;
015 import org.picocontainer.MutablePicoContainer;
016 import org.picocontainer.Parameter;
017 import org.picocontainer.PicoClassNotFoundException;
018 import org.picocontainer.PicoContainer;
019 import org.picocontainer.PicoException;
020 import org.picocontainer.security.CustomPermissionsURLClassLoader;
021 import org.picocontainer.DefaultPicoContainer;
022 import org.picocontainer.PicoCompositionException;
023 import org.picocontainer.NameBinding;
024 import org.picocontainer.PicoVisitor;
025 import org.picocontainer.lifecycle.LifecycleState;
026 import org.picocontainer.classname.ClassPathElement;
027 import org.picocontainer.classname.ClassLoadingPicoContainer;
028 import org.picocontainer.behaviors.Caching;
029 import org.picocontainer.containers.AbstractDelegatingMutablePicoContainer;
030
031 import java.lang.annotation.Annotation;
032 import java.lang.reflect.Type;
033 import java.net.URL;
034 import java.security.AccessController;
035 import java.security.PrivilegedAction;
036 import java.security.Permissions;
037 import java.util.ArrayList;
038 import java.util.Collection;
039 import java.util.HashMap;
040 import java.util.Iterator;
041 import java.util.List;
042 import java.util.Map;
043 import java.util.Properties;
044
045 /**
046 * Default implementation of ClassLoadingPicoContainer.
047 *
048 * @author Paul Hammant
049 * @author Mauro Talevi
050 * @author Michael Rimov
051 */
052 @SuppressWarnings("serial")
053 public class DefaultClassLoadingPicoContainer extends AbstractDelegatingMutablePicoContainer implements
054 ClassLoadingPicoContainer, ComponentMonitorStrategy {
055
056 /**
057 * Conversion Map to allow for primitives to be boxed to Object types.
058 */
059 private static final transient Map<String, String> primitiveNameToBoxedName = new HashMap<String, String>();
060
061 static {
062 primitiveNameToBoxedName.put("int", Integer.class.getName());
063 primitiveNameToBoxedName.put("byte", Byte.class.getName());
064 primitiveNameToBoxedName.put("short", Short.class.getName());
065 primitiveNameToBoxedName.put("long", Long.class.getName());
066 primitiveNameToBoxedName.put("float", Float.class.getName());
067 primitiveNameToBoxedName.put("double", Double.class.getName());
068 primitiveNameToBoxedName.put("boolean", Boolean.class.getName());
069 }
070
071 private final transient List<ClassPathElement> classPathElements = new ArrayList<ClassPathElement>();
072 private final transient ClassLoader parentClassLoader;
073
074 private transient ClassLoader componentClassLoader;
075 private transient boolean componentClassLoaderLocked;
076
077 protected final Map<String, PicoContainer> namedChildContainers = new HashMap<String, PicoContainer>();
078
079 public DefaultClassLoadingPicoContainer(ClassLoader classLoader, ComponentFactory componentFactory, PicoContainer parent) {
080 super(new DefaultPicoContainer(componentFactory, parent));
081 parentClassLoader = classLoader;
082 }
083
084 public DefaultClassLoadingPicoContainer(ClassLoader classLoader, MutablePicoContainer delegate) {
085 super(delegate);
086 parentClassLoader = classLoader;
087
088 }
089
090 public DefaultClassLoadingPicoContainer(ClassLoader classLoader, PicoContainer parent, ComponentMonitor componentMonitor) {
091 super(new DefaultPicoContainer(new Caching(), parent));
092 parentClassLoader = classLoader;
093 ((ComponentMonitorStrategy) getDelegate()).changeMonitor(componentMonitor);
094 }
095
096 public DefaultClassLoadingPicoContainer(ComponentFactory componentFactory) {
097 super(new DefaultPicoContainer(componentFactory, null));
098 parentClassLoader = DefaultClassLoadingPicoContainer.class.getClassLoader();
099 }
100
101
102 public DefaultClassLoadingPicoContainer(PicoContainer parent) {
103 super(new DefaultPicoContainer(parent));
104 parentClassLoader = DefaultClassLoadingPicoContainer.class.getClassLoader();
105 }
106
107 public DefaultClassLoadingPicoContainer(MutablePicoContainer delegate) {
108 super(delegate);
109 parentClassLoader = DefaultClassLoadingPicoContainer.class.getClassLoader();
110 }
111
112 public DefaultClassLoadingPicoContainer(ClassLoader classLoader) {
113 super(new DefaultPicoContainer());
114 parentClassLoader = classLoader;
115 }
116
117 public DefaultClassLoadingPicoContainer() {
118 super(new DefaultPicoContainer());
119 parentClassLoader = DefaultClassLoadingPicoContainer.class.getClassLoader();
120 }
121
122 public DefaultClassLoadingPicoContainer(ComponentFactory componentFactory, LifecycleStrategy lifecycleStrategy,
123 PicoContainer parent, ClassLoader cl, ComponentMonitor componentMonitor) {
124
125 super(new DefaultPicoContainer(componentFactory, lifecycleStrategy, parent, componentMonitor));
126 parentClassLoader = (cl != null) ? cl : DefaultClassLoadingPicoContainer.class.getClassLoader();
127 }
128
129 protected DefaultClassLoadingPicoContainer createChildContainer() {
130 MutablePicoContainer child = getDelegate().makeChildContainer();
131 DefaultClassLoadingPicoContainer container = new DefaultClassLoadingPicoContainer(getComponentClassLoader(), child);
132 container.changeMonitor(currentMonitor());
133 return container;
134 }
135
136 /**
137 * Propagates the monitor change down the delegate chain if a delegate that implements ComponentMonitorStrategy
138 * exists. Because of the ComponentMonitorStrategy API, not all delegates can have their API changed. If
139 * a delegate implementing ComponentMonitorStrategy cannot be found, an exception is thrown.
140 * @throws IllegalStateException if no delegate can be found that implements ComponentMonitorStrategy.
141 * @param monitor the monitor to swap.
142 */
143 public void changeMonitor(ComponentMonitor monitor) {
144
145 MutablePicoContainer picoDelegate = getDelegate();
146 while (picoDelegate != null) {
147 if (picoDelegate instanceof ComponentMonitorStrategy) {
148 ((ComponentMonitorStrategy)picoDelegate).changeMonitor(monitor);
149 return;
150 }
151
152 if (picoDelegate instanceof AbstractDelegatingMutablePicoContainer) {
153 picoDelegate = ((AbstractDelegatingMutablePicoContainer)picoDelegate).getDelegate();
154 } else {
155 break;
156 }
157 }
158
159 throw new IllegalStateException("Could not find delegate picocontainer that implemented ComponentMonitorStrategy");
160
161
162 }
163
164 public ComponentMonitor currentMonitor() {
165 MutablePicoContainer picoDelegate = getDelegate();
166 while (picoDelegate != null) {
167 if (picoDelegate instanceof ComponentMonitorStrategy) {
168 return ((ComponentMonitorStrategy)picoDelegate).currentMonitor();
169 }
170
171 if (picoDelegate instanceof AbstractDelegatingMutablePicoContainer) {
172 picoDelegate = ((AbstractDelegatingMutablePicoContainer)picoDelegate).getDelegate();
173 } else {
174 break;
175 }
176 }
177
178 throw new IllegalStateException("Could not find delegate picocontainer that implemented ComponentMonitorStrategy");
179 }
180
181 public final Object getComponent(Object componentKeyOrType) throws PicoException {
182
183 if (componentKeyOrType instanceof ClassName) {
184 componentKeyOrType = loadClass(componentKeyOrType.toString());
185 }
186
187 Object instance = getDelegate().getComponent(componentKeyOrType);
188
189 if (instance != null) {
190 return instance;
191 }
192
193 ComponentAdapter<?> componentAdapter = null;
194 if (componentKeyOrType.toString().startsWith("*")) {
195 String candidateClassName = componentKeyOrType.toString().substring(1);
196 Collection<ComponentAdapter<?>> cas = getComponentAdapters();
197 for (ComponentAdapter<?> ca : cas) {
198 Object key = ca.getComponentKey();
199 if (key instanceof Class && candidateClassName.equals(((Class<?>) key).getName())) {
200 componentAdapter = ca;
201 break;
202 }
203 }
204 }
205 if (componentAdapter != null) {
206 return componentAdapter.getComponentInstance(this, ComponentAdapter.NOTHING.class);
207 } else {
208 return getComponentInstanceFromChildren(componentKeyOrType);
209 }
210 }
211
212 private Object getComponentInstanceFromChildren(Object componentKey) {
213 String componentKeyPath = componentKey.toString();
214 int ix = componentKeyPath.indexOf('/');
215 if (ix != -1) {
216 String firstElement = componentKeyPath.substring(0, ix);
217 String remainder = componentKeyPath.substring(ix + 1, componentKeyPath.length());
218 Object o = getNamedContainers().get(firstElement);
219 if (o != null) {
220 MutablePicoContainer child = (MutablePicoContainer) o;
221 return child.getComponent(remainder);
222 }
223 }
224 return null;
225 }
226
227 public final MutablePicoContainer makeChildContainer() {
228 return makeChildContainer("containers" + namedChildContainers.size());
229 }
230
231 /**
232 * Makes a child container with the same basic characteristics of
233 * <tt>this</tt> object (ComponentFactory, PicoContainer type, Behavior,
234 * etc)
235 *
236 * @param name the name of the child container
237 * @return The child MutablePicoContainer
238 */
239 public ClassLoadingPicoContainer makeChildContainer(String name) {
240 DefaultClassLoadingPicoContainer child = createChildContainer();
241 MutablePicoContainer parentDelegate = getDelegate();
242 parentDelegate.removeChildContainer(child.getDelegate());
243 parentDelegate.addChildContainer(child);
244 namedChildContainers.put(name, child);
245 return child;
246 }
247
248 public boolean removeChildContainer(PicoContainer child) {
249 boolean result = getDelegate().removeChildContainer(child);
250 Iterator<Map.Entry<String, PicoContainer>> children = namedChildContainers.entrySet().iterator();
251 while (children.hasNext()) {
252 Map.Entry<String, PicoContainer> e = children.next();
253 PicoContainer pc = e.getValue();
254 if (pc == child) {
255 children.remove();
256 }
257 }
258 return result;
259 }
260
261 protected final Map<String, PicoContainer> getNamedContainers() {
262 return namedChildContainers;
263 }
264
265 public ClassPathElement addClassLoaderURL(URL url) {
266 if (componentClassLoaderLocked) {
267 throw new IllegalStateException("ClassLoader URLs cannot be added once this instance is locked");
268 }
269
270 ClassPathElement classPathElement = new ClassPathElement(url);
271 classPathElements.add(classPathElement);
272 return classPathElement;
273 }
274
275 public MutablePicoContainer addComponent(Object implOrInstance) {
276 if (implOrInstance instanceof ClassName) {
277 super.addComponent(loadClass(implOrInstance.toString()));
278 } else {
279 super.addComponent(implOrInstance);
280 }
281 return this;
282 }
283
284 public MutablePicoContainer addComponent(Object key, Object componentImplementationOrInstance,
285 Parameter... parameters) {
286 super.addComponent(classNameToClassIfApplicable(key),
287 classNameToClassIfApplicable(componentImplementationOrInstance), parameters);
288 return this;
289 }
290
291 private Object classNameToClassIfApplicable(Object key) {
292 if (key instanceof ClassName) {
293 key = loadClass(key.toString());
294 }
295 return key;
296 }
297
298 public MutablePicoContainer addAdapter(ComponentAdapter<?> componentAdapter) throws PicoCompositionException {
299 super.addAdapter(componentAdapter);
300 return this;
301 }
302
303 public ClassLoader getComponentClassLoader() {
304 if (componentClassLoader == null) {
305 componentClassLoaderLocked = true;
306 componentClassLoader = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
307 public ClassLoader run() {
308 return new CustomPermissionsURLClassLoader(getURLs(classPathElements), makePermissions(),
309 parentClassLoader);
310 }
311 });
312 }
313 return componentClassLoader;
314 }
315
316 public MutablePicoContainer addChildContainer(PicoContainer child) {
317 getDelegate().addChildContainer(child);
318 namedChildContainers.put("containers" + namedChildContainers.size(), child);
319 return this;
320 }
321
322 public ClassLoadingPicoContainer addChildContainer(String name, PicoContainer child) {
323
324 super.addChildContainer(child);
325
326 namedChildContainers.put(name, child);
327 return this;
328 }
329
330 private Class<?> loadClass(final String className) {
331 ClassLoader classLoader = getComponentClassLoader();
332 // this is deliberately not a doPrivileged operation.
333 String cn = getClassName(className);
334 try {
335 return classLoader.loadClass(cn);
336 } catch (ClassNotFoundException e) {
337 throw new PicoClassNotFoundException(cn, e);
338 }
339 }
340
341 private Map<URL, Permissions> makePermissions() {
342 Map<URL, Permissions> permissionsMap = new HashMap<URL, Permissions>();
343 for (ClassPathElement cpe : classPathElements) {
344 Permissions permissionCollection = cpe.getPermissionCollection();
345 permissionsMap.put(cpe.getUrl(), permissionCollection);
346 }
347 return permissionsMap;
348 }
349
350 private URL[] getURLs(List<ClassPathElement> classPathElemelements) {
351 final URL[] urls = new URL[classPathElemelements.size()];
352 for (int i = 0; i < urls.length; i++) {
353 urls[i] = (classPathElemelements.get(i)).getUrl();
354 }
355 return urls;
356 }
357
358 private static String getClassName(String primitiveOrClass) {
359 String fromMap = primitiveNameToBoxedName.get(primitiveOrClass);
360 return fromMap != null ? fromMap : primitiveOrClass;
361 }
362
363 public ComponentAdapter<?> getComponentAdapter(Object componentKey) {
364 Object componentKey2 = componentKey;
365 if (componentKey instanceof ClassName) {
366 componentKey2 = loadClass(componentKey.toString());
367 }
368 return super.getComponentAdapter(componentKey2);
369 }
370
371 public MutablePicoContainer change(Properties... properties) {
372 super.change(properties);
373 return this;
374 }
375
376 public MutablePicoContainer as(Properties... properties) {
377 return new AsPropertiesPicoContainer(properties);
378 }
379
380 private class AsPropertiesPicoContainer implements ClassLoadingPicoContainer {
381 private MutablePicoContainer delegate;
382
383 public AsPropertiesPicoContainer(Properties... props) {
384 delegate = DefaultClassLoadingPicoContainer.this.getDelegate().as(props);
385 }
386
387 public ClassPathElement addClassLoaderURL(URL url) {
388 return DefaultClassLoadingPicoContainer.this.addClassLoaderURL(url);
389 }
390
391 public ClassLoader getComponentClassLoader() {
392 return DefaultClassLoadingPicoContainer.this.getComponentClassLoader();
393 }
394
395 public ClassLoadingPicoContainer makeChildContainer(String name) {
396 return DefaultClassLoadingPicoContainer.this.makeChildContainer(name);
397 }
398
399 public ClassLoadingPicoContainer addChildContainer(String name, PicoContainer child) {
400 return (ClassLoadingPicoContainer) DefaultClassLoadingPicoContainer.this.addChildContainer(child);
401 }
402
403 public MutablePicoContainer addComponent(Object componentKey, Object componentImplementationOrInstance,
404 Parameter... parameters) {
405 delegate.addComponent(classNameToClassIfApplicable(componentKey),
406 classNameToClassIfApplicable(componentImplementationOrInstance), parameters);
407 return DefaultClassLoadingPicoContainer.this;
408 }
409
410 public MutablePicoContainer addComponent(Object implOrInstance) {
411 delegate.addComponent(classNameToClassIfApplicable(implOrInstance));
412 return DefaultClassLoadingPicoContainer.this;
413 }
414
415 public MutablePicoContainer addConfig(String name, Object val) {
416 delegate.addConfig(name, val);
417 return DefaultClassLoadingPicoContainer.this;
418 }
419
420 public MutablePicoContainer addAdapter(ComponentAdapter<?> componentAdapter) {
421 delegate.addAdapter(componentAdapter);
422 return DefaultClassLoadingPicoContainer.this;
423 }
424
425 public ComponentAdapter removeComponent(Object componentKey) {
426 return delegate.removeComponent(componentKey);
427 }
428
429 public ComponentAdapter removeComponentByInstance(Object componentInstance) {
430 return delegate.removeComponentByInstance(componentInstance);
431 }
432
433 public MutablePicoContainer makeChildContainer() {
434 return DefaultClassLoadingPicoContainer.this.makeChildContainer();
435 }
436
437 public MutablePicoContainer addChildContainer(PicoContainer child) {
438 return DefaultClassLoadingPicoContainer.this.addChildContainer(child);
439 }
440
441 public boolean removeChildContainer(PicoContainer child) {
442 return DefaultClassLoadingPicoContainer.this.removeChildContainer(child);
443 }
444
445 public MutablePicoContainer change(Properties... properties) {
446 return DefaultClassLoadingPicoContainer.this.change(properties);
447 }
448
449 public MutablePicoContainer as(Properties... properties) {
450 return new AsPropertiesPicoContainer(properties);
451 }
452
453 public Object getComponent(Object componentKeyOrType) {
454 return DefaultClassLoadingPicoContainer.this.getComponent(componentKeyOrType);
455 }
456
457 public Object getComponent(Object componentKeyOrType, Type into) {
458 return DefaultClassLoadingPicoContainer.this.getComponent(componentKeyOrType, into);
459 }
460
461 public <T> T getComponent(Class<T> componentType) {
462 return DefaultClassLoadingPicoContainer.this.getComponent(componentType);
463 }
464
465 public <T> T getComponent(Class<T> componentType, Class<? extends Annotation> binding) {
466 return DefaultClassLoadingPicoContainer.this.getComponent(componentType, binding);
467 }
468
469 public List<Object> getComponents() {
470 return DefaultClassLoadingPicoContainer.this.getComponents();
471 }
472
473 public PicoContainer getParent() {
474 return DefaultClassLoadingPicoContainer.this.getParent();
475 }
476
477 public ComponentAdapter<?> getComponentAdapter(Object componentKey) {
478 return DefaultClassLoadingPicoContainer.this.getComponentAdapter(componentKey);
479 }
480
481 public <T> ComponentAdapter<T> getComponentAdapter(Class<T> componentType, NameBinding componentNameBinding) {
482 return DefaultClassLoadingPicoContainer.this.getComponentAdapter(componentType, componentNameBinding);
483 }
484
485 public <T> ComponentAdapter<T> getComponentAdapter(Class<T> componentType, Class<? extends Annotation> binding) {
486 return DefaultClassLoadingPicoContainer.this.getComponentAdapter(componentType, binding);
487 }
488
489 public Collection<ComponentAdapter<?>> getComponentAdapters() {
490 return DefaultClassLoadingPicoContainer.this.getComponentAdapters();
491 }
492
493 public <T> List<ComponentAdapter<T>> getComponentAdapters(Class<T> componentType) {
494 return DefaultClassLoadingPicoContainer.this.getComponentAdapters(componentType);
495 }
496
497 public <T> List<ComponentAdapter<T>> getComponentAdapters(Class<T> componentType,
498 Class<? extends Annotation> binding) {
499 return DefaultClassLoadingPicoContainer.this.getComponentAdapters(componentType, binding);
500 }
501
502 public <T> List<T> getComponents(Class<T> componentType) {
503 return DefaultClassLoadingPicoContainer.this.getComponents(componentType);
504 }
505
506 public void accept(PicoVisitor visitor) {
507 DefaultClassLoadingPicoContainer.this.accept(visitor);
508 }
509
510 public void start() {
511
512 }
513
514 public void stop() {
515
516 }
517
518 public void dispose() {
519
520 }
521
522 public void setName(String name) {
523 DefaultClassLoadingPicoContainer.this.setName(name);
524 }
525
526 public void setLifecycleState(LifecycleState lifecycleState) {
527 DefaultClassLoadingPicoContainer.this.setLifecycleState(lifecycleState);
528 }
529 }
530
531 }