You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by sk...@apache.org on 2008/02/21 21:32:43 UTC

svn commit: r629975 [1/4] - in /myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation: ./ basic/ spring/

Author: skitching
Date: Thu Feb 21 12:32:37 2008
New Revision: 629975

URL: http://svn.apache.org/viewvc?rev=629975&view=rev
Log:
Tab to spaces only

Modified:
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/AccessScopeManager.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/AccessScopeManagerConfiguration.java
    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/ConversationAccessLifetimeAspect.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationAspect.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationAspects.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationAware.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationBindingEvent.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationBindingListener.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/ConversationFactory.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/ConversationMessager.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/conversation/ConversationTimeoutableAspect.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationUtils.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationWiperThread.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/CurrentConversationAdvice.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/CurrentConversationInfo.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/FlashScopeManager.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/_ConversationUtils.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/basic/LogConversationMessager.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/AbstractSpringOrchestraScope.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/BeanDefinitionConversationNameAttrDecorator.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/JpaPersistenceContextFactory.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/OrchestraAdvisorBeanPostProcessor.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/OrchestraNamespaceHandler.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/PersistenceContextCloser.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/PersistenceContextConversationInterceptor.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/PersistenceContextFactory.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/ScopedBeanTargetSource.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/SpringConversationScope.java
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/_SpringUtils.java

Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/AccessScopeManager.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/AccessScopeManager.java?rev=629975&r1=629974&r2=629975&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/AccessScopeManager.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/AccessScopeManager.java Thu Feb 21 12:32:37 2008
@@ -36,136 +36,136 @@
  */
 public class AccessScopeManager
 {
-	private static final Log log = LogFactory.getLog(AccessScopeManager.class);
-	private static final String REQ_ATTR_KEY = AccessScopeManager.class.getName();
-	private AccessScopeManagerConfiguration accessScopeManagerConfiguration;
-
-	private boolean recordAccess;
-	private boolean ignoreRequest;
-	private Set accessedConversations = new HashSet();
-
-	public static AccessScopeManager getInstance()
-	{
-		// Get the instance by looking up a variable whose name is this class name, using the normal
-		// managed bean lookup process. When an IOC framework like Spring is being used to extend
-		// the standard JSF managed bean declaration facilities, then the bean may be retrieved
-		// from there.
-		//
-		// Using a lookup of a managed bean allows the user to set configuration properties on the
-		// manager class and its properties.
-
-		FrameworkAdapter fa = FrameworkAdapter.getCurrentInstance();
-		AccessScopeManager manager = (AccessScopeManager) fa.getRequestAttribute(REQ_ATTR_KEY);
-		if (manager != null)
-		{
-			// already found and cached in request attributes
-			return manager;
-		}
-
-		// Backwards compatibility hack: look for FlashScopeManager. It is possible that
-		// a user of Orchestra 1.0 has copied the declaration from the original Orchestra
-		// config file into their own code to inject special settings.
-		manager = (AccessScopeManager) fa.getBean(FlashScopeManager.class.getName());
-		if (manager != null)
-		{
-			log.info("found FlashScopeManager object");
-			fa.setRequestAttribute(REQ_ATTR_KEY, manager);
-			return manager;
-		}
-		
-		// Backwards compatibility hack: look for FlashScopeManagerConfiguration. It is
-		// possible that a user of Orchestra 1.0 has overridden just the Configuration
-		// bit to set their own ignoredViewId values (as recommended!):
-		//
-		// This is a little dodgy as settings made through the new AccessScopeManage
-		// bean will will now be silently ignored.
-		FlashScopeManagerConfiguration cfg = (FlashScopeManagerConfiguration) fa.getBean(FlashScopeManagerConfiguration.class.getName());
-		if (cfg != null)
-		{
-			log.info("found FlashScopeManagerConfiguration object");
-			manager = new AccessScopeManager();
-			manager.setAccessScopeManagerConfiguration(cfg);
-			fa.setRequestAttribute(REQ_ATTR_KEY, manager);
-			return manager;
-		}
-		
-		// normal case
-		manager = (AccessScopeManager) fa.getBean(AccessScopeManager.class.getName());
-		if (manager != null)
-		{
-			log.info("found AccessScopeManager object");
-			fa.setRequestAttribute(REQ_ATTR_KEY, manager);
-			return manager;
-		}
-
-		// TODO: Make this error message less spring-specific. Spring is not the only IOC container
-		// that Orchestra can be used with.
-		throw new IllegalArgumentException(
-				"No AccessScopeManager found. Probably you forgot to add " 
-				+ "<import resource=\"classpath*:/META-INF/spring-orchestra-init.xml\" />" 
-				+ " to your spring configuration.");
-	}
-
-	public AccessScopeManagerConfiguration getAccessScopeManagerConfiguration()
-	{
-		return accessScopeManagerConfiguration;
-	}
-
-	public void setAccessScopeManagerConfiguration(AccessScopeManagerConfiguration accessScopeManagerConfiguration)
-	{
-		this.accessScopeManagerConfiguration = accessScopeManagerConfiguration;
-	}
-
-	/**
-	 * This is invoked at the point in the request lifecycle after which we want to
-	 * start tracking use of access-scoped objects.
-	 */
-	public void beginRecording() 
-	{
-		recordAccess = true;
-	}
-
-	/**
-	 * Add a conversation to the list of accessed conversations.
-	 * <p>
-	 * This method is expected to be called via AOP proxies wrapped around each conversation-scoped
-	 * bean; any invocation of a method on such a bean causes the conversation associated with that
-	 * bean to be added to the accessed list here.
-	 */
-	public void addConversationAccess(String conversationName)
-	{
-		// Don't bother tracking accessed conversations if we will never use the data.
-		// Otherwise, add this conversation name to the list of accessed conversations.
-		if (recordAccess && !ignoreRequest && !accessedConversations.contains(conversationName))
-		{
-			accessedConversations.add(conversationName);
-		}
-	}
-
-	public boolean isIgnoreRequest()
-	{
-		return ignoreRequest;
-	}
-
-	/**
-	 * Suppress access scope for the current request, ie do not terminate conversations that are
-	 * not accessed by this request.
-	 * <p>
-	 * This can come in useful occasionally, particularly when handling AJAX requests which
-	 * only access some of the beans associated with the current view.
-	 */
-	public void setIgnoreRequest()
-	{
-		this.ignoreRequest = true;
-	}
-
-	public boolean isConversationAccessed(String name)
-	{
-		if (ignoreRequest)
-		{
-			throw new IllegalStateException();
-		}
+    private static final Log log = LogFactory.getLog(AccessScopeManager.class);
+    private static final String REQ_ATTR_KEY = AccessScopeManager.class.getName();
+    private AccessScopeManagerConfiguration accessScopeManagerConfiguration;
+
+    private boolean recordAccess;
+    private boolean ignoreRequest;
+    private Set accessedConversations = new HashSet();
+
+    public static AccessScopeManager getInstance()
+    {
+        // Get the instance by looking up a variable whose name is this class name, using the normal
+        // managed bean lookup process. When an IOC framework like Spring is being used to extend
+        // the standard JSF managed bean declaration facilities, then the bean may be retrieved
+        // from there.
+        //
+        // Using a lookup of a managed bean allows the user to set configuration properties on the
+        // manager class and its properties.
+
+        FrameworkAdapter fa = FrameworkAdapter.getCurrentInstance();
+        AccessScopeManager manager = (AccessScopeManager) fa.getRequestAttribute(REQ_ATTR_KEY);
+        if (manager != null)
+        {
+            // already found and cached in request attributes
+            return manager;
+        }
+
+        // Backwards compatibility hack: look for FlashScopeManager. It is possible that
+        // a user of Orchestra 1.0 has copied the declaration from the original Orchestra
+        // config file into their own code to inject special settings.
+        manager = (AccessScopeManager) fa.getBean(FlashScopeManager.class.getName());
+        if (manager != null)
+        {
+            log.info("found FlashScopeManager object");
+            fa.setRequestAttribute(REQ_ATTR_KEY, manager);
+            return manager;
+        }
+        
+        // Backwards compatibility hack: look for FlashScopeManagerConfiguration. It is
+        // possible that a user of Orchestra 1.0 has overridden just the Configuration
+        // bit to set their own ignoredViewId values (as recommended!):
+        //
+        // This is a little dodgy as settings made through the new AccessScopeManage
+        // bean will will now be silently ignored.
+        FlashScopeManagerConfiguration cfg = (FlashScopeManagerConfiguration) fa.getBean(FlashScopeManagerConfiguration.class.getName());
+        if (cfg != null)
+        {
+            log.info("found FlashScopeManagerConfiguration object");
+            manager = new AccessScopeManager();
+            manager.setAccessScopeManagerConfiguration(cfg);
+            fa.setRequestAttribute(REQ_ATTR_KEY, manager);
+            return manager;
+        }
+        
+        // normal case
+        manager = (AccessScopeManager) fa.getBean(AccessScopeManager.class.getName());
+        if (manager != null)
+        {
+            log.info("found AccessScopeManager object");
+            fa.setRequestAttribute(REQ_ATTR_KEY, manager);
+            return manager;
+        }
+
+        // TODO: Make this error message less spring-specific. Spring is not the only IOC container
+        // that Orchestra can be used with.
+        throw new IllegalArgumentException(
+                "No AccessScopeManager found. Probably you forgot to add " 
+                + "<import resource=\"classpath*:/META-INF/spring-orchestra-init.xml\" />" 
+                + " to your spring configuration.");
+    }
+
+    public AccessScopeManagerConfiguration getAccessScopeManagerConfiguration()
+    {
+        return accessScopeManagerConfiguration;
+    }
+
+    public void setAccessScopeManagerConfiguration(AccessScopeManagerConfiguration accessScopeManagerConfiguration)
+    {
+        this.accessScopeManagerConfiguration = accessScopeManagerConfiguration;
+    }
+
+    /**
+     * This is invoked at the point in the request lifecycle after which we want to
+     * start tracking use of access-scoped objects.
+     */
+    public void beginRecording() 
+    {
+        recordAccess = true;
+    }
+
+    /**
+     * Add a conversation to the list of accessed conversations.
+     * <p>
+     * This method is expected to be called via AOP proxies wrapped around each conversation-scoped
+     * bean; any invocation of a method on such a bean causes the conversation associated with that
+     * bean to be added to the accessed list here.
+     */
+    public void addConversationAccess(String conversationName)
+    {
+        // Don't bother tracking accessed conversations if we will never use the data.
+        // Otherwise, add this conversation name to the list of accessed conversations.
+        if (recordAccess && !ignoreRequest && !accessedConversations.contains(conversationName))
+        {
+            accessedConversations.add(conversationName);
+        }
+    }
+
+    public boolean isIgnoreRequest()
+    {
+        return ignoreRequest;
+    }
+
+    /**
+     * Suppress access scope for the current request, ie do not terminate conversations that are
+     * not accessed by this request.
+     * <p>
+     * This can come in useful occasionally, particularly when handling AJAX requests which
+     * only access some of the beans associated with the current view.
+     */
+    public void setIgnoreRequest()
+    {
+        this.ignoreRequest = true;
+    }
+
+    public boolean isConversationAccessed(String name)
+    {
+        if (ignoreRequest)
+        {
+            throw new IllegalStateException();
+        }
 
-		return accessedConversations.contains(name);
-	}
+        return accessedConversations.contains(name);
+    }
 }

Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/AccessScopeManagerConfiguration.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/AccessScopeManagerConfiguration.java?rev=629975&r1=629974&r2=629975&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/AccessScopeManagerConfiguration.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/AccessScopeManagerConfiguration.java Thu Feb 21 12:32:37 2008
@@ -30,23 +30,23 @@
  */
 public class AccessScopeManagerConfiguration
 {
-	private Set ignoreViewIds;
+    private Set ignoreViewIds;
 
-	public Set getIgnoreViewIds()
-	{
-		return ignoreViewIds;
-	}
+    public Set getIgnoreViewIds()
+    {
+        return ignoreViewIds;
+    }
 
-	/**
-	 * Do not terminate any "unaccessed conversations" after handling a request to
-	 * any of the specified views.
-	 * 
-	 * Special "ignored views" are useful when dealing with things like nested
-	 * frames within a page that periodically refresh themselves while the "main"
-	 * part of the page remains unsubmitted.
-	 */
-	public void setIgnoreViewIds(Set ignoreViewIds)
-	{
-		this.ignoreViewIds = ignoreViewIds;
-	}
+    /**
+     * Do not terminate any "unaccessed conversations" after handling a request to
+     * any of the specified views.
+     * 
+     * Special "ignored views" are useful when dealing with things like nested
+     * frames within a page that periodically refresh themselves while the "main"
+     * part of the page remains unsubmitted.
+     */
+    public void setIgnoreViewIds(Set ignoreViewIds)
+    {
+        this.ignoreViewIds = ignoreViewIds;
+    }
 }

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=629975&r1=629974&r2=629975&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 Thu Feb 21 12:32:37 2008
@@ -57,399 +57,399 @@
  */
 public class Conversation
 {
-	// See getCurrentInstance, setCurrentInstance and class CurrentConversationAdvice.
-	private final static ThreadLocal CURRENT_CONVERSATION = new ThreadLocal();
+    // See getCurrentInstance, setCurrentInstance and class CurrentConversationAdvice.
+    private final static ThreadLocal CURRENT_CONVERSATION = new ThreadLocal();
 
-	private final Log log = LogFactory.getLog(Conversation.class);
+    private final Log log = LogFactory.getLog(Conversation.class);
 
-	private final String name;
-	
-	// The factory that created this conversation instance; needed
-	// when restarting the conversation.
-	private final ConversationFactory factory;
-
-	// The set of managed beans that are associated with this conversation.
-	private final Map beans = new TreeMap();
-
-	// The parent context to which this conversation belongs. This is needed
-	// when restarting the conversation.
-	private final ConversationContext conversationContext;
-
-	// See addAspect.
-	private ConversationAspects conversationAspects = new ConversationAspects();
-
-	// Is this object usable, or "destroyed"?
-	private boolean invalid = false;
-
-	// Is this object going to be destroyed as soon as it is no longer "active"?
-	private boolean queueInvalid = false;
-
-	// system timestamp in milliseconds at which this object was last accessed;
-	// see method touch().
-	private long lastAccess;
-
-	private Object activeCountMutex = new Object();
-	private int activeCount;
-
-	public Conversation(ConversationContext conversationContext, String name, ConversationFactory factory)
-	{
-		this.conversationContext = conversationContext;
-		this.name = name;
-		this.factory = factory;
-
-		if (log.isDebugEnabled())
-		{
-			log.debug("start conversation:" + name);
-		}
-
-		touch();
-	}
-
-	/**
-	 * Mark this conversation as having been used at the current time.
-	 * <p>
-	 * Conversations can have "timeouts" associated with them, so that when a user stops
-	 * a conversation and goes off to work on some other part of the webapp then the
-	 * conversation's memory can eventually be reclaimed.
-	 * <p>
-	 * Whenever user code causes this conversation object to be looked up and returned,
-	 * this "touch" method is invoked to indicate that the conversation is in use. Direct
-	 * conversation lookups by user code can occur, but the most common access is expected
-	 * to be via an EL expression which a lookup of a bean that is declared as being in
-	 * conversation scope. The bean lookup causes the corresponding conversation to be
-	 * looked up, which triggers this method.
-	 */
-	protected void touch()
-	{
-		lastAccess = System.currentTimeMillis();
-	}
-
-	/**
-	 * The system time in millis when this conversation has been accessed last
-	 */
-	public long getLastAccess()
-	{
-		return lastAccess;
-	}
-
-	/**
-	 * Add the given bean to the conversation scope.
-	 * 
-	 * <p>This will fire a {@link ConversationBindingEvent} on the bean parameter
-	 * object if the bean implements the {@link ConversationBindingListener}
-	 * interface</p>
-	 * 
-	 * <p>Note that any object can be stored into the conversation; it is not
-	 * limited to managed beans declared in a configuration file. This
-	 * feature is not expected to be heavily used however; most attributes of
-	 * a conversation are expected to be externally-declared "managed beans".</p>
-	 */
-	public void setAttribute(String name, Object bean)
-	{
-		checkValid();
-
-		synchronized(conversationContext)
-		{
-			removeAttribute(name);
-
-			if (log.isDebugEnabled())
-			{
-				log.debug("put bean to conversation:" + name + "(bean=" + bean + ")");
-			}
-
-			beans.put(name, bean);
-		}
-
-		if (bean instanceof ConversationBindingListener)
-		{
-			((ConversationBindingListener) bean).valueBound(
-				new ConversationBindingEvent(this, name));
-		}
-	}
-
-	/**
-	 * Assert the conversation is valid.
-	 * 
-	 * Throws IllegalStateException if this conversation has been destroyed;
-	 * see method setInvalid.
-	 */
-	protected void checkValid()
-	{
-		if (isInvalid())
-		{
-			throw new IllegalStateException("conversation '" + getName() + "' closed");
-		}
-	}
-
-	/**
-	 * Return the name of this conversation.
-	 * <p>
-	 * A conversation name is unique within a conversation context.
-	 */
-	public String getName()
-	{
-		return name;
-	}
-
-	/**
-	 * Return the factory that created this conversation.
-	 * <p>
-	 * Note that this factory will have set the initial aspects of this factory, which
-	 * configure such things as the lifetime (access, manual, etc) and conversation
-	 * timeout properties.
-	 */
-	public ConversationFactory getFactory()
-	{
-		return factory;
-	}
-
-	/**
-	 * Invalidate (end) the conversation.
-	 * <p>
-	 * If the conversation is currently active (ie the current call stack contains an object that
-	 * belongs to this conversation) then the conversation will just queue the object for later
-	 * destruction. Calls to methods like ConversationManager.getConversation(...) may still
-	 * return this object, and it will continue to function as a normal instance.
-	 * <p>
-	 * Only when the conversation is no longer active will the conversation (and the beans
-	 * it contains) actually be marked as invalid ("destroyed"). Once the conversation has been
-	 * destroyed, the ConversationManager will discard all references to it, meaning it will no
-	 * longer be accessable via lookups like ConversationManager.getConversation(). If something
-	 * does still have a reference to a destroyed conversation, then invoking almost any method
-	 * on that object will throw an IllegalStateException. In particular, adding a bean to the
-	 * conversation (invoking addAttribute) is not allowed.
-	 */
-	public void invalidate()
-	{
-		if (!isActive())
-		{
-			destroy();
-		}
-		else
-		{
-			queueInvalid = true;
-
-			if (log.isDebugEnabled())
-			{
-				log.debug("conversation '" + name + "' queued for destroy.");
-			}
-		}
-	}
-
-	/**
-	 * Invalidate/End and restart the conversation.
-	 * <p>
-	 * This conversation object is immediately "destroyed" (see comments for method
-	 * invalidate), and a new instance is registered with the conversation manager
-	 * using the same name. The new instance is returned from this method.
-	 * <p>
-	 * Any code holding a reference to the old conversation instance will receive
-	 * an IllegalStateException when calling almost any method on that instance.
-	 *
-	 * @returns the new conversation
-	 */
-	public Conversation invalidateAndRestart()
-	{
-		String conversationName = getName();
-		ConversationFactory factory = getFactory();
-
-		destroy();
-
-		return conversationContext.startConversation(conversationName, factory);
-	}
-
-	/**
-	 * Return true if the conversation is invalid, ie should not be used.
-	 */
-	public boolean isInvalid()
-	{
-		return invalid;
-	}
-
-	/**
-	 * Return true if the conversation has been queued to be invalidated.
-	 */
-	boolean isQueueInvalid()
-	{
-		return queueInvalid;
-	}
-
-	/**
-	 * Destroy the conversation.
-	 * <ul>
-	 * <li>inform all beans implementing the {@link ConversationBindingListener} about the conversation end</li>
-	 * <li>free all beans</li>
-	 * </ul>
-	 */
-	protected void destroy()
-	{
-		if (log.isDebugEnabled())
-		{
-			log.debug("destroy conversation:" + name);
-		}
-
-		synchronized(conversationContext)
-		{
-			String[] beanNames = (String[]) beans.keySet().toArray(new String[beans.size()]);
-			for (int i = 0; i< beanNames.length; i++)
-			{
-				removeAttribute(beanNames[i]);
-			}
-		}
-
-		conversationContext.removeConversation(getName());
-
-		invalid = true;
-	}
-
-	/**
-	 * Check if this conversation holds a specific attribute (ie has a specific
-	 * named managed bean instance).
-	 */
-	public boolean hasAttribute(String name)
-	{
-		synchronized(conversationContext)
-		{
-			return beans.containsKey(name);
-		}
-	}
-
-	/**
-	 * Get a specific attribute, ie a named managed bean.
-	 */
-	public Object getAttribute(String name)
-	{
-		synchronized(conversationContext)
-		{
-			return beans.get(name);
-		}
-	}
-
-	/**
-	 * Remove a bean from the conversation.
-	 * 
-	 * <p>This will fire a {@link ConversationBindingEvent} if the bean implements the
-	 * {@link ConversationBindingListener} interface.</p>
-	 */
-	public Object removeAttribute(String name)
-	{
-		synchronized(conversationContext)
-		{
-			Object bean = beans.remove(name);
-			if (bean instanceof ConversationBindingListener)
-			{
-				((ConversationBindingListener) bean).valueUnbound(
-					new ConversationBindingEvent(this, name));
-			}
-			return bean;
-		}
-	}
-
-	/**
-	 * Get the current conversation.
-	 *
-	 * @return The conversation object associated with the nearest object in the call-stack that
-	 * is configured to be in a conversation. Null is returned when no object in the call-stack
-	 * is in a conversation.
-	 */
-	public static Conversation getCurrentInstance()
-	{
-		CurrentConversationInfo conversation = getCurrentInstanceInfo();
-		if (conversation != null)
-		{
-			return conversation.getConversation();
-		}
-
-		return null;
-	}
-
-	/**
-	 * Sets info about the current conversation instance.
-	 * <p>
-	 * This method is only expected to be called by CurrentConversationAdvice.invoke,
-	 * which ensures that the current instance is reset to null as soon as no bean
-	 * in the call-stack is within a conversation.
-	 */
-	static void setCurrentInstance(CurrentConversationInfo conversation)
-	{
-		CURRENT_CONVERSATION.set(conversation);
-	}
-
-	/**
-	 * Returns the info about the current conversation
-	 */
-	static CurrentConversationInfo getCurrentInstanceInfo()
-	{
-		CurrentConversationInfo conversationInfo = (CurrentConversationInfo) CURRENT_CONVERSATION.get();
-		if (conversationInfo != null && conversationInfo.getConversation() != null)
-		{
-			conversationInfo.getConversation().touch();
-			return conversationInfo;
-		}
-
-		return null;
-	}
-
-	/**
-	 * Increase one to the "conversation active" counter.
-	 *
-	 * This is called when a method is invoked on a bean that is within this conversation.
-	 * When the method returns, leaveConversation is invoked. The result is that the count
-	 * is greater than zero whenever there is a bean belonging to this conversation on
-	 * the callstack.
-	 */
-	void enterConversation()
-	{
-		synchronized (activeCountMutex)
-		{
-			activeCount++;
-		}
-	}
-
-	/**
-	 * decrease one from the "conversation active" counter
-	 */
-	void leaveConversation()
-	{
-		synchronized (activeCountMutex)
-		{
-			activeCount--;
-		}
-	}
-
-	/**
-	 * check if the conversation is active
-	 */
-	private boolean isActive()
-	{
-		synchronized (activeCountMutex)
-		{
-			return activeCount > 0;
-		}
-	}
-
-	ConversationAspects getAspects()
-	{
-		return conversationAspects;
-	}
-
-	/**
-	 * Get the aspect corresponding to the given class.
-	 * 
-	 * @return null if such an aspect has not been attached to this conversation
-	 */
-	public ConversationAspect getAspect(Class conversationAspectClass)
-	{
-		return conversationAspects.getAspect(conversationAspectClass);
-	}
-
-	/**
-	 * Add an Aspect to this conversation. 
-	 * 
-	 * See class ConversationAspects for further details.
-	 */
-	public void addAspect(ConversationAspect aspect)
-	{
-		conversationAspects.addAspect(aspect);
-	}
+    private final String name;
+    
+    // The factory that created this conversation instance; needed
+    // when restarting the conversation.
+    private final ConversationFactory factory;
+
+    // The set of managed beans that are associated with this conversation.
+    private final Map beans = new TreeMap();
+
+    // The parent context to which this conversation belongs. This is needed
+    // when restarting the conversation.
+    private final ConversationContext conversationContext;
+
+    // See addAspect.
+    private ConversationAspects conversationAspects = new ConversationAspects();
+
+    // Is this object usable, or "destroyed"?
+    private boolean invalid = false;
+
+    // Is this object going to be destroyed as soon as it is no longer "active"?
+    private boolean queueInvalid = false;
+
+    // system timestamp in milliseconds at which this object was last accessed;
+    // see method touch().
+    private long lastAccess;
+
+    private Object activeCountMutex = new Object();
+    private int activeCount;
+
+    public Conversation(ConversationContext conversationContext, String name, ConversationFactory factory)
+    {
+        this.conversationContext = conversationContext;
+        this.name = name;
+        this.factory = factory;
+
+        if (log.isDebugEnabled())
+        {
+            log.debug("start conversation:" + name);
+        }
+
+        touch();
+    }
+
+    /**
+     * Mark this conversation as having been used at the current time.
+     * <p>
+     * Conversations can have "timeouts" associated with them, so that when a user stops
+     * a conversation and goes off to work on some other part of the webapp then the
+     * conversation's memory can eventually be reclaimed.
+     * <p>
+     * Whenever user code causes this conversation object to be looked up and returned,
+     * this "touch" method is invoked to indicate that the conversation is in use. Direct
+     * conversation lookups by user code can occur, but the most common access is expected
+     * to be via an EL expression which a lookup of a bean that is declared as being in
+     * conversation scope. The bean lookup causes the corresponding conversation to be
+     * looked up, which triggers this method.
+     */
+    protected void touch()
+    {
+        lastAccess = System.currentTimeMillis();
+    }
+
+    /**
+     * The system time in millis when this conversation has been accessed last
+     */
+    public long getLastAccess()
+    {
+        return lastAccess;
+    }
+
+    /**
+     * Add the given bean to the conversation scope.
+     * 
+     * <p>This will fire a {@link ConversationBindingEvent} on the bean parameter
+     * object if the bean implements the {@link ConversationBindingListener}
+     * interface</p>
+     * 
+     * <p>Note that any object can be stored into the conversation; it is not
+     * limited to managed beans declared in a configuration file. This
+     * feature is not expected to be heavily used however; most attributes of
+     * a conversation are expected to be externally-declared "managed beans".</p>
+     */
+    public void setAttribute(String name, Object bean)
+    {
+        checkValid();
+
+        synchronized(conversationContext)
+        {
+            removeAttribute(name);
+
+            if (log.isDebugEnabled())
+            {
+                log.debug("put bean to conversation:" + name + "(bean=" + bean + ")");
+            }
+
+            beans.put(name, bean);
+        }
+
+        if (bean instanceof ConversationBindingListener)
+        {
+            ((ConversationBindingListener) bean).valueBound(
+                new ConversationBindingEvent(this, name));
+        }
+    }
+
+    /**
+     * Assert the conversation is valid.
+     * 
+     * Throws IllegalStateException if this conversation has been destroyed;
+     * see method setInvalid.
+     */
+    protected void checkValid()
+    {
+        if (isInvalid())
+        {
+            throw new IllegalStateException("conversation '" + getName() + "' closed");
+        }
+    }
+
+    /**
+     * Return the name of this conversation.
+     * <p>
+     * A conversation name is unique within a conversation context.
+     */
+    public String getName()
+    {
+        return name;
+    }
+
+    /**
+     * Return the factory that created this conversation.
+     * <p>
+     * Note that this factory will have set the initial aspects of this factory, which
+     * configure such things as the lifetime (access, manual, etc) and conversation
+     * timeout properties.
+     */
+    public ConversationFactory getFactory()
+    {
+        return factory;
+    }
+
+    /**
+     * Invalidate (end) the conversation.
+     * <p>
+     * If the conversation is currently active (ie the current call stack contains an object that
+     * belongs to this conversation) then the conversation will just queue the object for later
+     * destruction. Calls to methods like ConversationManager.getConversation(...) may still
+     * return this object, and it will continue to function as a normal instance.
+     * <p>
+     * Only when the conversation is no longer active will the conversation (and the beans
+     * it contains) actually be marked as invalid ("destroyed"). Once the conversation has been
+     * destroyed, the ConversationManager will discard all references to it, meaning it will no
+     * longer be accessable via lookups like ConversationManager.getConversation(). If something
+     * does still have a reference to a destroyed conversation, then invoking almost any method
+     * on that object will throw an IllegalStateException. In particular, adding a bean to the
+     * conversation (invoking addAttribute) is not allowed.
+     */
+    public void invalidate()
+    {
+        if (!isActive())
+        {
+            destroy();
+        }
+        else
+        {
+            queueInvalid = true;
+
+            if (log.isDebugEnabled())
+            {
+                log.debug("conversation '" + name + "' queued for destroy.");
+            }
+        }
+    }
+
+    /**
+     * Invalidate/End and restart the conversation.
+     * <p>
+     * This conversation object is immediately "destroyed" (see comments for method
+     * invalidate), and a new instance is registered with the conversation manager
+     * using the same name. The new instance is returned from this method.
+     * <p>
+     * Any code holding a reference to the old conversation instance will receive
+     * an IllegalStateException when calling almost any method on that instance.
+     *
+     * @returns the new conversation
+     */
+    public Conversation invalidateAndRestart()
+    {
+        String conversationName = getName();
+        ConversationFactory factory = getFactory();
+
+        destroy();
+
+        return conversationContext.startConversation(conversationName, factory);
+    }
+
+    /**
+     * Return true if the conversation is invalid, ie should not be used.
+     */
+    public boolean isInvalid()
+    {
+        return invalid;
+    }
+
+    /**
+     * Return true if the conversation has been queued to be invalidated.
+     */
+    boolean isQueueInvalid()
+    {
+        return queueInvalid;
+    }
+
+    /**
+     * Destroy the conversation.
+     * <ul>
+     * <li>inform all beans implementing the {@link ConversationBindingListener} about the conversation end</li>
+     * <li>free all beans</li>
+     * </ul>
+     */
+    protected void destroy()
+    {
+        if (log.isDebugEnabled())
+        {
+            log.debug("destroy conversation:" + name);
+        }
+
+        synchronized(conversationContext)
+        {
+            String[] beanNames = (String[]) beans.keySet().toArray(new String[beans.size()]);
+            for (int i = 0; i< beanNames.length; i++)
+            {
+                removeAttribute(beanNames[i]);
+            }
+        }
+
+        conversationContext.removeConversation(getName());
+
+        invalid = true;
+    }
+
+    /**
+     * Check if this conversation holds a specific attribute (ie has a specific
+     * named managed bean instance).
+     */
+    public boolean hasAttribute(String name)
+    {
+        synchronized(conversationContext)
+        {
+            return beans.containsKey(name);
+        }
+    }
+
+    /**
+     * Get a specific attribute, ie a named managed bean.
+     */
+    public Object getAttribute(String name)
+    {
+        synchronized(conversationContext)
+        {
+            return beans.get(name);
+        }
+    }
+
+    /**
+     * Remove a bean from the conversation.
+     * 
+     * <p>This will fire a {@link ConversationBindingEvent} if the bean implements the
+     * {@link ConversationBindingListener} interface.</p>
+     */
+    public Object removeAttribute(String name)
+    {
+        synchronized(conversationContext)
+        {
+            Object bean = beans.remove(name);
+            if (bean instanceof ConversationBindingListener)
+            {
+                ((ConversationBindingListener) bean).valueUnbound(
+                    new ConversationBindingEvent(this, name));
+            }
+            return bean;
+        }
+    }
+
+    /**
+     * Get the current conversation.
+     *
+     * @return The conversation object associated with the nearest object in the call-stack that
+     * is configured to be in a conversation. Null is returned when no object in the call-stack
+     * is in a conversation.
+     */
+    public static Conversation getCurrentInstance()
+    {
+        CurrentConversationInfo conversation = getCurrentInstanceInfo();
+        if (conversation != null)
+        {
+            return conversation.getConversation();
+        }
+
+        return null;
+    }
+
+    /**
+     * Sets info about the current conversation instance.
+     * <p>
+     * This method is only expected to be called by CurrentConversationAdvice.invoke,
+     * which ensures that the current instance is reset to null as soon as no bean
+     * in the call-stack is within a conversation.
+     */
+    static void setCurrentInstance(CurrentConversationInfo conversation)
+    {
+        CURRENT_CONVERSATION.set(conversation);
+    }
+
+    /**
+     * Returns the info about the current conversation
+     */
+    static CurrentConversationInfo getCurrentInstanceInfo()
+    {
+        CurrentConversationInfo conversationInfo = (CurrentConversationInfo) CURRENT_CONVERSATION.get();
+        if (conversationInfo != null && conversationInfo.getConversation() != null)
+        {
+            conversationInfo.getConversation().touch();
+            return conversationInfo;
+        }
+
+        return null;
+    }
+
+    /**
+     * Increase one to the "conversation active" counter.
+     *
+     * This is called when a method is invoked on a bean that is within this conversation.
+     * When the method returns, leaveConversation is invoked. The result is that the count
+     * is greater than zero whenever there is a bean belonging to this conversation on
+     * the callstack.
+     */
+    void enterConversation()
+    {
+        synchronized (activeCountMutex)
+        {
+            activeCount++;
+        }
+    }
+
+    /**
+     * decrease one from the "conversation active" counter
+     */
+    void leaveConversation()
+    {
+        synchronized (activeCountMutex)
+        {
+            activeCount--;
+        }
+    }
+
+    /**
+     * check if the conversation is active
+     */
+    private boolean isActive()
+    {
+        synchronized (activeCountMutex)
+        {
+            return activeCount > 0;
+        }
+    }
+
+    ConversationAspects getAspects()
+    {
+        return conversationAspects;
+    }
+
+    /**
+     * Get the aspect corresponding to the given class.
+     * 
+     * @return null if such an aspect has not been attached to this conversation
+     */
+    public ConversationAspect getAspect(Class conversationAspectClass)
+    {
+        return conversationAspects.getAspect(conversationAspectClass);
+    }
+
+    /**
+     * Add an Aspect to this conversation. 
+     * 
+     * See class ConversationAspects for further details.
+     */
+    public void addAspect(ConversationAspect aspect)
+    {
+        conversationAspects.addAspect(aspect);
+    }
 }

Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationAccessLifetimeAspect.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationAccessLifetimeAspect.java?rev=629975&r1=629974&r2=629975&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationAccessLifetimeAspect.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationAccessLifetimeAspect.java Thu Feb 21 12:32:37 2008
@@ -25,18 +25,18 @@
  */
 public class ConversationAccessLifetimeAspect extends ConversationAspect
 {
-	public ConversationAccessLifetimeAspect(Conversation conversation)
-	{
-		super(conversation);
-	}
+    public ConversationAccessLifetimeAspect(Conversation conversation)
+    {
+        super(conversation);
+    }
 
-	public void markAsAccessed()
-	{
-		AccessScopeManager.getInstance().addConversationAccess(getConversation().getName());
-	}
+    public void markAsAccessed()
+    {
+        AccessScopeManager.getInstance().addConversationAccess(getConversation().getName());
+    }
 
-	public boolean isAccessed()
-	{
-		return AccessScopeManager.getInstance().isConversationAccessed(getConversation().getName());
-	}
+    public boolean isAccessed()
+    {
+        return AccessScopeManager.getInstance().isConversationAccessed(getConversation().getName());
+    }
 }

Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationAspect.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationAspect.java?rev=629975&r1=629974&r2=629975&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationAspect.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationAspect.java Thu Feb 21 12:32:37 2008
@@ -25,15 +25,15 @@
  */
 public abstract class ConversationAspect
 {
-	private final Conversation conversation;
+    private final Conversation conversation;
 
-	public ConversationAspect(Conversation conversation)
-	{
-		this.conversation = conversation;
-	}
+    public ConversationAspect(Conversation conversation)
+    {
+        this.conversation = conversation;
+    }
 
-	public Conversation getConversation()
-	{
-		return conversation;
-	}
+    public Conversation getConversation()
+    {
+        return conversation;
+    }
 }

Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationAspects.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationAspects.java?rev=629975&r1=629974&r2=629975&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationAspects.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationAspects.java Thu Feb 21 12:32:37 2008
@@ -45,15 +45,15 @@
  */
 public class ConversationAspects
 {
-	private Map conversationAspects = new HashMap();
+    private Map conversationAspects = new HashMap();
 
-	public void addAspect(ConversationAspect aspect)
-	{
-		conversationAspects.put(aspect.getClass().getName(), aspect);
-	}
+    public void addAspect(ConversationAspect aspect)
+    {
+        conversationAspects.put(aspect.getClass().getName(), aspect);
+    }
 
-	public ConversationAspect getAspect(Class aspectClass)
-	{
-		return (ConversationAspect) conversationAspects.get(aspectClass.getName());
-	}
+    public ConversationAspect getAspect(Class aspectClass)
+    {
+        return (ConversationAspect) conversationAspects.get(aspectClass.getName());
+    }
 }

Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationAware.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationAware.java?rev=629975&r1=629974&r2=629975&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationAware.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationAware.java Thu Feb 21 12:32:37 2008
@@ -30,8 +30,8 @@
  */
 public interface ConversationAware
 {
-	/**
-	 * The conversation the bean implementing this interface belongs to.
-	 */
-	public void setConversation(Conversation conversation);
+    /**
+     * The conversation the bean implementing this interface belongs to.
+     */
+    public void setConversation(Conversation conversation);
 }

Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationBindingEvent.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationBindingEvent.java?rev=629975&r1=629974&r2=629975&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationBindingEvent.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationBindingEvent.java Thu Feb 21 12:32:37 2008
@@ -25,22 +25,22 @@
  */
 public class ConversationBindingEvent
 {
-	private final Conversation conversation;
-	private final String name;
+    private final Conversation conversation;
+    private final String name;
 
-	protected ConversationBindingEvent(Conversation conversation, String name)
-	{
-		this.conversation = conversation;
-		this.name = name;
-	}
+    protected ConversationBindingEvent(Conversation conversation, String name)
+    {
+        this.conversation = conversation;
+        this.name = name;
+    }
 
-	public Conversation getConversation()
-	{
-		return conversation;
-	}
+    public Conversation getConversation()
+    {
+        return conversation;
+    }
 
-	public String getName()
-	{
-		return name;
-	}
+    public String getName()
+    {
+        return name;
+    }
 }

Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationBindingListener.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationBindingListener.java?rev=629975&r1=629974&r2=629975&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationBindingListener.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationBindingListener.java Thu Feb 21 12:32:37 2008
@@ -28,13 +28,13 @@
  */
 public interface ConversationBindingListener
 {
-	/**
-	 * The bean has been added to the conversation.
-	 */
-	public void valueBound(ConversationBindingEvent event);
+    /**
+     * The bean has been added to the conversation.
+     */
+    public void valueBound(ConversationBindingEvent event);
 
-	/**
-	 * The bean has been removed from the conversation.
-	 */
-	public void valueUnbound(ConversationBindingEvent event);
+    /**
+     * The bean has been removed from the conversation.
+     */
+    public void valueUnbound(ConversationBindingEvent event);
 }

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=629975&r1=629974&r2=629975&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 Thu Feb 21 12:32:37 2008
@@ -40,325 +40,325 @@
  */
 public class ConversationContext
 {
-	private final Log log = LogFactory.getLog(ConversationContext.class);
+    private final Log log = LogFactory.getLog(ConversationContext.class);
 
-	// 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;
-
-	// See addAttribute
-	private final Map attributes = new TreeMap();
-
-	// The conversations held by this context, keyed by conversation name.
-	private final Map conversations = new TreeMap();
-
-	// 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)
-	{
-		this.id = id;
-
-		touch();
-	}
-
-	/**
-	 * The conversation context id, unique within the current http session.
-	 */
-	public long getId()
-	{
-		return id;
-	}
-
-	/**
-	 * Mark this context as having been used.
-	 */
-	protected void touch()
-	{
-		lastAccess = System.currentTimeMillis();
-	}
-
-	/**
-	 * The system time in millis when this conversation has been accessed last.
-	 */
-	public long getLastAccess()
-	{
-		return lastAccess;
-	}
-
-	/**
-	 * Get the timeout after which this context will be closed.
-	 *
-	 * @see #setTimeout
-	 */
-	public long getTimeout()
-	{
-		return timeoutMillis;
-	}
-
-	/**
-	 * Set the timeout after which this context will be closed.
-	 * <p>
-	 * A value of -1 means no timeout checking.
-	 */
-	public void setTimeout(long timeoutMillis)
-	{
-		this.timeoutMillis = timeoutMillis;
-	}
-
-	/**
-	 * Invalidate all conversations within this context.
-	 */
-	protected void clear()
-	{
-		synchronized (this)
-		{
-			Conversation[] convArray = new Conversation[conversations.size()];
-			conversations.values().toArray(convArray);
-
-			for (int i = 0; i < convArray.length; i++)
-			{
-				Conversation conversation = convArray[i];
-				conversation.invalidate();
-			}
-
-			conversations.clear();
-		}
-	}
-
-	/**
-	 * Start a conversation if not already started.
-	 */
-	protected Conversation startConversation(String name, ConversationFactory factory)
-	{
-		synchronized (this)
-		{
-			touch();
-			Conversation conversation = (Conversation) conversations.get(name);
-			if (conversation == null)
-			{
-				conversation = factory.createConversation(this, name);
-
-				conversations.put(name, conversation);
-			}
-			return conversation;
-		}
-	}
-
-	/**
-	 * Remove the conversation from this context.
-	 * 
-	 * <p>Notice: It is assumed that the conversation has already been invalidated.</p>
-	 */
-	protected void removeConversation(Conversation conversation)
-	{
-		synchronized (this)
-		{
-			touch();
-			conversations.remove(conversation.getName());
-		}
-	}
-
-	/**
-	 * 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)
-	{
-		synchronized (this)
-		{
-			touch();
-			Conversation conversation = (Conversation) conversations.get(name);
-			if (conversation != null)
-			{
-				removeConversation(conversation);
-			}
-		}
-	}
-
-	/**
-	 * See if there is a conversation with the specified name.
-	 */
-	protected boolean hasConversations()
-	{
-		synchronized (this)
-		{
-			touch();
-			return conversations.size() > 0;
-		}
-	}
-
-	/**
-	 * Check if the given conversation exists.
-	 */
-	protected boolean hasConversation(String name)
-	{
-		synchronized (this)
-		{
-			touch();
-			return conversations.get(name) != null;
-		}
-	}
-
-	/**
-	 * Get a conversation by name.
-	 */
-	protected Conversation getConversation(String name)
-	{
-		synchronized (this)
-		{
-			touch();
-
-			Conversation conv = (Conversation) conversations.get(name);
-			if (conv != null)
-			{
-				conv.touch();
-			}
-
-			return conv;
-		}
-	}
-
-	/**
-	 * Iterates over all the conversations in this context.
-	 *
-	 * @return An iterator over a copy of the conversation list. It is safe to remove objects from
-	 * the conversation list while iterating, as the iterator refers to a different collection.
-	 */
-	public Iterator iterateConversations()
-	{
-		synchronized (this)
-		{
-			touch();
-
-			Conversation[] convs = (Conversation[]) conversations.values().toArray(new Conversation[conversations.size()]);
-			return Arrays.asList(convs).iterator();
-		}
-	}
-
-	/**
-	 * Check the timeout for every conversation in this context.
-	 * <p>
-	 * This method does not check the timeout for this context object itself.
-	 */
-	protected void checkConversationTimeout()
-	{
-		synchronized (this)
-		{
-			Conversation[] convArray = new Conversation[conversations.size()];
-			conversations.values().toArray(convArray);
-
-			for (int i = 0; i < convArray.length; i++)
-			{
-				Conversation conversation = convArray[i];
-
-				ConversationTimeoutableAspect timeoutAspect =
-					(ConversationTimeoutableAspect)
-						conversation.getAspect(ConversationTimeoutableAspect.class);
-
-				if (timeoutAspect != null && timeoutAspect.isTimeoutReached())
-				{
-					if (log.isDebugEnabled())
-					{
-						log.debug("end conversation due to timeout: " + conversation.getName());
-					}
-
-					conversation.invalidate();
-				}
-			}
-		}
-	}
-
-	/**
-	 * Add an attribute to the conversationContext.
-	 * <p>
-	 * A context provides a map into which any arbitrary objects can be stored. It
-	 * isn't a major feature of the context, but can occasionally be useful.
-	 */
-	public void setAttribute(String name, Object attribute)
-	{
-		synchronized(attributes)
-		{
-			attributes.remove(name);
-			attributes.put(name, attribute);
-		}
-	}
-
-	/**
-	 * Check if this conversationContext holds a specific attribute.
-	 */
-	public boolean hasAttribute(String name)
-	{
-		synchronized(attributes)
-		{
-			return attributes.containsKey(name);
-		}
-	}
-
-	/**
-	 * Get a specific attribute.
-	 */
-	public Object getAttribute(String name)
-	{
-		synchronized(attributes)
-		{
-			return attributes.get(name);
-		}
-	}
-
-	/**
-	 * Remove an attribute from the conversationContext.
-	 */
-	public Object removeAttribute(String name)
-	{
-		synchronized(attributes)
-		{
-			return attributes.remove(name);
-		}
-	}
-	
-	/**
-	 * Block until no other thread has this instance marked as reserved, then
-	 * mark the object as reserved for this thread.
-	 * <p>
-	 * It is safe to call this method multiple times.
-	 * <p>
-	 * 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. 
-	 * 
-	 * @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();
-	}
-}
\ No newline at end of file
+    // 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;
+
+    // See addAttribute
+    private final Map attributes = new TreeMap();
+
+    // The conversations held by this context, keyed by conversation name.
+    private final Map conversations = new TreeMap();
+
+    // 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)
+    {
+        this.id = id;
+
+        touch();
+    }
+
+    /**
+     * The conversation context id, unique within the current http session.
+     */
+    public long getId()
+    {
+        return id;
+    }
+
+    /**
+     * Mark this context as having been used.
+     */
+    protected void touch()
+    {
+        lastAccess = System.currentTimeMillis();
+    }
+
+    /**
+     * The system time in millis when this conversation has been accessed last.
+     */
+    public long getLastAccess()
+    {
+        return lastAccess;
+    }
+
+    /**
+     * Get the timeout after which this context will be closed.
+     *
+     * @see #setTimeout
+     */
+    public long getTimeout()
+    {
+        return timeoutMillis;
+    }
+
+    /**
+     * Set the timeout after which this context will be closed.
+     * <p>
+     * A value of -1 means no timeout checking.
+     */
+    public void setTimeout(long timeoutMillis)
+    {
+        this.timeoutMillis = timeoutMillis;
+    }
+
+    /**
+     * Invalidate all conversations within this context.
+     */
+    protected void clear()
+    {
+        synchronized (this)
+        {
+            Conversation[] convArray = new Conversation[conversations.size()];
+            conversations.values().toArray(convArray);
+
+            for (int i = 0; i < convArray.length; i++)
+            {
+                Conversation conversation = convArray[i];
+                conversation.invalidate();
+            }
+
+            conversations.clear();
+        }
+    }
+
+    /**
+     * Start a conversation if not already started.
+     */
+    protected Conversation startConversation(String name, ConversationFactory factory)
+    {
+        synchronized (this)
+        {
+            touch();
+            Conversation conversation = (Conversation) conversations.get(name);
+            if (conversation == null)
+            {
+                conversation = factory.createConversation(this, name);
+
+                conversations.put(name, conversation);
+            }
+            return conversation;
+        }
+    }
+
+    /**
+     * Remove the conversation from this context.
+     * 
+     * <p>Notice: It is assumed that the conversation has already been invalidated.</p>
+     */
+    protected void removeConversation(Conversation conversation)
+    {
+        synchronized (this)
+        {
+            touch();
+            conversations.remove(conversation.getName());
+        }
+    }
+
+    /**
+     * 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)
+    {
+        synchronized (this)
+        {
+            touch();
+            Conversation conversation = (Conversation) conversations.get(name);
+            if (conversation != null)
+            {
+                removeConversation(conversation);
+            }
+        }
+    }
+
+    /**
+     * See if there is a conversation with the specified name.
+     */
+    protected boolean hasConversations()
+    {
+        synchronized (this)
+        {
+            touch();
+            return conversations.size() > 0;
+        }
+    }
+
+    /**
+     * Check if the given conversation exists.
+     */
+    protected boolean hasConversation(String name)
+    {
+        synchronized (this)
+        {
+            touch();
+            return conversations.get(name) != null;
+        }
+    }
+
+    /**
+     * Get a conversation by name.
+     */
+    protected Conversation getConversation(String name)
+    {
+        synchronized (this)
+        {
+            touch();
+
+            Conversation conv = (Conversation) conversations.get(name);
+            if (conv != null)
+            {
+                conv.touch();
+            }
+
+            return conv;
+        }
+    }
+
+    /**
+     * Iterates over all the conversations in this context.
+     *
+     * @return An iterator over a copy of the conversation list. It is safe to remove objects from
+     * the conversation list while iterating, as the iterator refers to a different collection.
+     */
+    public Iterator iterateConversations()
+    {
+        synchronized (this)
+        {
+            touch();
+
+            Conversation[] convs = (Conversation[]) conversations.values().toArray(new Conversation[conversations.size()]);
+            return Arrays.asList(convs).iterator();
+        }
+    }
+
+    /**
+     * Check the timeout for every conversation in this context.
+     * <p>
+     * This method does not check the timeout for this context object itself.
+     */
+    protected void checkConversationTimeout()
+    {
+        synchronized (this)
+        {
+            Conversation[] convArray = new Conversation[conversations.size()];
+            conversations.values().toArray(convArray);
+
+            for (int i = 0; i < convArray.length; i++)
+            {
+                Conversation conversation = convArray[i];
+
+                ConversationTimeoutableAspect timeoutAspect =
+                    (ConversationTimeoutableAspect)
+                        conversation.getAspect(ConversationTimeoutableAspect.class);
+
+                if (timeoutAspect != null && timeoutAspect.isTimeoutReached())
+                {
+                    if (log.isDebugEnabled())
+                    {
+                        log.debug("end conversation due to timeout: " + conversation.getName());
+                    }
+
+                    conversation.invalidate();
+                }
+            }
+        }
+    }
+
+    /**
+     * Add an attribute to the conversationContext.
+     * <p>
+     * A context provides a map into which any arbitrary objects can be stored. It
+     * isn't a major feature of the context, but can occasionally be useful.
+     */
+    public void setAttribute(String name, Object attribute)
+    {
+        synchronized(attributes)
+        {
+            attributes.remove(name);
+            attributes.put(name, attribute);
+        }
+    }
+
+    /**
+     * Check if this conversationContext holds a specific attribute.
+     */
+    public boolean hasAttribute(String name)
+    {
+        synchronized(attributes)
+        {
+            return attributes.containsKey(name);
+        }
+    }
+
+    /**
+     * Get a specific attribute.
+     */
+    public Object getAttribute(String name)
+    {
+        synchronized(attributes)
+        {
+            return attributes.get(name);
+        }
+    }
+
+    /**
+     * Remove an attribute from the conversationContext.
+     */
+    public Object removeAttribute(String name)
+    {
+        synchronized(attributes)
+        {
+            return attributes.remove(name);
+        }
+    }
+    
+    /**
+     * Block until no other thread has this instance marked as reserved, then
+     * mark the object as reserved for this thread.
+     * <p>
+     * It is safe to call this method multiple times.
+     * <p>
+     * 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. 
+     * 
+     * @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();
+    }
+}

Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationFactory.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationFactory.java?rev=629975&r1=629974&r2=629975&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationFactory.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/ConversationFactory.java Thu Feb 21 12:32:37 2008
@@ -26,5 +26,5 @@
  */
 public interface ConversationFactory
 {
-	Conversation createConversation(ConversationContext context, String name);
-}
\ No newline at end of file
+    Conversation createConversation(ConversationContext context, String name);
+}