[exo-jcr-commits] exo-jcr SVN: r5411 - in jcr/branches/1.15.x/exo.jcr.component.core/src: main/java/org/exoplatform/services/jcr/impl/core and 2 other directories.

do-not-reply at jboss.org do-not-reply at jboss.org
Fri Dec 30 05:09:40 EST 2011


Author: andrew.plotnikov
Date: 2011-12-30 05:09:39 -0500 (Fri, 30 Dec 2011)
New Revision: 5411

Modified:
   jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/dataflow/PlainChangesLogImpl.java
   jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/dataflow/TransactionChangesLog.java
   jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/SessionDataManager.java
   jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/session/SessionChangesLog.java
   jcr/branches/1.15.x/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/version/TestFrozenNodeInitializer.java
Log:
EXOJCR-1336: Improved TransactionChangesLog

Modified: jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/dataflow/PlainChangesLogImpl.java
===================================================================
--- jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/dataflow/PlainChangesLogImpl.java	2011-12-30 09:54:01 UTC (rev 5410)
+++ jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/dataflow/PlainChangesLogImpl.java	2011-12-30 10:09:39 UTC (rev 5411)
@@ -19,6 +19,12 @@
 package org.exoplatform.services.jcr.dataflow;
 
 import org.exoplatform.services.jcr.core.ExtendedSession;
+import org.exoplatform.services.jcr.datamodel.IllegalPathException;
+import org.exoplatform.services.jcr.datamodel.ItemData;
+import org.exoplatform.services.jcr.datamodel.ItemType;
+import org.exoplatform.services.jcr.datamodel.NodeData;
+import org.exoplatform.services.jcr.datamodel.QPath;
+import org.exoplatform.services.jcr.datamodel.QPathEntry;
 import org.exoplatform.services.jcr.impl.Constants;
 
 import java.io.Externalizable;
@@ -26,7 +32,10 @@
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Created by The eXo Platform SAS.
@@ -37,21 +46,86 @@
  */
 public class PlainChangesLogImpl implements Externalizable, PlainChangesLog
 {
+   /**
+    * Constant null value
+    */
    private static final int NULL_VALUE = -1;
 
+   /**
+    * Constant not null value
+    */
    private static final int NOT_NULL_VALUE = 1;
 
+   /**
+    * Constant serial Version UID
+    */
    private static final long serialVersionUID = 5624550860372364084L;
 
+   /**
+    * Collect of all item 
+    */
    protected List<ItemState> items;
 
+   /**
+    * Value session id
+    */
    protected String sessionId;
 
+   /**
+    * Value event type
+    */
    protected int eventType;
 
+   /**
+    * Value session
+    */
    protected ExtendedSession session;
 
    /**
+    * ItemState index storage. Used in getItemState() by id and path.
+    */
+   protected Map<Object, ItemState> index = new HashMap<Object, ItemState>();
+
+   /**
+    * ItemState index storage. Used to store last child nodes states. 
+    */
+   protected Map<String, Map<String, ItemState>> lastChildNodeStates = new HashMap<String, Map<String, ItemState>>();
+
+   /**
+    * ItemState index storage. Used to store last child properties states.  
+    */
+   protected Map<String, Map<String, ItemState>> lastChildPropertyStates =
+      new HashMap<String, Map<String, ItemState>>();
+
+   /**
+    * ItemState index storage. Used to store child nodes states.
+    */
+   protected Map<String, List<ItemState>> childNodeStates = new HashMap<String, List<ItemState>>();
+
+   /**
+    * ItemState index storage. Used to store child properties states.
+    */
+   protected Map<String, List<ItemState>> childPropertyStates = new HashMap<String, List<ItemState>>();
+
+   /**
+    * Stores info for persisted child nodes by parent identifier. 
+    * <br>Index in array points to: 
+    * <br>0 - child nodes count. 
+    * <br>1 - last child order number 
+    */
+   protected Map<String, int[]> childNodesInfo = new HashMap<String, int[]>();
+
+   /** 
+    * Index in <code>childNodesInfo<code> value array to store child nodes count. 
+   */
+   protected final int CHILD_NODES_COUNT = 0;
+
+   /** 
+    * Index in <code>childNodesInfo<code> value array to store last child order number. 
+    */
+   protected final int CHILD_NODES_LAST_ORDER_NUMBER = 1;
+
+   /**
     * Identifier of system and non-system logs pair. Null if no pair found. 
     */
    protected String pairId;
@@ -92,7 +166,7 @@
    }
 
    /**
-    * An empty log.
+    * PlainChangesLogImpl constructor with an empty log.
     * 
     * @param session Session 
     */
@@ -102,7 +176,7 @@
    }
 
    /**
-    * An empty log.
+    * PlainChangesLogImpl constructor with an empty log.
     * 
     * @param sessionId String
     */
@@ -112,47 +186,39 @@
    }
 
    /**
-    * default constructor (for externalizable mainly)
+    * Default PlainChangesLogImpl constructor with an empty log. constructor (for externalizable mainly)
     */
    public PlainChangesLogImpl()
    {
       this(new ArrayList<ItemState>(), (String)null, -1);
    }
 
-   /*
-    * (non-Javadoc)
-    * 
-    * @see org.exoplatform.services.jcr.dataflow.ItemDataChangesLog#getAllStates()
+   /**
+    * {@inheritDoc}
     */
    public List<ItemState> getAllStates()
    {
       return items;
    }
 
-   /*
-    * (non-Javadoc)
-    * 
-    * @see org.exoplatform.services.jcr.dataflow.ItemDataChangesLog#getSize()
+   /**
+    * {@inheritDoc}
     */
    public int getSize()
    {
       return items.size();
    }
 
-   /*
-    * (non-Javadoc)
-    * 
-    * @see org.exoplatform.services.jcr.dataflow.PlainChangesLog#getEventType()
+   /**
+    * {@inheritDoc}
     */
    public int getEventType()
    {
       return eventType;
    }
 
-   /*
-    * (non-Javadoc)
-    * 
-    * @see org.exoplatform.services.jcr.dataflow.ItemDataChangesLog#getSessionId()
+   /**
+    * {@inheritDoc}
     */
    public String getSessionId()
    {
@@ -167,50 +233,56 @@
       return session;
    }
 
-   /*
-    * (non-Javadoc)
-    * 
-    * @see org.exoplatform.services.jcr.dataflow.PlainChangesLog#add(org.exoplatform.services.jcr.dataflow
-    *      .ItemState)
+   /**
+    * {@inheritDoc}
     */
    public PlainChangesLog add(ItemState change)
    {
       items.add(change);
+      addItem(change);
+
       return this;
    }
 
-   /*
-    * (non-Javadoc)
-    * 
-    * @see org.exoplatform.services.jcr.dataflow.PlainChangesLog#addAll(java.util.List)
+   /**
+    * {@inheritDoc}
     */
    public PlainChangesLog addAll(List<ItemState> changes)
    {
       items.addAll(changes);
+      for (int i = 0, length = changes.size(); i < length; i++)
+      {
+         addItem(changes.get(i));
+      }
+
       return this;
    }
 
