org.springframework.webflow.action.MultiAction Maven / Gradle / Ivy
/*
* Copyright 2004-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.webflow.action;
import org.springframework.util.Assert;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.util.DispatchMethodInvoker;
/**
* Action implementation that bundles two or more action execution methods into
* a single class. Action execution methods defined by subclasses must adhere to
* the following signature:
*
*
* public Event ${method}(RequestContext context) throws Exception;
*
*
* When this action is invoked, by default the id
of the calling
* action state state is treated as the action execution method name.
* Alternatively, the execution method name may be explicitly specified as a
* attribute of the calling action state.
*
* For example, the following action state definition:
*
*
* <action-state id="search">
* <action bean="searchAction"/>
* <transition on="success" to="results"/>
* </action-state>
*
*
* ... when entered, executes the method:
*
*
* public Event search(RequestContext context) throws Exception;
*
*
* Alternatively (and typically recommended), you may explictly specify the method name:
*
*
* <action-state id="search">
* <action bean="searchAction" method="executeSearch"/>
* <transition on="success" to="results"/>
* </action-state>
*
*
*
* A typical use of the MultiAction is to centralize all command logic for a
* flow in one place. Another common use is to centralize form setup and submit
* logic in one place, or CRUD (create/read/update/delete) operations for a
* single domain object in one place.
*
* @see MultiAction.MethodResolver
* @see org.springframework.webflow.action.DefaultMultiActionMethodResolver
*
* @author Keith Donald
* @author Erwin Vervaet
*/
public class MultiAction extends AbstractAction {
/**
* A cache for dispatched action execute methods. The default signature is
* public Event ${method}(RequestContext context) throws Exception;
.
*/
private DispatchMethodInvoker methodInvoker;
/**
* The action method resolver strategy.
*/
private MethodResolver methodResolver = new DefaultMultiActionMethodResolver();
/**
* Protected default constructor; not invokable for direct MultiAction instantiation.
* Intended for use by subclasses.
*
* Sets the target to this multi action instance.
* @see #setTarget(Object)
*/
protected MultiAction() {
setTarget(this);
}
/**
* Constructs a multi action that invokes methods on the specified target
* object. Note: invokable methods on the target must conform to the multi action
* method signature:
*
* public Event ${method}(RequestContext context) throws Exception;
*
* @param target the target of this multi action's invocations
*/
public MultiAction(Object target) {
setTarget(target);
}
/**
* Sets the target of this multi action's invocations.
* @param target the target
*/
protected final void setTarget(Object target) {
methodInvoker = new DispatchMethodInvoker(target, new Class[] { RequestContext.class } );
}
/**
* Get the strategy used to resolve action execution method names.
*/
public MethodResolver getMethodResolver() {
return methodResolver;
}
/**
* Set the strategy used to resolve action execution method names.
* Allows full control over the method resolution algorithm.
* Defaults to {@link DefaultMultiActionMethodResolver}.
*/
public void setMethodResolver(MethodResolver methodResolver) {
this.methodResolver = methodResolver;
}
protected final Event doExecute(RequestContext context) throws Exception {
String method = getMethodResolver().resolveMethod(context);
Object obj = methodInvoker.invoke(method, new Object[] { context });
if (obj != null) {
Assert.isInstanceOf(Event.class, obj,
"The '" + method + "' action execution method on target object '" +
methodInvoker.getTarget() + "' did not return an Event object but '" +
obj + "' of type " + obj.getClass().getName() + " -- " +
"Programmer error; make sure the method signature conforms to " +
"'public Event ${method}(RequestContext context) throws Exception;'.");
}
return (Event)obj;
}
/**
* Strategy interface used by the MultiAction to map a request context to
* the name of an action execution method.
*
* @author Keith Donald
* @author Erwin Vervaet
*/
public interface MethodResolver {
/**
* Resolve a method name from given flow execution request context.
* @param context the flow execution request context
* @return the name of the method that should handle action
* execution
*/
public String resolveMethod(RequestContext context);
}
}