You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by im...@apache.org on 2008/04/05 16:42:15 UTC

svn commit: r645109 - in /myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra: conversation/ lib/jsf/

Author: imario
Date: Sat Apr  5 07:42:13 2008
New Revision: 645109

URL: http://svn.apache.org/viewvc?rev=645109&view=rev
Log:
ORCHESTRA-19: First draft which should allow one to start child conversation context as required by dialog frameworks or e.g. if one would like to have contexts one can programmatically start/stop/pause/restart

Modified:
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/Conversation.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationContext.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationManager.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationRequestParameterProvider.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/lib/jsf/ContextLockRequestHandler.java

Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/Conversation.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/Conversation.java?rev=645109&r1=645108&r2=645109&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/Conversation.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/Conversation.java Sat Apr  5 07:42:13 2008
@@ -364,7 +364,7 @@
         }
 
         // see if there is a single conversation hanging around in the conversation context
-        ConversationContext cctx = ConversationManager.getInstance().getCurrentConversationContext(false);
+        ConversationContext cctx = ConversationManager.getInstance().getCurrentConversationContext();
         if (cctx != null)
         {
             return cctx.getConversation(SpringSingleConversationScope.CONVERSATION_NAME);

Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationContext.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationContext.java?rev=645109&r1=645108&r2=645109&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationContext.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationContext.java Sat Apr  5 07:42:13 2008
@@ -19,15 +19,15 @@
 
 package org.apache.myfaces.orchestra.conversation;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.myfaces.orchestra.lib._ReentrantLock;
+
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.TreeMap;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.myfaces.orchestra.lib._ReentrantLock;
-
 /**
  * A ConversationContext is a container for a set of conversations.
  * <p>
@@ -44,44 +44,80 @@
 
     // This id is attached as a query parameter to every url rendered in a page
     // (forms and links) so that if that url is invoked then the request will
-    // cause the same context to be used from the user's http session. 
-    private final long id;
+    // cause the same context to be used from the user's http session.
+    private final Long id;
 
     // See addAttribute
     private final Map attributes = new TreeMap();
 
+    // the parent conversation context
+    private final ConversationContext parent;
+
     // The conversations held by this context, keyed by conversation name.
     private final Map conversations = new TreeMap();
 
+    /**
+     * A name associated with this context
+     */
+    private String name;
+
     // time at which this was last accessed, used for timeouts.
     private long lastAccess;
 
     // default timeout for contexts: 30 minutes.
     private long timeoutMillis = 30 * 60 * 1000;
-    
+
     private final _ReentrantLock lock = new _ReentrantLock();
 
-    protected ConversationContext(long id)
+    protected ConversationContext(ConversationContext parent, Long id)
     {
+        this.parent = parent;
         this.id = id;
 
         touch();
     }
 
     /**
+     * get the name associated to this context
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * a name associated with this context
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
      * The conversation context id, unique within the current http session.
      */
-    public long getId()
+    public Long getId()
     {
         return id;
     }
 
     /**
+     * The parent conversation context
+     */
+    public ConversationContext getParent()
+    {
+        return parent;
+    }
+
+    /**
      * Mark this context as having been used.
      */
     protected void touch()
     {
         lastAccess = System.currentTimeMillis();
+
+        if (getParent() != null)
+        {
+            getParent().touch();
+        }
     }
 
     /**
@@ -153,7 +189,7 @@
 
     /**
      * Remove the conversation from this context.
-     * 
+     *
      * <p>Notice: It is assumed that the conversation has already been invalidated.</p>
      */
     protected void removeConversation(Conversation conversation)
@@ -167,7 +203,7 @@
 
     /**
      * Remove the conversation with the given name from this context.
-     * 
+     *
      * <p>Notice: Its assumed that the conversation has already been invalidated</p>
      */
     protected void removeConversation(String name)
@@ -323,7 +359,7 @@
             return attributes.remove(name);
         }
     }
-    
+
     /**
      * Block until no other thread has this instance marked as reserved, then
      * mark the object as reserved for this thread.
@@ -333,32 +369,47 @@
      * If this method is called, then an equal number of calls to
      * unlockForCurrentThread <b>MUST</b> made, or this context object
      * will remain locked until the http session times out.
-     * 
+     *
      * @since 1.1
      */
     public void lockInterruptablyForCurrentThread() throws InterruptedException
     {
         lock.lockInterruptibly();
     }
-    
+
     /**
      * Block until no other thread has this instance marked as reserved, then
-     * mark the object as reserved for this thread. 
-     * 
+     * mark the object as reserved for this thread.
+     *
      * @since 1.1
      */
     public void unlockForCurrentThread()
     {
         lock.unlock();
     }
