/* * 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.storage.value; import org.exoplatform.services.jcr.impl.storage.value.fs.operations.ValueLockSupport; import java.io.IOException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * Created by The eXo Platform SAS. * * <br> * * This is singleton object for resources holding. * * <br> * Date: 01.04.2009 * * @author <a href="mailto:peter.nedonosko@exoplatform.com.ua">Peter Nedonosko</a> * @version $Id: ValueDataResourceHolder.java 34801 2009-07-31 15:44:50Z dkatayev $ */ public class ValueDataResourceHolder { /** * Resources map. */ protected final Map<Object, VDResource> resources = new ConcurrentHashMap<Object, VDResource>(); /** * ValueData resource holder. * */ class VDResource { /** * User Thread. */ final Thread user; /** * Per-JVM lock. */ final Object lock; /** * Lock support. */ final ValueLockSupport lockSupport; /** * Same user locks count. */ int userLocks = 0; /** * VDResource constructor. * * @param user Thread * @param lock Object * @param lockSupport ValueLockSupport * @throws IOException if lock error occurs */ VDResource(Thread user, Object lock, ValueLockSupport lockSupport) throws IOException { this.user = user; this.lock = lock; this.lockSupport = lockSupport; lockSupport.lock(); userLocks = 1; } /** * Add user lock. * * Lock can be added by only the lock creator user (Thread recorded in user variable). * * @param user * Thread * @param lockSupport * ValueLockSupport * @return boolean, true if the resource reaquired by the same user * @throws IOException * if share is not supported */ boolean addUserLock(Thread user, ValueLockSupport lockSupport) throws IOException { if (this.user.equals(user)) { lockSupport.share(this.lockSupport); userLocks++; return true; } return false; } /** * Remove user lock. * * Lock can be removed by only the lock creator user (Thread recorded in user variable). * * @param user * Thread * @return boolean true - if no more locks of this user on the resource, false - otherwise */ boolean removeUserLock(Thread user) { if (this.user.equals(user)) { userLocks--; return userLocks <= 0; } return false; } } /** * Aquire ValueData resource. * * @param resource * Object * @param lockHolder * ValueLockSupport * @throws InterruptedException * if resource lock is interrupted * @return boolean, false - if the resource reaquired by the same user (Thread), true otherwise * @throws IOException * if lock error occurs */ public boolean aquire(final Object resource, final ValueLockSupport lockHolder) throws InterruptedException, IOException { final Thread myThread = Thread.currentThread(); final VDResource res = resources.get(resource); if (res != null) { if (res.addUserLock(myThread, lockHolder)) // resource locked in this thread (by me) return false; synchronized (res.lock) { // resource locked, wait for unlock res.lock.wait(); // new record with existing lock (to respect Object.notify()) resources.put(resource, new VDResource(myThread, res.lock, lockHolder)); } } else resources.put(resource, new VDResource(myThread, new Object(), lockHolder)); return true; } /** * Release resource. * * @param resource * Object * @return boolean, true - if resource is released, false - if the resource still in use. * @throws IOException * if unlock error occurs */ public boolean release(final Object resource) throws IOException { final Thread myThread = Thread.currentThread(); final VDResource res = resources.get(resource); if (res != null) { if (res.removeUserLock(myThread)) { synchronized (res.lock) { // unlock holder res.lockSupport.unlock(); // locked by this thread (by me) // ...Wakes up a single thread that is waiting on this object's monitor res.lock.notify(); // resources will be reputed with new VDResource in aquire() of another Thread resources.remove(resource); } return true; } } return false; } }