2010-04-13 22 views
3

我有一個非常簡單的應用程序,WebLogic 10.3.2(11g),Seam 2.2.0.GA上只有2個頁面。我有一個命令按鈕,每個命令按鈕都會在後者之間進行重定向。這很好,因爲我看到了我在地址欄中看到的當前頁面的URL。沒有長時間運行的對話 - IllegalArgumentException:堆棧不能爲空

,即使我有沒有長時間運行的對話定義,點擊一個隨機數後,並 - 我認爲 - 一個隨機數秒(〜10秒 - 60秒)後,我得到了可愛的例外在這篇文章的末尾。

現在,當重定向發生這種情況,如果我已經明白瞭如何臨時對話的工作:

  1. 當我第一次看到我的應用程序,URL是http://localhost:7001/myapp
  2. 當我點擊pageA.xhtml按鈕,我最終在「pageB.xhtml?cid = 26」。這很正常,因爲Seam將第一個請求的臨時對話擴展到了重定向的renderResponse階段。因此,它使用擴展臨時對話的cid(對話Id)來查找任何傳播的參數。

  3. 當我點擊pageB.xhtml按鈕,我結束了pageA.xhtml?CID = 26

相同的CID給予了新的擴展臨時對話。這是很正常的,因爲對話在之前的重定向後結束時結束,而不是26號可以自由用作cid。

這一切是否正確?如果是的話,爲什麼會發生這種情況:如果我重新鍵入應用程序的家庭地址(顯示pageA)並重新點擊,我最終在pageB.xhtml?cid = 29,這是一個不同於26的數字。但26已結束在之前的RenderResponse階段之後,我會重新輸入url。爲什麼不使用29而不是29?

所以,共進晚餐了,2個問題:

  1. 爲什麼我得到的異常,儘管我還沒有開始任何長期運行的對話?
  2. cid究竟會發生什麼?它改變的基礎是什麼?

乾杯,

UPDATE:

其他信息:我用H:CommandButton控件像這樣在第A:

<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。請注意,它是無關緊要的,因爲當我讀here時,它僅用於背景對話。堆棧跟蹤如下:

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) 
+0

@Markos Fragkakis有趣的是,你能告訴你的堆棧跟蹤?你使用sither sLink還是sButton在你的頁面之間導航?您設置coreManager會話超時屬性的值(毫秒)是多少? – 2010-04-13 13:56:28

+0

@Arthur,請參閱更新 – 2010-04-13 14:06:23

+1

每頁有關#{conversation.longRunning} 輸出:true或false? – 2010-04-13 14:46:10

回答

1

首先,在嘗試調試問題時查看相關代碼和堆棧跟蹤總是有幫助的。

因此,我不能給你的第一個問題的答案。不過,我會嘗試解釋對話模型的工作原理。

這是在行動書縫:

@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 現在您重定向到下一個頁面(b.xhtml),它採用了ComponentA

@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) 
} 

所以在現在的背景下,縫創造了一個新的CID你,結束了之前的CID,因爲一個對話範圍組件只能活一個請求。

+0

@Shervin有趣的,謝爾文(+1)爲什麼在ComponentC中注入ComponentA時注入ComponentA失敗(我想這是因爲create = true)對嗎? – 2010-04-13 13:58:29

+0

@Shervin沒有任何頁面有組件。我只有兩個最小的頁面:h:commandButtons和相應的導航xml文件。請注意,我不會在xml文件中開始或結束任何對話。 – 2010-04-13 14:09:16

+0

@Arthur Ronald F D Garcia:不,那不是它失敗的原因。實際上,create = true(如果組件上沒有@AutoCreate)使得它不會失敗。當你有create = true時,它將創建組件,如果它不在範圍內。我說失敗的原因是因爲你真正想要的組件(注入了正確的字段)不可用,因爲它已經被垃圾收集。如果您希望能夠在「第二次」重定向中使用該組件,則必須推廣到長時間運行的對話。 – 2010-04-13 14:26:51

1

看到你的堆棧跟蹤和你的使用情況(點擊的隨機數後)

讓我們來看看FacesManages.beforeRedirect(如您的堆棧跟蹤)文檔

