001/* 
002    Licensed to the Apache Software Foundation (ASF) under one
003    or more contributor license agreements.  See the NOTICE file
004    distributed with this work for additional information
005    regarding copyright ownership.  The ASF licenses this file
006    to you under the Apache License, Version 2.0 (the
007    "License"); you may not use this file except in compliance
008    with the License.  You may obtain a copy of the License at
009
010       http://www.apache.org/licenses/LICENSE-2.0
011
012    Unless required by applicable law or agreed to in writing,
013    software distributed under the License is distributed on an
014    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015    KIND, either express or implied.  See the License for the
016    specific language governing permissions and limitations
017    under the License.  
018 */
019package org.apache.wiki.workflow;
020
021import java.io.Serializable;
022import java.security.Principal;
023import java.util.Collection;
024import java.util.Date;
025import java.util.List;
026
027import org.apache.wiki.api.exceptions.WikiException;
028
029/**
030 * <p>
031 * Discrete unit of work in a Workflow, such as a {@link Decision} or a
032 * {@link Task}. Decisions require user input, while Tasks do not. All Steps,
033 * however, possess these properties:
034 * </p>
035 * <ul>
036 * <li><strong>actor</strong>: the Principal responsible for executing the
037 * Step; returned by {@link Step#getActor()}.</li>
038 * <li><strong>availableOutcomes</strong>: a collection of possible
039 * "outcomes," such as "approve decision" ({@link Outcome#DECISION_APPROVE}),
040 * "reassign decision" ({@link Outcome#DECISION_REASSIGN}), "abort step" ({@link Outcome#STEP_ABORT})
041 * and others. The range of possible Outcomes for the Step is returned by
042 * {@link Step#getAvailableOutcomes()}; see the Outcome class for more details.</li>
043 * <li><strong>errors</strong>: an collection of Strings indicating errors
044 * returned by the Step. These values are returned by {@link Step#getErrors()}.</li>
045 * <li><strong>started</strong> and <strong>completed</strong>: whether the
046 * Step has started/finished. These values are returned by
047 * {@link Step#isStarted()} and {@link Step#isCompleted()}.</li>
048 * <li><strong>startTime</strong> and <strong>endTime</strong>: the time when
049 * the Step started and finished. These values are returned by
050 * {@link Step#getStartTime()} and {@link Step#getEndTime()}, respectively.</li>
051 * <li><strong>workflow</strong>: the parent Workflow. </li>
052 * </ul>
053 * <p>
054 * Steps contain a {@link #getMessageKey()} method that returns a key that can
055 * be used with the {@link org.apache.wiki.i18n.InternationalizationManager}.
056 * See also {@link Workflow#getMessageArguments()}, which is a convenience
057 * method that returns message arguments.
058 * </p>
059 * 
060 * @since 2.5
061 */
062public interface Step extends Serializable
063{
064
065    /**
066     * Adds a successor Step to this one, which will be triggered by a supplied
067     * Outcome. Implementations should respect the order in which Outcomes are
068     * added; {@link #getAvailableOutcomes()} should return them in the same
069     * order they were added.
070     * 
071     * @param outcome
072     *            the Outcome triggering a particular successor Step
073     * @param step
074     *            the Step to associated with this Outcomes (<code>null</code>
075     *            denotes no Steps)
076     */
077    void addSuccessor( Outcome outcome, Step step );
078
079    /**
080     * Returns a Collection of available outcomes, such as "approve", "deny" or
081     * "reassign", in the order in which they were added via
082     * {@link #addSuccessor(Outcome, Step)}. Concrete implementations should
083     * always return a defensive copy of the outcomes, not the original backing
084     * collection.
085     * 
086     * @return the set of outcomes
087     */
088    Collection< Outcome > getAvailableOutcomes();
089
090    /**
091     * Returns a List of error strings generated by this Step. If this Step
092     * generated no errors, this method returns a zero-length array.
093     * 
094     * @return the errors
095     */
096    List< String > getErrors();
097
098    /**
099     * <p>
100     * Executes the processing for this Step and returns an Outcome indicating
101     * if it succeeded ({@link Outcome#STEP_COMPLETE} or
102     * {@link Outcome#STEP_ABORT}). Processing instructions can do just about
103     * anything, such as executing custom business logic or changing the Step's
104     * final outcome via {@link #setOutcome(Outcome)}. A return value of
105     * <code>STEP_COMPLETE</code> indicates that the instructions executed completely,
106     * without errors; <code>STEP_ABORT</code> indicates that the Step and its
107     * parent Workflow should be aborted (that is, fail silently without error).
108     * If the execution step encounters any errors, it should throw a
109     * WikiException or a subclass.
110     * </p>
111     * <p>
112     * Note that successful execution of this methods does not necessarily mean
113     * that the Step is considered "complete"; rather, it just means that it has
114     * executed. Therefore, it is possible that <code>execute</code> could run
115     * multiple times.
116     * </p>
117     * 
118     * @return the result of the Step, expressed as an Outcome
119     * @throws WikiException
120     *             if the step encounters errors while executing
121     */
122    Outcome execute() throws WikiException;
123
124    /**
125     * The Principal responsible for completing this Step, such as a system user
126     * or actor assigned to a Decision.
127     * 
128     * @return the responsible Principal
129     */
130    Principal getActor();
131
132    /**
133     * The end time for this Step. This value should be set when the step
134     * completes. Returns {@link Workflow#TIME_NOT_SET} if not completed yet.
135     * 
136     * @return the end time
137     */
138    Date getEndTime();
139
140    /**
141     * Message key for human-friendly name of this Step, including any parameter
142     * substitutions. By convention, the message prefix should be a lower-case
143     * version of the Step's type, plus a period (<em>e.g.</em>,
144     * <code>task.</code> and <code>decision.</code>).
145     * 
146     * @return the message key for this Step.
147     */
148    String getMessageKey();
149
150    /**
151     * Returns the message arguments for this Step, typically by delegating to the
152     * parent Workflow's {@link Workflow#getMessageArguments()} method.
153     * 
154     * @return the message arguments.
155     */
156    Serializable[] getMessageArguments();
157
158    /**
159     * Returns the Outcome of this Step's processing; by default,
160     * {@link Outcome#STEP_CONTINUE}.
161     * 
162     * @return the outcome
163     */
164    Outcome getOutcome();
165
166    /**
167     * The start time for this Step. Returns {@link Workflow#TIME_NOT_SET} if
168     * not started yet.
169     * 
170     * @return the start time
171     */
172    Date getStartTime();
173
174    /**
175     * Gets the Workflow that is the parent of this Step.
176     * 
177     * @return the workflow
178     */
179    Workflow getWorkflow();
180
181    /**
182     * Determines whether the Step is completed; if not, it is by definition
183     * awaiting action by the owner or in process. If a Step has completed, it
184     * <em>must also</em> return a non-<code>null</code> result for
185     * {@link #getOutcome()}.
186     * 
187     * @return <code>true</code> if the Step has completed; <code>false</code>
188     *         if not.
189     */
190    boolean isCompleted();
191
192    /**
193     * Determines whether the Step has started.
194     * 
195     * @return <code>true</code> if the Step has started; <code>false</code>
196     *         if not.
197     */
198    boolean isStarted();
199
200    /**
201     * Starts the Step, and sets the start time to the moment when this method
202     * is first invoked. If this Step has already been started, this method
203     * throws an {@linkplain IllegalStateException}. If the Step cannot
204     * be started because the underlying implementation encounters an error,
205     * it the implementation should throw a WikiException.
206     * 
207     * @throws WikiException if the step encounters errors while starting
208     */
209    void start() throws WikiException;
210
211    /**
212     * Sets the current Outcome for the step. If the Outcome is a "completion"
213     * Outcome, it should also sets the completon time and mark the Step as
214     * complete. Once a Step has been marked complete, this method cannot be
215     * called again. If the supplied Outcome is not in the set returned by
216     * {@link #getAvailableOutcomes()}, or is not  {@link Outcome#STEP_CONTINUE}
217     * or {@link Outcome#STEP_ABORT}, this method returns an
218     * IllegalArgumentException. If the caller attempts to set an Outcome
219     * and the Step has already completed, this method throws an 
220     * IllegalStateException.
221     * 
222     * @param outcome whether the step should be considered completed
223     */
224    void setOutcome( Outcome outcome );
225
226    /**
227     * Convenience method that returns the owner of the Workflow by delegating
228     * to {@link Workflow#getOwner()}.
229     * 
230     * @return the owner of the Workflow
231     */
232    Principal getOwner();
233
234    /**
235     * Identifies the next Step for a particular Outcome; if there is no next
236     * Step for this Outcome, this method returns <code>null</code>.
237     * 
238     * @param outcome
239     *            the outcome
240     * @return the next step
241     */
242    Step getSuccessor( Outcome outcome );
243
244    /**
245     * Sets the parent Workflow post-construction. Should be called after building a {@link Step}.
246     *
247     * @param workflow the parent workflow to set
248     */
249    void setWorkflow( Workflow workflow );
250
251}