2010-04-13 4 views
3

J'ai une application très simple avec seulement 2 pages sur WebLogic 10.3.2 (11g), Seam 2.2.0.GA. J'ai un bouton de commande dans chacun, ce qui fait une redirection après post à l'autre. Cela fonctionne bien, car je vois l'URL de la page actuelle que je vois dans la barre d'adresse.Aucune conversation de longue durée - IllegalArgumentException: La pile ne doit pas être nulle

MAIS, même si je pas de conversations long en cours d'exécution définies, après un nombre aléatoire de clics, et - je pense - après un nombre aléatoire de secondes (~ 10s - 60s) Je reçois la belle exception à la fin de ce post.

Maintenant, si je comprends comment des conversations travail temporaire lors de la redirection cela se produit:

  1. Quand je vois ma demande, l'URL est http://localhost:7001/myapp
  2. Lorsque je clique sur le bouton pageA.xhtml, Je me retrouve dans "pageB.xhtml? Cid = 26". Ceci est normal car Seam prolonge la conversation temporaire de la première requête jusqu'à la phase renderResponse de la redirection. Ainsi, il utilise le cid (Conversation Id) de la conversation temporaire étendue pour trouver les paramètres propagés.

  3. Lorsque je clique sur le bouton dans pageB.xhtml, je me retrouve dans pageA.xhtml? Cid = 26

Le même cid a été donné à la nouvelle conversation temporaire prolongée. Ceci est normal car la conversation s'est terminée à la fin de la précédente redirection après publication, et non le numéro 26 est libre d'utiliser en tant que cid.

Est-ce que tout est correct? Si oui, pourquoi cela arrive-t-il? Si je tape à nouveau l'adresse du domicile des applications (pageA) et que je clique de nouveau, je me retrouve dans la pageB.xhtml? Cid = 29, qui est un nombre différent de 26. Mais 26 est terminé après la phase RenderResponse précédente, befire je re-tape l'URL. Pourquoi n'est-il pas utilisé au lieu de 29?

Donc, pour sup up, 2 questions:

  1. Pourquoi dois-je obtenir l'exception, même si je ne l'ai pas commencé des conversations en cours d'exécution à long?
  2. Que se passe-t-il exactement avec le cid? Sur quelle base cela change-t-il?

Cheers,

MISE À JOUR:

Informations complémentaires: J'utilise h: commandButtons comme celui-ci en page A:

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

et page B

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

page de navigationA.page.xml:

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

et un très similaire pour pageB. En ce qui concerne le délai d'expiration de la conversation, je l'ai réglé sur 1h.Notez que ce n'est pas pertinent, car en lisant here, il est uniquement destiné aux conversations en arrière-plan. La piletrace suit:

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 intéressants, Pouvez-vous montrer votre StackTrace? Utilisez-vous SLink ou sButton pour naviguer entre vos pages? Quelle valeur (milliseconde) définissez-vous pour l'attribut core-time-time de CoreManager? –

+0

@ Arthur, s'il vous plaît voir la mise à jour –

+1

Pour chaque page, voir ce que # {conversation.longRunning} sorties: vrai ou faux? –

Répondre

1

Tout d'abord, il est toujours utile de voir le code et la piletrace pertinents lorsque vous essayez de déboguer un problème.

Ainsi, je ne peux pas répondre à votre première question. Cependant, je vais essayer d'expliquer comment fonctionne le modèle de conversation.

C'est de la Seam dans le livre d'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.

Alors, imaginez que vous êtes a.xhtml vous appuyez sur un bouton qui prendra ComponentA et remplir certaines données qu'il contient. Ce composant vous voulez injecter et utiliser dans b.xhtml -à-dire:

Push commandbutton in a.xhtml performing post, putting some data in ComponentA Maintenant vous redirigez à la page suivante (b.xhtml) qui utilise le ComponentA

@Name("componentB") 
@Scope(ScopeType.CONVERSATION) 
public class ComponentB { 
    @In(create=true) 
    ComponentA componentA; //OK 
} 

Donc, si vous appuyez maintenant sur un autre bouton de b.xhtml attendant à être en mesure d'injecter à nouveau ComponentA, cela échouera. -à-dire:

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

Alors en arrière-plan maintenant, la couture a créé une nouvelle cid pour vous, mettre fin à la cid précédente, car une conversation composante scope ne peut vivre une demande.

+0

