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
009 package org.picocontainer.web.struts2;
010
011 import java.util.Map;
012 import java.util.Collection;
013 import java.util.Iterator;
014
015 import org.picocontainer.ComponentAdapter;
016 import org.picocontainer.MutablePicoContainer;
017 import org.picocontainer.injectors.AbstractInjector;
018 import org.picocontainer.web.PicoServletContainerFilter;
019
020 import com.opensymphony.xwork2.ObjectFactory;
021 import com.opensymphony.xwork2.config.ConfigurationException;
022 import com.opensymphony.xwork2.config.entities.InterceptorConfig;
023 import com.opensymphony.xwork2.interceptor.Interceptor;
024
025 /**
026 * XWork2 ObjectFactory implementation to delegate action/component/bean lookups
027 * to PicoContainer.
028 *
029 * @author Paul Hammant
030 * @author Mauro Talevi
031 */
032 @SuppressWarnings("serial")
033 public class PicoObjectFactory extends ObjectFactory {
034
035 private static ThreadLocal<MutablePicoContainer> currentRequestContainer = new ThreadLocal<MutablePicoContainer>();
036 private static ThreadLocal<MutablePicoContainer> currentSessionContainer = new ThreadLocal<MutablePicoContainer>();
037 private static ThreadLocal<MutablePicoContainer> currentAppContainer = new ThreadLocal<MutablePicoContainer>();
038
039 public static class ServletFilter extends PicoServletContainerFilter {
040 protected void setAppContainer(MutablePicoContainer container) {
041 currentAppContainer.set(container);
042 }
043 protected void setRequestContainer(MutablePicoContainer container) {
044 currentRequestContainer.set(container);
045 }
046 protected void setSessionContainer(MutablePicoContainer container) {
047 currentSessionContainer.set(container);
048 }
049 }
050
051 @SuppressWarnings("unchecked")
052 public Class getClassInstance(String name) throws ClassNotFoundException {
053 Class clazz = super.getClassInstance(name);
054 registerAction(clazz);
055 return clazz;
056 }
057
058 private void registerAction(Class<?> clazz) throws NoClassDefFoundError {
059
060 synchronized (this) {
061
062 MutablePicoContainer reqContainer = currentRequestContainer.get();
063 if (reqContainer == null) {
064 return;
065 }
066 ComponentAdapter<?> ca = reqContainer.getComponentAdapter(clazz);
067 if (ca == null) {
068 try {
069 reqContainer.addComponent(clazz);
070 } catch (NoClassDefFoundError e) {
071 if (e.getMessage().equals("org/apache/velocity/context/Context")) {
072 // half expected. XWork seems to setup stuff that cannot
073 // work
074 // TODO if this is the case we should make configurable
075 // the list of classes we "expect" not to find. Odd!
076 } else {
077 throw e;
078 }
079 }
080 }
081 }
082 }
083
084 @SuppressWarnings("unchecked")
085 public Object buildBean(Class clazz, Map extraContext) throws Exception {
086
087 MutablePicoContainer requestContainer = currentRequestContainer.get();
088 if (requestContainer == null) {
089 MutablePicoContainer appContainer = currentAppContainer.get();
090 Object comp = appContainer.getComponent(clazz);
091 if (comp == null) {
092 appContainer.addComponent(clazz);
093 comp = appContainer.getComponent(clazz);
094 }
095 return comp;
096
097 }
098 // try {
099 return requestContainer.getComponent(clazz);
100 // } catch (AbstractInjector.UnsatisfiableDependenciesException e) {
101 // Collection<ComponentAdapter<?>> adapters = requestContainer.getComponentAdapters();
102 // for (Iterator<ComponentAdapter<?>> componentAdapterIterator = adapters.iterator(); componentAdapterIterator.hasNext();) {
103 // ComponentAdapter<?> adapter = componentAdapterIterator.next();
104 // System.out.println("--> " + adapter.getComponentKey());
105 // }
106 // throw e;
107 // }
108
109 }
110
111 @SuppressWarnings("unchecked")
112 public Interceptor buildInterceptor(InterceptorConfig config, Map params) throws ConfigurationException {
113 return super.buildInterceptor(config, params);
114 }
115
116 public boolean isNoArgConstructorRequired() {
117 return false;
118 }
119
120 }