/*
* Copyright 2004-2012 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.engine.impl;
import org.springframework.binding.message.MessageContext;
import org.springframework.core.style.ToStringCreator;
import org.springframework.webflow.context.ExternalContext;
import org.springframework.webflow.core.collection.LocalAttributeMap;
import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.core.collection.ParameterMap;
import org.springframework.webflow.definition.FlowDefinition;
import org.springframework.webflow.definition.StateDefinition;
import org.springframework.webflow.definition.TransitionDefinition;
import org.springframework.webflow.engine.Flow;
import org.springframework.webflow.engine.RequestControlContext;
import org.springframework.webflow.engine.State;
import org.springframework.webflow.engine.Transition;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.FlowExecutionContext;
import org.springframework.webflow.execution.FlowExecutionException;
import org.springframework.webflow.execution.FlowExecutionKey;
import org.springframework.webflow.execution.View;
/**
* Default request control context implementation used internally by the web flow system. This class is closely coupled
* with <code>FlowExecutionImpl</code> and <code>FlowSessionImpl</code>. The three classes work together to form a
* complete flow execution implementation based on a finite state machine.
*
* @see FlowExecutionImpl
*
* @author Keith Donald
* @author Erwin Vervaet
*/
class RequestControlContextImpl implements RequestControlContext {
/**
* The owning flow execution carrying out this request.
*/
private FlowExecutionImpl flowExecution;
/**
* A source context for the caller who initiated this request.
*/
private ExternalContext externalContext;
/**
* A source context for messages to record during this flow execution request.
*/
private MessageContext messageContext;
/**
* The request scope data map. Never null, initially empty.
*/
private LocalAttributeMap<Object> requestScope = new LocalAttributeMap<Object>();
/**
* Holder for contextual properties describing the currently executing request; never null, initially empty.
*/
private LocalAttributeMap<Object> attributes = new LocalAttributeMap<Object>();
/**
* The current event being processed by this flow; initially null.
*/
private Event currentEvent;
/**
* The last transition that executed in this request context; initially null.
*/
private Transition currentTransition;
/**
* The current view associated with this request context; initially null.
*/
private View currentView;
/**
* Create a new request context.
* @param flowExecution the owning flow execution
* @param externalContext the external context that originated the flow execution request
* @param messageContext the message context for recording status or validation messages during the execution of
* this request
*/
public RequestControlContextImpl(FlowExecutionImpl flowExecution, ExternalContext externalContext,
MessageContext messageContext) {
this.flowExecution = flowExecution;
this.externalContext = externalContext;
this.messageContext = messageContext;
}
// implementing RequestContext
public FlowDefinition getActiveFlow() {
return flowExecution.getActiveSession().getDefinition();
}
public StateDefinition getCurrentState() {
return flowExecution.getActiveSession().getState();
}
public TransitionDefinition getMatchingTransition(String eventId) throws IllegalStateException {
return flowExecution.getMatchingTransition(eventId);
}
public MutableAttributeMap<Object> getRequestScope() {
return requestScope;
}
public MutableAttributeMap<Object> getFlashScope() {
return flowExecution.getFlashScope();
}
public boolean inViewState() {
return flowExecution.isActive() && getCurrentState() != null && getCurrentState().isViewState();
}
public MutableAttributeMap<Object> getViewScope() throws IllegalStateException {
return flowExecution.getActiveSession().getViewScope();
}
public MutableAttributeMap<Object> getFlowScope() {
return flowExecution.getActiveSession().getScope();
}
public MutableAttributeMap<Object> getConversationScope() {
return flowExecution.getConversationScope();
}
public ParameterMap getRequestParameters() {
return externalContext.getRequestParameterMap();
}
public ExternalContext getExternalContext() {
return externalContext;
}
public MessageContext getMessageContext() {
return messageContext;
}
public FlowExecutionContext getFlowExecutionContext() {
return flowExecution;
}
public Event getCurrentEvent() {
return currentEvent;
}
public TransitionDefinition getCurrentTransition() {
return currentTransition;
}
public View getCurrentView() {
return currentView;
}
public MutableAttributeMap<Object> getAttributes() {
return attributes;
}
// implementing RequestControlContext
public String getFlowExecutionUrl() {
String key = flowExecution.getKey() != null ? flowExecution.getKey().toString() : null;
if (key != null) {
return externalContext.getFlowExecutionUrl(flowExecution.getDefinition().getId(), key);
} else {
return null;
}
}
public void sendFlowExecutionRedirect() {
externalContext.requestFlowExecutionRedirect();
}
public void setCurrentState(State state) {
flowExecution.setCurrentState(state, this);
}
public FlowExecutionKey assignFlowExecutionKey() {
return flowExecution.assignKey();
}
public void setCurrentView(View currentView) {
this.currentView = currentView;
}
public void viewRendering(View view) {
flowExecution.viewRendering(view, this);
}
public void viewRendered(View view) {
flowExecution.viewRendered(view, this);
}
public boolean handleEvent(Event event) throws FlowExecutionException {
this.currentEvent = event;
return flowExecution.handleEvent(event, this);
}
public boolean execute(Transition transition) {
return flowExecution.execute(transition, this);
}
public void setCurrentTransition(Transition transition) {
this.currentTransition = transition;
}
public void updateCurrentFlowExecutionSnapshot() {
flowExecution.updateCurrentFlowExecutionSnapshot();
}
public void removeCurrentFlowExecutionSnapshot() {
flowExecution.removeCurrentFlowExecutionSnapshot();
}
public void removeAllFlowExecutionSnapshots() {
flowExecution.removeAllFlowExecutionSnapshots();
}
public void start(Flow flow, MutableAttributeMap<?> input) throws FlowExecutionException {
flowExecution.start(flow, input, this);
}
public void endActiveFlowSession(String outcome, MutableAttributeMap<Object> output) throws IllegalStateException {
flowExecution.endActiveFlowSession(outcome, output, this);
}
public boolean getRedirectOnPause() {
if (!getExternalContext().isResponseAllowed()) {
return true;
}
Boolean redirectOnPause = flowExecution.getAttributes().getBoolean("alwaysRedirectOnPause");
return redirectOnPause == null ? false : redirectOnPause;
}
public boolean getRedirectInSameState() {
if (!getExternalContext().isResponseAllowed()) {
return true;
}
Boolean redirectInSameState = flowExecution.getAttributes().getBoolean("redirectInSameState");
return (redirectInSameState != null) ? redirectInSameState : getRedirectOnPause();
}
public boolean getEmbeddedMode() {
return flowExecution.getActiveSession().isEmbeddedMode();
}
public String toString() {
return new ToStringCreator(this).append("externalContext", externalContext)
.append("currentEvent", currentEvent).append("requestScope", requestScope)
.append("attributes", attributes).append("messageContext", messageContext)
.append("flowExecution", flowExecution).toString();
}
}