-    
+
     /**
      * Return true if this object is currently locked by the calling thread.
-     * 
+     *
      * @since 1.1
      */
     public boolean isLockedForCurrentThread()
     {
         return lock.isHeldByCurrentThread();
+    }
+
+    /**
+     * get the topmost conversation context this conversation context is associated with
+     * @return
+     */
+    public ConversationContext getTopmostConversationContext() {
+
+        ConversationContext cctx = this;
+        while (cctx != null && cctx.getParent() != null)
+        {
+            cctx = getParent();
+        }
+
+        return cctx;
     }
 }

Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationManager.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationManager.java?rev=645109&r1=645108&r2=645109&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationManager.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationManager.java Sat Apr  5 07:42:13 2008
@@ -27,9 +27,11 @@
 import java.io.IOException;
 import java.io.ObjectStreamException;
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -53,6 +55,8 @@
     private final static String CONVERSATION_MANAGER_KEY = "org.apache.myfaces.ConversationManager";
     private final static String CONVERSATION_CONTEXT_REQ = "org.apache.myfaces.ConversationManager.conversationContext";
 
+    private final static ConversationContext[] EMPTY_CONTEXTS = new ConversationContext[0];
+
     private static final Iterator EMPTY_ITERATOR = Collections.EMPTY_LIST.iterator();
 
     private final Log log = LogFactory.getLog(ConversationManager.class);
@@ -159,11 +163,7 @@
             }
             else
             {
-                synchronized(this)
-                {
-                    conversationContextId = new Long(nextConversationContextId);
-                    nextConversationContextId++;
-                }
+                conversationContextId = createNextConversationContextId();
             }
 
             fa.setRequestAttribute(CONVERSATION_CONTEXT_REQ, conversationContextId);
@@ -172,6 +172,16 @@
         return conversationContextId;
     }
 
+    protected Long createNextConversationContextId() {
+        Long conversationContextId;
+        synchronized(this)
+        {
+            conversationContextId = new Long(nextConversationContextId);
+            nextConversationContextId++;
+        }
+        return conversationContextId;
+    }
+
     /**
      * Get the conversation context for the given id
      */
@@ -184,17 +194,79 @@
     }
 
     /**
+     * Return a snapshot array of all conversation contexts associated with the
+     * current topmost conversation context.
+     */
+    protected ConversationContext[] getConversationContexts()
+    {
+        synchronized (this)
+        {
+            List ret = new ArrayList();
+
+            ConversationContext topmost = getTopmostConversationContext(false);
+            if (topmost == null)
+            {
+                return EMPTY_CONTEXTS;
+            }
+
+            Iterator iterConversationContexts = conversationContexts.values().iterator();
+            while (iterConversationContexts.hasNext())
+            {
+                ConversationContext conversationContext = (ConversationContext) iterConversationContexts.next();
+                if (conversationContext.getParent() == null)
+                {
+                    // this is a topmost conversation context already
+                    continue;
+                }
+
+                if (topmost != conversationContext.getTopmostConversationContext())
+                {
+                    continue;
+                }
+
+                ret.add(conversationContext);
+            }
+
+            ConversationContext[] contexts = new ConversationContext[ret.size()];
+            ret.toArray(contexts);
+            return contexts;
+        }
+    }
+
+    /**
      * Get the conversation context for the given id. <br />
-     * If there is no conversation context a new one will be created
+     * If there is no conversation context a new one will be created. The new conversation context
+     * will be a "top-level" context.
      */
