001: /*
002: * Copyright 2004-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.springframework.webflow.action;
017:
018: import java.util.ArrayList;
019: import java.util.List;
020:
021: import org.springframework.core.style.ToStringCreator;
022: import org.springframework.util.Assert;
023: import org.springframework.webflow.core.collection.LocalAttributeMap;
024: import org.springframework.webflow.core.collection.MutableAttributeMap;
025: import org.springframework.webflow.execution.Action;
026: import org.springframework.webflow.execution.Event;
027: import org.springframework.webflow.execution.RequestContext;
028:
029: /**
030: * An action that will execute an ordered chain of other actions when executed.
031: * <p>
032: * The event id of the last not-null result returned by the executed actions
033: * will be used as the result event id of the composite action. Lacking that,
034: * the action will return the "success" event.
035: * <p>
036: * The resulting event will have an "actionResults" event attribute
037: * with a list of all events returned by the executed actions, including the null
038: * events. This allows you to relate an executed action and its result event by
039: * their index in the list.
040: * <p>
041: * This is the classic GoF composite design pattern.
042: *
043: * @author Keith Donald
044: */
045: public class CompositeAction extends AbstractAction {
046:
047: /**
048: * The resulting event whill have an attribute of this name which holds a
049: * list of all events returned by the executed actions. ("actionResults")
050: */
051: public static final String ACTION_RESULTS_ATTRIBUTE_NAME = "actionResults";
052:
053: /**
054: * The actions to execute.
055: */
056: private Action[] actions;
057:
058: /**
059: * Should execution stop if one action returns an error event?
060: */
061: private boolean stopOnError;
062:
063: /**
064: * Create a composite action composed of given actions.
065: * @param actions the actions
066: */
067: public CompositeAction(Action[] actions) {
068: Assert.notEmpty(actions, "At least one action is required");
069: this .actions = actions;
070: }
071:
072: /**
073: * Returns the actions contained by this composite action.
074: * @return the actions
075: */
076: protected Action[] getActions() {
077: return actions;
078: }
079:
080: /**
081: * Returns the stop on error flag.
082: */
083: public boolean isStopOnError() {
084: return stopOnError;
085: }
086:
087: /**
088: * Sets the stop on error flag. This determines whether or not execution
089: * should stop with the first action that returns an error event. In the
090: * error case, the composite action will also return the "error" event.
091: */
092: public void setStopOnError(boolean stopOnError) {
093: this .stopOnError = stopOnError;
094: }
095:
096: public Event doExecute(RequestContext context) throws Exception {
097: Action[] actions = getActions();
098: String eventId = getEventFactorySupport().getSuccessEventId();
099: MutableAttributeMap eventAttributes = new LocalAttributeMap();
100: List actionResults = new ArrayList(actions.length);
101: for (int i = 0; i < actions.length; i++) {
102: Event result = actions[i].execute(context);
103: actionResults.add(result);
104: if (result != null) {
105: eventId = result.getId();
106: if (isStopOnError()
107: && result.getId().equals(
108: getEventFactorySupport()
109: .getErrorEventId())) {
110: break;
111: }
112: }
113: }
114: eventAttributes.put(ACTION_RESULTS_ATTRIBUTE_NAME,
115: actionResults);
116: return new Event(this , eventId, eventAttributes);
117: }
118:
119: public String toString() {
120: return new ToStringCreator(this )
121: .append("actions", getActions()).append("stopOnError",
122: isStopOnError()).toString();
123: }
124: }
|