没有长时间运行的对话 - IllegalArgumentException:堆栈不得为空
我有一个非常简单的应用程序,在 WebLogic 10.3.2 (11g)、Seam 2.2.0.GA 上只有 2 个页面。我每个都有一个命令按钮,可以在发布后重定向到另一个。这很有效,因为我在地址栏中看到了当前页面的 URL。
但是,即使我没有定义长时间运行的对话,在随机次数的点击之后,并且 - 我认为 - 在随机的秒数(〜10秒 - 60秒)之后)我在这篇文章的末尾得到了一个可爱的例外。
现在,如果我已经了解重定向发生这种情况时临时对话是如何工作的:
- 当我第一次看到我的应用程序时,URL 是 http:// /localhost:7001/myapp
当我单击 pageA.xhtml 中的按钮时,我最终会看到“pageB.xhtml?cid=26”。这是正常的,因为 Seam 将第一个请求的临时会话延长到重定向的 renderResponse 阶段。因此,它使用扩展临时会话的 cid(会话 ID)来查找任何传播的参数。
当我单击 pageB.xhtml 中的按钮时,我最终会进入 pageA.xhtml?cid=26
26相同的 cid 被赋予新的扩展临时对话。这是正常的,因为对话在上一个重定向后结束时结束,并且数字 26 不是可以免费用作 cid 的。
这一切都正确吗?如果是,为什么会发生这种情况:如果我重新输入应用程序主地址(显示 pageA)并重新单击,我最终会出现 pageB.xhtml?cid=29,该数字与 26 不同。但是 26 已结束在上一个 RenderResponse 阶段之后,我重新输入 url。为什么不使用它而是使用29?
因此,要解决两个问题:
- 即使我没有开始任何长时间运行的对话,为什么我会遇到异常?
- cid 到底发生了什么?改变的依据是什么?
干杯,
更新:
中使用这样的 h:commandButtons,
<h:commandButton action="showPageB" value="Show page B" />
附加信息:我在页面 A:和页面 B
<h:commandButton action="showPageA" value="Show page A" />
导航 pageA.page.xml:
<page view-id="/pageA.xhtml">
<navigation>
<rule if-outcome="showPageB">
<redirect view-id="/pageB.xhtml" />
</rule>
</navigation>
</page>
并且对于 pageB 非常相似。
至于对话超时,我设置为1h。请注意,这是无关紧要的,因为正如我所读的 这里,它仅用于后台对话。堆栈跟踪如下:
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)
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)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
首先,在尝试调试问题时查看相关代码和堆栈跟踪总是有帮助的。
因此我无法回答你的第一个问题。不过,我将尝试解释对话模型是如何工作的。
这是来自《Seam in Action》一书:
@ScopeType.EVENT = 从恢复视图转到渲染响应,但不重定向
@ScopeType.CONVERSATION = 从“恢复视图”转到“渲染响应”,然后重定向。如果对话长时间运行,那么它会跨越多个 JSF 生命周期。
因此,假设您在
a.xhtml
中,按下一个按钮,该按钮将获取ComponentA
并在其中填充一些数据。您要在b.xhtml
中注入和使用该组件即:
在 a.xhtml 中按下命令按钮执行 post,将一些数据放入 ComponentA
现在您重定向到使用
ComponentA
的下一页 (b.xhtml
)因此,如果您现在从
b.xhtml
按下另一个按钮,期望能够再次注入ComponentA
,那将会失败。即:
现在,seam 在后台为您创建了一个新的 cid,结束了之前的 cid,因为会话范围组件只能处理一个请求。
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 takeComponentA
and fill some data in it. This component you want to inject and use inb.xhtml
ie:
Push commandbutton in a.xhtml performing post, putting some data in ComponentA
Now you redirect to next page (
b.xhtml
)which uses theComponentA
So if you now push another button from
b.xhtml
expecting to be able to injectComponentA
again, that will fail.ie:
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.
查看您的 StackTrace 和用例后(随机点击次数后)
让我们查看 FacesManages.beforeRedirect (如您的 StackTrace 所示)文档
,让我们看一下 beforeRedirect 方法的一些代码
...
updateCurrentConversationId 负责创建堆栈,该堆栈必须be not null 再次查看您的 StackTrace
在上面显示的代码之后,您的堆栈将被创建。所以我想对话id没有改变,因为浏览器重定向的持续时间(由随机数量的点击引起),甚至是处理导航时的Seam错误从一个页面重定向到另一个页面,反之亦然
为每个尝试以下页面规则(请参阅 timeout =“0”)
我希望现在它可以正常工作!但是,如果没有,现在您知道为什么会出现异常
UPDATE
尝试作为解决方法(针对每个页面)
或(参见重定向之前)
现在我希望它工作正常!
编辑
正如 beforeRedirect 方法所说
1° 它解释了为什么当您转到 pageB 时#{conversation.longRunning} 输出 true。由重定向引起的“长时间运行的对话”应该在渲染响应阶段后被销毁。
当使用重定向时,Seam 将会话 ID 参数附加到 URL。
行动中的接缝书说
但是因为当您返回 pageA 时,您会再次看到相同的对话 id 参数 ,我想当 url 不包含任何人时,Seam 只是创建一个新的。而且由于每个长时间运行的对话都有自己的超时期限,因此您的长时间运行的对话将保持活动状态。
要验证我所说的是否属实,请执行以下操作,
...
对于每个页面,查看 #{conversation.timeout} 输出。我期望看到类似 5 秒或 5000 毫秒的内容。等待 5 秒以上(约 10 秒),然后按 按钮再次重定向。并查看对话id参数是否已更改。
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
Now, let's see some piece of code of beforeRedirect method
...
updateCurrentConversationId is responsible for creating the Stack which must be not null See again your StackTrace
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")
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)
or (see before-redirect)
Now i hope it works fine!
EDIT
As said by beforeRedirect method
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
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
...
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.
您应该很久以前就提供该信息。现在问题出在哪里更加清楚了。
首先,您不应该使用带有空操作的命令按钮。当您在pages.xml中编写以下内容时:
这通常意味着您有一些返回showPageB的操作,如下所示:
无论如何,回到您的问题。
帮自己一个忙,创建一个 Seam 组件。
将pages.xml更改为:
然后将xhtml
h:commandButton
更改为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:
It means normally that you have some action that returns showPageB like this:
Anyhow, back to your problem.
Do your self a favor and create a Seam component.
Change your pages.xml to this:
Then change xhtml
h:commandButton
to