1 Reply Latest reply on Sep 10, 2007 10:28 AM by trickyvail

    Redirecting to Previous Long Running Conversations

    trickyvail

      Seam 2.0.0.BETA1

      I would like a shopping website that allows users to have multiple carts open in different browser windows at the same time. Seam's conversation model appears to provide a solution: use a long running conversation for each cart and nested conversations everywhere a regular application would use a conversation.

      One of the problems is how to transparently connect a user back to their cart (most recently accessed session) if they leave the site and come back using a url without the conversation id? I've tried the following solution:

      pages.xml (fragment):
      
      <page view-id="*" action="#{conversationManager.manage}">
      
      ConversationManager.java:
      
      @Name("conversationManager")
      @Scope(ScopeType.SESSION)
      public class ConversationManager
      {
       private Stack<String> conversationStack = new Stack<String>();
      
       public String manage()
       {
       Manager manager = Manager.instance();
       HttpServletRequest httpServletRequest = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
       String conversationIdRequestParameter = httpServletRequest.getParameter(manager.getConversationIdParameter());
      
       if(! manager.isLongRunningOrNestedConversation())
       {
       ConversationEntries conversationEntries = ConversationEntries.instance();
      
       if(conversationEntries.getConversationEntries().size() == 0)
       {
       manager.beginConversation();
       conversationStack.push(Conversation.instance().getId());
       }
       else if
       (
       conversationEntries.getConversationEntries().size() > 0
       && conversationIdRequestParameter == null
       )
       {
       while(conversationStack.size() > 0)
       {
       String conversationId = conversationStack.pop();
       ConversationEntry conversationEntry = conversationEntries.getConversationEntry(conversationId);
       if(conversationEntry != null)
       {
       conversationEntry.redirect();
       }
       }
       }
       }
       else if(manager.isLongRunningConversation())
       {
       try
       {
       if(conversationStack.peek() != Conversation.instance().getId())
       {
       conversationStack.remove(Conversation.instance().getId());
       conversationStack.push(Conversation.instance().getId());
       }
       }
       catch(EmptyStackException e){}
       }
      
       return null;
       }
      }

      For every view the manage method:
      - begins a long running conversation for new sessions.
      - for requests that have conversations but no conversation id, redirects to last accessed existing conversation.

      I've not tested this extensively but it appears to work as intended.

      Because the conversation holds the cart, its timeout should be set to a long span. However when creating nested conversations it would be preferable for them to have a short span. Here's where I've run into a problem. I can set the conversation timeout like so:
      Conversation.instance().setTimeout(int);

      but as soon as I go to the next page the timeout will be back to the default setting. I've would like to use an approach like:
      ConversationEntries.instance().getConversationEntry("2").setTimeout(int);

      which would set the ConversationEntry dirty, but this method is not visible.

      Here are my questions:
      =============================================
      - How do you permanently change a conversation's timeout?

      - Is there a better multiple cart solution without hijacking the seam conversation model? (e.g. storing the carts in the sesssion and creating management similar to conversations)

      - If this is an acceptable solution would it be better implemented as a servlet filter instead of mapping an action to the "*" view in pages.xml?
      =============================================

      Thanks in advance for your feedback.

      references:
      http://www.jboss.com/index.html?module=bb&op=viewtopic&t=109084

        • 1. Redirecting to Previous Long Running Conversations
          trickyvail

          I have fixed a small error in the last version.

          @Name("stickyConversationManager")
          @Scope(ScopeType.SESSION)
          public class StickyConversationManager
          {
           private Stack<String> conversationStack = new Stack<String>();
          
           @Logger
           private Log log;
          
           @In(create = true)
           @Out
           private CartHome cartHome;
          
           public String stick()
           {
           Manager manager = Manager.instance();
           HttpServletRequest httpServletRequest = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
           String conversationIdRequestParameter = httpServletRequest.getParameter(manager.getConversationIdParameter());
          
           if(! manager.isLongRunningOrNestedConversation())
           {
           ConversationEntries conversationEntries = ConversationEntries.instance();
          
           if(conversationEntries.getConversationEntries().size() == 0)
           {
           manager.beginConversation();
          
           // the following change to the conversation timeout
           // is gone on the next page submission
           Conversation.instance().setTimeout(24 * 60 * 60 * 1000);
           conversationStack.push(Conversation.instance().getId());
           }
           else if(conversationIdRequestParameter == null)
           {
           while(conversationStack.size() > 0)
           {
           ConversationEntry conversationEntry = conversationEntries.getConversationEntry(conversationStack.peek());
           if(conversationEntry != null)
           {
           conversationEntry.redirect();
           break;
           }
           else
           {
           conversationStack.pop();
           }
           }
           }
           }
           else if(manager.isLongRunningConversation())
           {
           try
           {
           if(conversationStack.peek() != Conversation.instance().getId())
           {
           conversationStack.remove(Conversation.instance().getId());
           conversationStack.push(Conversation.instance().getId());
           }
           }
           catch(EmptyStackException e){}
           }
          
           log.debug(toString());
           return null;
           }
          
           @Override
           public String toString()
           {
           StringBuffer stringBuffer = new StringBuffer();
           stringBuffer
           .append("<ConversationManager>")
           .append("<Stack>");
           for(String conversationId : conversationStack)
           {
           stringBuffer
           .append("<ConversationId>")
           .append(conversationId)
           .append("</ConversationId>");
           }
           stringBuffer
           .append("</Stack>")
           .append("</ConversationManager>");
           return stringBuffer.toString();
           }
          }