-    protected ConversationContext getOrCreateConversationContext(Long conversationContextId)
+    protected ConversationContext createConversationContext(Long conversationContextId)
+    {
+        return new ConversationContext(null, conversationContextId);
+    }
+
+    /**
+     * This will start a new conversation context using the current conversation context as the parent.
+     * If there is no parent a topmost conversation context will be created.
+     * The returned conversation context is then a child of this automatically created conversation context.
+     * <br />
+     * Notice: The created conversation context is not activated after this method call. You have to call
+     * {@link #activateConversationContext(ConversationContext)} on the newly create context too.
+     */
+    protected ConversationContext startNewConversationContext()
     {
         synchronized (this)
         {
+            ConversationContext parent = getCurrentConversationContext();
+            if (parent == null)
+            {
+                parent = getTopmostConversationContext(true);
+            }
+
+            Long conversationContextId = createNextConversationContextId();
+
             ConversationContext conversationContext = (ConversationContext) conversationContexts.get(conversationContextId);
             if (conversationContext == null)
             {
-                conversationContext = new ConversationContext(conversationContextId.longValue());
+                conversationContext = new ConversationContext(parent, conversationContextId);
                 conversationContexts.put(conversationContextId, conversationContext);
             }
 
@@ -203,6 +275,16 @@
     }
 
     /**
+     * Actually activate the given conversation context. This means the current conversation context will be
+     * deactivated and the conversations of the passed in conversation context are those used again.
+     */
+    public void activateConversationContext(ConversationContext ctx)
+    {
+        FrameworkAdapter fa = FrameworkAdapter.getCurrentInstance();
+        fa.setRequestAttribute(CONVERSATION_CONTEXT_REQ, ctx.getId());
+    }
+
+    /**
      * Ends all conversations within the current context; the context itself will remain active.
      */
     public void clearCurrentConversationContext()
@@ -235,7 +317,11 @@
      */
     public Conversation startConversation(String name, ConversationFactory factory)
     {
-        ConversationContext conversationContext = getCurrentConversationContext(true);
+        ConversationContext conversationContext = getCurrentConversationContext();
+        if (conversationContext == null)
+        {
+            conversationContext = getTopmostConversationContext(true);
+        }
         return conversationContext.startConversation(name, factory);
     }
 
@@ -300,17 +386,41 @@
     }
 
     /**
-     * Get the current conversation context.
+     * Get the current conversation context. In an plain Orchestra installation this will also be the tompost
+     * conversation context. When using a dialog/page-flow environment this might be the bottom conversation context.
      */
-    public ConversationContext getCurrentConversationContext(boolean create)
+    public ConversationContext getCurrentConversationContext()
     {
         Long conversationContextId = getConversationContextId();
-        ConversationContext conversationContext = getConversationContext(conversationContextId);
-        if (conversationContext == null && create)
+        return getConversationContext(conversationContextId);
+    }
+
+    /**
+     * Get the topmost conversation context (aka the window conversation context).
+     */
+    public ConversationContext getTopmostConversationContext(boolean create)
+    {
+        Long conversationContextId = getConversationContextId();
+        synchronized (this)
         {
-            conversationContext = getOrCreateConversationContext(conversationContextId);
+            ConversationContext conversationContext = getConversationContext(conversationContextId);
+            while (conversationContext != null && conversationContext.getParent() != null)
+            {
+                conversationContext = conversationContext.getParent();
+            }
+            if (conversationContext == null && create)
+            {
+                    conversationContext = (ConversationContext) conversationContexts.get(conversationContextId);
+                    if (conversationContext == null)
+                    {
+                        conversationContext = createConversationContext(conversationContextId);
+                        conversationContexts.put(conversationContextId, conversationContext);
+                    }
+
+                    return conversationContext;
+            }
+            return conversationContext;
         }
-        return conversationContext;
     }
 
     /**
@@ -318,9 +428,9 @@
      *
      * @return null if there is no context active
      */
-    public ConversationContext getCurrentConversationContext()
+    public ConversationContext getTopmostConversationContext()
     {
-        return getCurrentConversationContext(false);
+        return getTopmostConversationContext(false);
     }
 
     /**

Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationRequestParameterProvider.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationRequestParameterProvider.java?rev=645109&r1=645108&r2=645109&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationRequestParameterProvider.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationRequestParameterProvider.java Sat Apr  5 07:42:13 2008
@@ -83,9 +83,13 @@
             throw new IllegalStateException("can find the conversationManager");
         }
 
-        ConversationContext ctx = conversationManager.getCurrentConversationContext(true);
+        ConversationContext ctx = conversationManager.getCurrentConversationContext();
+        if (ctx == null)
+        {
+            ctx = conversationManager.getTopmostConversationContext(true);
+        }
 
-        return Long.toString(ctx.getId(), Character.MAX_RADIX);
+        return Long.toString(ctx.getId().longValue(), Character.MAX_RADIX);
     }
 
     public String[] getFields()

Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/lib/jsf/ContextLockRequestHandler.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/lib/jsf/ContextLockRequestHandler.java?rev=645109&r1=645108&r2=645109&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/lib/jsf/ContextLockRequestHandler.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/lib/jsf/ContextLockRequestHandler.java Sat Apr  5 07:42:13 2008
@@ -48,7 +48,11 @@
             ConversationManager manager = ConversationManager.getInstance(false);
             if (manager != null)
             {
-                context = manager.getCurrentConversationContext(true);
+                context = manager.getCurrentConversationContext();
+                if (context == null)
+                {
+                    context = manager.getTopmostConversationContext(true);
+                }
                 try
                 {
                     context.lockInterruptablyForCurrentThread();