簡體   English   中英

沒有長時間運行的對話 - IllegalArgumentException:Stack不能為null

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

我有一個非常簡單的應用程序,在WebLogic 10.3.2(11g),Seam 2.2.0.GA上只有2頁。 我在每個中都有一個命令按鈕,它會在另一個后面進行重定向。 這很好用,因為我在地址欄中看到了當前頁面的URL。

但是 ,即使我沒有定義長時間運行的對話 ,經過隨機的點擊次數,並且 - 我認為 - 在一個隨機的秒數(~10s - 60s)之后,我在這篇文章的最后得到了可愛的例外。

現在,如果我已經理解了重定向時臨時對話的工作原理:

  1. 當我第一次看到我的應用程序時,網址是http:// localhost:7001 / myapp
  2. 當我點擊pageA.xhtml中的按鈕時,我最終進入“pageB.xhtml?cid = 26”。 這是正常的,因為Seam會將第一個請求的臨時會話延長到重定向的renderResponse階段。 因此,它使用擴展臨時對話的cid(Conversation Id)來查找任何傳播的參數。

  3. 當我點擊pageB.xhtml中的按鈕時,我最終進入pageA.xhtml?cid = 26

同樣的cid被賦予新的擴展臨時對話。 這是正常的,因為會話在之前的重定向后結束時結束,而不是數字26可以自由地用作cid。

這都是正確的嗎? 如果是,為什么會發生這種情況:如果我重新鍵入應用程序主頁地址(顯示pageA)並重新點擊,我最終會在pageB.xhtml?cid = 29,這是一個不同於26的數字。但是26已經結束在之前的RenderResponse階段之后,我會重新輸入網址。 為什么不使用而不是29?

所以,要補充,2個問題:

  1. 為什么我得到異常,即使我還沒有開始任何長時間的對話?
  2. cid究竟發生了什么? 它以什么為基礎改變?

干杯,

更新:

附加信息:我在頁面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方法所說的那樣

在瀏覽器重定向期間暫時將臨時對話提升為長時間運行的對話 重定向后,會話將被降級為臨時會話。

它解釋了為什么#{conversation.longRunning}在你轉到pageB時輸出為true。 在渲染響應階段之后,應該銷毀由重定向引起的“長時間運行的對話”。

使用重定向時,Seam會將會話ID paratemer附加到URL。

Seam in Action書中說

在Seam生命周期的開始,Seam 在URL參數中查找會話ID

但是因為當你回到pageA時,你會再次看到相同的會話id參數 ,我想當網址不包含任何人時,Seam只會創建一個新 參數 而且因為每個長時間運行的對話都有自己的超時時間,所以您長時間運行的對話會保持活躍狀態​​。

要驗證我說的是否屬實,請執行以下操作

  • 將全局超時時間減少到五秒(5000毫秒)

...

<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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM