Нет длительных разговоров - IllegalArgumentException: стек не должен быть нулевым - PullRequest
3 голосов
/ 13 апреля 2010

У меня очень простое приложение с двумя страницами на WebLogic 10.3.2 (11g), Seam 2.2.0.GA. У меня есть командная кнопка в каждой, которая делает перенаправление после поста для другого. Это хорошо работает, так как я вижу URL текущей страницы в адресной строке.

НО , хотя у меня не определены длительные разговоры после случайного количества нажатий и, я думаю, через случайное количество секунд (~ 10 с - 60-е) В конце этого поста я получаю прекрасное исключение.

Теперь, если я понял, как временные разговоры работают при перенаправлении, это происходит:

  1. Когда я впервые вижу свое приложение, URL-адрес http://localhost:7001/myapp
  2. Когда я нажимаю кнопку в pageA.xhtml, я получаю «pageB.xhtml? Cid = 26». Это нормально, потому что Seam продлевает временную беседу первого запроса до фазы renderResponse перенаправления. Таким образом, он использует cid (идентификатор беседы) расширенного временного диалога, чтобы найти любые распространяемые параметры.

  3. Когда я нажимаю кнопку в pageB.xhtml, я оказываюсь в pageA.xhtml? Cid = 26

Такой же cid был дан для нового расширенного временного разговора. Это нормально, потому что разговор закончился в конце предыдущего редиректа после поста, а номер 26 не может свободно использоваться в качестве cid.

Это все правильно? Если да, то почему это происходит? после предыдущей фазы RenderResponse, перед тем как я повторно наберу URL. Почему он не используется вместо 29?

Итак, на вопрос, 2 вопроса:

  1. Почему я получаю исключение, несмотря на то, что я не начал никаких длительных разговоров?
  2. Что именно происходит с cid? На каком основании это меняется?

Приветствия

UPDATE:

Дополнительная информация: Я использую h: commandButtons, как это на странице A:

<h:commandButton action="showPageB" value="Show page B" />

и на странице B

<h:commandButton action="showPageA" value="Show page A" />

навигационная страницаA.page.xml:

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

и очень похоже на pageB.

Что касается времени ожидания разговора, я установил его на 1 час. Обратите внимание, что это не имеет значения, потому что когда я читаю здесь , оно предназначено только для фоновых разговоров. Трассировка стека следующая:

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)

Ответы [ 3 ]

1 голос
/ 13 апреля 2010

После просмотра вашей StackTrace и вашего варианта использования (после случайного количества нажатий)

Давайте посмотрим документацию FacesManages.beforeRedirect (как показано вашей StackTrace)

Временно перевести временный разговор в длительный разговор на время переадресации браузера

Теперь давайте посмотрим на фрагмент кода метода beforeRedirect

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

...

updateCurrentConversationId отвечает за создание стека , который должен быть не нулевым Еще раз увидеть ваш StackTrace

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

После кода, показанного выше, ваш стек будет создан. Поэтому я полагаю, Идентификатор разговора не изменился из-за Продолжительность перенаправления браузера (вызванного случайным количеством нажатий) или даже ошибка шва при работе с навигацией с перенаправлением с одной страницы на другую и наоборот

Попробуйте следующее для каждого правила страницы (см. Timeout = "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

Временно преобразовать временный разговор в длительный разговор на время перенаправления браузера. После перенаправления разговор будет переведен обратно во временный разговор.

1 ° Это объясняет, почему # {разговор.longRunning} выводит true, когда вы переходите на страницу B. Ваш «длительный разговор», вызванный вашим перенаправлением, должен быть уничтожен после фазы ответа при ответе.

При использовании перенаправления Seam добавляет к URL URL-адрес paratemer.

Книга «Шов в действии» гласит:

В начале жизненного цикла Seam Seam ищет идентификатор разговора в параметре URL

Но поскольку, вернувшись на страницу A, вы снова видите тот же параметр идентификатора разговора , я полагаю Seam просто создайте новый, если в URL-адресе никого нет . А поскольку каждый длительный разговор имеет свой собственный период ожидания, ваш продолжительный разговор сохраняется.

Чтобы проверить, правда ли то, что я сказал, сделайте следующее

  • уменьшить глобальный период ожидания до пяти секунд (5000 миллисекунд)

...

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

Для каждой страницы смотрите, что выводит # {разговор.timeout}. Я ожидаю увидеть что-то вроде 5 секунд или 5000 миллисекунд. Подождите более 5 секунд (около 10 секунд) и нажмите кнопку для повторного перенаправления. И посмотрите, был ли изменен параметр идентификатора разговора.

1 голос
/ 13 апреля 2010

Прежде всего, всегда полезно видеть соответствующий код и трассировку стека при попытке отладки проблемы.

Таким образом, я не могу дать ответ на ваш первый вопрос. Однако я попытаюсь объяснить, как работает модель разговора.

Это из книги «Шов в действии»:

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

Итак, теперь в фоновом режиме seam создал для вас новый cid, заканчивая предыдущий cid, поскольку компонент с областью диалога может выполнять только один запрос.

0 голосов
/ 14 апреля 2010

Вы должны были предоставить эту информацию давно. Теперь стало намного понятнее, в чем проблема.

Прежде всего, вы не должны использовать 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";
}

Во всяком случае, вернемся к вашей проблеме. Сделайте себе одолжение и создайте шовный компонент.

@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"/>
...