NPE while trying to render a View in Spring Webflow - java

When trying to use a webflow, I keep getting the following error:
{
"failure":"true",
"exception.message":"org.springframework.webflow.execution.ActionExecutionException: Exception thrown executing org.springframework.webflow.action.ViewFactoryActionAdapter#200a5beb in state 'accountCannotLogInView' of flow 'login' -- action execution attributes were 'map[[empty]]'",
"exception.stacktrace":"org.springframework.webflow.execution.ActionExecutionException: Exception thrown executing org.springframework.webflow.action.ViewFactoryActionAdapter#200a5beb in state 'accountCannotLogInView' of flow 'login' -- action execution attributes were 'map[[empty]]'
...
Caused by: java.lang.IllegalStateException: Exception occurred rendering view null
at org.springframework.webflow.mvc.view.AbstractMvcView.render(AbstractMvcView.java:191)
at org.springframework.webflow.action.ViewFactoryActionAdapter.doExecute(ViewFactoryActionAdapter.java:40)
at org.springframework.webflow.action.AbstractAction.execute(AbstractAction.java:188)
at org.springframework.webflow.execution.ActionExecutor.execute(ActionExecutor.java:51)
... 66 more
Caused by: java.lang.NullPointerException
at org.springframework.webflow.mvc.servlet.ServletMvcView.doRender(ServletMvcView.java:50)
at org.springframework.webflow.mvc.view.AbstractMvcView.render(AbstractMvcView.java:187)
... 69 more
"
}
Does anybody have any idea what the cause of this might be?
From my login-webflow.xml:
<action-state id="checkAccountType">
<evaluate expression="lookupAccountTypeAction.lookup(flowScope.principal)" />
<transition on="EMAIL" to="accountCannotLogInView" />
<transition on="Login" to="checkAccountStatus" />
<transition on="CONTACT" to="accountCannotLogInView" />
</action-state>
<end-state id="accountCannotLogInView" view="myAccountCannotLogInView"/>
From default_views.properties:
myAccountCannotLogInView.(class)=org.springframework.web.servlet.view.JstlView
myAccountCannotLogInView.url=/WEB-INF/view/jsp/default/ui/myAccountCannotLogInView.jsp
From my log file:
2013-09-09 08:29:25,645 DEBUG [org.springframework.webflow.engine.EndState] - Entering state 'accountCannotLogInView' of flow 'login'
2013-09-09 08:29:25,645 DEBUG [org.springframework.webflow.execution.ActionExecutor] - Executing org.springframework.webflow.action.ViewFactoryActionAdapter#359d136a
2013-09-09 08:29:25,645 DEBUG [org.springframework.webflow.mvc.view.AbstractMvcView] - Rendering MVC [null] with model map [{flowRequestContext=[RequestControlContextImpl#55bf756b externalContext = org.springframework.webflow.mvc.servlet.MvcExternalContext#2bb4d74, currentEvent = EMAIL, requestScope = map['ticketGrantingTicketId' -> 'TGT-1-GxALVR7PEtbagbnRlStOTbHoRHlb61YVm1m2hvWx3pgWCEXgPb-cas01.example.org'], attributes = map[[empty]], messageContext = [DefaultMessageContext#cb5efc8 sourceMessages = map[[null] -> list[[empty]]]], flowExecution = [FlowExecutionImpl#3f5c0d33 flow = 'login', flowSessions = list[[FlowSessionImpl#419d87bc flow = 'login', state = 'accountCannotLogInView', scope = map['principal' -> sso_test_user, 'userInfoBean' -> com.mycompany.authentication.UserInfoBean#54394557[username=<null>,firstName=<null>,lastName=<null>,emailAddress=<null>,streetAddress=<null>,city=<null>,state=<null>,zip=<null>,country=<null>], 'changePasswordBean' -> com.mycompany.authentication.ChangePasswordBean(username=null, newPassword=null, confirmNewPassword=null), 'service' -> https://my.server.com:443/casauth/facade/norenew?idp=https://my.server.com/idp/externalAuthnCallback, 'credentials' -> [username: sso_test_user], 'warnCookieValue' -> false, 'ticketGrantingTicketId' -> 'TGT-1-GxALVR7PEtbagbnRlStOTbHoRHlb61YVm1m2hvWx3pgWCEXgPb-cas01.example.org']]]]], flashScope=map[[empty]], principal=sso_test_user, currentUser=null, userInfoBean=com.mycompany.authentication.UserInfoBean#54394557[username=<null>,firstName=<null>,lastName=<null>,emailAddress=<null>,streetAddress=<null>,city=<null>,state=<null>,zip=<null>,country=<null>], changePasswordBean=com.mycompany.authentication.ChangePasswordBean(username=null, newPassword=null, confirmNewPassword=null), service=https://my.server.com:443/casauth/facade/norenew?idp=https://my.server.com/idp/externalAuthnCallback, credentials=[username: sso_test_user], flowExecutionKey=e1s1, warnCookieValue=false, flowExecutionUrl=/authentication/login?username=%5BLjava.lang.String%3B%405b65afa5&submit=%5BLjava.lang.String%3B%4070eea883&_eventId=%5BLjava.lang.String%3B%4044796a61&service=%5BLjava.lang.String%3B%407f372965&lt=%5BLjava.lang.String%3B%407e7ee722&password=%5BLjava.lang.String%3B%403d78aa0f&execution=%5BLjava.lang.String%3B%403ce4de50, ticketGrantingTicketId=TGT-1-GxALVR7PEtbagbnRlStOTbHoRHlb61YVm1m2hvWx3pgWCEXgPb-cas01.example.org}]
2013-09-09 08:29:25,645 DEBUG [org.springframework.webflow.engine.impl.FlowExecutionImpl] - Attempting to handle [org.springframework.webflow.execution.ActionExecutionException: Exception thrown executing org.springframework.webflow.action.ViewFactoryActionAdapter#359d136a in state 'accountCannotLogInView' of flow 'login' -- action execution attributes were 'map[[empty]]'] with root cause [java.lang.NullPointerException]
2013-09-09 08:29:25,645 DEBUG [org.springframework.webflow.engine.impl.FlowExecutionImpl] - Rethrowing unhandled flow execution exception
And yes, the file does exist in that location. I've been banging on this for a few days, so if anybody has any insight, I'd really appreciate it.

And the correct answer is "user error". I'm building CAS via maven. I created profiles to hold logging, and then incorrectly configured it so that the default_views.properties file wasn't in the profiles. As a result, when CAS did its overlay as part of the maven build, it included the baseline default_views.properties instead of my copy.

it seems like your property is not parsed to your flow.xml.
defining your view hardcoded should work.
see here: Specifying view identifiers

The reason for this issue is: The JSP view is not found.
In cas-servlet.xml, mention the properties file which has the basename of the custom JSP view inside the "viewResolver" bean as below:
<bean id="viewResolver"
class="org.springframework.web.servlet.view.ResourceBundleViewResolver"
p:order="0">
<property name="basenames">
<util:list>
<value>${cas.viewResolver.basename}</value>
<value>custom_view</value>
<value>protocol_views</value>
</util:list>
</property>
</bean>
And in the custom_view.properties, mention the following:
casRegisterView.(class)=org.springframework.web.servlet.view.JstlView
casRegisterView.url=/WEB-INF/view/jsp/default/ui/casRegisterView.jsp
Here the JSP view is "casRegisterView.jsp".
Place custom_view.properties in /src/main/resources.

Related

Cannot resolve ${url} in applicationcontext-ws.xml while running test

An url is set with something like http:xxx.com in ..test/java/resources/application-local.properties and ..main/java/resources/application-local.properties
A file called applicationcontext-ws.xml used ${url} :
<jaxws:client id="xxx"
serviceClass="RemoteService"
address="${url}">
<jaxws:outInterceptors>
<ref bean="headerInterceptor"/>
</jaxws:outInterceptors>
</jaxws:client>
When running test, I got an exception:
Caused by: java.net.URISyntaxException: Illegal character in path at
index 1: ${url} at java.net.URI$Parser.fail(URI.java:2848) at
java.net.URI$Parser.checkChars(URI.java:3021) at
java.net.URI$Parser.parseHierarchical(URI.java:3105) at
java.net.URI$Parser.parse(URI.java:3063) at
java.net.URI.(URI.java:588) at
org.apache.cxf.transport.http.HTTPConduit.setupURI(HTTPConduit.java:664)
at
org.apache.cxf.transport.http.HTTPConduit.prepare(HTTPConduit.java:458)
However, when running it normally, i.e., not running test, this problem never occurs.
At first I suspect that it's because ..test/resources/application-local.properties is not loaded. I annotate a field url with #Value(${url}) in my test class, and in debug mode I can see the field's value is exactly the url's content in ..test/resources/application-local.properties, so that's not the cause.
Would you please offer some advice to help me figure out what's the cause and how to resove url while running test? Thanks.
I believe '${url}' itself is going as the url and '{' is being treated as an illegal character. Please debug and check what is the url that is being passed/created at runtime. I believe ${url} is not getting replaced correctly at runtime.

Polling HTTP endpoint followed by jersey REST WS does not work in Mule 3.5

I have a requirement where i need to poll a rest service and then proxy the response from this web service on to a REST web service.
I am using Mule 3.5 and my flow looks like the below.
I get the below exception where the REST service is being invoked
********************************************************************************
Message : Failed to invoke JerseyResourcesComponent{TestFlow.component.1106552446}. Component that caused exception is: JerseyResourcesComponent{TestFlow.component.1106552446}. Message payload is of type: String
Code : MULE_ERROR--2
--------------------------------------------------------------------------------
Exception stack is:
1. null (java.lang.NullPointerException)
org.mule.module.jersey.JerseyResourcesComponent:192 (null)
2. Failed to invoke JerseyResourcesComponent{TestFlow.component.1106552446}. Component that caused exception is: JerseyResourcesComponent{TestFlow.component.1106552446}. Message payload is of type: String (org.mule.component.ComponentException)
org.mule.component.AbstractComponent:144 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/component/ComponentException.html)
--------------------------------------------------------------------------------
Root Exception stack trace:
java.lang.NullPointerException
at org.mule.module.jersey.JerseyResourcesComponent.getBaseUri(JerseyResourcesComponent.java:192)
at org.mule.module.jersey.JerseyResourcesComponent.doInvoke(JerseyResourcesComponent.java:146)
at org.mule.component.AbstractComponent.invokeInternal(AbstractComponent.java:122)
+ 3 more (set debug level logging or '-Dmule.verbose.exceptions=true' for everything)
********************************************************************************
After debugging i figured out it is because Mule expects the MuleMessage inbound property for contextPath to be populated however in this case it is null.
In JerseyResourcesComponent line 117 is returned as null and hence line 195 throws a NPE.
I wanted to know if this kind of requirement/pattern is invalid or is it some kind of limitation in the way Mule is handling its messaging infrastructure ?
The flow xml just in case you want to inspect it.
<flow name="TestFlow" doc:name="TestFlow">
<poll doc:name="Poll">
<fixed-frequency-scheduler frequency="10" timeUnit="SECONDS" startDelay="10"/>
<http:outbound-endpoint exchange-pattern="request-response" host="localhost" port="8080" doc:name="Order Generator" method="GET" contentType="application/json" path="order"/>
</poll>
<object-to-string-transformer doc:name="Object to String"/>
<jersey:resources doc:name="Tax Calculator">
<component class="org.nthdimenzion.TaxCalculator"/>
</jersey:resources>
<logger level="INFO" doc:name="Logger"/>
</flow>
PS : The work around i got was to use a java/spring component instead of a REST WS and then call the REST WS from the Java component.

Representing a route list from xml in camel DSL

How can I represent this route in Camel's DSL:
<camel:camelContext id="camel-context">
<camel:route id="conductor-event" trace="true">
<camel:from uri="direct:conductor/event"/>
<camel:log message="handling conductor-event: id=${exchangeId}"/>
<!-- execute each filter in sorted order -->
<camel:bean ref="beaner.BProcessors"/>
<camel:log message="after: [bprocessors]: id=${exchangeId}"/>
<!-- map the event to a route -->
<camel:recipientList parallelProcessing="false">
<camel:method ref="beaner.Mappings" />
</camel:recipientList>
<camel:log message="after event mapping: id=${exchangeId}"/>
</camel:route>
</camel:camelContext>
I have this so far, but I get a "Caused by: java.net.URISyntaxException: Illegal character in scheme name at index 0: %7BCamelToEndpoint=...":
RouteDefinition routeDef = from("direct:conductor/event")
.log( "handling conductor-event: id=${exchangeId}" )
.beanRef( "beaner.BProcessors" )
.log( "after: [bprocessors]: id=${exchangeId}" );
ExpressionClause<RecipientListDefinition<RouteDefinition>> recipientList = routeDef.recipientList();
recipientList.properties().setParallelProcessing( false );
recipientList.method( "beaner.EventMappings" );
routeDef.log( "after event mapping: id=${exchangeId}" );
here is the route in JavaDSL...note that the recipientList parallelProcessing is false by default...
from("direct:conductor/event")
.log("handling conductor-event: id=${exchangeId}")
.beanRef("beaner.BProcessors")
.log("after: [bprocessors]: id=${exchangeId}")
.recipientList(bean("beaner.Mappings"))
.log("after event mapping: id=${exchangeId}");
You should use a RouteBuilder class in Java DSL to access the DSL.
Then inside the configure method you can build the routes almost identical as in XML DSL.
See the getting started guide here: http://camel.apache.org/walk-through-an-example.html

How to configure 2.6 spring: Failed to create route route2 at:

I'm trying to upgrade from Camel 2.0 to 2.6
I have this in my applicationContext-camel.xml file...
<camel:route >
<camel:from uri="transactionSaleBuffer" />
<camel:policy ref="routeTransactionPolicy"/>
<camel:transacted ref="transactionManagerETL" />
<camel:to uri="detailFactProcessor" />
</camel:route>
by adding in the two lines in the middle (policy and transacted) I get the exception...
Caused by: org.apache.camel.FailedToCreateRouteException: Failed to create route route2 at: >>> From[transactionSaleBuffer] <<< in route: Route[[From[transactionSaleBuffer]] -> [Tr
ansacted[ref:trans... because of Route route2 has no output processors. You need to add outputs to the route such as to("log:foo").
I can see this is because the Camel class RouteDefinition.java makes a call to ProcessorDefinitionHelper.hasOutputs(outputs, true).
This passes in an array of one Object ([Transacted[ref:transactionManagerETL]])
This one object has one two children
[Transacted[ref:transactionManagerETL]]
CHILD-[Policy[ref:routeTransactionPolicy],
CHILD-To[detailFactProcessor]
The Policy child has no outputs, so the exception is thrown.
Yet I don't know how to add a child, my XML above matches the schema.
Maybe I'm missing something else?
My setup matches the example...Apache Camel: Book in One Page (See section: Camel 1.x - JMS Sample)
Can anyone please help me out.
Thanks!
Jeff Porter
Try as follows
<camel:route>
<camel:from uri="transactionSaleBuffer" />
<camel:transacted ref="transactionManagerETL" />
<camel:policy ref="routeTransactionPolicy">
<camel:to uri="detailFactProcessor" />
</camel:policy>
</camel:route>

No long-running conversations - IllegalArgumentException: Stack must not be null

I have a very simple application with just 2 pages on WebLogic 10.3.2 (11g), Seam 2.2.0.GA. I have a command button in each, which makes a redirect-after-post to the other. This works well, as I see the URL of the current page I am seeing in the address bar.
BUT, even though I have no long-running conversations defined, after a random number of clicks, and - I think - after a random number of seconds (~10s - 60s) I get the lovely exception at the end of this post.
Now, if I have understood how temporary conversations work when redirecting this happens:
When I first see my application, the url is http://localhost:7001/myapp
When I click the button in pageA.xhtml, I end up in "pageB.xhtml?cid=26". This is normal because Seam extends the temporary conversation of the first request to last until the renderResponse phase of the redirect. So, it uses the cid (Conversation Id) of the extended temporary conversation to find any propagated parameters.
When I click the button in pageB.xhtml, I end up in pageA.xhtml?cid=26
The same cid was given to the new extended temporary conversation. This is normal because the conversation ended at the end of the previous redirect-after-post, and not the number 26 is free to use as a cid.
Is this all correct? If yes, why does this happen: If I re-type the applications home address (showing pageA) and re-click, I end up in pageB.xhtml?cid=29, which is a different number than 26. But 26 has ended after the previous RenderResponse phase, befire I re-types the url. Why is it not used instead of 29?
So, to sup up, 2 questions:
Why do I get the exception, even though I have not started any long-running conversations?
What happens exactly with the cid? On what basis does it change?
Cheers,
UPDATE:
Additional information: I use h:commandButtons like this in page A:
<h:commandButton action="showPageB" value="Show page B" />
and in page B
<h:commandButton action="showPageA" value="Show page A" />
navigation pageA.page.xml:
<page view-id="/pageA.xhtml">
<navigation>
<rule if-outcome="showPageB">
<redirect view-id="/pageB.xhtml" />
</rule>
</navigation>
</page>
and a very similar for pageB.
As for the conversation timeout, I have set it to 1h. Note that it is irrelevant, because as I read here, it is only meant for background conversations. The stacktrace follows:
Error 500--Internal Server Error
java.lang.IllegalArgumentException: Stack must not be null
at org.jboss.seam.core.ConversationEntry.(ConversationEntry.java:45)
at org.jboss.seam.core.ConversationEntries.createConversationEntry(ConversationEntries.java:53)
at org.jboss.seam.core.Manager.createConversationEntry(Manager.java:664)
at org.jboss.seam.core.Manager.beforeRedirect(Manager.java:836)
at org.jboss.seam.faces.FacesManager.beforeRedirect(FacesManager.java:66)
at org.jboss.seam.faces.FacesManager.redirect(FacesManager.java:182)
at org.jboss.seam.faces.Navigator.redirect(Navigator.java:55)
at org.jboss.seam.navigation.RedirectNavigationHandler.navigate(RedirectNavigationHandler.java:61)
at org.jboss.seam.navigation.Rule.execute(Rule.java:101)
at org.jboss.seam.navigation.Navigation.navigate(Navigation.java:58)
at org.jboss.seam.navigation.Pages.navigate(Pages.java:203)
at org.jboss.seam.jsf.SeamNavigationHandler.handleNavigation(SeamNavigationHandler.java:42)
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:130)
at javax.faces.component.UICommand.broadcast(UICommand.java:387)
at org.ajax4jsf.component.AjaxViewRoot.processEvents(AjaxViewRoot.java:324)
at org.ajax4jsf.component.AjaxViewRoot.broadcastEvents(AjaxViewRoot.java:299)
at org.ajax4jsf.component.AjaxViewRoot.processPhase(AjaxViewRoot.java:256)
at org.ajax4jsf.component.AjaxViewRoot.processApplication(AjaxViewRoot.java:469)
at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:82)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:265)
at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:292)
at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:26)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:530)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83)
at org.jboss.seam.web.IdentityFilter.doFilter(IdentityFilter.java:40)
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
at org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:90)
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64)
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45)
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
at org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:178)
at org.ajax4jsf.webapp.BaseFilter.handleRequest(BaseFilter.java:290)
at org.ajax4jsf.webapp.BaseFilter.processUploadsAndHandleRequest(BaseFilter.java:388)
at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:515)
at org.jboss.seam.web.Ajax4jsfFilter.doFilter(Ajax4jsfFilter.java:56)
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
at org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:60)
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
at org.jboss.seam.web.HotDeployFilter.doFilter(HotDeployFilter.java:53)
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
at weblogic.servlet.internal.RequestEventsFilter.doFilter(RequestEventsFilter.java:27)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3592)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:121)
at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2202)
at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2108)
at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1432)
at weblogic.work.ExecuteThread.execute(ExecuteThread.java:201)
at weblogic.work.ExecuteThread.run(ExecuteThread.java:173)
First of all, it is always helpful to see the relevant code and stacktrace when trying to debug a problem.
Thus I cannot give an answer to your first question. However, I will try to explain how the conversation model works.
This is from the Seam in Action book:
#ScopeType.EVENT = Goes from Restore View to Render Response, but not redirect
#ScopeType.CONVERSATION = Goes from Restore VIew to Render Response, and redirect. If long-running conversation, then it spans multiple JSF life cycles.
So imagine you are in a.xhtml you push a button that will take ComponentA and fill some data in it. This component you want to inject and use in b.xhtml
ie:
Push commandbutton in a.xhtml performing post, putting some data in ComponentA
Now you redirect to next page (b.xhtml)which uses the ComponentA
#Name("componentB")
#Scope(ScopeType.CONVERSATION)
public class ComponentB {
#In(create=true)
ComponentA componentA; //OK
}
So if you now push another button from b.xhtml expecting to be able to inject ComponentA again, that will fail.
ie:
#Name("componentC")
#Scope(ScopeType.CONVERSATION)
public class ComponentC {
#In(create=true)
ComponentA componentA; //Injection of the component you really want fails (you will get default component)
}
So in the background now, seam has created a new cid for you, ending the previous cid because a conversation scoped component can only live one request.
After seeing your StackTrace and your Use case (after a random number of clicks)
Let's see FacesManages.beforeRedirect (as shown by your StackTrace) documentation
Temporarily promote a temporary conversation to a long running conversation for the duration of a browser redirect
Now, let's see some piece of code of beforeRedirect method
if (isDifferentConversationId(currentPage, targetPage))
updateCurrentConversationId(targetPage.getConversationId());
...
updateCurrentConversationId is responsible for creating the Stack which must be not null See again your StackTrace
public void updateCurrentConversationId(String id) {
if (id != null && id.equals(currentConversationId)) {
// The conversation id has not changed, do nothing
return;
}
After code shown above, your Stack will be created. So i suppose The conversation id has not changed because of The duration of a browser redirect (caused by a random number of clicks) or even a Seam bug when dealing with a navigation with redirect from one page to another and vice-versa
Try the following one for each Page rule (see timeout="0")
<page view-id="/pageA.xhtml" timeout="0">
<navigation>
<rule if-outcome="showPageB">
<redirect view-id="/pageB.xhtml" />
</rule>
</navigation>
</page>
I expect now it works fine! But, if not, now, you know why you get your exception
UPDATE
Try <end-conversation/> as a workaround (for each page)
<page view-id="/pageA.xhtml">
<navigation>
<rule if-outcome="showPageB">
<end-conversation/>
<redirect view-id="/pageB.xhtml" />
</rule>
</navigation>
</page>
or (see before-redirect)
<page view-id="/pageA.xhtml">
<navigation>
<rule if-outcome="showPageB">
<end-conversation before-redirect="true"/>
<redirect view-id="/pageB.xhtml" />
</rule>
</navigation>
</page>
Now i hope it works fine!
EDIT
As said by beforeRedirect method
Temporarily promote a temporary conversation to a long running conversation for the duration of a browser redirect. After the redirect, the conversation will be demoted back to a temporary conversation.
1° It explains why #{conversation.longRunning} outputs true when you go to pageB. Your "long running conversation" caused by your redirect should be destroyed after the Render Response phase.
When using a redirect, Seam appends conversation id paratemer to URL.
Seam in Action book says
At the beginning of the Seam life cycle, Seam looks for the conversation id in a URL parameter
But because when you are back to pageA, you see again the same conversation id parameter, I suppose Seam just create a new one when the url does not contain anyone. And because each long running conversation has it own Timeout period, your long running conversation is keeped alive.
To verify whether what i said is true, do as follows
reduce global Timeout period to five seconds (5000 milliseconds)
...
<core:manager conversation-timeout="5000"/>
For each Page, see what #{conversation.timeout} outputs. I expect to see something like Either 5 seconds or 5000 miliseconds. Wait for more than 5 seconds (about 10s) and press button to redirect again. And see whether conversation id parameter has been changed.
You should have provided that information long ago. Now it is much more clear what the problem is.
First of all you shouldn't use a commandButton with an empty action like that. When you in pages.xml write the following:
<page view-id="/pageA.xhtml">
<navigation>
<rule if-outcome="showPageB">
<redirect view-id="/pageB.xhtml" />
</rule>
</navigation>
</page>
It means normally that you have some action that returns showPageB like this:
public String someAction() {
//Do something complex
return "showPageB";
}
Anyhow, back to your problem.
Do your self a favor and create a Seam component.
#Name("myComponent")
public Class MyComponent {
public String showPageB() {
return "showPageB";
}
public String showPageA() {
return "showPageA";
}
}
Change your pages.xml to this:
<page view-id="/pageA.xhtml">
<navigation from action="#{myComponent.showPageB}">
<redirect view-id="/pageB.xhtml" />
</navigation>
<navigation from action="#{myComponent.showPageA}">
<redirect view-id="/pageA.xhtml" />
</navigation>
<!-- OR you can do like this -->
<navigation from action="#{myComponent.showPageB}">
<rule if-outcome="showPageA">
<redirect view-id="/pageA.xhtml" />
</rule>
<rule if-outcome="showPageB">
<redirect view-id="/pageA.xhtml" />
</rule>
</navigation>
</page>
Then change xhtml h:commandButton to
<h:commandButton action="#{myComponent.showPageA}" value="showA"/>
<h:commandButton action="#{myComponent.showPageB}" value="showB"/>

Categories