-   /*
-    * (non-Javadoc)
-    * 
-    * @see org.exoplatform.services.jcr.dataflow.PlainChangesLog#clear()
+   /**
+    * {@inheritDoc}
     */
    public void clear()
    {
       items.clear();
+      index.clear();
+      lastChildNodeStates.clear();
+      lastChildPropertyStates.clear();
+      childNodeStates.clear();
+      childPropertyStates.clear();
+      childNodesInfo.clear();
    }
 
    /**
-    * Return pair Id for linked logs (when original log splitted into two, for system and non-system workspaces).
-    *
-    * @return String
-    *           pair identifier 
+    * {@inheritDoc}
     */
    public String getPairId()
    {
       return pairId;
    }
 
+   /**
+    * {@inheritDoc}
+    */
    public String dump()
    {
       StringBuilder str = new StringBuilder("ChangesLog: \n");
@@ -238,11 +310,12 @@
    protected PlainChangesLogImpl(List<ItemState> items, String sessionId, int eventType, String pairId,
       ExtendedSession session)
    {
-      this.items = items;
       this.session = session;
       this.sessionId = sessionId;
       this.eventType = eventType;
       this.pairId = pairId;
+      this.items = new ArrayList<ItemState>();
+      addAll(items);
    }
 
    /**
@@ -276,6 +349,622 @@
       return new PlainChangesLogImpl(items, originalLog.getSessionId(), originalLog.getEventType(), pairId, null);
    }
 
+   /**
+    * Adds item to the changes log.
+    * 
+    * @param item
+    *          the item
+    */
+   protected void addItem(ItemState item)
+   {
+      index.put(item.getData().getIdentifier(), item);
+      index.put(item.getData().getQPath(), item);
+      index.put(new ParentIDQPathBasedKey(item), item);
+      index.put(new IDStateBasedKey(item.getData().getIdentifier(), item.getState()), item);
+
+      if (item.getData().isNode())
+      {
+         Map<String, ItemState> children = lastChildNodeStates.get(item.getData().getParentIdentifier());
+         if (children == null)
+         {
+            children = new HashMap<String, ItemState>();
+            lastChildNodeStates.put(item.getData().getParentIdentifier(), children);
+         }
+         children.put(item.getData().getIdentifier(), item);
+
+         List<ItemState> listItemState = childNodeStates.get(item.getData().getParentIdentifier());
+         if (listItemState == null)
+         {
+            listItemState = new ArrayList<ItemState>();
+            childNodeStates.put(item.getData().getParentIdentifier(), listItemState);
+         }
+         listItemState.add(item);
+      }
+      else
+      {
+         Map<String, ItemState> children = lastChildPropertyStates.get(item.getData().getParentIdentifier());
+         if (children == null)
+         {
+            children = new HashMap<String, ItemState>();
+            lastChildPropertyStates.put(item.getData().getParentIdentifier(), children);
+         }
+         children.put(item.getData().getIdentifier(), item);
+
+         List<ItemState> listItemState = childPropertyStates.get(item.getData().getParentIdentifier());
+         if (listItemState == null)
+         {
+            listItemState = new ArrayList<ItemState>();
+            childPropertyStates.put(item.getData().getParentIdentifier(), listItemState);
+         }
+         listItemState.add(item);
+      }
+
+      if (item.isNode() && item.isPersisted())
+      {
+         int[] childInfo = childNodesInfo.get(item.getData().getParentIdentifier());
+         if (childInfo == null)
+         {
+            childInfo = new int[2];
+         }
+
+         if (item.isDeleted())
+         {
+            --childInfo[CHILD_NODES_COUNT];
+         }
+         else if (item.isAdded())
+         {
+            ++childInfo[CHILD_NODES_COUNT];
+            childInfo[CHILD_NODES_LAST_ORDER_NUMBER] = ((NodeData)item.getData()).getOrderNumber();
+
+         }
+         childNodesInfo.put(item.getData().getParentIdentifier(), childInfo);
+      }
+   }
+
+   public int getChildNodesCount(String rootIdentifier)
+   {
+      int[] childInfo = childNodesInfo.get(rootIdentifier);
+      return childInfo == null ? 0 : childInfo[CHILD_NODES_COUNT];
+   }
+
+   public int getLastChildOrderNumber(String rootIdentifier)
+   {
+      int[] childInfo = childNodesInfo.get(rootIdentifier);
+      return childInfo == null ? -1 : childInfo[CHILD_NODES_LAST_ORDER_NUMBER];
+   }
+
+   /**
+    * Removes the item at the rootPath and all descendants from the log
+    * 
+    * @param root
+    *          path
+    */
+   public void remove(QPath rootPath)
+   {
+      for (int i = items.size() - 1; i >= 0; i--)
+      {
+         ItemState item = items.get(i);
+
+         QPath qPath = item.getData().getQPath();
+         if (qPath.isDescendantOf(rootPath) || item.getAncestorToSave().isDescendantOf(rootPath)
+            || item.getAncestorToSave().equals(rootPath) || qPath.equals(rootPath))
+         {
+            items.remove(i);
+            index.remove(item.getData().getIdentifier());
+            index.remove(item.getData().getQPath());
+            index.remove(new ParentIDQPathBasedKey(item));
+            index.remove(new IDStateBasedKey(item.getData().getIdentifier(), item.getState()));
+            childNodesInfo.remove(item.getData().getIdentifier());
+            lastChildNodeStates.remove(item.getData().getIdentifier());
+            lastChildPropertyStates.remove(item.getData().getIdentifier());
+            childNodeStates.remove(item.getData().getIdentifier());
+            childPropertyStates.remove(item.getData().getIdentifier());
+
+            if (item.isNode() && item.isPersisted())
+            {
+               
+               int childInfo[] = childNodesInfo.get(item.getData().getParentIdentifier());
+               
+               if (childInfo != null)
+               {
+                  if (item.isDeleted())
+                  {
+                     ++childInfo[CHILD_NODES_COUNT];
+                  }
+                  else if (item.isAdded())
+                  {
+                     --childInfo[CHILD_NODES_COUNT];
+                  }
+
+                  childNodesInfo.put(item.getData().getParentIdentifier(), childInfo);
+               }
+            }
+
+            if (item.getData().isNode())
+            {
+               Map<String, ItemState> children = lastChildNodeStates.get(item.getData().getParentIdentifier());
+               if (children != null)
+               {
+                  children.remove(item.getData().getIdentifier());
+               }
+
+               List<ItemState> listItemStates = childNodeStates.get(item.getData().getParentIdentifier());
+               if (listItemStates != null)
+               {
+                  listItemStates.remove(item);
+               }
+            }
+            else
+            {
+               Map<String, ItemState> children = lastChildPropertyStates.get(item.getData().getParentIdentifier());
+               if (children != null)
+               {
+                  children.remove(item.getData().getIdentifier());
+               }
+
+               List<ItemState> listItemStates = childPropertyStates.get(item.getData().getParentIdentifier());
+               if (listItemStates != null)
+               {
+                  listItemStates.remove(item);
+               }
+            }
+         }
+      }
+   }
+
+   /**
+    * Collect last in ChangesLog order item child changes.
+    * 
+    * @param rootData
+    *          - a item root of the changes scan
+    * @param forNodes
+    *          retrieves nodes' ItemStates is true, or properties' otherwise
+    * @return child items states
+    */
+   public Collection<ItemState> getLastChildrenStates(ItemData rootData, boolean forNodes)
+   {
+      Map<String, ItemState> children =
+         forNodes ? lastChildNodeStates.get(rootData.getIdentifier()) : lastChildPropertyStates.get(rootData
+            .getIdentifier());
+
+      return children == null ? new ArrayList<ItemState>() : children.values();
+   }
+
+   /**
+    * Return the last item state from ChangesLog.
+    *  
+    * @param item 
+    *          an item data the last state which need to be taken
+    * @param forNode 
+    *          retrieves nodes' ItemStates is true, or properties' otherwise
+    * @return the last item state
+    */
+   public ItemState getLastState(ItemData item, boolean forNode)
+   {
+      Map<String, ItemState> children =
+         forNode ? lastChildNodeStates.get(item.getParentIdentifier()) : lastChildPropertyStates.get(item
+            .getParentIdentifier());
+
+      return children == null ? null : children.get(item.getIdentifier());
+   }
+   /**
+    * Collect changes of all item direct childs. Including the item itself.
+    * @param rootIdentifier root identifier
+    * @param forNodes must be returned nodes or properties
+    * @return Collect changes of all item direct childs
+    */
+   public List<ItemState> getChildrenChanges(String rootIdentifier, boolean forNodes)
+   {
+      List<ItemState> children =
+         forNodes ? childNodeStates.get(rootIdentifier) : childPropertyStates.get(rootIdentifier);
+
+      return children == null ? new ArrayList<ItemState>() : children;
+   }
+
+   /**
+    * Get ItemState by identifier and state.
+    * 
+    * NOTE: Uses index HashMap.
+    * 
+    * @param itemIdentifier
+    * @param sate
+    * @return
+    */
+   public ItemState getItemState(String itemIdentifier, int state)
+   {
+      return index.get(new IDStateBasedKey(itemIdentifier, state));
+   }
+
+   /**
+    * Get ItemState by identifier
+    * @param itemIdentifier
+    * @return
+    */
+   public ItemState getItemState(String itemIdentifier)
+   {
+      return index.get(itemIdentifier);
+   }
+
+   /**
+    * Get ItemState by absolute path.
+    * 
+    * NOTE: Uses index HashMap.
+    * 
+    * @param itemPath
+    * @return
+    */
+   public ItemState getItemState(QPath itemPath)
+   {
+      return index.get(itemPath);
+   }
+
+   /**
+    * Get ItemState by parent and item name.
+    * 
+    * @param parentData
+    *          parent
+    * @param name
+    *          item name
+    * @param itemType
+    *          item type
+    * @return
+    * @throws IllegalPathException
+    */
+   public ItemState getItemState(NodeData parentData, QPathEntry name, ItemType itemType) throws IllegalPathException
+   {
+      if (itemType != ItemType.UNKNOWN)
+      {
+         return index.get(new ParentIDQPathBasedKey(parentData.getIdentifier(), name, itemType));
+      }
+      else
+      {
+         ItemState state = index.get(new ParentIDQPathBasedKey(parentData.getIdentifier(), name, ItemType.NODE));
+         if (state == null)
+         {
+            state = index.get(new ParentIDQPathBasedKey(parentData.getIdentifier(), name, ItemType.PROPERTY));
+         }
+         return state;
+      }
+   }
+
+   /**
+    * @param rootPath
+    * @return item state at the rootPath and its descendants
+    */
+   public List<ItemState> getDescendantsChanges(QPath rootPath)
+   {
+      List<ItemState> list = new ArrayList<ItemState>();
+      if (rootPath.equals(Constants.ROOT_PATH))
+      {
+         list.addAll(items);
+      }
+      else
+      {
+         for (int i = 0, length = items.size(); i < length; i++)
+         {
+            ItemState item = items.get(i);
+            if (item.isDescendantOf(rootPath))
+            {
+               list.add(item);
+            }
+         }
+      }
+
+      return list;
+   }
+
+   /**
+    * Gets items by identifier.
+    *
+    * @param itemIdentifier
+    * @return
+    */
+   public List<ItemState> getItemStates(String itemIdentifier)
+   {
+      List<ItemState> states = new ArrayList<ItemState>();
+      List<ItemState> currentStates = getAllStates();
+      for (int i = 0, length = currentStates.size(); i < length; i++)
+      {
+         ItemState state = currentStates.get(i);
+         if (state.getData().getIdentifier().equals(itemIdentifier))
+         {
+            states.add(state);
+         }
+      }
+      return states;
+   }
+
+   /**
+    * Collect last in ChangesLog order node (and direct childs) changes.
+    * 
+    * @param rootData
+    *          - a item root of the changes scan
+    * @return this item (!) and child items last modify states (i.e. updates, not adds or deletes)
+    */
+   public Collection<ItemState> getLastModifyStates(NodeData rootData)
+   {
+      HashMap<String, ItemState> changes = new HashMap<String, ItemState>();
+
+      for (int i = 0; i < items.size(); i++)
+      {
+         ItemData item = items.get(i).getData();
+         if (item.getIdentifier().equals(rootData.getIdentifier()))
+         {
+            // the node
+            if (items.get(i).isAdded())
+            {
+               // if a new item - no modify changes can be
+               return new ArrayList<ItemState>();
+            }
+
+            if (!items.get(i).isDeleted())
+            {
+               changes.put(item.getIdentifier(), items.get(i));
+            }
+         }
+         else if (item.getParentIdentifier().equals(rootData.getIdentifier()))
+         {
+            // childs
+            changes.put(item.getIdentifier(), items.get(i));
+         }
+      }
+
+      return changes.values();
+   }
+
+   /**
+    * Search for an item state of item with given id and filter parameters.
+    * 
+    * @param id
+    *          - item id
+    * @param states
+    *          - filter only the given list states (ORed), or all if it's null
+    * @param isPersisted
+    *          - filter only persisted/not persisted, or all if it's null
+    * @param orAncestor
+    *          - may return the item ancestor if true and the ancestor was changed last, or only item
+    *          with given path if it's null
+    * @return - filtered {@link ItemState}
+    * @throws IllegalPathException
+    */
+   public ItemState findItemState(String id, Boolean isPersisted, int... states) throws IllegalPathException
+   {
+      List<ItemState> allStates = getAllStates();
+      // search from the end for state
+      for (int i = allStates.size() - 1; i >= 0; i--)
+      {
+         ItemState istate = allStates.get(i);
+         boolean byState = false;
+         if (states != null)
+         {
+            for (int state : states)
+            {
+               if (istate.getState() == state)
+               {
+                  byState = true;
+                  break;
+               }
+            }
+         }
+         else
+         {
+            byState = true;
+         }
+         if (byState && (isPersisted != null ? istate.isPersisted() == isPersisted : true)
+            && istate.getData().getIdentifier().equals(id))
+         {
+            return istate;
+         }
+      }
+      return null;
+   }
+
+   /**
+    * This class is used as a key for index map.
+    */
+   protected class IDStateBasedKey
+   {
+
+      /**
+       * Item identifier.
+       */
+      private final String identifier;
+
+      /**
+       * Item state.
+       */
+      private final int state;
+
+      /**
+       * KeyUUIDState  constructor.
+       *
+       * @param identifier
+       *          item identifier
+       * @param state
+       *          item state
+       */
+      public IDStateBasedKey(String identifier, int state)
+      {
+         this.identifier = identifier;
+         this.state = state;
+      }
+
+      /**
+       * {@inheritDoc}
+       */
+      @Override
+      public int hashCode()
+      {
+         final int prime = 31;
+         int result = 1;
+         result = prime * result + identifier.hashCode();
+         result = prime * result + state;
+
+         return result;
+      }
+
+      /**
+       * {@inheritDoc}
+       */
+      @Override
+      public boolean equals(Object obj)
+      {
+         if (this == obj)
+         {
+            return true;
+         }
+         if (obj == null)
+         {
+            return false;
+         }
+         if (getClass() != obj.getClass())
+         {
+            return false;
+         }
+         IDStateBasedKey other = (IDStateBasedKey)obj;
+
+         if (identifier == null)
+         {
+            if (other.identifier != null)
+            {
+               return false;
+            }
+         }
+         else if (!identifier.equals(other.identifier))
+         {
+            return false;
+         }
+         if (state != other.state)
+         {
+            return false;
+         }
+         return true;
+      }
+   }
+
+   /**
+    * This class is used as a key for index map.
+    */
+   protected class ParentIDQPathBasedKey
+   {
+      /**
+       * Item name.
+       */
+      private final QPathEntry name;
+
+      /**
+       * Parent identifier.
+       */
+      private final String parentIdentifier;
+
+      private final ItemType itemType;
+
+      /**
+       * KeyParentUUIDQPath  constructor.
+       *
+       * @param item
+       *          the item
+       */
+      public ParentIDQPathBasedKey(ItemState item)
+      {
+         this.name = item.getData().getQPath().getEntries()[item.getData().getQPath().getEntries().length - 1];
+         this.parentIdentifier = item.getData().getParentIdentifier();
+         this.itemType = ItemType.getItemType(item.getData());
+      }
+
+      /**
+       * KeyParentUUIDQPath  constructor.
+       *
+       * @param parentIdentifier
+       *          the parent identifier
+       * @param name
+       *          item name
+       */
+      ParentIDQPathBasedKey(String parentIdentifier, QPathEntry name, ItemType itemType)
+      {
+         this.name = name;
+         this.parentIdentifier = parentIdentifier;
+         this.itemType = itemType;
+      }
+
+      /**
+       * {@inheritDoc}
+       */
+      @Override
+      public int hashCode()
+      {
+         final int prime = 31;
+         int result = 1;
+         result = prime * result + name.getName().hashCode();
+         result = prime * result + name.getNamespace().hashCode();
+         result = prime * result + name.getIndex();
+         result = prime * result + (parentIdentifier == null ? 0 : parentIdentifier.hashCode());
+         result = prime * result + itemType.ordinal();
+
+         return result;
+      }
+
+      /**
+       * {@inheritDoc}
+       */
+      @Override
+      public boolean equals(Object obj)
+      {
+         if (this == obj)
+         {
+            return true;
+         }
+         if (obj == null)
+         {
+            return false;
+         }
+         if (getClass() != obj.getClass())
+         {
+            return false;
+         }
+         ParentIDQPathBasedKey other = (ParentIDQPathBasedKey)obj;
+
+         if (name == null)
+         {
+            if (other.name != null)
+            {
+               return false;
+            }
+         }
+         else if (!name.getName().equals(other.name.getName())
+            || !name.getNamespace().equals(other.name.getNamespace()) || name.getIndex() != other.name.getIndex())
+         {
+            return false;
+         }
+
+         if (parentIdentifier == null)
+         {
+            if (other.parentIdentifier != null)
+            {
+               return false;
+            }
+         }
+         else if (!parentIdentifier.equals(other.parentIdentifier))
+         {
+            return false;
+         }
+
+         if (itemType == null)
+         {
+            if (other.itemType != null)
+            {
+               return false;
+            }
+         }
+         else if (!itemType.equals(other.itemType))
+         {
+            return false;
+         }
+
+         return true;
+      }
+   }
+
    // Need for Externalizable
    // ------------------ [ BEGIN ] ------------------
 

Modified: jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/dataflow/TransactionChangesLog.java
===================================================================
--- jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/dataflow/TransactionChangesLog.java	2011-12-30 09:54:01 UTC (rev 5410)
+++ jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/dataflow/TransactionChangesLog.java	2011-12-30 10:09:39 UTC (rev 5411)
@@ -18,7 +18,7 @@
  */
 package org.exoplatform.services.jcr.dataflow;
 
-import org.exoplatform.services.jcr.datamodel.ItemData;
+import org.exoplatform.services.jcr.datamodel.IllegalPathException;
 import org.exoplatform.services.jcr.datamodel.ItemType;
 import org.exoplatform.services.jcr.datamodel.NodeData;
 import org.exoplatform.services.jcr.datamodel.QPathEntry;
@@ -37,7 +37,6 @@
  * @author Gennady Azarenkov
  * @version $Id: TransactionChangesLog.java 11907 2008-03-13 15:36:21Z ksm $
  */
-
 public class TransactionChangesLog implements CompositeChangesLog, Externalizable
 {
 
@@ -74,10 +73,8 @@
       changesLogs.remove(log);
    }
 
-   /*
-    * (non-Javadoc)
-    * 
-    * @see org.exoplatform.services.jcr.dataflow.CompositeChangesLog#getLogIterator()
+   /**
+    * {@inheritDoc}
     */
    public ChangesLogIterator getLogIterator()
    {
@@ -133,26 +130,35 @@
 
    public ItemState getItemState(String itemIdentifier)
    {
-      List<ItemState> allStates = getAllStates();
-      for (int i = allStates.size() - 1; i >= 0; i--)
+      ItemState state;
+      for (PlainChangesLog changesLog : changesLogs)
       {
-         ItemState state = allStates.get(i);
-         if (state.getData().getIdentifier().equals(itemIdentifier))
+         state = ((PlainChangesLogImpl)changesLog).getItemState(itemIdentifier);
+         if (state != null)
+         {
             return state;
+         }
       }
       return null;
    }
 
    public ItemState getItemState(NodeData parentData, QPathEntry name, ItemType itemType)
    {
-      List<ItemState> allStates = getAllStates();
-      for (int i = allStates.size() - 1; i >= 0; i--)
+      ItemState state;
+      for (PlainChangesLog changesLog : changesLogs)
       {
-         ItemState state = allStates.get(i);
-         if (state.getData().getParentIdentifier().equals(parentData.getIdentifier())
-            && state.getData().getQPath().getEntries()[state.getData().getQPath().getEntries().length - 1].isSame(name)
-            && itemType.isSuitableFor(state.getData()))
-            return state;
+         try
+         {
+            state = ((PlainChangesLogImpl)changesLog).getItemState(parentData, name, itemType);
+            if (state != null)
+            {
+               return state;
+            }
+         }
+         catch (IllegalPathException e)
+         {
+
+         }
       }
       return null;
    }
@@ -160,13 +166,10 @@
    public List<ItemState> getChildrenChanges(String rootIdentifier, boolean forNodes)
    {
       List<ItemState> list = new ArrayList<ItemState>();
-      for (ItemState state : getAllStates())
+      for (PlainChangesLog changesLog : changesLogs)
       {
-         ItemData item = state.getData();
-         if (item.getParentIdentifier().equals(rootIdentifier) && item.isNode() == forNodes)
-         {
-            list.add(state);
-         }
+         List<ItemState> subList = ((PlainChangesLogImpl)changesLog).getChildrenChanges(rootIdentifier, forNodes);
+         list.addAll(subList);
       }
       return list;
    }

Modified: jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/SessionDataManager.java
===================================================================
--- jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/SessionDataManager.java	2011-12-30 09:54:01 UTC (rev 5410)
+++ jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/SessionDataManager.java	2011-12-30 10:09:39 UTC (rev 5411)
@@ -817,11 +817,11 @@
          return nodeChanges.size() > 0;
       }
 
-      List<ItemState> states = changesLog.getItemStates(item.getIdentifier());
-      if (states.size() > 0)
+      ItemState state = changesLog.getLastState(item, false);
+
+      if (state != null)
       {
-         ItemState lastState = states.get(states.size() - 1);
-         if (lastState.isAdded() || lastState.isDeleted())
+         if (state.isAdded() || state.isDeleted())
          {
             return false;
          }

Modified: jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/session/SessionChangesLog.java
===================================================================
--- jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/session/SessionChangesLog.java	2011-12-30 09:54:01 UTC (rev 5410)
+++ jcr/branches/1.15.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/session/SessionChangesLog.java	2011-12-30 10:09:39 UTC (rev 5411)
@@ -22,17 +22,9 @@
 import org.exoplatform.services.jcr.dataflow.ItemState;
 import org.exoplatform.services.jcr.dataflow.PlainChangesLog;
 import org.exoplatform.services.jcr.dataflow.PlainChangesLogImpl;
-import org.exoplatform.services.jcr.datamodel.IllegalPathException;
-import org.exoplatform.services.jcr.datamodel.ItemData;
-import org.exoplatform.services.jcr.datamodel.ItemType;
-import org.exoplatform.services.jcr.datamodel.NodeData;
 import org.exoplatform.services.jcr.datamodel.QPath;
-import org.exoplatform.services.jcr.datamodel.QPathEntry;
 import org.exoplatform.services.jcr.impl.Constants;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -47,40 +39,6 @@
 {
 
    /**
-    * ItemState index storage. Used in getItemState() by id and path.
-    */
-   protected Map<Object, ItemState> index = new HashMap<Object, ItemState>();
-
-   /**
-    * ItemState index storage. Used to store last nodes states. 
-    */
-   protected Map<String, Map<String, ItemState>> lastChildNodeStates = new HashMap<String, Map<String, ItemState>>();
-
-   /**
-    * ItemState index storage. Used to store last properties states.  
-    */
-   protected Map<String, Map<String, ItemState>> lastChildPropertyStates =
-      new HashMap<String, Map<String, ItemState>>();
-
-   /**
-    * Stores info for persisted child nodes by parent identifier. 
-    * <br>Index in array points to: 
-    * <br>0 - child nodes count. 
-    * <br>1 - last child order number 
-    */
-   protected Map<String, int[]> childNodesInfo = new HashMap<String, int[]>();
-
-   /** 
-    * Index in <code>childNodesInfo<code> value array to store child nodes count. 
-   */
-   protected final int CHILD_NODES_COUNT_INDEX = 0;
-
-   /** 
-    * Index in <code>childNodesInfo<code> value array to store last child order number. 
-    */
-   protected final int CHILD_NODES_LAST_ORDER_NUMBER_INDEX = 1;
-
-   /**
     * Create empty ChangesLog.
     * 
     * @param sessionId
@@ -107,149 +65,6 @@
    }
 
    /**
-    * {@inheritDoc}
-    */
-   @Override
-   public PlainChangesLog add(ItemState change)
-   {
-      super.add(change);
-      addItem(change);
-
-      return this;
-   }
-
-   /**
-    * {@inheritDoc}
-    */
-   @Override
-   public PlainChangesLog addAll(List<ItemState> changes)
-   {
-      super.addAll(changes);
-      for (int i = 0, length = changes.size(); i < length; i++)
-      {
-         ItemState change = changes.get(i);
-         addItem(change);
-      }
-      return this;
-   }
-
-   /**
-    * {@inheritDoc}
-    */
-   @Override
-   public void clear()
-   {
-      super.clear();
-      index.clear();
-      lastChildNodeStates.clear();
-      lastChildPropertyStates.clear();
-      childNodesInfo.clear();
-   }
-
-   /**
-    * Removes the item at the rootPath and all descendants from the log
-    * 
-    * @param root
-    *          path
-    */
-   public void remove(QPath rootPath)
-   {
-      for (int i = items.size() - 1; i >= 0; i--)
-      {
-         ItemState item = items.get(i);
-
-         QPath qPath = item.getData().getQPath();
-         if (qPath.isDescendantOf(rootPath) || item.getAncestorToSave().isDescendantOf(rootPath)
-            || item.getAncestorToSave().equals(rootPath) || qPath.equals(rootPath))
-         {
-            items.remove(i);
-            index.remove(item.getData().getIdentifier());
-            index.remove(item.getData().getQPath());
-            index.remove(new ParentIDQPathBasedKey(item));
-            index.remove(new IDStateBasedKey(item.getData().getIdentifier(), item.getState()));
-            childNodesInfo.remove(item.getData().getIdentifier());
-            lastChildNodeStates.remove(item.getData().getIdentifier());
-            lastChildPropertyStates.remove(item.getData().getIdentifier());
-
-            if (item.isNode() && item.isPersisted())
-            {
-               int childInfo[] = childNodesInfo.get(item.getData().getParentIdentifier());
-               if (childInfo != null)
-               {
-                  if (item.isDeleted())
-                  {
-                     ++childInfo[CHILD_NODES_COUNT_INDEX];
-                  }
-                  else if (item.isAdded())
-                  {
-                     --childInfo[CHILD_NODES_COUNT_INDEX];
-                  }
-
-                  childNodesInfo.put(item.getData().getParentIdentifier(), childInfo);
-               }
-            }
-
-            if (item.getData().isNode())
-            {
-               Map<String, ItemState> children = lastChildNodeStates.get(item.getData().getParentIdentifier());
-               if (children != null)
-               {
-                  children.remove(item.getData().getIdentifier());
-               }
-            }
-            else
-            {
-               Map<String, ItemState> children = lastChildPropertyStates.get(item.getData().getParentIdentifier());
-               if (children != null)
-               {
-                  children.remove(item.getData().getIdentifier());
-               }
-            }
-         }
-      }
-   }
-
-   /**
-    * Returns list with changes of this node and its descendants. NOTE: this operation may cost more
-    * than use of getDescendantsChanges() by path
-    * 
-    * @param rootIdentifier
-    */
-   public List<ItemState> getDescendantsChanges(String rootIdentifier)
-   {
-      List<ItemState> changesList = new ArrayList<ItemState>();
-
-      traverseChangesByIdentifier(rootIdentifier, changesList);
-
-      return changesList;
-   }
-
-   private void traverseChangesByIdentifier(String identifier, List<ItemState> changesList)
-   {
-      ItemState item = getItemState(identifier);
-      if (item != null)
-      {
-         changesList.add(item);
-         Map<String, ItemState> children = lastChildPropertyStates.get(identifier);
-         if (children != null)
-         {
-            // Add all the properties
-            changesList.addAll(children.values());
-         }
-         children = lastChildNodeStates.get(identifier);
-         if (children != null)
-         {
-            // Recursively call the method traverseChangesByIdentifier(String identifier, List<ItemState> changesList)
-            // for each sub node
-            for (ItemState child : children.values())
-            {
-               traverseChangesByIdentifier(child.getData().getIdentifier(), changesList);
-            }
-         }
-      }
-   }
-
-   /**
     * An example of use: transient changes of item added and removed in same session. These changes
     * must not fire events in observation.
     * 
@@ -283,45 +98,6 @@
    }
 
    /**
-    * @param rootPath
-    * @return item state at the rootPath and its descendants
-    */
-   public List<ItemState> getDescendantsChanges(QPath rootPath)
-   {
-      List<ItemState> list = new ArrayList<ItemState>();
-      for (int i = 0, length = items.size(); i < length; i++)
-      {
-         ItemState item = items.get(i);
-         if (item.isDescendantOf(rootPath))
-         {
-            list.add(item);
-         }
-      }
-      return list;
-   }
-
-   /**
-    * Gets items by identifier.
-    *
-    * @param itemIdentifier
-    * @return
-    */
-   public List<ItemState> getItemStates(String itemIdentifier)
-   {
-      List<ItemState> states = new ArrayList<ItemState>();
-      List<ItemState> currentStates = getAllStates();
-      for (int i = 0, length = currentStates.size(); i < length; i++)
-      {
-         ItemState state = currentStates.get(i);
-         if (state.getData().getIdentifier().equals(itemIdentifier))
-         {
-            states.add(state);
-         }
-      }
-      return states;
-   }
-
-   /**
     * Creates new changes log with rootPath and its descendants of this one and removes those
     * entries.
     * 
@@ -331,604 +107,15 @@
    public PlainChangesLog pushLog(QPath rootPath)
    {
       // session instance is always present in SessionChangesLog
-      PlainChangesLog cLog = new PlainChangesLogImpl(session);
-
+      PlainChangesLog cLog = new PlainChangesLogImpl(getDescendantsChanges(rootPath), session);
       if (rootPath.equals(Constants.ROOT_PATH))
       {
-         cLog.addAll(items);
          clear();
       }
       else
       {
-         cLog.addAll(getDescendantsChanges(rootPath));
          remove(rootPath);
       }
-
       return cLog;
    }
-
-   /**
-    * Get ItemState by parent and item name.
-    * 
-    * @param parentData
-    *          parent
-    * @param name
-    *          item name
-    * @param itemType
-    *          item type
-    * @return
-    * @throws IllegalPathException
-    */
-   public ItemState getItemState(NodeData parentData, QPathEntry name, ItemType itemType) throws IllegalPathException
-   {
-      if (itemType != ItemType.UNKNOWN)
-      {
-         return index.get(new ParentIDQPathBasedKey(parentData.getIdentifier(), name, itemType));
-      }
-      else
-      {
-         ItemState state = index.get(new ParentIDQPathBasedKey(parentData.getIdentifier(), name, ItemType.NODE));
-         if (state == null)
-         {
-            state = index.get(new ParentIDQPathBasedKey(parentData.getIdentifier(), name, ItemType.PROPERTY));
-         }
-         return state;
-      }
-   }
-
-   /**
-    * Get ItemState by identifier.
-    * 
-    * NOTE: Uses index HashMap.
-    * 
-    * @param itemIdentifier
-    * @return
-    */
-   public ItemState getItemState(String itemIdentifier)
-   {
-      return index.get(itemIdentifier);
-   }
-
-   /**
-    * Get ItemState by absolute path.
-    * 
-    * NOTE: Uses index HashMap.
-    * 
-    * @param itemPath
-    * @return
-    */
-   public ItemState getItemState(QPath itemPath)
-   {
-      return index.get(itemPath);
-   }
-
-   /**
-    * Get ItemState by identifier and state.
-    * 
-    * NOTE: Uses index HashMap.
-    * 
-    * @param itemIdentifier
-    * @param sate
-    * @return
-    */
-   public ItemState getItemState(String itemIdentifier, int state)
-   {
-      return index.get(new IDStateBasedKey(itemIdentifier, state));
-   }
-
-   /**
-    * Collect changes of all item direct childs (only). Including the item itself.
-    * 
-    * @param rootIdentifier
-    * @return
-    */
-   public List<ItemState> getChildrenChanges(String rootIdentifier)
-   {
-      List<ItemState> list = new ArrayList<ItemState>();
-      for (int i = 0; i < items.size(); i++)
-      {
-         ItemData item = items.get(i).getData();
-         if (item.getParentIdentifier().equals(rootIdentifier) || item.getIdentifier().equals(rootIdentifier))
-         {
-            list.add(items.get(i));
-         }
-      }
-      return list;
-   }
-
-   public int getChildNodesCount(String rootIdentifier)
-   {
-      int[] childInfo = childNodesInfo.get(rootIdentifier);
-      return childInfo == null ? 0 : childInfo[CHILD_NODES_COUNT_INDEX];
-   }
-
-   public int getLastChildOrderNumber(String rootIdentifier)
-   {
-
-      int[] childInfo = childNodesInfo.get(rootIdentifier);
-      return childInfo == null ? -1 : childInfo[CHILD_NODES_LAST_ORDER_NUMBER_INDEX];
-   }
-
-   /**
-    * Collect last in ChangesLog order item child changes.
-    * 
-    * @param rootData
-    *          - a item root of the changes scan
-    * @param forNodes
-    *          retrieves nodes' ItemStates is true, or properties' otherwice
-    * @return child items states
-    */
-   public Collection<ItemState> getLastChildrenStates(ItemData rootData, boolean forNodes)
-   {
-      Map<String, ItemState> children =
-         forNodes ? lastChildNodeStates.get(rootData.getIdentifier()) : lastChildPropertyStates.get(rootData
-            .getIdentifier());
-
-      return children == null ? new ArrayList<ItemState>() : children.values();
-   }
-
-   /**
-    * Collect last in ChangesLog order node (and direct childs) changes.
-    * 
-    * @param rootData
-    *          - a item root of the changes scan
-    * @param forNodes
-    *          retrieves nodes' ItemStates is true, or properties' otherwice
-    * @return this item (!) and child items last modify states (i.e. updates, not adds or deletes)
-    */
-   public Collection<ItemState> getLastModifyStates(NodeData rootData)
-   {
-      HashMap<String, ItemState> changes = new HashMap<String, ItemState>();
-
-      for (int i = 0; i < items.size(); i++)
-      {
-         ItemData item = items.get(i).getData();
-         if (item.getIdentifier().equals(rootData.getIdentifier()))
-         {
-            // the node
-            if (items.get(i).isAdded())
-            {
-               // if a new item - no modify changes can be
-               return new ArrayList<ItemState>();
-            }
-
-            if (!items.get(i).isDeleted())
-            {
-               changes.put(item.getIdentifier(), items.get(i));
-            }
-         }
-         else if (item.getParentIdentifier().equals(rootData.getIdentifier()))
-         {
-            // childs
-            changes.put(item.getIdentifier(), items.get(i));
-         }
-      }
-
-      return changes.values();
-   }
-
-   /**
-    * EXPERIMENTAL. NOT USED. Find a rename operation pair of states by path of DELETED item. Search
-    * from the end of log for DELETED state first. Then repeat the search for RENAMED state.
-    * 
-    * @param deletedPath
-    *          - target node path
-    * @return - the pair of states of item (or its ancestors), ItemState[] {DELETED, RENAMED} or null
-    *         if renaming is not detected.
-    * @throws IllegalPathException
-    */
-   @Deprecated
-   public ItemState[] findRenamed(QPath deletedPath) throws IllegalPathException
-   {
-      List<ItemState> allStates = getAllStates();
-      // search from the end for DELETED state.
-      // RENAMED comes after the DELETED in the log immediately (in back order)
-      for (int i = allStates.size() - 1; i >= 0; i--)
-      {
-         ItemState state = allStates.get(i);
-         if (state.getState() == ItemState.DELETED
-            && !state.isPersisted()
-            && (deletedPath.isDescendantOf(state.getData().getQPath()) || deletedPath
-               .equals(state.getData().getQPath())))
-         {
-            // 1. if it's an item or ancestor of logged data
-            try
-            {
-               ItemState delete = state;
-               ItemState rename = allStates.get(i + 1);
-
-               if (rename.getState() == ItemState.RENAMED && rename.isPersisted()
-                  && rename.getData().getIdentifier().equals(delete.getData().getIdentifier()))
-               {
-
-                  // 2. search of most fresh state for searched rename state
-                  for (int bi = allStates.size() - 1; bi >= i + 2; bi--)
-                  {
-                     state = allStates.get(bi);
-                     if (state.getState() == ItemState.RENAMED && state.isPersisted()
-                        && state.getData().getIdentifier().equals(rename.getData().getIdentifier()))
-                     {
-                        // got much fresh
-                        rename = state;
-                        delete = allStates.get(i - 1); // try the fresh delete state
-                        if (delete.getData().getIdentifier().equals(rename.getData().getIdentifier()))
-                        {
-                           return new ItemState[]{delete, rename}; // 3. ok, got it
-                        }
-                     }
-                  }
-
-                  return new ItemState[]{delete, rename}; // 4. ok, there are no
-                  // more fresh we have
-                  // found before p.2
-               } // else, it's not a rename, search deeper
-            }
-            catch (IndexOutOfBoundsException e)
-            {
-               // the pair not found
-               return null;
-            }
-         }
-      }
-      return null;
-   }
-
-   /**
-    * NOT USED. Search for an item state of item with given path (or its ancestor) and filter
-    * parameters.
-    * 
-    * @param rootPath
-    *          - item path (root path)
-    * @param states
-    *          - filter only the given list states, or all if it's null
-    * @param isPersisted
-    *          - filter only persisted/not persisted, or all if it's null
-    * @param orAncestor
-    *          - may return the item ancestor if true and the ancestor was changed last, or only item
-    *          with given path if it's null
-    * @return - filtered {@link ItemState}
-    * @throws IllegalPathException
-    */
-   public ItemState findItemState(QPath rootPath, Boolean isPersisted, Boolean orAncestor, int... states)
-      throws IllegalPathException
-   {
-      List<ItemState> allStates = getAllStates();
-      // search from the end for state
-      for (int i = allStates.size() - 1; i >= 0; i--)
-      {
-         ItemState istate = allStates.get(i);
-         boolean byState = false;
-         if (states != null)
-         {
-            for (int state : states)
-            {
-               if (istate.getState() == state)
-               {
-                  byState = true;
-                  break;
-               }
-            }
-         }
-         else
-         {
-            byState = true;
-         }
-         if (byState
-            && (isPersisted != null ? istate.isPersisted() == isPersisted : true)
-            && ((orAncestor != null && orAncestor ? rootPath.isDescendantOf(istate.getData().getQPath()) : true) || rootPath
-               .equals(istate.getData().getQPath())))
-         {
-            return istate;
-         }
-      }
-      return null;
-   }
-
-   /**
-    * Search for an item state of item with given id and filter parameters.
-    * 
-    * @param id
-    *          - item id
-    * @param states
-    *          - filter only the given list states (ORed), or all if it's null
-    * @param isPersisted
-    *          - filter only persisted/not persisted, or all if it's null
-    * @param orAncestor
-    *          - may return the item ancestor if true and the ancestor was changed last, or only item
-    *          with given path if it's null
-    * @return - filtered {@link ItemState}
-    * @throws IllegalPathException
-    */
-   public ItemState findItemState(String id, Boolean isPersisted, int... states) throws IllegalPathException
-   {
-      List<ItemState> allStates = getAllStates();
-      // search from the end for state
-      for (int i = allStates.size() - 1; i >= 0; i--)
-      {
-         ItemState istate = allStates.get(i);
-         boolean byState = false;
-         if (states != null)
-         {
-            for (int state : states)
-            {
-               if (istate.getState() == state)
-               {
-                  byState = true;
-                  break;
-               }
-            }
-         }
-         else
-         {
-            byState = true;
-         }
-         if (byState && (isPersisted != null ? istate.isPersisted() == isPersisted : true)
-            && istate.getData().getIdentifier().equals(id))
-         {
-            return istate;
-         }
-      }
-      return null;
-   }
-
-   /**
-    * Adds item to the changes log.
-    * 
-    * @param item
-    *          the item
-    */
-   private void addItem(ItemState item)
-   {
-      index.put(item.getData().getIdentifier(), item);
-      index.put(item.getData().getQPath(), item);
-      index.put(new ParentIDQPathBasedKey(item), item);
-      index.put(new IDStateBasedKey(item.getData().getIdentifier(), item.getState()), item);
-
-      if (item.getData().isNode())
-      {
-         Map<String, ItemState> children = lastChildNodeStates.get(item.getData().getParentIdentifier());
-         if (children == null)
-         {
-            children = new HashMap<String, ItemState>();
-            lastChildNodeStates.put(item.getData().getParentIdentifier(), children);
-         }
-         children.put(item.getData().getIdentifier(), item);
-      }
-      else
-      {
-         Map<String, ItemState> children = lastChildPropertyStates.get(item.getData().getParentIdentifier());
-         if (children == null)
-         {
-            children = new HashMap<String, ItemState>();
-            lastChildPropertyStates.put(item.getData().getParentIdentifier(), children);
-         }
-         children.put(item.getData().getIdentifier(), item);
-      }
-
-      if (item.isNode() && item.isPersisted())
-      {
-         int[] childInfo = childNodesInfo.get(item.getData().getParentIdentifier());
-         if (childInfo == null)
-         {
-            childInfo = new int[2];
-         }
-
-         if (item.isDeleted())
-         {
-            --childInfo[CHILD_NODES_COUNT_INDEX];
-         }
-         else if (item.isAdded())
-         {
-            ++childInfo[CHILD_NODES_COUNT_INDEX];
-            childInfo[CHILD_NODES_LAST_ORDER_NUMBER_INDEX] = ((NodeData)item.getData()).getOrderNumber();
-         }
-         childNodesInfo.put(item.getData().getParentIdentifier(), childInfo);
-      }
-   }
-
-   /**
-    * This class is used as a key for index map.
-    */
-   private class IDStateBasedKey
-   {
-
-      /**
-       * Item identifier.
-       */
-      private final String identifier;
-
-      /**
-       * Item state.
-       */
-      private final int state;
-
-      /**
-       * KeyUUIDState  constructor.
-       *
-       * @param identifier
-       *          item identifier
-       * @param state
-       *          item state
-       */
-      IDStateBasedKey(String identifier, int state)
-      {
-         this.identifier = identifier;
-         this.state = state;
-      }
-
-      /**
-       * {@inheritDoc}
-       */
-      @Override
-      public int hashCode()
-      {
-         final int prime = 31;
-         int result = 1;
-         result = prime * result + identifier.hashCode();
-         result = prime * result + state;
-
-         return result;
-      }
-
-      /**
-       * {@inheritDoc}
-       */
-      @Override
-      public boolean equals(Object obj)
-      {
-         if (this == obj)
-         {
-            return true;
-         }
-         if (obj == null)
-         {
-            return false;
-         }
-         if (getClass() != obj.getClass())
-         {
-            return false;
-         }
-         IDStateBasedKey other = (IDStateBasedKey)obj;
-
-         if (identifier == null)
-         {
-            if (other.identifier != null)
-            {
-               return false;
-            }
-         }
-         else if (!identifier.equals(other.identifier))
-         {
-            return false;
-         }
-         if (state != other.state)
-         {
-            return false;
-         }
-         return true;
-      }
-   }
-
-   /**
-    * This class is used as a key for index map.
-    */
-   private class ParentIDQPathBasedKey
-   {
-      /**
-       * Item name.
-       */
-      private final QPathEntry name;
-
-      /**
-       * Parent identifier.
-       */
-      private final String parentIdentifier;
-
-      private final ItemType itemType;
-
-      /**
-       * KeyParentUUIDQPath  constructor.
-       *
-       * @param item
-       *          the item
-       */
-      ParentIDQPathBasedKey(ItemState item)
-      {
-         this.name = item.getData().getQPath().getEntries()[item.getData().getQPath().getEntries().length - 1];
-         this.parentIdentifier = item.getData().getParentIdentifier();
-         this.itemType = ItemType.getItemType(item.getData());
-      }
-
-      /**
-       * KeyParentUUIDQPath  constructor.
-       *
-       * @param parentIdentifier
-       *          the parent identifier
-       * @param name
-       *          item name
-       */
-      ParentIDQPathBasedKey(String parentIdentifier, QPathEntry name, ItemType itemType)
-      {
-         this.name = name;
-         this.parentIdentifier = parentIdentifier;
-         this.itemType = itemType;
-      }
-
-      /**
-       * {@inheritDoc}
-       */
-      @Override
-      public int hashCode()
-      {
-         final int prime = 31;
-         int result = 1;
-         result = prime * result + name.getName().hashCode();
-         result = prime * result + name.getNamespace().hashCode();
-         result = prime * result + name.getIndex();
-         result = prime * result + (parentIdentifier == null ? 0 : parentIdentifier.hashCode());
-         result = prime * result + itemType.ordinal();
-
-         return result;
-      }
-
-      /**
-       * {@inheritDoc}
-       */
-      @Override
-      public boolean equals(Object obj)
-      {
-         if (this == obj)
-         {
-            return true;
-         }
-         if (obj == null)
-         {
-            return false;
-         }
-         if (getClass() != obj.getClass())
-         {
-            return false;
-         }
-         ParentIDQPathBasedKey other = (ParentIDQPathBasedKey)obj;
-
-         if (name == null)
-         {
-            if (other.name != null)
-            {
-               return false;
-            }
-         }
-         else if (!name.getName().equals(other.name.getName())
-            || !name.getNamespace().equals(other.name.getNamespace()) || name.getIndex() != other.name.getIndex())
-         {
-            return false;
-         }
-
-         if (parentIdentifier == null)
-         {
-            if (other.parentIdentifier != null)
-            {
-               return false;
-            }
-         }
-         else if (!parentIdentifier.equals(other.parentIdentifier))
-         {
-            return false;
-         }
-
-         if (itemType == null)
-         {
-            if (other.itemType != null)
-            {
-               return false;
-            }
-         }
-         else if (!itemType.equals(other.itemType))
-         {
-            return false;
-         }
-
-         return true;
-      }
-   }
 }

Modified: jcr/branches/1.15.x/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/version/TestFrozenNodeInitializer.java
===================================================================
--- jcr/branches/1.15.x/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/version/TestFrozenNodeInitializer.java	2011-12-30 09:54:01 UTC (rev 5410)
+++ jcr/branches/1.15.x/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/version/TestFrozenNodeInitializer.java	2011-12-30 10:09:39 UTC (rev 5411)
@@ -30,6 +30,7 @@
 import org.exoplatform.services.jcr.impl.Constants;
 import org.exoplatform.services.jcr.impl.dataflow.TransientNodeData;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import javax.jcr.version.VersionException;
@@ -52,9 +53,14 @@
       versionable.accept(visitor);
 
       // ask for nt:frozenNode
-      List<ItemState> versionableChanges = versionableLog.getChildrenChanges(versionable.getIdentifier());
-      List<ItemState> testChanges = changesLog.getChildrenChanges(frozenRoot.getIdentifier());
+      List<ItemState> versionableChanges = new ArrayList<ItemState>();
+      versionableChanges.addAll(versionableLog.getChildrenChanges(versionable.getIdentifier(), true));
+      versionableChanges.addAll(versionableLog.getChildrenChanges(versionable.getIdentifier(), false));
 
+      List<ItemState> testChanges = new ArrayList<ItemState>();
+      testChanges.addAll(changesLog.getChildrenChanges(frozenRoot.getIdentifier(), true));
+      testChanges.addAll(changesLog.getChildrenChanges(frozenRoot.getIdentifier(), false));
+
       next : for (ItemState state : versionableChanges)
       {
          if (versionable.equals(state.getData()))



More information about the exo-jcr-commits mailing list