I am creating a ShoppingCart Application in Spring mvc.Here I have two flows for now.
Registration Flow(flow id=registrationFlow)
MailSender Flow(flow id=mailFlow)
When user registration data gets entered in DB successfully a mailSender flow(Subflow) will get triggered.
My Parent Flow is RegistrationFlow.
Please find below Subflow invocation code:
<!-- other navigation rules of parent flow -->
<subflow-state id="mailSenderFlow" subflow="mailFlow">
<input name="userEmail" value="flowScope.regBean.userDTO.userMail"/>
<transition on="finishMailFlow" to="checkMailFlowResult" />
</subflow-state>
<decision-state id="checkMailFlowResult">
<if test="mailSender.mailConfirmation(currentEvent.attributes.mailFlowOutcome)"
then="regSuccess" else="regConfirm" />
</decision-state>
<end-state id="regSuccess" view="/WEB-INF/view/regSuccess.jsp" />
Based on subflow outcome I have created a decision state which will take the control to regSuccess page or back to regConfirm page.
Please find below Subflow definition file:
<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.4.xsd">
<input name="userEmail" required="true" type="java.lang.String"/>
<action-state id="mailSenderAction">
<evaluate expression="mailSender.sendEmail(userEmail)" />
<transition on="success" to="finishMailFlow" />
</action-state>
<end-state id="finishMailFlow">
<output name="mailFlowOutcome" value="mail sending done"/>
</end-state>
</flow>
Now during subflow invocation time I am getting following exception :
org.springframework.webflow.execution.FlowExecutionException: Exception thrown in state 'mailSenderFlow' of flow 'registrationFlow'
at org.springframework.webflow.engine.impl.FlowExecutionImpl.wrap(FlowExecutionImpl.java:573)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.resume(FlowExecutionImpl.java:263)
at org.springframework.webflow.executor.FlowExecutorImpl.resumeExecution(FlowExecutorImpl.java:169)
at org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:253)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
Truncated. see log file for complete stacktrace
Caused By: org.springframework.expression.spel.SpelParseException: EL1041E: After parsing a valid expression, there is still more data in the expression: 'sending'
at org.springframework.expression.spel.standard.InternalSpelExpressionParser.doParseExpression(InternalSpelExpressionParser.java:130)
at org.springframework.expression.spel.standard.SpelExpressionParser.doParseExpression(SpelExpressionParser.java:60)
at org.springframework.expression.spel.standard.SpelExpressionParser.doParseExpression(SpelExpressionParser.java:32)
at org.springframework.expression.common.TemplateAwareExpressionParser.parseExpression(TemplateAwareExpressionParser.java:73)
at org.springframework.binding.expression.spel.SpringELExpressionParser.parseSpelExpression(SpringELExpressionParser.java:96)
Truncated. see log file for complete stacktrace>
Can anyone figure out the issue???
try with single quote inside your value:
<output name="mailFlowOutcome" value="'mail sending done'"/>
Related
I have added a validation in my flow and it works fine, the only problem is I am not able to execute my action class method after the validation. If I remove the validation it works fine.
Here is what my flow.xml looks like
<view-state id="myView" view="newView" model="viewModel">
<transition on="doChangeView" to="doChangeView" />
<transition on="done" to="home" validate="false" />
</view-state>
<action-state id="doChangeView">
<evaluate expression="viewAction.doChangeView" />
<transition on="done" to="home" />
</action-state>
I am guessing that I am not setting the flow correctly. Any help will be appreciated.
In my case, after looking through logs I found that there was some error in the validation method. After resolving it I was able to execute the method in my action class.
Similar to this discussion Maintain Payload State during mule flow execution
I would like to know how to maintain an entire Mule Message throughout my flow.
I am trying to call a jersey resource component after I have received information that the user is authorized to call it. In this authorization request the payload and original http request gets altered.
My predicament is that I don't want to call the resource first as that would be inefficient and insecure however I cannot see any other plausible way to do this.
<flow name="test">
<http:inbound-endpoint exchange-pattern="request-response" host="0.0.0.0" port="1234" path="test" doc:name="HTTP"/>
<!-- sub-flow here which changes the MuleMessage and loses all original inbound properties -->
<jersey:resources doc:name="REST">
<component class="com.Test" />
</jersey:resources>
</flow>
Thanks for any help in advance
Mule 3 includes two scopes that will allow you to preserve the original message, while executing other message processors:
If you must wait for the sub-flow to complete because you need to use information produced by the sub-flow, use a message enricher like so. This example assigns the variable "authorized" to whatever the payload is once the sub-flow finishes processing the message.
<enricher target="#[variable:authorized]">
<flow-ref name="checkAuthorization" />
</enricher>
If you do not need to wait for the sub-flow to complete before allowing your Jersey Resource to run, use the async scope like so:
<async>
<flow-ref name="goForthAndDoSomething" />
</async>
There are multiple ways to save a mule message and it's properties so that it could be retrieve when required .. In your case you could save the entire Mule message in a variable and retrieve it when required for example :
<flow name="test">
<http:inbound-endpoint exchange-pattern="request-response" host="0.0.0.0" port="1234" path="test" doc:name="HTTP"/>
<!-- You save your entire message in a session variable named entireMessage before calling a subflow-->
<set-session-variable variableName="entireMessage" value="#[message.payload]" />
<!-- You can now call your Sub flow -->
<jersey:resources doc:name="REST">
<component class="com.Test" />
</jersey:resources>
</flow>
Here in the above flow you store your Mule message in a session variable named entireMessage .. You can easily retrieve the value of this session variable whenever you need in any flow anywhere like the following :-
<logger level="INFO" message="#[sessionVars['entireMessage']]"/>
This will print you Mule message
There is also an alternative way to store the http headers before it get altered ..
you can also use the following :-
<flow name="test">
<http:inbound-endpoint exchange-pattern="request-response" host="0.0.0.0" port="1234" path="test" doc:name="HTTP"/>
<!-- You copy all the HTTP headers before calling a subflow-->
<copy-properties propertyName="http.*" doc:name="Copy All HTTP Headers"/>
<!-- You can now call your Sub flow -->
<jersey:resources doc:name="REST">
<component class="com.Test" />
</jersey:resources>
</flow>
The above flow will copy all the HTTP headers before calling any other flow
UPDATED FLOW :-
If you need the original unaltered payload for your Jersy component , please overwrite the current payload with the original payload stored in session variable using set payload component
<flow name="test">
<http:inbound-endpoint exchange-pattern="request-response" host="0.0.0.0" port="1234" path="test" doc:name="HTTP"/>
<!-- You save your entire message in a session variable named entireMessage before calling a subflow-->
<set-session-variable variableName="entireMessage" value="#[message.payload]" />
<!-- You can now call your Sub flow -->
<!-- overwrite current payload with original unaltered payload -->
<set-payload value="#[sessionVars['entireMessage']]" doc:name="Set Payload"/>
<jersey:resources doc:name="REST">
<component class="com.Test" />
</jersey:resources>
</flow>
Try somthing like this to store the original message in session:
<message-properties-transformer scope="session" doc:name="Save original message">
<add-message-property key="originalMessage" value="#[message:payload]"></add-message-property>
</message-properties-transformer>
Then try something like this to get it from session:
<expression-transformer evaluator="..." expression="SESSION:originalMessage" doc:name="Restore original message"></expression-transformer>
Thanks for all your help. The final solution answer was:
<flow name="test">
<http:inbound-endpoint exchange-pattern="request-response" host="0.0.0.0" port="1234" path="test" doc:name="HTTP"/>
<enricher target="#[variable:unwantedPayload]" source="#[payload]">
<flow-ref name="anotherFlowCalled" />
</enricher>
<jersey:resources doc:name="REST">
<component class="com.Test" />
</jersey:resources>
</flow>
best way to store the mule message into session , whether you flow contains subflows are private flow session vars carry till end of the execeution.
Global Exception handing with Spring WebFlow Flow.
I am working in a Spring webflow project and I would like to know if anyone knows how to add sometype of global exception handing in the flow so if any of my java calls throw a example it will catch in and bring in to the same error system for the full system?
My old flow worked with out a issues:
<var name="member" class="xxxx" />
<decision-state id="checkIsInPending">
<if test="flowControllerActions.isInPending(member)" then="endStateMemberPending" else="name" />
</decision-state>
once I added the global to it, I started to get a error.
<var name="member" class="xxxxx" />
<global-transitions>
<transition on-exception="java.lang.Exception"
to="SystemException" />
</global-transitions>
<decision-state id="checkIsInPending">
<if test="flowControllerActions.isInPending(member)" then="endStateMemberPending" else="name" />
</decision-state>
Here is my error:
org.xml.sax.SAXParseException; lineNumber: 29; columnNumber: 40; cvc-complex-type.2.4.a: Invalid content was found starting with element 'decision-state'. One of '{"http://www.springframework.org/schema/webflow":on-end, "http://www.springframework.org/schema/webflow":output, "http://www.springframework.org/schema/webflow":exception-handler, "http://www.springframework.org/schema/webflow":bean-import}' is expected.
Try to rearrange XML tags. You are getting this exception because your flow XML does not comply with XSD. Myabe just put global-transition in the end
You can use global-transitions to catch exceptions:
<global-transitions>
<transition on-exception="example.MyBusinessException" to="state3"/>
</global-transitions>
For more details see : the documentation
My application uses CAS 3.4.11, Spring 3.1 and Hibernate 4.
My login-webflow.xml uses spring-webflow-2.0.xsd and the login flow is given below,
<var name="credentials" class="org.jasig.cas.authentication.principal.UsernamePasswordCredentials" />
<on-start>
<evaluate expression="initialFlowSetupAction" />
</on-start>
<view-state id="viewLoginForm" view="casLoginView" model="credentials">
<binder>
<binding property="username" />
<binding property="password" />
</binder>
<on-entry>
<set name="viewScope.commandName" value="'credentials'" />
</on-entry>
<transition on="submit" bind="true" validate="true" to="realSubmit">
<evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credentials)" />
</transition>
</view-state>
The beans "initialFlowSetupAction" and "authenticationViaFormAction" are defined in cas-servlet.xml as,
<bean id="initialFlowSetupAction" class="org.jasig.cas.web.flow.InitialFlowSetupAction"
p:argumentExtractors-ref="argumentExtractors"
p:warnCookieGenerator-ref="warnCookieGenerator"
p:ticketGrantingTicketCookieGenerator-ref="ticketGrantingTicketCookieGenerator"/>
<bean id="authenticationViaFormAction" class="org.jasig.cas.web.flow.AuthenticationViaFormAction"
p:centralAuthenticationService-ref="centralAuthenticationService"
p:warnCookieGenerator-ref="warnCookieGenerator"/>
The issue here is, the InitialFlowSetupAction is called while launch the login page. On click of "Sign In" button the bind/submit method of AuthenticationViaFormAction class should be invoked. But always the InitialFlowSetupAction is called and the form is redisplayed with out any exception. Atleast I could track if there is an exception.
Can it be a binding issue with username and password fields of the form to set its properties to UsernamePasswordCredentials?
Basically I would like to know why InitialFlowSetupAction is invoked onclick of "Sign In" button?
Probably it is because your form does not hold value of "_flowExecutionKey" field.
It should contain next input elements to be able to resume flow execution.
<form>
...
<input type="hidden" name="_eventId" value="submit" />
<input type="hidden" name="_flowExecutionKey" value="${flowExecutionKey}" />
</form>
http://static.springsource.org/spring-webflow/docs/2.0-m1/reference/flow-executor.html
In CAS 3.5.2 for some reason field "execution" is used instead of "_flowExecutionKey".
Try setting validate to false:
<transition on="submit" bind="true" validate="false" to="realSubmit">
I'm setting up an application using Spring Webflow 2, and I'm running into a problem. The app takes in a reservation on one page and then allows for payment on another page. The reservation model object works fine; I can fill out the form, submit it, and it shows the fully populated object on the following confirmation screen. When I do the same thing with the paymentInformation model object however, none of the form's contents are bound into the model object when it is processed.
Here's my flow definition. (I moved the payment flow into a subflow while I was trying to troubleshoot this problem.)
<?xml version="1.0" encoding="UTF-8"?>
<flow
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/webflow"
xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
<var name="paymentInfo" class="com.myapp.payments.domain.PaymentInfo" />
<input name="reservation" />
<decision-state id="paymentDecision">
<if test="reservationServiceImpl.needsPayment(reservation)"
then="enterPayment"
else="resolvePayment" />
</decision-state>
<view-state id="enterPayment" view="enterPayment" model="paymentInfo">
<on-render>
<evaluate expression="reservationMultiAction.preparePayment" />
<set name="viewScope.stepNumber" value="3" />
</on-render>
<transition on="back" to="editReservation" />
<transition on="submitPayment" to="resolvePayment" />
</view-state>
<action-state id="resolvePayment">
<evaluate expression="reservationMultiAction.submitPayment" />
<transition on="success" to="receipt" />
<transition on="failure" to="payment" />
</action-state>
<end-state id="editReservation" />
<end-state id="receipt" />
</flow>
Calling preparePayment populates the bean in the flowScope, and then correctly populates the form on the enterPayment page. But when I debug the submitPayment action method, the paymentInfo bean only has the results of preparePayment, and nothing from the submitted form.
And since I'm sure someone will ask, here's the opening form tag from the enterPayment page:
<form:form modelAttribute="paymentInfo" method="post">
It is hard to identify the error if full form html code is not included. At first sight, it could be a missing action attribute in the form tag.
<form:form action="${flowExecutionUrl}" modelAttribute="paymentInfo" method="post">
<input type="submit" id="_eventId" value="submitPayment" />
</form:form>