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