global transition on exception and transition not found - spring

I have 3 spring web-flows - flow1, flow2, flow3. flow2 and flow 3 have assigned parent flow1 like this :
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd"
parent="flow1">
In flow1 i have a global-transition and an end-state :
<end-state id="flowInterrupted" view="flowInterruptedPage"/>
<global-transitions>
<transition on-exception="com.core.exceptions.policy.InvalidPolicyContactException" to="flowInterrupted">
<evaluate expression="webFlowService.clearCurrentInterruptCause()"/>
</transition>
</global-transitions>
At some point in my application, in flow2 a subflow flow3 is called
<subflow-state id="stateInFlow2WhereSubFlow3IsDefined" subflow="flow3">
</subflow-state>
, and in flow3, an InvalidPolicyContactException is thrown. It is properly found in flow1 (as its get's to clearCurrentInterruptCause()) but later an exception is thrown, that the flowInterrupted transition is not found in flow2 - and that's true, cause it's in flow1 (where the global-transition is defined). Here is the exception :
org.springframework.webflow.engine.NoMatchingTransitionException: No transition found on occurence of event 'flowInterrupted' in state 'stateInFlow2WhereSubFlow3IsDefined' of flow 'flow2' -- valid transitional criteria are array<TransitionCriteria>[exit, contactSelected] -- likely programmer error, check the set of TransitionCriteria for this state at org.springframework.webflow.engine.TransitionableState.getRequiredTransition(TransitionableState.java:93) at org.springframework.webflow.engine.TransitionableState.handleEvent(TransitionableState.java:119)
at org.springframework.webflow.engine.SubflowState.handleEvent(SubflowState.java:116)
at org.springframework.webflow.engine.Flow.handleEvent(Flow.java:555)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.handleEvent(FlowExecutionImpl.java:388)
at org.springframework.webflow.engine.impl.RequestControlContextImpl.handleEvent(RequestControlContextImpl.java:210)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.endActiveFlowSession(FlowExecutionImpl.java:412)
at org.springframework.webflow.engine.impl.RequestControlContextImpl.endActiveFlowSession(RequestControlContextImpl.java:238)
When I change end-state id="flowInterrupted" to view-state it works fine. when it's called from other flows, that have flow1 as parent it works also fine. When I remove parent=flow1 from flow3, I wouldn't catch an exceptin on global-transition. The only problem is, when an exception is raised from a subflow.
Any help would be appreciated - I can of course put flowInterrupted state in flow2 and solve the problem, but I would like to understand, why this is happening
Thanks.

add
<transition on="flowInterrupted" to="flowInterrupted"/>
in your global transition

Related

killing fragment observing live-data instance in a shared view model

I am using shared view model to get values from socket across an activity, with help of observing a live-data instance, and navigation component to navigate between fragments so there's a situation where i show a payment receipt value then user clicks pay this fragment should navigate to another fragment and destroy the first one but what's actually happening it's still alive due to shared view model live-data instance that i was observing, so how to kill this fragment instance when navigating to another fragment
so first i was in trip status -> payment -> thanks
here's my navigation code
private fun updateTripStatusUI(isPayed: Boolean = false) {
if (isPayed) {
findNavController(R.id.navigationFragment).popBackStack()
findNavController(R.id.navigationFragment).navigate(
TripStatusFragmentDirections.actionTripStatusFragmentToThanksFragment()
)
} else
findNavController(R.id.navigationFragment).navigate(TripStatusFragmentDirections.actionGlobalPaymentFragment())
}
and here's my graph
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/trip_graph"
app:startDestination="#id/tripStatusFragment">
<fragment
android:id="#+id/tripStatusFragment"
android:name="package.TripStatusFragment"
android:label="fragment_trip_status"
tools:layout="#layout/fragment_trip_status">
<action
android:id="#+id/action_tripStatusFragment_to_thanksFragment"
app:destination="#id/thanksFragment"
app:enterAnim="#anim/nav_default_enter_anim"
app:exitAnim="#anim/nav_default_exit_anim"
app:popEnterAnim="#anim/popup_enter"
app:popExitAnim="#anim/popup_exit" />
</fragment>
<fragment
android:id="#+id/paymentFragment"
android:name="package.PaymentFragment"
android:label="PaymentFragment"
tools:layout="#layout/fragment_payment" />
<fragment
android:id="#+id/thanksFragment"
android:name="package.ThanksFragment"
android:label="ThanksFragment"
tools:layout="#layout/fragment_thanks" />
<action
android:id="#+id/action_global_paymentFragment"
app:destination="#id/paymentFragment"
app:enterAnim="#anim/nav_default_enter_anim"
app:exitAnim="#anim/nav_default_exit_anim"
app:popEnterAnim="#anim/nav_default_pop_enter_anim"
app:popExitAnim="#anim/nav_default_pop_exit_anim" />
</navigation>
and in ThanksFragment i navigate back to TripStatusFragment with this line
findNavController().navigate(R.id.tripStatusFragment)

Spring Webflow - Prevent subflow being accessed directly

I'm using Spring Web Flow in my webapp and i would like to know if there is a general way to prevent some subflows to be accessed directly. These subflows are meant to be accessed just from certain flows, not directly by the url, so in these subflows i would like to check "if i was called from a flow".
is there any mechanisms to achieve it? I was looking at spring security but i couldn't find any useful feature to make this kind of restriction.
Thanks you!
You can check this by using input mapper attribute as shown below. Suppose you have a parent flow which invokes 'subflow-flow'. You need to pass an input value containing the name of the parent flow as:
<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
...
<subflow-state id="subflow-flow" subflow="subflow-flow">
<!--flowInitiatedBy should be different for each different parent flow-->
<input name="flowInitiatedBy" value="'parentFlowName'"/>
<transition on="invalidAccess" to="someViewWithMessage"/>
<transition on="processedSubflow" to="someOtherState"/>
</subflow-state>
...
</flow>
Then in subflow you can retrieve the parentflowname and perform the check in yourAction class. You can define subflow as:
<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd"
start-state="start">
<input name="flowInitiatedBy" type="java.lang.String"/>
<action-state id="start">
<evaluate expression="yourAction.checkAccessibility(flowRequestContext)"/>
<transition on="invalidAccess" to="verifyWhetherDraftsExists"/>
<transition on="continue" to="continueToState"/>
</action-state>
<!--define other states for continue transition -->
...
<end-state id="invalidAccess"/>
<end-state id="processedSubflow"/>
</flow>
In your action class:
public class YourAction{
...
public String checkAccessibility(RequestContext context){
String flowInitiatedBy = context.getFlowScope().get("flowInitiatedBy");
//flowInitiatedBy will be empty if initiated by url.
if(flowInitiatedBy is empty){
return "invalidAccess";
}else{
// dosomething
return "continue";
}
}
...
}
Hope this helps.
I also wish there was some kind of built-in, simple mechanism. However, I just did this a slightly different way I thought I'd share. That is, since my Subflow knows its own name, I just had the first state in the Flow configuration check whether or not the Flow ID (name) matches that hardcoded name:
<decision-state id="subOnly">
<if test="flowExecutionContext.definition.id == 'thisSubflowFlowName'" then="invalidAccess" else="mySubflowFirstState"/>
</decision-state>
Where "invalidAccess" is an end-state like the prior answer shows.

How to return Java Set object to webflowc state

I am new to spring web flow , my requirement is return a set object to spring web flow action state by evaluating an expression .I am facing problem with below code please correct me.
<action-state id="openDocument">
<set name="requestScope.startPoint" value="requestParameters.startPoint" />
<set name="requestScope.fileName" value="requestParameters.fileName" />
<set name="requestScope.ext" value="requestParameters.ext" />
<evaluate expression="workflowController.workflowopenFile(requestScope.startPoint,requestScope.fileName,requestScope.ext)"></evaluate>
</action-state>
return the expected object from workflowopenFile() , and set it to a variable in flow with result attribute.
I solved my problem. the problem was in
add return attribute to evaluate tag . (result = "workflowSet").

How to set a literal String flowScope value on-exception?

In my Spring web flow app, one of my action-state transitions looks like this:
<transition on-exception="com.foo.BarException" to="barView">
<set name="flowScope.error" value="foo.bar" type="string" />
</transition>
I would like to set flowScope.error to the literal String "foo.bar", but Spring interprets this as a reference to the foo object's bar attribute. How can I force Spring to take the String literally?
I figured it out: the value needs needs to be enclosed in single quotes:
<set name="flowScope.error" value="'foo.bar'" type="string" />

Returning value (output) from web flow

I am using spring web-flow 2.0 and I need to return a variable from sub-flow to parent flow like:
<end-state id="end" >
<output name="mvViewBean" value="viewBean" />
</end-state>
and use it inside my parent flow like :
<subflow-state id="updateSubflowState" subflow="mv-update" >
<on-exit>
<evaluate expression="mvService.onblabla(mvViewBean)" />
</on-exit>
</subflow-state>
Do i need to define variable definitions or something else?
Just came across this issue...The currentEvent does work, but if you indicate that you accept the variable in your updateSubflowState through a
<output name="mvViewBean" value="flowScope.mvViewBean"/>
then you will be able to access it as mvViewBean.
Yo can get the output values getting attribute in currentEvent.
<subflow-state id="updateSubflowState" subflow="mv-update" >
<on-exit>
<evaluate expression="mvService.onblabla(currentEvent.attributes.mvViewBean)" />
</on-exit>
</subflow-state>

Resources