/*******************************************************************************
* Copyright 2006 - 2012 Vienna University of Technology,
* Department of Software Technology and Interactive Systems, IFS
*
* 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 eu.scape_project.planning.plato.wfview;
import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
import javax.enterprise.context.ConversationScoped;
import javax.inject.Named;
import eu.scape_project.planning.exception.PlanningException;
import eu.scape_project.planning.model.Plan;
import eu.scape_project.planning.model.PlanState;
/**
* Class representing a viewWorkflow which consist of several steps. This class
* is responsible for correct navigation between these steps.
*
* @author Markus Hamm, Michael Kraxner
*/
@Named("viewWorkflow")
@ConversationScoped
public class ViewWorkflow implements Serializable {
private static final long serialVersionUID = -8304259709178234866L;
private List<AbstractView> steps;
private AbstractView currentView;
private Plan plan;
/**
* Method responsible for providing the object with all required
* information(dependencies) to operate. (Because this is a managed bean and
* created by the container this cannot be passed via the constructor)
*
* @param steps
* All steps of the viewWorkflow
*/
public void init(final Plan plan, final List<AbstractView> steps) throws PlanningException {
if (steps == null || steps.isEmpty()) {
throw new PlanningException("No views defined!");
}
this.plan = plan;
this.steps = steps;
currentView = getViewForPlanState(plan.getPlanProperties().getState());
}
/**
* Proceed to the next step and return the view-url of the next page to
* show.
*
* @return View-url of the next page to show.
* @throws PlanningException
* If the viewWorkflow is in an unknown stage (should not happen
* during normal operation)
*/
public String proceed() throws PlanningException {
boolean mayProceed = "success".equals(currentView.proceed());
// because of storing the plan, the state might have changed
plan = currentView.getPlan();
if (mayProceed) {
currentView = this.getViewForPlanState(plan.getPlanProperties().getState());
return showCurrentView();
} else {
return null;
}
}
/**
* Saves the currently open changes. (the actual save is delegated to the
* view)
*
* @throws PlanningException
* if no currentView is set
*/
public void save() throws PlanningException {
if (currentView != null) {
currentView.save();
// the plan instance might have changed
plan = currentView.getPlan();
} else {
throw new PlanningException("Invalid viewWorkflow-state, no current view available.");
}
}
/**
* Discards unsaved changes. (the actual discard is delegated to the view)
*
* @throws PlanningException
* if no currentView is set
*/
public String discard() throws PlanningException {
if (currentView != null) {
currentView.discard();
// the plan instance might have changed
plan = currentView.getPlan();
// return the current-view-url to recreate the view
// (populate the view with updated model values - after immediate
// event changing the underlying model)
return currentView.getViewUrl();
} else {
throw new PlanningException("Invalid viewWorkflow-state, no current view available.");
}
}
/**
* Will display the current view: - initialization of the view - Returns the
* views-url dependent of the current plan-state.
*
* @return view-url of the current page to show.
* @throws PlanningException
* If the viewWorkflow is in an unknown stage (should not happen
* during normal operation)
*/
public String showCurrentView() throws PlanningException {
if (currentView != null) {
currentView.init(plan);
return currentView.getViewUrl();
} else {
throw new PlanningException("Invalid viewWorkflow-state, no current view available.");
}
}
/**
* Returns the view URL for the given plan state (if reachable).
*
* @param state
* ViewWorkflow-state to get the view-url for
* @return View URL corresponding to the given state, or null if the plan
* has not progressed this far (and thus the wanted stage is not yet
* reachable).
*/
public String goToStep(final PlanState state) throws PlanningException {
AbstractView result = getViewForPlanState(state);
if (result != null) {
currentView = result;
return showCurrentView();
}
return null;
}
/**
* Method responsible for returning if the viewWorkflow state is reachable
* (the viewWorkflow has progressed so far).
*
* @param planstate
* ViewWorkflow-state to chech for reachability.
* @return True if the viewWorkflow has progressed so far that this
* viewWorkflow-step is reachable, null otherwise.
*/
public boolean reachable(final PlanState planstate) {
int wfStartStateValue = steps.get(0).getCurrentPlanState().getValue();
int currentPlanStateValue = plan.getPlanProperties().getState().getValue();
// reachable steps are all steps between start- and current-state.
if (planstate.getValue() < wfStartStateValue || planstate.getValue() > currentPlanStateValue) {
return false;
}
return true;
}
/**
* Returns the appropriate view for the given plan state. The appropriate
* view is the view with the highest plan-state which is <= current
* plan-state.
*
* @param state
* Plan state to to find the appropriate view for.
* @return View to show for the given plan state. Null if no appropriate
* view corresponding to the given state can be identifies. Null if
* the plan has not progressed this far (and thus the wanted stage
* is not yet reachable/allowed).
*/
private AbstractView getViewForPlanState(final PlanState state) {
if (!reachable(state)) {
return null;
}
AbstractView result = null;
Iterator<AbstractView> viewIterator = steps.iterator();
AbstractView view = null;
do {
view = viewIterator.next();
// check if the iterated view is "better" than the current result
if (result == null || result.getCurrentPlanState().getValue() < view.getCurrentPlanState().getValue()) {
result = view;
}
} while (viewIterator.hasNext() && view.getCurrentPlanState().getValue() < state.getValue());
return result;
}
// ------------------------- getter/setter -------------------------
public List<AbstractView> getSteps() {
return steps;
}
public void setSteps(final List<AbstractView> steps) {
this.steps = steps;
}
public Plan getPlan() {
return plan;
}
public void setPlan(final Plan plan) {
this.plan = plan;
}
public AbstractView getCurrentView() {
return currentView;
}
public void setCurrentView(final AbstractView currentView) {
this.currentView = currentView;
}
}