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