Package org.jboss.seam.contexts

Source Code of org.jboss.seam.contexts.ServerConversationContext

/*
* JBoss, Home of Professional Open Source �
*
* Distributable under LGPL license.
�* See terms of license at gnu.org. �
*/
package org.jboss.seam.contexts;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.jboss.seam.Component;
import org.jboss.seam.ScopeType;
import org.jboss.seam.Seam;
import org.jboss.seam.annotations.PerNestedConversation;
import org.jboss.seam.core.Events;
import org.jboss.seam.core.Manager;

/**
* A conversation context is a logical context that lasts longer than
* a request but shorter than a login session
*
* @author Gavin King
* @author <a href="mailto:theute@jboss.org">Thomas Heute</a>
* @version $Revision: 1.21 $
*/
public class ServerConversationContext implements Context {

   private final ContextAdaptor session;
   private final Map<String, Object> additions = new HashMap<String, Object>();
   private final Set<String> removals = new HashSet<String>();
   private final String id;
   private final List<String> idStack;
  
   private List<String> getIdStack()
   {
      return idStack==null ? Manager.instance().getCurrentConversationIdStack() : idStack;
   }
  
   private String getId()
   {
      return id==null ? Manager.instance().getCurrentConversationId() : id;
   }
  
   public ScopeType getType()
   {
      return ScopeType.CONVERSATION;
   }

   private String getKey(String name)
   {
      return getPrefix( getId() ) + name;
   }

   private String getKey(String name, String id)
   {
      return getPrefix(id) + name;
   }

   private String getPrefix(String id)
   {
      return ScopeType.CONVERSATION.getPrefix() + '#' + id + '$';
   }

   public ServerConversationContext(ContextAdaptor session)
   {
      this.session = session;
      id = null;
      idStack = null;
   }
     
   public ServerConversationContext(ContextAdaptor session, String id)
   {
      this.session = session;
      this.id = id;
      this.idStack = new LinkedList<String>();
      idStack.add(id);
   }
     
    public Object get(String name)
    {
      Object result = additions.get(name);
      if (result!=null)
      {
         return unwrapEntityBean(result);
      }
      else
      {
         if ( removals.contains(name) )
         {
            return null;
         }
         else
         {
            List<String> stack = getIdStack();
            if (stack==null)
            {
               return unwrapEntityBean( session.getAttribute( getKey(name) ) );
            }
            else
            {
               for ( int i=0; i<stack.size(); i++ )
               {
                  String id = stack.get(i);
                  result = session.getAttribute( getKey(name, id) );

                  if (result != null) {
                      return unwrapEntityBean(result);

                  }

                  // only continue checking if it is not pernestedconversation
                  if (i==0 && isPerNestedConversation(name)) {
                      return null;
                  }
               }
               return null;
            }
         }
      }
    }

    private boolean isPerNestedConversation(String name) {
        Component component = Component.forName(name);
        return (component != null) && component.beanClassHasAnnotation(PerNestedConversation.class);
    }

   private Object unwrapEntityBean(Object result)
   {
      if (result==null) return null;
      if ( result instanceof EntityBean )
      {
         return ( (EntityBean) result ).getInstance();
      }
      else
      {
         return result;
      }
   }

   public void set(String name, Object value)
   {
      if ( Events.exists() ) Events.instance().raiseEvent("org.jboss.seam.preSetVariable." + name);
      if (value==null)
      {
         //yes, we need this
         remove(name);
      }
      else
      {
         removals.remove(name);
         if ( Seam.isEntityClass( value.getClass() ) )
         {
            value = new EntityBean(value);
         }
         additions.put(name, value);
      }
      if ( Events.exists() ) Events.instance().raiseEvent("org.jboss.seam.postSetVariable." + name);
  }

  public boolean isSet(String name)
   {
    return get(name)!=null;
  }
  
  public void remove(String name)
   {
      if ( Events.exists() ) Events.instance().raiseEvent("org.jboss.seam.preRemoveVariable." + name);
      additions.remove(name);
      removals.add(name);
      if ( Events.exists() ) Events.instance().raiseEvent("org.jboss.seam.postRemoveVariable." + name);
  }

   public String[] getNames()
   {
      Set<String> results = getNamesFromSession();
      results.addAll( additions.keySet() ); //after, to override
      return results.toArray(new String[]{});
   }

   private Set<String> getNamesFromSession()
   {
      HashSet<String> results = new HashSet<String>();
      Enumeration names = session.getAttributeNames();
      String prefix = getPrefix( getId() );
      while ( names.hasMoreElements() ) {
         String name = (String) names.nextElement();
         if ( name.startsWith(prefix) && session.getAttribute(name)!=null )
         {
            name = name.substring( prefix.length() );
            if ( !removals.contains(name) ) results.add(name);
         }
      }
      return results;
   }

   public Object get(Class clazz)
   {
      return get( Component.getComponentName(clazz) );
   }
  
   public void clear()
   {
      additions.clear();
      removals.addAll( getNamesFromSession() );
   }
  
   /**
    * Propagate additions and removals to the HttpSession if
    * the current conversation is long-running, or remove all
    * attributes if it is a temporary conversation. This work
    * may only be done at the end of the request, since we
    * don't know for sure the conversation id until then.
    */
   public void flush()
   {     
      boolean longRunning = !isCurrent() || Manager.instance().isLongRunningConversation()
      if ( longRunning )
      {
         //force update for dirty mutable objects
         for ( String name: getNamesFromSession() )
         {
            String key = getKey(name);
            Object attribute = session.getAttribute(key);
            if ( attribute!=null && Lifecycle.isAttributeDirty(attribute) )
            {
               session.setAttribute(key, attribute);
            }
         }
         //remove removed objects
         for (String name: removals)
         {
            session.removeAttribute( getKey(name) );
         }
         removals.clear();
         //add new objects
         for (Map.Entry<String, Object> entry: additions.entrySet())
         {
            session.setAttribute( getKey( entry.getKey() ), entry.getValue() );
         }
         additions.clear();
      }
      else
      {
         //TODO: for a pure temporary conversation, this is unnecessary, optimize it
         for (String name: getNamesFromSession())
         {
            session.removeAttribute( getKey(name) );
         }
      }
   }

   private boolean isCurrent()
   {
      return id==null || id.equals( Manager.instance().getCurrentConversationId() );
   }

   @Override
   public String toString()
   {
      return "ConversationContext(" + getId() + ")";
   }

}
TOP

Related Classes of org.jboss.seam.contexts.ServerConversationContext

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.