[exo-jcr-commits] exo-jcr SVN: r1386 - in jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src: main/java/org/exoplatform/services/jcr/impl/core/lock and 3 other directories.

do-not-reply at jboss.org do-not-reply at jboss.org
Thu Jan 14 04:21:57 EST 2010


Author: sergiykarpenko
Date: 2010-01-14 04:21:56 -0500 (Thu, 14 Jan 2010)
New Revision: 1386

Added:
   jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/cache/
   jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/cache/CacheLockImpl.java
   jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/cache/CacheableLockManager.java
   jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/cache/LockData.java
   jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/resources/conf/standalone/test-jbosscache-lockconfig.xml
Modified:
   jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/LockManagerEntry.java
   jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/LockImpl.java
   jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/LockManager.java
   jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/LockManagerImpl.java
   jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/LockRemover.java
   jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/resources/binding.xml
Log:
EXOJCR-332: CacheableLockManager added


Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/LockManagerEntry.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/LockManagerEntry.java	2010-01-14 08:57:09 UTC (rev 1385)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/LockManagerEntry.java	2010-01-14 09:21:56 UTC (rev 1386)
@@ -29,6 +29,8 @@
 
    private LockPersisterEntry persister;
 
+   private String cacheConfig;
+
    public long getTimeout()
    {
       return timeout;
@@ -49,4 +51,14 @@
       this.persister = persister;
    }
 
+   public String getCacheConfig()
+   {
+      return cacheConfig;
+   }
+
+   public void steCacheConfig(String cacheConfig)
+   {
+      this.cacheConfig = cacheConfig;
+   }
+
 }

Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/LockImpl.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/LockImpl.java	2010-01-14 08:57:09 UTC (rev 1385)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/LockImpl.java	2010-01-14 09:21:56 UTC (rev 1386)
@@ -38,6 +38,11 @@
 
    private SessionImpl session;
 
+   // TODO remove this construector, need refactor lock classes ierarchy
+   public LockImpl()
+   {
+   }
+
    public LockImpl(SessionImpl session, LockData lockData)
    {
       this.lockData = lockData;

Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/LockManager.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/LockManager.java	2010-01-14 08:57:09 UTC (rev 1385)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/LockManager.java	2010-01-14 09:21:56 UTC (rev 1386)
@@ -112,4 +112,5 @@
     */
    public void removeLockToken(String sessionId, String lt);
 
+   public void removeExpired();
 }

Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/LockManagerImpl.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/LockManagerImpl.java	2010-01-14 08:57:09 UTC (rev 1385)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/LockManagerImpl.java	2010-01-14 09:21:56 UTC (rev 1386)
@@ -529,7 +529,7 @@
    /**
     * Remove expired locks. Used from LockRemover.
     */