@Shervin Intéressant, Shervin (+1) Pourquoi l'injection de ComponentA échoue lors de l'injection dans ComponentC (je suppose que c'est à cause de create = true) Ai-je raison? –

+0

@Shervin Aucune des pages n'a de composant. Je n'ai que deux pages minimales avec h: commandButtons et les fichiers xml de navigation correspondants. Notez que je ne commence ni ne termine aucune conversation dans les fichiers XML non plus. –

+0

@Arthur Ronald F D Garcia: Non ce n'est pas pourquoi il échoue. En fait, le create = true (s'il n'y a pas de @AutoCreate sur le composant) ne le fait pas. Lorsque vous avez create = true, le composant sera créé s'il n'est pas dans la portée. La raison pour laquelle je dis échouer, c'est parce que le composant que vous voulez vraiment (l'injection avec les champs corrects) n'est pas disponible, car il a déjà été récupéré. Vous devez promouvoir à la conversation à long terme si vous voulez être en mesure d'utiliser le composant dans la "deuxième" redirection. –

1

Après avoir vu votre StackTrace et votre cas d'utilisation (après un nombre aléatoire de clics)

Voyons voir FacesManages.beforeRedirect (comme le montre votre StackTrace) documentation

promouvoir temporairement une conversation temporaire à un longue conversation en cours d'exécution pendant toute la durée d'un navigateur rediriger

maintenant, nous allons voir un morceau de code de la méthode beforeRedirect

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

...

updateCurrentConversationId est responsable de la création de la pile qui doit être non nul REVOIR votre StackTrace

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

Après le code indiqué ci-dessus, votre pile sera créé.Donc je suppose L'identifiant de la conversation n'a pas changé raison de La durée d'une redirection de navigateur (causée par un nombre aléatoire de clics) ou même un bug Seam lors d'une navigation avec redirection d'une page à l'autre et vice-versa versa

Essayez le suivant pour chaque règle de page (voir timeout = "0")

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

Je me attends maintenant il fonctionne très bien! Mais, sinon, maintenant, vous savez pourquoi vous obtenez votre exception

MISE À JOUR

Essayez < fin la conversation/> comme solution de contournement (pour chaque page)

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

ou (voir avant-redirect)

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

Maintenant j'espère que ça fonctionne bien!

EDIT

Comme dit par la méthode beforeRedirect

temporairement promouvoir une conversation temporaire à une longue conversation en cours d'exécution pendant toute la durée d'une redirection du navigateur. Après la redirection, la conversation sera rétrogradée à une conversation temporaire.

1 ° Il explique pourquoi # {} conversation.longRunning sorties vrai quand vous allez à pageB. Votre «conversation longue durée» causée par votre redirection doit être détruite après la phase de réponse de rendu. Lorsque vous utilisez une redirection, Seam ajoute l'identifiant de la conversation à l'adresse URL.

Seam dans le livre d'action dit

Au début du cycle de vie de Seam, Seam semble pour l'ID de conversation dans un paramètre d'URL

Mais parce que quand vous êtes de retour à pageA , vous voyez à nouveau le même paramètre id de conversation, je suppose Seam juste en créer un nouveau lorsque l'URL ne contient personne. Et parce que chaque conversation de longue durée a sa propre période de temporisation, votre conversation de longue durée est maintenue vivante.

Pour vérifier si ce que je dis est vrai, procédez comme suit

  • réduire la période globale du délai d'attente de cinq secondes (5000 millisecondes)

...

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

Pour chaque page, consultez les résultats de # {conversation.timeout}. Je m'attends à voir quelque chose comme Soit 5 secondes ou 5000 milisecondes. Attendez plus de 5 secondes (environ 10 secondes) et appuyez sur le bouton pour rediriger à nouveau. Et voir si le paramètre id de la conversation a été modifié.

+0

@ Arthur merci pour la réponse (+1). Malheureusement, j'ai toujours l'exception. J'ai lu dans Seam in Action que le timeout défini par la page est utilisé pour remplacer celui défini dans , qui spécifie quand les conversations * abandonnées * se terminent. Même si cela a affecté ma conversation, la redirection post-post ne dure que quelques millisecondes, ce qui est beaucoup moins que 1h. –

+0

@Markos Fragkakis Voir https://jira.jboss.org/jira/browse/JBSEAM-3901 et http://www.seamframework.org/Community/SeamAddsUnwantedConversationIdToURL –

+0

Oui, j'ai vu ça hier. Dans ce problème, ils ont désactivé le filtre de redirection, alors que je l'ai par défaut sur. –

0

Vous auriez dû fournir cette information depuis longtemps. Maintenant, il est beaucoup plus clair quel est le problème.

Tout d'abord vous ne devriez pas utiliser un commandButton avec une action vide comme ça. Lorsque vous écrivez dans pages.xml les éléments suivants:

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

Cela signifie normalement que vous avez une action qui retourne showPageB comme ceci:

public String someAction() { 
    //Do something complex 
    return "showPageB"; 
} 

Quoi qu'il en soit, à votre problème. Faites-vous plaisir et créez un composant Seam.

@Name("myComponent") 
public Class MyComponent { 

public String showPageB() { 
    return "showPageB"; 
} 

public String showPageA() { 
    return "showPageA"; 
} 

} 

Changer votre pages.xml à ceci:

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

Puis changer xhtml h:commandButton à

<h:commandButton action="#{myComponent.showPageA}" value="showA"/> 
<h:commandButton action="#{myComponent.showPageB}" value="showB"/> 
+1

l'attribut d'action * can * est une chaîne: http://www.horstmann.com/corejsf/jsf-tags.html#Table4_15. Pourquoi avoir la surcharge de créer un Bean pour faire une navigation? Disons que c'est ma page d'accueil. Si j'appuie sur le bouton "Aide", je veux toujours naviguer vers la page d'aide, aucun bean ou méthode n'est nécessaire pour déterminer l'action. –

+0

Néanmoins, j'ai fait ce que vous suggérez, et ne résout pas mon problème ... Merci quand même! –

+0

Je ne peux pas croire que ça ne marche pas. Ce n'est tout simplement pas possible. Cela signifie que l'erreur est ailleurs dans votre configuration de couture. Mais pourquoi voudriez-vous faire un post pour une navigation simple? Qu'est-ce que J'utilise est ' Vous devriez également lire la documentation de couture trouvée dans http://seamframework.org/Documentation –

Questions connexes