[英]No long-running conversations - IllegalArgumentException: Stack must not be null
我有一個非常簡單的應用程序,在WebLogic 10.3.2(11g),Seam 2.2.0.GA上只有2頁。 我在每個中都有一個命令按鈕,它會在另一個后面進行重定向。 這很好用,因為我在地址欄中看到了當前頁面的URL。
但是 ,即使我沒有定義長時間運行的對話 ,經過隨機的點擊次數,並且 - 我認為 - 在一個隨機的秒數(~10s - 60s)之后,我在這篇文章的最后得到了可愛的例外。
現在,如果我已經理解了重定向時臨時對話的工作原理:
當我點擊pageA.xhtml中的按鈕時,我最終進入“pageB.xhtml?cid = 26”。 這是正常的,因為Seam會將第一個請求的臨時會話延長到重定向的renderResponse階段。 因此,它使用擴展臨時對話的cid(Conversation Id)來查找任何傳播的參數。
當我點擊pageB.xhtml中的按鈕時,我最終進入pageA.xhtml?cid = 26
同樣的cid被賦予新的擴展臨時對話。 這是正常的,因為會話在之前的重定向后結束時結束,而不是數字26可以自由地用作cid。
這都是正確的嗎? 如果是,為什么會發生這種情況:如果我重新鍵入應用程序主頁地址(顯示pageA)並重新點擊,我最終會在pageB.xhtml?cid = 29,這是一個不同於26的數字。但是26已經結束在之前的RenderResponse階段之后,我會重新輸入網址。 為什么不使用而不是29?
所以,要補充,2個問題:
干杯,
更新:
附加信息:我在頁面A中使用h:commandButtons:
<h:commandButton action="showPageB" value="Show page B" />
在第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)
首先,在嘗試調試問題時查看相關代碼和堆棧跟蹤總是有幫助的。
因此,我不能回答你的第一個問題。 但是,我將嘗試解釋對話模型的工作原理。
這是來自Seam in Action的書:
@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.
所以想象一下你在a.xhtml
按下一個按鈕,它將接受ComponentA
並在其中填充一些數據。 您希望在b.xhtml
注入和使用的此組件,即:
Push commandbutton in a.xhtml performing post, putting some data in ComponentA
現在重定向到使用ComponentA
下一頁( b.xhtml
)
@Name("componentB")
@Scope(ScopeType.CONVERSATION)
public class ComponentB {
@In(create=true)
ComponentA componentA; //OK
}
因此,如果您現在從b.xhtml
推送另一個按鈕,希望能夠再次注入ComponentA
,那將失敗。 即:
@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)
}
所以現在在后台,seam為你創建了一個新的cid,結束了之前的cid,因為會話范圍組件只能生成一個請求。
看到你的StackTrace和你的用例(在隨機點擊次數之后)
我們來看看FacesManages.beforeRedirect(如StackTrace所示)文檔
在瀏覽器重定向期間暫時將臨時對話提升為長時間運行的對話
現在,讓我們看一下beforeRedirect方法的一些代碼
if (isDifferentConversationId(currentPage, targetPage))
updateCurrentConversationId(targetPage.getConversationId());
...
updateCurrentConversationId負責創建必須不為null的Stack再次查看StackTrace
public void updateCurrentConversationId(String id) {
if (id != null && id.equals(currentConversationId)) {
// The conversation id has not changed, do nothing
return;
}
在上面顯示的代碼之后,將創建您的堆棧。 所以我認為會話ID沒有改變,因為瀏覽器重定向的持續時間 (由隨機的點擊次數引起)甚至在處理從一個頁面到另一個頁面的重定向導航時出現的Seam錯誤,反之亦然
對每個頁面規則嘗試以下一個(請參閱timeout =“0”)
<page view-id="/pageA.xhtml" timeout="0">
<navigation>
<rule if-outcome="showPageB">
<redirect view-id="/pageB.xhtml" />
</rule>
</navigation>
</page>
我希望現在它工作正常! 但是,如果沒有,現在,你知道為什么你得到你的例外
UPDATE
嘗試<end-conversation />作為解決方法(針對每個頁面)
<page view-id="/pageA.xhtml">
<navigation>
<rule if-outcome="showPageB">
<end-conversation/>
<redirect view-id="/pageB.xhtml" />
</rule>
</navigation>
</page>
或(見前重定向)
<page view-id="/pageA.xhtml">
<navigation>
<rule if-outcome="showPageB">
<end-conversation before-redirect="true"/>
<redirect view-id="/pageB.xhtml" />
</rule>
</navigation>
</page>
現在我希望它工作正常!
編輯
正如beforeRedirect方法所說的那樣
在瀏覽器重定向期間暫時將臨時對話提升為長時間運行的對話 。 重定向后,會話將被降級為臨時會話。
1°它解釋了為什么#{conversation.longRunning}在你轉到pageB時輸出為true。 在渲染響應階段之后,應該銷毀由重定向引起的“長時間運行的對話”。
使用重定向時,Seam會將會話ID paratemer附加到URL。
Seam in Action書中說
在Seam生命周期的開始,Seam 在URL參數中查找會話ID
但是因為當你回到pageA時,你會再次看到相同的會話id參數 ,我想當網址不包含任何人時,Seam只會創建一個新 參數 。 而且因為每個長時間運行的對話都有自己的超時時間,所以您長時間運行的對話會保持活躍狀態。
要驗證我說的是否屬實,請執行以下操作
...
<core:manager conversation-timeout="5000"/>
對於每個頁面,請查看#{conversation.timeout}輸出內容。 我希望看到像5秒或5000毫秒的東西。 等待超過5秒(約10秒),然后按按鈕再次重定向。 並查看對話ID參數是否已更改。
您應該很久以前就提供了這些信息。 現在問題是什么更清楚了。
首先,您不應該使用具有類似空操作的commandButton。 當你在pages.xml中寫下以下內容:
<page view-id="/pageA.xhtml">
<navigation>
<rule if-outcome="showPageB">
<redirect view-id="/pageB.xhtml" />
</rule>
</navigation>
</page>
通常意味着你有一些動作會像這樣返回showPageB:
public String someAction() {
//Do something complex
return "showPageB";
}
無論如何,回到你的問題。 幫自己一個忙,創建一個Seam組件。
@Name("myComponent")
public Class MyComponent {
public String showPageB() {
return "showPageB";
}
public String showPageA() {
return "showPageA";
}
}
將pages.xml更改為:
<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>
然后將xhtml h:commandButton
更改為
<h:commandButton action="#{myComponent.showPageA}" value="showA"/>
<h:commandButton action="#{myComponent.showPageB}" value="showB"/>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.