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.web.webwork2;
009
010 import java.util.HashMap;
011 import java.util.Map;
012
013 import org.picocontainer.DefaultPicoContainer;
014 import org.picocontainer.MutablePicoContainer;
015 import org.picocontainer.PicoCompositionException;
016 import org.picocontainer.PicoContainer;
017 import org.picocontainer.web.PicoServletContainerFilter;
018
019 import com.opensymphony.xwork.ObjectFactory;
020
021 /**
022 * <p>
023 * XWork ObjectFactory which uses a PicoContainer to create component instances.
024 * </p>
025 *
026 * @author Cyrille Le Clerc
027 * @author Jonas Engman
028 * @author Mauro Talevi
029 * @author Grégory Joseph
030 * @author Konstatin Pribluda
031 */
032 public class PicoObjectFactory extends ObjectFactory {
033
034 private static ThreadLocal<MutablePicoContainer> currentRequestContainer = new ThreadLocal<MutablePicoContainer>();
035 private static ThreadLocal<MutablePicoContainer> currentSessionContainer = new ThreadLocal<MutablePicoContainer>();
036 private static ThreadLocal<MutablePicoContainer> currentAppContainer = new ThreadLocal<MutablePicoContainer>();
037
038 @SuppressWarnings("serial")
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 private final Map<String, Class<?>> classCache = new HashMap<String, Class<?>>();
052
053 public boolean isNoArgConstructorRequired() {
054 return false;
055 }
056
057 @SuppressWarnings("unchecked")
058 public Object buildBean(Class clazz, Map extraContext) throws Exception {
059 return buildBean(clazz);
060 }
061
062 @SuppressWarnings("unchecked")
063 public Object buildBean(String className, Map extraContext) throws Exception {
064 return buildBean(className);
065 }
066
067
068 @SuppressWarnings("unchecked")
069 public Class getClassInstance(String className) {
070 return getActionClass(className);
071 }
072
073 /**
074 * Instantiates an action using the PicoContainer found in the request scope.
075 * if action or bean is not registered explicitely, new instance will be provided
076 * on every invocation.
077 *
078 * @see com.opensymphony.xwork.ObjectFactory#buildBean(java.lang.Class)
079 */
080 public Object buildBean(Class<?> actionClass) throws Exception {
081 PicoContainer actionsContainer = currentRequestContainer.get();
082 Object action = actionsContainer.getComponent(actionClass);
083
084 if (action == null) {
085 // The action wasn't registered. Attempt to instantiate it.
086 // use child container to prevent weirdest errors
087 MutablePicoContainer child = new DefaultPicoContainer(actionsContainer);
088
089 child.addComponent(actionClass);
090 action = child.getComponent(actionClass);
091 }
092 return action;
093 }
094
095 /**
096 * As {@link ObjectFactory#buildBean(java.lang.String)}does not delegate to
097 * {@link ObjectFactory#buildBean(java.lang.Class)} but directly calls
098 * <code>clazz.newInstance()</code>, overwrite this method to call
099 * <code>buildBean()</code>
100 *
101 * @see com.opensymphony.xwork.ObjectFactory#buildBean(java.lang.String)
102 */
103 public Object buildBean(String className) throws Exception {
104 return buildBean(getActionClass(className));
105 }
106
107 public Class<?> getActionClass(String className) throws PicoCompositionException {
108 try {
109 return loadClass(className);
110 } catch (ClassNotFoundException e) {
111 throw new PicoCompositionException("Action class '" + className + "' not found", e);
112 }
113 }
114
115 protected Class<?> loadClass(String className) throws ClassNotFoundException {
116 if (classCache.containsKey(className)) {
117 return (Class<?>) classCache.get(className);
118 } else {
119 Class<?> result = Thread.currentThread().getContextClassLoader().loadClass(className);
120 classCache.put(className, result);
121 return result;
122 }
123 }
124
125 }