暫時促進臨時對話的長時間運行的對話對瀏覽器的時間重定向

現在,讓我們看到一些片beforeRedirect方法的代碼

if (isDifferentConversationId(currentPage, targetPage)) 
    updateCurrentConversationId(targetPage.getConversationId()); 

...

updateCurrentConversationId負責創建堆棧必須是不爲空再次見到你的堆棧跟蹤

public void updateCurrentConversationId(String id) { 
    if (id != null && id.equals(currentConversationId)) { 
    // The conversation id has not changed, do nothing  
    return; 
    } 

上面顯示的代碼後,你的籌碼將被創建。所以我想因爲與重定向導航從一個頁面處理到另一個副當瀏覽器的持續時間重定向(由點擊隨機數),或者甚至是一個Seam錯誤對話ID沒有改變反之亦然

嘗試每個頁面規則如下一個(見超時= 「0」)

<page view-id="/pageA.xhtml" timeout="0"> 
    <navigation> 
     <rule if-outcome="showPageB"> 
      <redirect view-id="/pageB.xhtml" /> 
     </rule> 
    </navigation> 
</page> 

我希望現在能正常工作!但是,如果沒有,現在,你知道爲什麼讓你的異常

UPDATE

嘗試<結束談話/ >作爲一種解決方法(每一頁)

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

現在我希望它能正常工作!

EDIT

如所述通過beforeRedirect方法

暫時促進臨時對話到長時間運行會話對瀏覽器重定向的持續時間。重定向後,對話將降級爲臨時對話。

它解釋了爲什麼#{} conversation.longRunning當你去到頁面B輸出正確的。您的重定向導致的「長時間運行的對話」應該在渲染響應階段後被銷燬。

當使用重定向時,Seam追加對話id paratemer到URL。

縫在行動書上說

在縫生命週期的開始,縫看起來的對話id的URL參數

但因爲當你回到pageA的,你看再同一個會話ID參數,我想縫只需創建一個新的當URL中不包含任何。而且由於每個長時間運行的對話都有自己的超時期限,所以長時間運行的對話將保持活躍。

爲了驗證我的話是否屬實,請執行以下操作

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

...

<core:manager conversation-timeout="5000"/> 

對於每個頁面,請查看#{conversation.timeout}輸出的內容。我期望看到類似5秒或5000毫秒的東西。等待超過5秒(約10秒),然後按按鈕重新導向。並查看對話ID參數是否已更改。

+0

@Arthur謝謝你的回答(+1)。不幸的是,我仍然得到了例外。我在Seam in Action中讀到,頁面定義的超時被用來覆蓋中定義的超時,它指定*放棄*對話何時結束。即使它影響了我的談話,重定向後的郵件只能持續幾毫秒,這比1小時少得多。 – 2010-04-13 15:47:29

+0

@Markos Fragkakis請參閱https://jira.jboss.org/jira/browse/JBSEAM-3901和http://www.seamframework.org/Community/SeamAddsUnwantedConversationIdToURL – 2010-04-13 16:19:52

+0

是的,我昨天看到了。在這個問題上,他們已經禁用了重定向過濾器,而我默認使用它。 – 2010-04-13 16:24:27

0

很早以前你應該提供這些信息。現在更清楚問題是什麼。

首先你不應該使用一個像這樣的空行爲的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"/> 
+1

action屬性*可以是一個字符串:http://www.horstmann.com/corejsf/jsf-tags.html#Table4_15。爲什麼要創建一個Bean來製作導航?讓我們說這是我的主頁。如果我按「幫助」按鈕,我總是想要導航到幫助頁面,不需要bean或方法來確定操作。 – 2010-04-14 09:30:41

+0

然而,我做了你的建議,並沒有解決我的問題......無論如何,謝謝! – 2010-04-14 10:41:43

+0

我不相信它不起作用。這根本不可能。這意味着這個錯誤在你縫紉設置的其他地方。 但是,你爲什麼要發佈一個簡單的導航?我使用的是什麼 是'' 您還應該閱讀http://seamframework.org/Documentation中找到的seam文檔 – 2010-04-14 10:58:23