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.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.core.Events;
import org.jboss.seam.core.Manager;
import org.jboss.seam.persistence.PersistenceContexts;

/**
* A conversation context is a logical context that lasts longer than
* a request but shorter than a login session. Conversation state
* may be passivated or replicated.
*
* @author Gavin King
* @author <a href="mailto:theute@jboss.org">Thomas Heute</a>
*/
public class ServerConversationContext implements Context
{

   private final Map<String, Object> 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(Map<String, Object> session)
   {
      this.session = session;
      id = null;
      idStack = null;
   }
     
   public ServerConversationContext(Map<String, Object> 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.get( getKey(name) ) );
            }
            else
            {
               for ( int i=0; i<stack.size(); i++ )
               {
                  String id = stack.get(i);
                  result = session.get( 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.isPerNestedConversation();
    }

   private Object unwrapEntityBean(Object result)
   {
      if (result==null) return null;
      if ( result instanceof Wrapper )
      {
         return ( (Wrapper) 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);
         }
         else if ( value instanceof List )
         {
            value = new EntityBeanList( (List) value );
         }
         else if ( value instanceof Map )
         {
            value = new EntityBeanMap( (Map) value );
         }
         else if ( value instanceof Set )
         {
            value = new EntityBeanSet( (Set) 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>();
      
       String prefix = getPrefix(getId());
       for (String name: session.keySet()) {
           if (name.startsWith(prefix)) {
               name = name.substring(prefix.length());
               if (!removals.contains(name)) {
                   results.add(name);
               }
           }
       }

       return results;
   }
  
   private Set<String> getNamesForAllConversationsFromSession()
   {      
       Set<String> results = new HashSet<String>();
      
       List<String> ids = Manager.instance().getCurrentConversationIdStack();
      
       if (ids != null) {
           for (String conversationId: ids) {
               String prefix = getPrefix(conversationId);
               for (String name: session.keySet()) {
                   if (name.startsWith(prefix)) {
                       String shortName = name.substring(prefix.length());
                       if (!removals.contains(shortName)) {
                           results.add(name);
                       }
                   }
               }
           }
       }

       return results;
   }
  

   public Object get(Class clazz)
   {
      return get( Component.getComponentName(clazz) );
   }
  
   public void clear()
   {
      additions.clear();
      removals.addAll( getNamesFromSession() );
   }
  
   public void unflush()
   {
      for ( String key: getNamesForAllConversationsFromSession() )
      {
         Object attribute = session.get(key);
         if ( attribute!=null && attribute instanceof Wrapper )
         {
            ( (Wrapper) attribute ).activate();
         }
      }
   }
  
   /**
    * 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 key: getNamesForAllConversationsFromSession())  {
              Object attribute = session.get(key);
             
              if (attribute!=null) {
                  if (passivate(attribute) || isAttributeDirty(attribute)) {
                      session.put(key, attribute);
                  }
              }
          }
   
          //remove removed objects
          for (String name: removals) {
              session.remove(getKey(name));
          }
          removals.clear();

          // TODO this is a hack! We should find a more elegant way of handling
          // new objects being added to additions during the following for-loop
          PersistenceContexts.instance();
         
          //add new objects
          for (Map.Entry<String, Object> entry: additions.entrySet())  {
              Object attribute = entry.getValue();
             
              passivate(attribute);
              session.put(getKey(entry.getKey()), attribute);
          }
          additions.clear();
      }
      else
      {
         //TODO: for a pure temporary conversation, this is unnecessary, optimize it
         for ( String name: getNamesFromSession() )
         {
            session.remove( getKey(name) );
         }
      }
   }

    private boolean passivate(Object attribute) {
        if (attribute instanceof Wrapper) {
            return ((Wrapper) attribute).passivate();
        } else {
            return false;
        }
    }
   
    private boolean isAttributeDirty(Object attribute) {
        return Contexts.isAttributeDirty(attribute);
    }
   
   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.