    001package com.hammurapi.store;
    002
    003import java.util.concurrent.TimeUnit;
    004import java.util.concurrent.atomic.AtomicInteger;
    005import java.util.concurrent.locks.Condition;
    006import java.util.concurrent.locks.Lock;
    007
    008/**
    009 * Lock which acts on behalf of another lock and acquires its own lock only
    010 *  if the master lock is not held. This lock is used for executing one logical
    011 *  store operation in multiple threads.
    012 * @author Pavel Vlasov
    013 *
    014 */
    015public class DeputyLock implements TrackingLock {
    016
    017        private Lock master;
    018        private boolean masterLocked;
    019        private AtomicInteger lockCounter = new AtomicInteger(0);
    020        private boolean canNotBeLocked;
    021        private String msg;
    022
    023        public DeputyLock(Lock master, boolean masterLocked, boolean canNotBeLocked, String msg) {
    024                this.master = master;
    025                this.masterLocked = masterLocked;
    026                this.canNotBeLocked = canNotBeLocked;
    027                this.msg = msg;
    028        }
    029
    030        private void checkLockability() {
    031                if (canNotBeLocked) {
    032                        throw new IllegalStateException(msg);
    033                }
    034        }
    035
    036        @Override
    037        public void lock() {
    038                if (!masterLocked) {
    039                        checkLockability();
    040                        master.lock();
    041                        lockCounter.incrementAndGet();
    042                }
    043        }
    044
    045        @Override
    046        public void lockInterruptibly() throws InterruptedException {
    047                if (!masterLocked) {
    048                        checkLockability();
    049                        master.lockInterruptibly();
    050                        lockCounter.incrementAndGet();
    051                }
    052        }
    053
    054        @Override
    055        public boolean tryLock() {
    056                if (masterLocked) {
    057                        return true;
    058                }
    059                checkLockability();
    060                if (master.tryLock()) {
    061                        lockCounter.incrementAndGet();
    062                        return true;
    063                }
    064                return false;
    065        }
    066
    067        @Override
    068        public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
    069                if (masterLocked) {
    070                        return true;
    071                }
    072                checkLockability();
    073                if (master.tryLock(time, unit)) {
    074                        lockCounter.incrementAndGet();
    075                        return true;
    076                }
    077                return false;
    078        }
    079
    080        @Override
    081        public void unlock() {
    082                if (masterLocked) {
    083                        master.unlock();
    084                        lockCounter.decrementAndGet();
    085                }
    086        }
    087
    088        public boolean isLocked() {
    089                return masterLocked || lockCounter.get()>0;
    090        }
    091
    092        @Override
    093        public Condition newCondition() {
    094                return master.newCondition();
    095        }
    096
    097//      public DeputyLock createDeputy() {
    098//              return new DeputyLock(this, isLocked(), canNotBeLocked, msg);
    099//      }
    100
    101}