View Javadoc
1   package siouxsie.mvc.impl;
2   
3   import java.beans.PropertyChangeEvent;
4   import java.beans.PropertyChangeListener;
5   import java.util.ArrayList;
6   import java.util.Collection;
7   import java.util.HashMap;
8   import java.util.Map;
9   
10  import org.apache.commons.logging.Log;
11  import org.apache.commons.logging.LogFactory;
12  
13  import siouxsie.mvc.ActionTriggerDescription;
14  import siouxsie.mvc.IActionLauncher;
15  import siouxsie.mvc.IActionTrigger;
16  import siouxsie.mvc.IController;
17  
18  import com.opensymphony.xwork2.ActionProxy;
19  import com.opensymphony.xwork2.ActionProxyFactory;
20  import com.opensymphony.xwork2.ObjectFactory;
21  import com.opensymphony.xwork2.config.Configuration;
22  import com.opensymphony.xwork2.config.ConfigurationManager;
23  import com.opensymphony.xwork2.config.ConfigurationProvider;
24  import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
25  
26  /**
27   * MVC controller.
28   * Handle XWork engine configuration and execution.
29   * @author Arnaud Cogoluegnes
30   * @version $Id$
31   */
32  public class Controller implements IController, PropertyChangeListener {
33  	
34  	/**
35  	 * XWork configuration.
36  	 * Can be usefull to get object from the container.
37  	 */ 
38  	private Configuration configuration;
39  	
40  	/** how to launch action */
41  	private IActionLauncher actionLauncher;
42  	
43  	private ActionProxyFactory actionProxyFactory;
44  	
45  	@SuppressWarnings("unchecked")
46  	private Map extraContext = new HashMap();  
47  	
48  	private static final Log LOG = LogFactory.getLog(Controller.class);
49  
50  	private String [] configFiles;
51  	
52  	private Class<? extends ObjectFactory> objectFactoryClazz;
53  	
54  	/**
55  	 * collection of configuration providers.
56  	 * (container providers to be more exact).
57  	 */
58  	private Collection<ConfigurationProvider> providers = new ArrayList<ConfigurationProvider>(); 
59  	
60  	/** should we add the XWork default container provider */
61  	private boolean defaultConfigurationProvider = true;
62  
63  	public String[] getConfigFiles() {
64  		return configFiles;
65  	}
66  
67  	public void setConfigFiles(String[] configFiles) {
68  		this.configFiles = configFiles;
69  	}
70  
71  	public IActionLauncher getActionLauncher() {
72  		return actionLauncher;
73  	}
74  
75  	public void setActionLauncher(IActionLauncher actionLauncher) {
76  		this.actionLauncher = actionLauncher;
77  	}
78  	
79  	@SuppressWarnings("unchecked")
80  	public void executeAction(String name,String nameSpace,Map parameters) {
81  		try {
82  			// TODO: add the possibility not to execute result and let it done by the controller
83  			ActionProxy actionProxy = actionProxyFactory.createActionProxy(nameSpace,name,null,extraContext,true,false);
84  			actionProxy.getInvocation().getInvocationContext().setParameters(parameters);
85  			// launches the action
86  			String result = getActionLauncher().launch(actionProxy);
87  			
88  			// TODO: handle waiting in multithreaded environment
89  			
90  			
91  		} catch(Exception e) {
92  			// TODO handle exception message?
93  			// handler(s) could be define in the XWork config file and retrieve from the container
94  			LOG.error(e.getMessage(),e);
95  		}		
96  	}
97  	
98  	public void init() {
99  		ConfigurationManager confManager = new ConfigurationManager();
100 		if(defaultConfigurationProvider) {
101 			// default XWork configuration (necessary since XWork 2.1)
102 			SiouxsieMVCConfigurationProvider provider = new SiouxsieMVCConfigurationProvider();
103 			provider.setObjectFactoryClazz(objectFactoryClazz);
104 			confManager.addContainerProvider(provider);			
105 		}
106 		
107 		// container providers (usually Java classes, with extra container configurations)
108 		for(ConfigurationProvider provider : providers) {
109 			confManager.addContainerProvider(provider);
110 		}
111 		
112 		// configuration files (usually XML file for interceptor, action and so on...)
113 		for(String configFile : getConfigFiles()) {
114 			confManager.addContainerProvider(
115 				new XmlConfigurationProvider(configFile, true)
116 			);
117 		}				
118 		this.configuration = confManager.getConfiguration();		
119 		this.actionProxyFactory = configuration.getContainer().getInstance(ActionProxyFactory.class);
120 		
121 		// handle the action trigger mechanism
122 		IActionTrigger trigger = configuration.getContainer().getInstance(IActionTrigger.class);
123 		if(trigger != null) {
124 			// register the controller to the trigger
125 			trigger.addPropertyChangeListener(this);
126 		} else {
127 			LOG.warn("no action trigger found in the XW container, how screens are supposed to launch the controller?");
128 		}
129 		
130 	}
131 
132 	@SuppressWarnings("unchecked")
133 	public Map getExtraContext() {
134 		return extraContext;
135 	}
136 
137 	@SuppressWarnings("unchecked")
138 	public void setExtraContext(Map extraContext) {
139 		this.extraContext = extraContext;
140 	}
141 
142 	public Configuration getConfiguration() {
143 		return configuration;
144 	}
145 
146 	public void setConfiguration(Configuration configuration) {
147 		this.configuration = configuration;
148 	}
149 	
150 	/**
151 	 * Add a configuration provider.
152 	 * @param provider
153 	 * @return
154 	 */
155 	public Controller addConfigurationProvider(ConfigurationProvider provider) {
156 		if(!this.providers.contains(provider)) {
157 			providers.add(provider);
158 		}
159 		return this;
160 	}
161 
162 	public void setObjectFactoryClazz(
163 			Class<? extends ObjectFactory> objectFactoryClazz) {
164 		this.objectFactoryClazz = objectFactoryClazz;
165 	}
166 
167 	/**
168 	 * Handle the action trigger.
169 	 */
170 	public void propertyChange(PropertyChangeEvent evt) {
171 		if(evt.getNewValue() instanceof ActionTriggerDescription) {
172 			ActionTriggerDescription desc = (ActionTriggerDescription) evt.getNewValue();
173 			executeAction(desc.getActionName(),
174 					desc.getActionNamespace(),
175 					desc.getParameters()
176 			);			
177 		} else {
178 			LOG.warn("this kind of value cannot be handled: "+evt.getNewValue());
179 		}
180 		
181 	}
182 	
183 }