001: /*
002: * Copyright 2005-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005: * in compliance with the License. You may obtain a copy of the License at
006: *
007: * http://www.apache.org/licenses/LICENSE-2.0
008: *
009: * Unless required by applicable law or agreed to in writing, software distributed under the License
010: * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011: * or implied. See the License for the specific language governing permissions and limitations under
012: * the License.
013: */
014:
015: package org.strecks.controller;
016:
017: import java.lang.annotation.Annotation;
018: import java.util.HashMap;
019: import java.util.LinkedHashMap;
020: import java.util.Map;
021: import java.util.Set;
022:
023: import org.apache.commons.logging.Log;
024: import org.apache.commons.logging.LogFactory;
025: import org.apache.struts.action.Action;
026: import org.strecks.action.BasicAction;
027: import org.strecks.action.BasicDispatchAction;
028: import org.strecks.action.BasicFormAction;
029: import org.strecks.action.BasicSubmitAction;
030: import org.strecks.action.NavigableAction;
031: import org.strecks.action.NavigableDispatchAction;
032: import org.strecks.action.NavigableFormAction;
033: import org.strecks.action.NavigableSubmitAction;
034: import org.strecks.action.basic.BasicController;
035: import org.strecks.action.basic.BasicDispatchController;
036: import org.strecks.action.basic.BasicFormController;
037: import org.strecks.action.basic.BasicSubmitController;
038: import org.strecks.action.navigable.NavigableController;
039: import org.strecks.action.navigable.NavigableDispatchController;
040: import org.strecks.action.navigable.NavigableFormController;
041: import org.strecks.action.navigable.NavigableSubmitController;
042: import org.strecks.controller.annotation.ActionInterface;
043: import org.strecks.controller.annotation.BeanAnnotationReader;
044: import org.strecks.controller.annotation.Controller;
045: import org.strecks.controller.internal.ActionBeanAnnotationReader;
046: import org.strecks.exceptions.ApplicationConfigurationException;
047: import org.strecks.injection.internal.InjectionAnnotationReader;
048: import org.strecks.interceptor.internal.ActionBeanInterceptorReader;
049: import org.strecks.lifecycle.LifecycleMethodAware;
050: import org.strecks.lifecycle.impl.LifecycleMethodReader;
051: import org.strecks.source.BeanSourceAnnotationReader;
052: import org.strecks.source.DefaultActionBeanSource;
053: import org.strecks.util.ReflectHelper;
054:
055: /**
056: * The default implementation of the <code>ActionController</code>
057: * @author Phil Zoio
058: */
059: public class ActionCreatorImpl implements ActionCreator {
060:
061: private static Log log = LogFactory.getLog(ActionCreatorImpl.class);
062:
063: private HashMap<Class, Class> implicitControllers;
064:
065: public ActionCreatorImpl() {
066: // we don't need to worry about this method returning null
067: this .implicitControllers = new HashMap<Class, Class>();
068: this .implicitControllers.putAll(initImplicitControllers());
069: }
070:
071: public Action createAction(Class actionClass) throws Exception {
072:
073: Action strutsAction = null;
074:
075: // Create and return a new Action instance
076: if (log.isTraceEnabled()) {
077: log.trace("Creating new Action instance");
078: }
079:
080: if (Action.class.isAssignableFrom(actionClass)) {
081: strutsAction = (Action) actionClass.newInstance();
082: } else {
083: strutsAction = createControllerAction(actionClass);
084: }
085:
086: return strutsAction;
087:
088: }
089:
090: Class getActionInterfaceType(Class controllerClass,
091: Class actionBeanClass) {
092:
093: @SuppressWarnings("unchecked")
094: ActionInterface actionInterface = (ActionInterface) controllerClass
095: .getAnnotation(ActionInterface.class);
096:
097: if (actionInterface == null) {
098: throw new ApplicationConfigurationException(
099: "The controller class " + controllerClass
100: + " declared from " + actionBeanClass
101: + " does not have an "
102: + ActionInterface.class + " annnotation");
103: }
104:
105: Class actionInterfaceType = actionInterface.name();
106:
107: // check that actionInterfaceType is an interface
108: if (!actionInterfaceType.isInterface()) {
109: throw new ApplicationConfigurationException(
110: "The controller class " + controllerClass
111: + " declared from " + actionBeanClass
112: + " declares an action interface type "
113: + actionInterfaceType
114: + " which is not an interface");
115: }
116: return actionInterfaceType;
117: }
118:
119: Object instantiateControllerAction(Class controllerClass,
120: Class actionBeanClass) {
121: // now instantiate the controllerClass
122: Object controllerActionInstance = null;
123: try {
124: controllerActionInstance = controllerClass.newInstance();
125: } catch (InstantiationException e) {
126: throw new ApplicationConfigurationException(
127: "Could not instantiate " + controllerClass
128: + " declared from action bean class "
129: + actionBeanClass);
130: } catch (IllegalAccessException e) {
131: throw new ApplicationConfigurationException(
132: "Illegal access to " + controllerClass
133: + " declared from action bean class "
134: + actionBeanClass);
135: }
136: return controllerActionInstance;
137: }
138:
139: void checkIsAssignable(Class actionClass,
140: Class actionInterfaceType, Class controllerClass) {
141: // check that actionBean implements this interface
142: @SuppressWarnings("unchecked")
143: boolean assignableFrom = actionInterfaceType
144: .isAssignableFrom(actionClass);
145: if (!assignableFrom) {
146: throw new ApplicationConfigurationException(
147: "The action bean class "
148: + actionClass
149: + " does not implement the action interface type "
150: + actionInterfaceType
151: + " mandated by the controller action class "
152: + controllerClass
153: + " with which it is associated ");
154: }
155: }
156:
157: Class getControllerClass(Class actionClass) {
158: @SuppressWarnings("unchecked")
159: Controller controller = (Controller) actionClass
160: .getAnnotation(Controller.class);
161:
162: Class controllerClass = null;
163:
164: if (controller == null) {
165: // check for implicity controllers
166: controllerClass = checkImplicitController(actionClass);
167:
168: if (controllerClass == null) {
169: throw new ApplicationConfigurationException(
170: actionClass.getName()
171: + " is not a Struts Action subclass and does not have a "
172: + Controller.class.getName()
173: + " annotation");
174: }
175: } else {
176: controllerClass = controller.name();
177: }
178:
179: if (!ControllerAction.class.isAssignableFrom(controllerClass)) {
180: throw new ApplicationConfigurationException(actionClass
181: .getName()
182: + " has a controller class "
183: + controllerClass.getName()
184: + " which does not implement the "
185: + ControllerAction.class.getName() + " interface");
186: }
187: if (!Action.class.isAssignableFrom(controllerClass)) {
188: throw new ApplicationConfigurationException(actionClass
189: .getName()
190: + " is has a "
191: + Controller.class.getName()
192: + " annotation which points to the class "
193: + controllerClass.getName()
194: + " which is not a Struts Action subclass");
195: }
196: return controllerClass;
197: }
198:
199: /**
200: * Looks for implicit controller for given action bean class. Returns the first one encountered
201: */
202: Class checkImplicitController(Class actionClass) {
203: Class controllerClass = null;
204:
205: Set<Class> actionInterfaces = implicitControllers.keySet();
206: for (Class<Object> interfaceClass : actionInterfaces) {
207: if (interfaceClass.isAssignableFrom(actionClass)) {
208: controllerClass = implicitControllers
209: .get(interfaceClass);
210: break;
211: }
212: }
213: return controllerClass;
214: }
215:
216: /**
217: * Creates action which will need to be an instance of <code>ControllerAction</code>
218: */
219: Action createControllerAction(Class actionBeanClass) {
220:
221: // get the class of the controller struts action
222: Class controllerClass = getControllerClass(actionBeanClass);
223:
224: // check that the conroller has the correct annotations
225: Class actionInterfaceType = getActionInterfaceType(
226: controllerClass, actionBeanClass);
227:
228: // check that the action class is assignable to the declared action interface type
229: checkIsAssignable(actionBeanClass, actionInterfaceType,
230: controllerClass);
231:
232: Object controllerActionInstance = instantiateControllerAction(
233: controllerClass, actionBeanClass);
234:
235: // cast to Struts action
236: Action strutsAction = (Action) controllerActionInstance;
237:
238: // cast the same reference to ControllerAction, so that its factory can be set
239: ControllerAction controllerAction = (ControllerAction) controllerActionInstance;
240:
241: if (controllerAction instanceof BeanSourceAware) {
242:
243: BeanSourceAware bsa = (BeanSourceAware) controllerAction;
244:
245: // set the name of the actionBean to be instantiated
246: bsa.setBeanSource(new DefaultActionBeanSource(
247: actionBeanClass));
248:
249: // set action class injection handlers
250: BeanSourceAnnotationReader sourceAnnotationReader = new BeanSourceAnnotationReader();
251: sourceAnnotationReader.readAnnotations(actionBeanClass);
252:
253: // tell controller action about action class injection handlers
254: sourceAnnotationReader.populateController(bsa);
255:
256: }
257:
258: if (controllerAction instanceof Injectable) {
259:
260: // set action class injection handlers
261: InjectionAnnotationReader injectionAnnotationReader = new InjectionAnnotationReader();
262: injectionAnnotationReader.readAnnotations(actionBeanClass);
263:
264: // tell controller action about action class injection handlers
265: injectionAnnotationReader
266: .populateController((Injectable) controllerAction);
267:
268: }
269:
270: if (controllerAction instanceof InterceptorAware) {
271: ActionBeanInterceptorReader interceptorAware = new ActionBeanInterceptorReader();
272: interceptorAware.readAnnotations(actionBeanClass);
273:
274: interceptorAware
275: .populateController((InterceptorAware) controllerAction);
276: }
277:
278: if (controllerAction instanceof LifecycleMethodAware) {
279: LifecycleMethodReader initMethodReader = new LifecycleMethodReader();
280: initMethodReader.readAnnotations(actionBeanClass);
281:
282: initMethodReader
283: .populateController((LifecycleMethodAware) controllerAction);
284: }
285:
286: readControllerClassAnnotations(actionBeanClass,
287: controllerAction);
288:
289: return strutsAction;
290:
291: }
292:
293: @SuppressWarnings("unchecked")
294: void readControllerClassAnnotations(Class actionBeanClass,
295: ControllerAction controllerAction) {
296:
297: Annotation[] annotations = controllerAction.getClass()
298: .getAnnotations();
299:
300: for (Annotation annotation : annotations) {
301: Class<? extends Annotation> annotationType = annotation
302: .annotationType();
303: BeanAnnotationReader readerAnnotation = annotationType
304: .getAnnotation(BeanAnnotationReader.class);
305:
306: if (readerAnnotation != null) {
307: Class value = readerAnnotation.value();
308:
309: ActionBeanAnnotationReader reader = ReflectHelper
310: .createInstance(value,
311: ActionBeanAnnotationReader.class);
312: if (reader.readAnnotations(actionBeanClass)) {
313: reader.populateController(controllerAction);
314: }
315: }
316: }
317:
318: }
319:
320: protected Map<Class, Class> initImplicitControllers() {
321: Map<Class, Class> map = new LinkedHashMap<Class, Class>();
322: map.put(BasicAction.class, BasicController.class);
323: map.put(BasicFormAction.class, BasicFormController.class);
324: map.put(BasicSubmitAction.class, BasicSubmitController.class);
325: map.put(BasicDispatchAction.class,
326: BasicDispatchController.class);
327: map.put(NavigableAction.class, NavigableController.class);
328: map.put(NavigableFormAction.class,
329: NavigableFormController.class);
330: map.put(NavigableSubmitAction.class,
331: NavigableSubmitController.class);
332: map.put(NavigableDispatchAction.class,
333: NavigableDispatchController.class);
334:
335: return map;
336: }
337:
338: }
|