-   synchronized void removeExpired()
+   public synchronized void removeExpired()
    {
       final List<String> removeLockList = new ArrayList<String>();
 

Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/LockRemover.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/LockRemover.java	2010-01-14 08:57:09 UTC (rev 1385)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/LockRemover.java	2010-01-14 09:21:56 UTC (rev 1386)
@@ -37,14 +37,14 @@
 
    // sec
 
-   private final LockManagerImpl lockManagerImpl;
+   private final LockManager lockManagerImpl;
 
-   public LockRemover(LockManagerImpl lockManagerImpl)
+   public LockRemover(LockManager lockManagerImpl)
    {
       this(lockManagerImpl, DEFAULT_THREAD_TIMEOUT);
    }
 
-   private LockRemover(LockManagerImpl lockManagerImpl, long timeout)
+   private LockRemover(LockManager lockManagerImpl, long timeout)
    {
       super(timeout);
       this.lockManagerImpl = lockManagerImpl;

Added: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/cache/CacheLockImpl.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/cache/CacheLockImpl.java	                        (rev 0)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/cache/CacheLockImpl.java	2010-01-14 09:21:56 UTC (rev 1386)
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2003-2010 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see<http://www.gnu.org/licenses/>.
+ */
+package org.exoplatform.services.jcr.impl.core.lock.cache;
+
+import org.exoplatform.services.jcr.impl.core.SessionImpl;
+import org.exoplatform.services.jcr.impl.core.lock.LockImpl;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.lock.LockException;
+
+/**
+ * Created by The eXo Platform SAS.
+ * 
+ * <br/>Date: 
+ *
+ * @author <a href="karpenko.sergiy at gmail.com">Karpenko Sergiy</a> 
+ * @version $Id: CacheLockImpl.java 111 2008-11-11 11:11:11Z serg $
+ */
+public class CacheLockImpl extends LockImpl
+{
+   private LockData lockData;
+
+   private SessionImpl session;
+
+   public CacheLockImpl(SessionImpl session, LockData lockData)
+   {
+
+      this.lockData = lockData;
+      this.session = session;
+   }
+
+   public String getLockOwner()
+   {
+      return lockData.getOwner();
+   }
+
+   public String getLockToken()
+   {
+      //TODO
+      //return lockData.getLockToken(session.getId());
+      return null;
+   }
+
+   public boolean isLive()
+   {
+      //TODO
+      //return lockData.isLive();
+
+      return false;
+   }
+
+   public void refresh() throws LockException, RepositoryException
+   {
+      //TODO
+      //      if (!isLive())
+      //         throw new LockException("Lock is not live");
+      //      lockData.refresh();
+   }
+
+   public Node getNode()
+   {
+      try
+      {
+         return (Node)session.getTransientNodesManager().getItemByIdentifier(lockData.getNodeIdentifier(), true);
+      }
+      catch (RepositoryException e)
+      {
+         e.printStackTrace();
+      }
+      return null;
+   }
+
+   public boolean isDeep()
+   {
+
+      return lockData.isDeep();
+   }
+
+   public boolean isSessionScoped()
+   {
+      return lockData.isSessionScoped();
+   }
+
+   public long getTimeToDeath()
+   {
+      return lockData.getTimeToDeath();
+   }
+
+   protected void setTimeOut(long timeOut)
+   {
+      // TODO make same as refresh
+      //lockData.setTimeOut(timeOut);
+
+   }
+}

Added: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/cache/CacheableLockManager.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/cache/CacheableLockManager.java	                        (rev 0)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/cache/CacheableLockManager.java	2010-01-14 09:21:56 UTC (rev 1386)
@@ -0,0 +1,1011 @@
+/*
+ * Copyright (C) 2003-2010 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see<http://www.gnu.org/licenses/>.
+ */
+package org.exoplatform.services.jcr.impl.core.lock.cache;
+
+import org.exoplatform.management.annotations.Managed;
+import org.exoplatform.management.annotations.ManagedDescription;
+import org.exoplatform.management.jmx.annotations.NameTemplate;
+import org.exoplatform.management.jmx.annotations.Property;
+import org.exoplatform.services.jcr.access.SystemIdentity;
+import org.exoplatform.services.jcr.config.RepositoryConfigurationException;
+import org.exoplatform.services.jcr.config.WorkspaceEntry;
+import org.exoplatform.services.jcr.core.ExtendedSession;
+import org.exoplatform.services.jcr.dataflow.ChangesLogIterator;
+import org.exoplatform.services.jcr.dataflow.CompositeChangesLog;
+import org.exoplatform.services.jcr.dataflow.DataManager;
+import org.exoplatform.services.jcr.dataflow.ItemState;
+import org.exoplatform.services.jcr.dataflow.ItemStateChangesLog;
+import org.exoplatform.services.jcr.dataflow.PlainChangesLog;
+import org.exoplatform.services.jcr.dataflow.PlainChangesLogImpl;
+import org.exoplatform.services.jcr.dataflow.TransactionChangesLog;
+import org.exoplatform.services.jcr.datamodel.InternalQName;
+import org.exoplatform.services.jcr.datamodel.ItemData;
+import org.exoplatform.services.jcr.datamodel.NodeData;
+import org.exoplatform.services.jcr.datamodel.PropertyData;
+import org.exoplatform.services.jcr.datamodel.QPathEntry;
+import org.exoplatform.services.jcr.impl.Constants;
+import org.exoplatform.services.jcr.impl.core.NodeImpl;
+import org.exoplatform.services.jcr.impl.core.SessionImpl;
+import org.exoplatform.services.jcr.impl.core.lock.LockImpl;
+import org.exoplatform.services.jcr.impl.core.lock.LockManagerImpl;
+import org.exoplatform.services.jcr.impl.core.lock.LockPersister;
+import org.exoplatform.services.jcr.impl.core.lock.LockRemover;
+import org.exoplatform.services.jcr.impl.dataflow.TransientItemData;
+import org.exoplatform.services.jcr.impl.dataflow.TransientPropertyData;
+import org.exoplatform.services.jcr.impl.dataflow.persistent.WorkspacePersistentDataManager;
+import org.exoplatform.services.jcr.impl.dataflow.persistent.jbosscache.BufferedJBossCache;
+import org.exoplatform.services.jcr.observation.ExtendedEvent;
+import org.exoplatform.services.jcr.util.IdGenerator;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+import org.jboss.cache.CacheFactory;
+import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.Node;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.lock.Lock;
+import javax.jcr.lock.LockException;
+
+/**
+ * Created by The eXo Platform SAS.
+ * 
+ * <br/>Date: 
+ *
+ * @author <a href="karpenko.sergiy at gmail.com">Karpenko Sergiy</a> 
+ * @version $Id: CacheableLockManager.java 111 2008-11-11 11:11:11Z serg $
+ */
+ at Managed
+ at NameTemplate(@Property(key = "service", value = "lockmanager"))
+public class CacheableLockManager extends LockManagerImpl
+{
+   /**
+    * Default lock time out. 30min
+    */
+   public static final long DEFAULT_LOCK_TIMEOUT = 1000 * 60 * 30;
+
+   // Search constants
+   /**
+    * The exact lock token.
+    */
+   private static final int SEARCH_EXECMATCH = 1;
+
+   /**
+    * Lock token of closed parent
+    */
+   private static final int SEARCH_CLOSEDPARENT = 2;
+
+   /**
+    * Lock token of closed child
+    */
+   private static final int SEARCH_CLOSEDCHILD = 4;
+
+   /**
+    * Path to jbosscache-configuration
+    */
+   public static final String JBOSSCACHE_CONFIG = "jbosscache-configuration";
+
+   public static final String LOCK_DATA = "$LOCK_DATA";
+
+   public static final String LOCKED_NODE_ID = "$NODE_ID";
+
+   public static final String TOKENS = "$TOKENS";
+
+   public static final String LOCKS = "$LOCKS";
+
+   /**
+    * Logger
+    */
+   private final Log log = ExoLogger.getLogger("jcr.lock.LockManager");
+
+   /**
+    * Map NodeIdentifier -- lockData
+    */
+   //private final Map<String, LockData> locks;
+
+   /**
+    * Data manager.
+    */
+   private final DataManager dataManager;
+
+   /**
+    * Map NodeIdentifier -- lockData
+    */
+   private final Map<String, LockData> pendingLocks;
+
+   /**
+    * Map lockToken --lockData
+    */
+   //private final Map<String, LockData> tokensMap;
+
+   /**
+    * [session id , [lock tokens ids..]]
+    */
+   private final Map<String, Set<String>> lockTokenHolders;
+
+   /**
+    * Pending token maps. [lock tokens, node id] 
+    */
+   private final Map<String, String> pendingLockTokens;
+
+   /**
+    * Run time lock time out.
+    */
+   private long lockTimeOut;
+
+   /**
+    * Lock remover thread.
+    */
+   private LockRemover lockRemover;
+
+   /**
+    * Lock persister instance.
+    */
+   private final LockPersister persister;
+
+   private BufferedJBossCache cache;
+
+   private Node<Serializable, Object> lockRoot;
+
+   private Node<Serializable, Object> tokenRoot;
+
+   /**
+    * Constructor for workspace without LockPersister
+    * 
+    * @param dataManager
+    * @param config
+    */
+   public CacheableLockManager(WorkspacePersistentDataManager dataManager, WorkspaceEntry config)
+      throws RepositoryConfigurationException
+   {
+      this(dataManager, config, null);
+   }
+
+   public CacheableLockManager(WorkspacePersistentDataManager dataManager, WorkspaceEntry config,
+      LockPersister persister) throws RepositoryConfigurationException
+   {
+      super(dataManager, config, null);
+      this.dataManager = dataManager;
+      this.persister = persister;
+      if (config.getLockManager() != null)
+      {
+         lockTimeOut =
+            config.getLockManager().getTimeout() > 0 ? config.getLockManager().getTimeout() : DEFAULT_LOCK_TIMEOUT;
+      }
+      else
+         lockTimeOut = DEFAULT_LOCK_TIMEOUT;
+
+      lockTokenHolders = new HashMap<String, Set<String>>();
+
+      //locks = new HashMap<String, LockData>();
+      //tokensMap = new HashMap<String, LockData>();
+      pendingLockTokens = new HashMap<String, String>();
+      pendingLocks = new HashMap<String, LockData>();
+
+      dataManager.addItemPersistenceListener(this);
+
+      CacheFactory<Serializable, Object> factory = new DefaultCacheFactory<Serializable, Object>();
+      cache = new BufferedJBossCache(factory.createCache(readJBCConfig(config), false));
+      cache.create();
+   }
+
+   protected static String readJBCConfig(final WorkspaceEntry wsConfig) throws RepositoryConfigurationException
+   {
+      if (wsConfig.getLockManager() != null)
+      {
+         return wsConfig.getLockManager().getCacheConfig();
+      }
+      else
+      {
+         throw new RepositoryConfigurationException("Cache configuration not found");
+      }
+   }
+
+   /*
+    * (non-Javadoc)
+    * @see
+    * org.exoplatform.services.jcr.impl.core.lock.LockManager#lockTokenAdded(org.exoplatform.services
+    * .jcr.impl.core.SessionImpl, java.lang.String)
+    */
+   public synchronized void addLockToken(String sessionId, String lt)
+   {
+      //LockData currLock = tokensMap.get(lt);
+      if (pendingLockTokens.get(lt) != null || tokenRoot.hasChild(Fqn.fromString(lt)))
+      {
+         holdLockToken(sessionId, lt);
+      }
+   }
+
+   private void holdLockToken(String sessionId, String lt)
+   {
+      if (lockTokenHolders.get(sessionId) == null)
+      {
+         lockTokenHolders.put(sessionId, new HashSet<String>());
+      }
+      lockTokenHolders.get(sessionId).add(lt);
+
+   }
+
+   /*
+    * (non-Javadoc)
+    * @see
+    * org.exoplatform.services.jcr.impl.core.lock.LockManager#addPendingLock(org.exoplatform.services
+    * .jcr.impl.core.NodeImpl, boolean, boolean, long)
+    */
+   public synchronized Lock addPendingLock(NodeImpl node, boolean isDeep, boolean isSessionScoped, long timeOut)
+      throws LockException
+   {
+      LockData lData = getLockData((NodeData)node.getData(), SEARCH_EXECMATCH | SEARCH_CLOSEDPARENT);
+      if (lData != null)
+      {
+         if (lData.getNodeIdentifier().equals(node.getInternalIdentifier()))
+         {
+            throw new LockException("Node already locked: " + node.getData().getQPath());
+         }
+         else if (lData.isDeep())
+         {
+            throw new LockException("Parent node has deep lock.");
+         }
+      }
+
+      if (isDeep && getLockData((NodeData)node.getData(), SEARCH_CLOSEDCHILD) != null)
+      {
+         throw new LockException("Some child node is locked.");
+      }
+
+      String lockToken = IdGenerator.generate();
+      lData =
+         new LockData(node.getInternalIdentifier(), lockToken, isDeep, isSessionScoped, node.getSession().getUserID(),
+            timeOut > 0 ? timeOut : lockTimeOut);
+
+      //lData.addLockHolder(node.getSession().getId());
+
+      holdLockToken(node.getSession().getId(), lockToken);
+
+      pendingLocks.put(node.getInternalIdentifier(), lData);
+      pendingLockTokens.put(lockToken, node.getInternalIdentifier());
+      //tokensMap.put(lockToken, lData);
+
+      LockImpl lock = new CacheLockImpl(node.getSession(), lData);
+      return lock;
+   }
+
+   /*
+    * (non-Javadoc)
+    * @see
+    * org.exoplatform.services.jcr.impl.core.lock.LockManager#getLock(org.exoplatform.services.jcr
+    * .impl.core.NodeImpl)
+    */
+   public LockImpl getLock(NodeImpl node) throws LockException, RepositoryException
+   {
+
+      LockData lData = getLockData((NodeData)node.getData(), SEARCH_EXECMATCH | SEARCH_CLOSEDPARENT);
+
+      if (lData == null || (!node.getInternalIdentifier().equals(lData.getNodeIdentifier()) && !lData.isDeep()))
+      {
+         throw new LockException("Node not locked: " + node.getData().getQPath());
+      }
+      return new CacheLockImpl(node.getSession(), lData);
+   }
+
+   /*
+    * (non-Javadoc)
+    * @see org.exoplatform.services.jcr.impl.core.lock.LockManager#getLockTokens(java.lang.String)
+    */
+   public synchronized String[] getLockTokens(String sessionID)
+   {
+      Set<String> lockTokens = lockTokenHolders.get(sessionID);
+
+      if (lockTokens != null)
+      {
+         String[] arr = new String[lockTokens.size()];
+         lockTokens.toArray(arr);
+         return arr;
+      }
+      else
+      {
+         return new String[0];
+      }
+   }
+
+   /*
+    * (non-Javadoc)
+    * @see
+    * org.exoplatform.services.jcr.impl.core.lock.LockManager#holdsLock(org.exoplatform.services.
+    * jcr.impl.core.NodeImpl)
+    */
+   public boolean holdsLock(NodeData node) throws RepositoryException
+   {
+      return getLockData(node, SEARCH_EXECMATCH) != null;
+   }
+
+   /*
+    * (non-Javadoc)
+    * @see
+    * org.exoplatform.services.jcr.impl.core.lock.LockManager#isLocked(org.exoplatform.services.jcr
+    * .datamodel.NodeData)
+    */
+   public boolean isLocked(NodeData node)
+   {
+      LockData lData = getLockData(node, SEARCH_EXECMATCH | SEARCH_CLOSEDPARENT);
+
+      if (lData == null || (!node.getIdentifier().equals(lData.getNodeIdentifier()) && !lData.isDeep()))
+      {
+         return false;
+      }
+      return true;
+   }
+
+   /*
+    * (non-Javadoc)
+    * @see
+    * org.exoplatform.services.jcr.impl.core.lock.LockManager#isLockHolder(org.exoplatform.services
+    * .jcr.impl.core.NodeImpl)
+    */
+   public boolean isLockHolder(NodeImpl node) throws RepositoryException
+   {
+      LockData lData = getLockData((NodeData)node.getData(), SEARCH_EXECMATCH | SEARCH_CLOSEDPARENT);
+      return lData != null && isLockHolder(node.getSession().getId(), lData.getToken());
+   }
+
+   private boolean isLockHolder(String sessionId, String lockToken)
+   {
+      Set<String> lockTokens = lockTokenHolders.get(sessionId);
+      if (lockTokens != null)
+      {
+         return lockTokens.contains(lockToken);
+      }
+      return false;
+   }
+
+   /*
+    * (non-Javadoc)
+    * @see
+    * org.exoplatform.services.jcr.core.SessionLifecycleListener#onCloseSession(org.exoplatform.services
+    * .jcr.core.ExtendedSession)
+    */
+   public synchronized void onCloseSession(ExtendedSession session)
+   {
+      // List<String> deadLocksList = new ArrayList<String>();
+      SessionImpl sessionImpl = (SessionImpl)session;
+
+      Set<String> lockTokens = lockTokenHolders.get(session.getId());
+
+      for (String token : lockTokens)
+      {
+
+         String nodeId = null;
+         if (pendingLockTokens.containsKey(token))
+         {
+            // unlock node   
+            nodeId = pendingLockTokens.get(token);
+         }
+
+         if (tokenRoot.hasChild(Fqn.fromString(token)))
+         {
+            nodeId = (String)tokenRoot.getData().get(LOCKED_NODE_ID);
+         }
+
+         if (nodeId != null)
+         {
+            // unlock node
+            try
+            {
+               // TODO it's possible to have next error
+               // java.lang.NullPointerException
+               // at
+               // org.exoplatform.services.jcr.impl.core.lock.LockManagerImpl.onCloseSession(LockManagerImpl.java:312)
+               // at org.exoplatform.services.jcr.impl.core.SessionImpl.logout(SessionImpl.java:794)
+               // at
+               // org.exoplatform.services.jcr.impl.core.XASessionImpl.logout(XASessionImpl.java:254)
+               // at
+               // org.exoplatform.services.jcr.impl.core.SessionRegistry$SessionCleaner.callPeriodically(SessionRegistry.java:165)
+               // at
+               // org.exoplatform.services.jcr.impl.proccess.WorkerThread.run(WorkerThread.java:46)
+               ((NodeImpl)sessionImpl.getTransientNodesManager().getItemByIdentifier(nodeId, false)).unlock();
+            }
+            catch (UnsupportedRepositoryOperationException e)
+            {
+               log.error(e.getLocalizedMessage());
+            }
+            catch (LockException e)
+            {
+               log.error(e.getLocalizedMessage());
+            }
+            catch (AccessDeniedException e)
+            {
+               log.error(e.getLocalizedMessage());
+            }
+            catch (RepositoryException e)
+            {
+               log.error(e.getLocalizedMessage());
+            }
+         }
+      }
+
+      //      //for (Iterator<Map.Entry<String, LockData>> entries = locks.entrySet().iterator(); entries.hasNext();)
+      //      for (LockData lockData : getLockList())
+      //      {
+      //         //Map.Entry<String, LockData> entry = entries.next();
+      //         //LockData lockData = entry.getValue();
+      //         // TODO remove is Alive construction
+      //         //if (lockData.isLive())
+      //         //{
+      //            if (lockData.isLockHolder(session.getId()))
+      //            {
+      //               if (lockData.isSessionScoped())
+      //               {
+      //                  // if no session currently holds lock except this
+      //                  try
+      //                  {
+      //                     // TODO it's possible to have next error
+      //                     // java.lang.NullPointerException
+      //                     // at
+      //                     // org.exoplatform.services.jcr.impl.core.lock.LockManagerImpl.onCloseSession(LockManagerImpl.java:312)
+      //                     // at org.exoplatform.services.jcr.impl.core.SessionImpl.logout(SessionImpl.java:794)
+      //                     // at
+      //                     // org.exoplatform.services.jcr.impl.core.XASessionImpl.logout(XASessionImpl.java:254)
+      //                     // at
+      //                     // org.exoplatform.services.jcr.impl.core.SessionRegistry$SessionCleaner.callPeriodically(SessionRegistry.java:165)
+      //                     // at
+      //                     // org.exoplatform.services.jcr.impl.proccess.WorkerThread.run(WorkerThread.java:46)
+      //                     ((NodeImpl)sessionImpl.getTransientNodesManager().getItemByIdentifier(
+      //                        lockData.getNodeIdentifier(), false)).unlock();
+      //                  }
+      //                  catch (UnsupportedRepositoryOperationException e)
+      //                  {
+      //                     log.error(e.getLocalizedMessage());
+      //                  }
+      //                  catch (LockException e)
+      //                  {
+      //                     log.error(e.getLocalizedMessage());
+      //                  }
+      //                  catch (AccessDeniedException e)
+      //                  {
+      //                     log.error(e.getLocalizedMessage());
+      //                  }
+      //                  catch (RepositoryException e)
+      //                  {
+      //                     log.error(e.getLocalizedMessage());
+      //                  }
+      //
+      //               }
+      //               else
+      //               {
+      //                  lockData.removeLockHolder(session.getId());
+      //               }
+      //            }
+      //         }
+      //         else
+      //         {
+      //            //TODO
+      //            //entries.remove();
+      //         }
+      //      }
+   }
+
+   /*
+    * (non-Javadoc)
+    * @seeorg.exoplatform.services.jcr.dataflow.persistent.ItemsPersistenceListener#onSaveItems(org.
+    * exoplatform.services.jcr.dataflow.ItemStateChangesLog)
+    */
+   public void onSaveItems(ItemStateChangesLog changesLog)
+   {
+      List<PlainChangesLog> chengesLogList = new ArrayList<PlainChangesLog>();
+      if (changesLog instanceof TransactionChangesLog)
+      {
+         ChangesLogIterator logIterator = ((TransactionChangesLog)changesLog).getLogIterator();
+
+         while (logIterator.hasNextLog())
+         {
+            chengesLogList.add(logIterator.nextLog());
+         }
+      }
+      else if (changesLog instanceof PlainChangesLog)
+      {
+         chengesLogList.add((PlainChangesLog)changesLog);
+      }
+      else if (changesLog instanceof CompositeChangesLog)
+      {
+         for (ChangesLogIterator iter = ((CompositeChangesLog)changesLog).getLogIterator(); iter.hasNextLog();)
+         {
+            chengesLogList.add(iter.nextLog());
+         }
+      }
+
+      for (PlainChangesLog currChangesLog : chengesLogList)
+      {
+         String nodeIdentifier;
+         try
+         {
+            switch (currChangesLog.getEventType())
+            {
+               case ExtendedEvent.LOCK :
+                  if (currChangesLog.getSize() < 2)
+                  {
+                     log.error("Incorrect changes log  of type ExtendedEvent.LOCK size=" + currChangesLog.getSize()
+                        + "<2 \n" + currChangesLog.dump());
+                     break;
+                  }
+                  nodeIdentifier = currChangesLog.getAllStates().get(0).getData().getParentIdentifier();
+
+                  if (pendingLocks.containsKey(nodeIdentifier))
+                  {
+                     internalLock(nodeIdentifier);
+                  }
+                  else
+                  {
+                     throw new LockException("Lock must exist in pending locks.");
+
+                     //                     log.warn("No lock in pendingLocks for identifier " + nodeIdentifier
+                     //                        + " Probably lock come from replication.");
+                     //
+                     //                     String lockToken = IdGenerator.generate();
+                     //                     ItemState ownerState = getItemState(currChangesLog, Constants.JCR_LOCKOWNER);
+                     //                     ItemState isDeepState = getItemState(currChangesLog, Constants.JCR_LOCKISDEEP);
+                     //                     if (ownerState != null && isDeepState != null)
+                     //                     {
+                     //
+                     //                        String owner =
+                     //                           new String(((((TransientPropertyData)(ownerState.getData())).getValues()).get(0))
+                     //                              .getAsByteArray(), Constants.DEFAULT_ENCODING);
+                     //
+                     //                        boolean isDeep =
+                     //                           Boolean.valueOf(
+                     //                              new String(((((TransientPropertyData)(isDeepState.getData())).getValues()).get(0))
+                     //                                 .getAsByteArray(), Constants.DEFAULT_ENCODING)).booleanValue();
+                     //
+                     //                        createRemoteLock(currChangesLog.getSessionId(), nodeIdentifier, lockToken, isDeep, false, owner);
+                     //                     }
+                  }
+                  break;
+               case ExtendedEvent.UNLOCK :
+                  if (currChangesLog.getSize() < 2)
+                  {
+                     log.error("Incorrect changes log  of type ExtendedEvent.UNLOCK size=" + currChangesLog.getSize()
+                        + "<2 \n" + currChangesLog.dump());
+                     break;
+                  }
+
+                  internalUnLock(currChangesLog.getSessionId(), currChangesLog.getAllStates().get(0).getData()
+                     .getParentIdentifier());
+                  break;
+               default :
+                  HashSet<String> removedLock = new HashSet<String>();
+                  for (ItemState itemState : currChangesLog.getAllStates())
+                  {
+                     // this is a node and node is locked
+                     if (itemState.getData().isNode() && lockExist(itemState.getData().getIdentifier()))
+                     {
+                        nodeIdentifier = itemState.getData().getIdentifier();
+                        if (itemState.isDeleted())
+                        {
+                           removedLock.add(nodeIdentifier);
+                        }
+                        else if (itemState.isAdded() || itemState.isRenamed() || itemState.isUpdated())
+                        {
+                           removedLock.remove(nodeIdentifier);
+                        }
+                     }
+                  }
+                  for (String identifier : removedLock)
+                  {
+                     internalUnLock(currChangesLog.getSessionId(), identifier);
+                  }
+                  break;
+            }
+         }
+         catch (LockException e)
+         {
+            log.error(e.getLocalizedMessage(), e);
+         }
+         //         catch (UnsupportedEncodingException e)
+         //         {
+         //            log.error(e.getLocalizedMessage(), e);
+         //         }
+         catch (IllegalStateException e)
+         {
+            log.error(e.getLocalizedMessage(), e);
+         }
+         //         catch (IOException e)
+         //         {
+         //            log.error(e.getLocalizedMessage(), e);
+         //         }
+      }
+   }
+
+   private boolean lockExist(String nodeId)
+   {
+      return cache.getRoot().hasChild(Fqn.fromString(nodeId));
+   }
+
+   /*
+    * (non-Javadoc)
+    * @see
+    * org.exoplatform.services.jcr.impl.core.lock.LockManager#lockTokenRemoved(org.exoplatform.services
+    * .jcr.impl.core.SessionImpl, java.lang.String)
+    */
+   public synchronized void removeLockToken(String sessionId, String lt)
+   {
+      if (lockTokenHolders.containsKey(sessionId))
+      {
+         lockTokenHolders.get(sessionId).remove(lt);
+      }
+   }
+
+   /*
+    * (non-Javadoc)
+    * @see org.picocontainer.Startable#start()
+    */
+   public void start()
+   {
+      cache.start();
+      lockRoot = cache.getRoot().addChild(Fqn.fromString(LOCKS));
+      tokenRoot = cache.getRoot().addChild(Fqn.fromString(TOKENS));
+
+      lockRemover = new LockRemover(this);
+   }
+
+   // Quick method. We need to reconstruct
+   // TODO was synchronized
+   protected List<LockData> getLockList()
+   {
+
+      Set<Node<Serializable, Object>> lockSet = cache.getRoot().getChildren();
+
+      List<LockData> locksData = new ArrayList<LockData>();
+      for (Node<Serializable, Object> node : lockSet)
+      {
+         if (node != null)
+         {
+            LockData lockData = (LockData)node.get(LOCK_DATA);
+            if (lockData != null)
+            {
+               locksData.add(lockData);
+            }
+         }
+      }
+      return locksData;
+   }
+
+   /**
+    * Remove expired locks. Used from LockRemover.
+    */
+   public synchronized void removeExpired()
+   {
+      final List<String> removeLockList = new ArrayList<String>();
+
+      for (LockData lock : getLockList())
+      {
+         if (!lock.isSessionScoped() && lock.getTimeToDeath() < 0)
+         {
+            removeLockList.add(lock.getNodeIdentifier());
+         }
+      }
+
+      for (String rLock : removeLockList)
+      {
+         removeLock(rLock);
+      }
+   }
+
+   /*
+    * (non-Javadoc)
+    * @see org.picocontainer.Startable#stop()
+    */
+   public void stop()
+   {
+
+      lockRemover.halt();
+      lockRemover.interrupt();
+      //locks.clear();
+      pendingLocks.clear();
+      pendingLockTokens.clear();
+      //tokensMap.clear();
+      cache.stop();
+   }
+
+   /**
+    * Copy <code>PropertyData prop<code> to new TransientItemData
+    * 
+    * @param prop
+    * @return
+    * @throws RepositoryException
+    */
+   private TransientItemData copyItemData(PropertyData prop) throws RepositoryException
+   {
+
+      if (prop == null)
+         return null;
+
+      // make a copy, value may be null for deleting items
+      TransientPropertyData newData =
+         new TransientPropertyData(prop.getQPath(), prop.getIdentifier(), prop.getPersistedVersion(), prop.getType(),
+            prop.getParentIdentifier(), prop.isMultiValued(), prop.getValues());
+
+      return newData;
+
+   }
+
+   /**
+    * Search item with name <code>itemName<code> in changesLog
+    * 
+    * @param changesLog
+    * @param itemName
+    * @return Item
+    */
+   private ItemState getItemState(PlainChangesLog changesLog, InternalQName itemName)
+   {
+      List<ItemState> allStates = changesLog.getAllStates();
+      for (int i = allStates.size() - 1; i >= 0; i--)
+      {
+         ItemState state = allStates.get(i);
+         if (state.getData().getQPath().getName().equals(itemName))
+            return state;
+      }
+      return null;
+   }
+
+   /**
+    * Search lock in maps.
+    * 
+    * @param data
+    * @param searchType
+    * @return
+    */
+   private LockData getLockData(NodeData data, int searchType)
+   {
+      if (data == null || getNumLocks() == 0)
+         return null;
+      LockData retval = null;
+      try
+      {
+         if ((searchType & SEARCH_EXECMATCH) != 0)
+         {
+            retval = getLockDataById(data.getIdentifier());
+         }
+         if (retval == null && (searchType & SEARCH_CLOSEDPARENT) != 0)
+         {
+
+            NodeData parentData = (NodeData)dataManager.getItemData(data.getParentIdentifier());
+            if (parentData != null)
+            {
+               retval = getLockDataById(parentData.getIdentifier());
+               // parent not found try to fo upper
+               if (retval == null)
+               {
+                  retval = getLockData(parentData, SEARCH_CLOSEDPARENT);
+               }
+            }
+         }
+         if (retval == null && (searchType & SEARCH_CLOSEDCHILD) != 0)
+         {
+
+            List<NodeData> childData = dataManager.getChildNodesData(data);
+            for (NodeData nodeData : childData)
+            {
+               retval = getLockDataById(nodeData.getIdentifier());
+               if (retval != null)
+                  break;
+            }
+            if (retval == null)
+            {
+               // child not found try to find diper
+               for (NodeData nodeData : childData)
+               {
+                  retval = getLockData(nodeData, SEARCH_CLOSEDCHILD);
+                  if (retval != null)
+                     break;
+               }
+            }
+         }
+      }
+      catch (RepositoryException e)
+      {
+         return null;
+      }
+
+      return retval;
+   }
+
+   private LockData getLockDataById(String nodeId)
+   {
+      LockData lockData = null;
+      Node<Serializable, Object> node = lockRoot.getChild(Fqn.fromString(nodeId));
+      if (node != null)
+      {
+         lockData = (LockData)node.get(LOCK_DATA);
+      }
+      return lockData;
+   }
+
+   /**
+    * Internal lock
+    * 
+    * @param nodeIdentifier
+    * @throws LockException
+    */
+   private synchronized void internalLock(String nodeIdentifier) throws LockException
+   {
+      //      LockData ldata = pendingLocks.get(nodeIdentifier);
+      //      if (ldata != null)
+      //      {
+      //         locks.put(nodeIdentifier, ldata);
+      //
+      //         if (persister != null)
+      //         {
+      //            persister.add(ldata);
+      //         }
+      //         pendingLocks.remove(nodeIdentifier);
+      //      }
+      //      else
+      //      {
+      //         throw new LockException("No lock in pending locks");
+      //      }
+
+      LockData lockData = pendingLocks.get(nodeIdentifier);
+
+      if (lockData == null)
+      {
+         //TODO remove me
+         throw new LockException("Lock data to write can't be null!");
+      }
+      // addChild will add if absent or return old if present
+      Node<Serializable, Object> node = lockRoot.addChild(Fqn.fromString(lockData.getNodeIdentifier()));
+
+      // this will prevent from deleting by eviction.
+      node.setResident(true);
+
+      // this will return null if success. And old data if something exists...
+      LockData oldLockData = (LockData)node.putIfAbsent(LOCK_DATA, lockData);
+      // if oldLockData is present (not null):
+      // 1. this is Lock.refresh(): oldLockData and lockData will have the same tokens 
+      // 2. this node is already locked: data-s will have different tokens
+
+      if (oldLockData != null)
+      {
+         // if LockData already present with different lock token, then node has already been locked! 
+         if (!oldLockData.getToken().equals(lockData.getToken()))
+         {
+            throw new LockException("Unable to write LockData. Node [" + lockData.getNodeIdentifier()
+               + "] already has LockData!");
+         }
+         else
+         {
+            // token is the same, then Lock is just refreshed. Putting new LockData.
+            if (!node.replace(LOCK_DATA, oldLockData, lockData))
+            {
+               throw new LockException("Unable to re-write LockData. Possibly LockData for the Node["
+                  + lockData.getNodeIdentifier() + "] has just been changed!");
+            }
+         }
+      }
+   }
+
+   /**
+    * Internal unlock.
+    * 
+    * @param sessionId
+    * @param nodeIdentifier
+    * @throws LockException
+    */
+   private synchronized void internalUnLock(String sessionId, String nodeIdentifier) throws LockException
+   {
+      LockData lData = getLockDataById(nodeIdentifier);
+
+      if (lData != null)
+      {
+         //tokensMap.remove(lData.getLockToken(sessionId));
+         tokenRoot.removeChild(lData.getToken());
+         lockRoot.removeChild(Fqn.fromString(nodeIdentifier));
+      }
+   }
+
+   /**
+    * For locks comes from remote JCRs (replication usecase)
+    * 
+    * @param sessionId
+    *          String
+    * @param nodeIdentifier
+    *          String
+    * @param lockToken
+    *          String
+    * @param isDeep
+    *          boolean
+    * @param sessionScoped
+    *          boolean
+    * @param owner
+    *          String
+    * @return LockData
+    */
+   //   private synchronized LockData createRemoteLock(String sessionId, String nodeIdentifier, String lockToken,
+   //      boolean isDeep, boolean sessionScoped, String owner)
+   //   {
+   //      LockData lData = new LockData(nodeIdentifier, lockToken, isDeep, sessionScoped, owner, lockTimeOut);
+   //      lData.addLockHolder(sessionId);
+   //      locks.put(nodeIdentifier, lData);
+   //      tokensMap.put(lockToken, lData);
+   //
+   //      return lData;
+   //   }
+
+   /**
+    * Remove lock, used by Lock remover.
+    * 
+    * @param nodeIdentifier String
+    */
+   protected void removeLock(String nodeIdentifier)
+   {
+      try
+      {
+         NodeData nData = (NodeData)dataManager.getItemData(nodeIdentifier);
+         PlainChangesLog changesLog =
+            new PlainChangesLogImpl(new ArrayList<ItemState>(), SystemIdentity.SYSTEM, ExtendedEvent.UNLOCK);
+
+         ItemData lockOwner =
+            copyItemData((PropertyData)dataManager.getItemData(nData, new QPathEntry(Constants.JCR_LOCKOWNER, 1)));
+
+         changesLog.add(ItemState.createDeletedState(lockOwner));
+
+         ItemData lockIsDeep =
+            copyItemData((PropertyData)dataManager.getItemData(nData, new QPathEntry(Constants.JCR_LOCKISDEEP, 1)));
+         changesLog.add(ItemState.createDeletedState(lockIsDeep));
+
+         // lock probably removed by other thread
+         if (lockOwner == null && lockIsDeep == null)
+            return;
+         dataManager.save(new TransactionChangesLog(changesLog));
+
+      }
+      catch (RepositoryException e)
+      {
+         log.error("Error occur during removing lock" + e.getLocalizedMessage());
+      }
+   }
+
+   @Managed
+   @ManagedDescription("The number of active locks")
+   public int getNumLocks()
+   {
+      return cache.getRoot().getChildrenNames().size();
+   }
+
+   @Managed
+   @ManagedDescription("Remove the expired locks")
+   public void cleanExpiredLocks()
+   {
+      removeExpired();
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public boolean isTXAware()
+   {
+      return true;
+   }
+}

Added: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/cache/LockData.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/cache/LockData.java	                        (rev 0)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/lock/cache/LockData.java	2010-01-14 09:21:56 UTC (rev 1386)
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.jcr.impl.core.lock.cache;
+
+import org.exoplatform.services.jcr.impl.Constants;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+/**
+ * Created by The eXo Platform SAS.
+ * 
+ * @author <a href="mailto:gennady.azarenkov at exoplatform.com">Gennady Azarenkov</a>
+ * @version $Id: LockData.java 787 2009-11-20 11:36:15Z nzamosenchuk $
+ */
+
+public class LockData implements Externalizable //extends org.exoplatform.services.jcr.impl.core.lock.LockData
+{
+   /**
+    * The time of birth. From this time we start count the time of death. death = birthday+TIME_OUT;
+    */
+   private long birthday;
+
+   /**
+    * If isDeep is true then the lock applies to this node and all its descendant nodes; if false,
+    * the lock applies only to this, the holding node.
+    */
+   private boolean deep;
+
+   /**
+    * A lock token is a string that uniquely identifies a particular lock and acts as a “key”
+    * allowing a user to alter a locked node. LockData stores only token hash.
+    */
+   private String token;
+
+   /**
+    * Identifier of locked node.
+    */
+   private String nodeIdentifier;
+
+   /**
+    * The owner of the locked node.
+    */
+   private String owner;
+
+   /**
+    * If isSessionScoped is true then this lock will expire upon the expiration of the current
+    * session (either through an automatic or explicit Session.logout); if false, this lock does not
+    * expire until explicitly unlocked or automatically unlocked due to a implementation-specific
+    * limitation, such as a timeout.
+    */
+   private boolean sessionScoped;
+
+   /**
+    * <B>8.4.9 Timing Out</B> An implementation may unlock any lock at any time due to
+    * implementation-specific criteria, such as time limits on locks.
+    */
+   private long timeOut;
+
+   // Need for Externalizable
+   public LockData()
+   {
+      this.sessionScoped = false;
+      this.deep = false;
+   }
+
+   /**
+    * @param nodeIdentifier
+    * @param lockToken
+    * @param deep
+    * @param sessionScoped
+    * @param owner
+    * @param timeOut
+    *       is seconds!
+    */
+   public LockData(String nodeIdentifier, String lockToken, boolean deep, boolean sessionScoped, String owner,
+      long timeOut)
+   {
+      this.nodeIdentifier = nodeIdentifier;
+      this.token = lockToken;
+      this.deep = deep;
+      this.sessionScoped = sessionScoped;
+      this.owner = owner;
+      this.timeOut = timeOut;
+      this.birthday = System.currentTimeMillis() / 1000;
+   }
+
+   /*
+    * (non-Javadoc)
+    * @see java.lang.Object#equals(java.lang.Object)
+    */
+   @Override
+   public boolean equals(Object obj)
+   {
+      if (super.equals(obj))
+      {
+         return true;
+      }
+      if (obj instanceof LockData)
+      {
+         return hashCode() == obj.hashCode();
+      }
+      return false;
+   }
+
+   /**
+    * @return the nodeIdentifier
+    */
+   public String getNodeIdentifier()
+   {
+      return nodeIdentifier;
+   }
+
+   /**
+    * @return
+    */
+   public String getOwner()
+   {
+      return owner;
+   }
+
+   /**
+    * @return The time to death in millis
+    */
+   public long getTimeToDeath()
+   {
+      return birthday + timeOut - System.currentTimeMillis() / 1000;
+   }
+
+   public String getToken()
+   {
+      return token;
+   }
+
+   /*
+    * (non-Javadoc)
+    * @see java.lang.Object#hashCode()
+    */
+   @Override
+   public int hashCode()
+   {
+      return token.hashCode();
+   }
+
+   public boolean isDeep()
+   {
+      return deep;
+   }
+
+   /**
+    * @return
+    */
+   public boolean isSessionScoped()
+   {
+      return sessionScoped;
+   }
+
+   /**
+    * @see java.io.Externalizable#readExternal(java.io.ObjectInput)
+    */
+   public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
+   {
+      // read boolean
+      this.deep = in.readBoolean();
+      this.sessionScoped = in.readBoolean();
+      // read long
+      this.birthday = in.readLong();
+      this.timeOut = in.readLong();
+      //read strings
+      // read uuid
+      byte[] buf;
+      buf = new byte[in.readInt()];
+      in.readFully(buf);
+      this.nodeIdentifier = new String(buf, Constants.DEFAULT_ENCODING);
+      // read owner
+      buf = new byte[in.readInt()];
+      in.readFully(buf);
+      this.owner = new String(buf, Constants.DEFAULT_ENCODING);
+      // read token
+      buf = new byte[in.readInt()];
+      in.readFully(buf);
+      this.token = new String(buf, Constants.DEFAULT_ENCODING);
+   }
+
+   /**
+    * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput)
+    */
+   public void writeExternal(ObjectOutput out) throws IOException
+   {
+      // write boolean
+      out.writeBoolean(deep);
+      out.writeBoolean(sessionScoped);
+      // write long
+      out.writeLong(birthday);
+      out.writeLong(timeOut);
+      // write string
+      // node uuid
+      byte[] ptbuf = nodeIdentifier.getBytes(Constants.DEFAULT_ENCODING);
+      out.writeInt(ptbuf.length);
+      out.write(ptbuf);
+      // node owner
+      ptbuf = owner.getBytes(Constants.DEFAULT_ENCODING);
+      out.writeInt(ptbuf.length);
+      out.write(ptbuf);
+      // node token
+      ptbuf = token.getBytes(Constants.DEFAULT_ENCODING);
+      out.writeInt(ptbuf.length);
+      out.write(ptbuf);
+
+   }
+
+   /**
+    * @return
+    */
+   protected long getTimeOut()
+   {
+      return timeOut;
+   }
+
+}

Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/resources/binding.xml
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/resources/binding.xml	2010-01-14 08:57:09 UTC (rev 1385)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/resources/binding.xml	2010-01-14 09:21:56 UTC (rev 1386)
@@ -67,6 +67,9 @@
     <structure name="lock-manager" field="lockManager" usage="optional">
       <value name="time-out" field="timeout" usage="optional" 
 			  deserializer="org.exoplatform.services.jcr.util.ConfigurationFormat.parseTime" />
+      
+      <value name="cache-config" field="cacheConfig" usage="optional" />
+      
       <structure name="persister" field="persister" usage="optional">
         <value name="class" field="type" style="attribute" />
         <collection name="properties" field="parameters" usage="optional"

Added: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/resources/conf/standalone/test-jbosscache-lockconfig.xml
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/resources/conf/standalone/test-jbosscache-lockconfig.xml	                        (rev 0)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/resources/conf/standalone/test-jbosscache-lockconfig.xml	2010-01-14 09:21:56 UTC (rev 1386)
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jbosscache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:jboss:jbosscache-core:config:3.1">
+
+   <locking useLockStriping="false" concurrencyLevel="50000" lockParentForChildInsertRemove="false" lockAcquisitionTimeout="3600000"/>
+   
+   <!-- Configure the TransactionManager -->
+   <transaction transactionManagerLookupClass="org.jboss.cache.transaction.JBossStandaloneJTAManagerLookup" />
+
+   <!-- Enable batching -->
+   <invocationBatching enabled="true" />
+
+   <!-- Eviction configuration -->
+   <eviction wakeUpInterval="5000">
+      <default algorithmClass="org.jboss.cache.eviction.LRUAlgorithm">
+         <property name="maxNodes" value="5000" />
+         <property name="timeToLiveSeconds" value="120" />
+      </default>
+      <region name="/" algorithmClass="org.jboss.cache.eviction.LRUAlgorithm" actionPolicyClass="org.exoplatform.services.jcr.impl.dataflow.persistent.jbosscache.ChildListEvictionActionPolicy" eventQueueSize="1000000">
+         <property name="maxNodes" value="5000" />
+         <property name="timeToLiveSeconds" value="120" />
+      </region>
+   </eviction>
+
+</jbosscache>



More information about the exo-jcr-commits mailing list