Package org.apache.ojb.broker.locking

Source Code of org.apache.ojb.broker.locking.CommonsOJBLockManager

package org.apache.ojb.broker.locking;

import org.apache.commons.transaction.locking.GenericLock;
import org.apache.commons.transaction.locking.GenericLockManager;
import org.apache.commons.transaction.locking.LockException;
import org.apache.commons.transaction.locking.MultiLevelLock;
import org.apache.commons.transaction.util.LoggerFacade;

/* Copyright 2002-2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* Extension of {@link org.apache.commons.transaction.locking.GenericLockManager} to
* support all locking isolation level defined in OJB locking api and a provider of
* specific {@link org.apache.commons.transaction.locking.GenericLock} implementation classes
* representing the isolation levels specified in {@link org.apache.ojb.broker.locking.LockManager}, like
* {@link org.apache.ojb.broker.locking.LockManager#IL_READ_COMMITTED}, ... .
* <p/>
* The specific lock classes will be returned on call of
* {@link #createIsolationLevel(Object, Object, org.apache.commons.transaction.util.LoggerFacade)}
* dependend on the specified isolation level.
*
* @author <a href="mailto:arminw@apache.org">Armin Waibel</a>
* @version $Id: CommonsOJBLockManager.java,v 1.1.2.1 2005/02/19 21:49:53 arminw Exp $
*/
public class CommonsOJBLockManager extends GenericLockManager
{
    static final int COMMON_READ_LOCK = 101;
    static final int COMMON_WRITE_LOCK = 107;
    static final int COMMON_UPGRADE_LOCK = 113;

    public CommonsOJBLockManager(LoggerFacade logger, long timeoutMSecs, long checkThreshholdMSecs)
            throws IllegalArgumentException
    {
        super(1, logger, timeoutMSecs, checkThreshholdMSecs);
    }

    /**
     * @see org.apache.commons.transaction.locking.GenericLockManager#tryLock(Object, Object, int, boolean)
     */
    public boolean tryLock(Object ownerId, Object resourceId, int targetLockLevel, boolean reentrant)
    {
        return tryLock(ownerId, resourceId, targetLockLevel, reentrant, null);
    }

    /**
     * Tries to acquire a lock on a resource. <br>
     * <br>
     * This method does not block, but immediatly returns. If a lock is not
     * available <code>false</code> will be returned.
     *
     * @param ownerId         a unique id identifying the entity that wants to acquire this
     *                        lock
     * @param resourceId      the resource to get the level for
     * @param targetLockLevel the lock level to acquire
     * @param reentrant       <code>true</code> if this request shall not be influenced by
     *                        other locks held by the same owner
     * @param isolationId     the isolation level identity key. See {@link CommonsOJBLockManager}.
     * @return <code>true</code> if the lock has been acquired, <code>false</code> otherwise
     */
    public boolean tryLock(Object ownerId, Object resourceId, int targetLockLevel, boolean reentrant, Object isolationId)
    {
        timeoutCheck(ownerId);

        OJBLock lock = atomicGetOrCreateLock(resourceId, isolationId);
        boolean acquired = lock.tryLock(ownerId, targetLockLevel,
                reentrant ? GenericLock.COMPATIBILITY_REENTRANT : GenericLock.COMPATIBILITY_NONE,
                false);

        if(acquired)
        {
            addOwner(ownerId, lock);
        }
        return acquired;
    }

    /**
     * @see org.apache.commons.transaction.locking.GenericLockManager#lock(Object, Object, int, int, boolean, long)
     */
    public void lock(Object ownerId, Object resourceId, int targetLockLevel, int compatibility,
                     boolean preferred, long timeoutMSecs) throws LockException
    {
        lock(ownerId, resourceId, targetLockLevel, compatibility, preferred, timeoutMSecs, null);
    }

    /**
     * Most flexible way to acquire a lock on a resource. <br>
     * <br>
     * This method blocks and waits for the lock in case it is not avaiable. If
     * there is a timeout or a deadlock or the thread is interrupted a
     * LockException is thrown.
     *
     * @param ownerId         a unique id identifying the entity that wants to acquire this
     *                        lock
     * @param resourceId      the resource to get the level for
     * @param targetLockLevel the lock level to acquire
     * @param compatibility   {@link GenericLock#COMPATIBILITY_NONE}if no additional compatibility is
     *                        desired (same as reentrant set to false) ,
     *                        {@link GenericLock#COMPATIBILITY_REENTRANT}if lock level by the same
     *                        owner shall not affect compatibility (same as reentrant set to
     *                        true), or {@link GenericLock#COMPATIBILITY_SUPPORT}if lock levels that
     *                        are the same as the desired shall not affect compatibility, or
     *                        finally {@link GenericLock#COMPATIBILITY_REENTRANT_AND_SUPPORT}which is
     *                        a combination of reentrant and support
     * @param preferred       in case this lock request is incompatible with existing ones
     *                        and we wait, it shall be granted before other waiting requests
     *                        that are not preferred
     * @param timeoutMSecs    specifies the maximum wait time in milliseconds
     * @param isolationId     the isolation level identity key. See {@link CommonsOJBLockManager}.
     * @throws LockException will be thrown when the lock can not be acquired
     */
    public void lock(Object ownerId, Object resourceId, int targetLockLevel, int compatibility,
                     boolean preferred, long timeoutMSecs, Object isolationId) throws LockException
    {
        timeoutCheck(ownerId);
        GenericLock lock = (GenericLock) atomicGetOrCreateLock(resourceId, isolationId);
        super.doLock(lock, ownerId, resourceId, targetLockLevel, compatibility, preferred, timeoutMSecs);
    }

    /**
     * @see org.apache.commons.transaction.locking.GenericLockManager#atomicGetOrCreateLock(Object)
     */
    public MultiLevelLock atomicGetOrCreateLock(Object resourceId)
    {
        return atomicGetOrCreateLock(resourceId, null);
    }

    /**
     * Either gets an existing lock on the specified resource or creates one if none exists.
     * This methods guarantees to do this atomically.
     *
     * @param resourceId  the resource to get or create the lock on
     * @param isolationId the isolation level identity key. See {@link CommonsOJBLockManager}.
     * @return the lock for the specified resource
     */
    public OJBLock atomicGetOrCreateLock(Object resourceId, Object isolationId)
    {
        synchronized(globalLocks)
        {
            MultiLevelLock lock = getLock(resourceId);
            if(lock == null)
            {
                lock = createLock(resourceId, isolationId);
            }
            return (OJBLock) lock;
        }
    }

    /**
     * @see org.apache.commons.transaction.locking.GenericLockManager#createLock(Object)
     */
    protected GenericLock createLock(Object resourceId)
    {
        return createLock(resourceId, null);
    }

    protected GenericLock createLock(Object resourceId, Object isolationId)
    {
        synchronized(globalLocks)
        {
            if(isolationId != null)
            {
                GenericLock lock = createIsolationLevel(resourceId, isolationId, logger);
                globalLocks.put(resourceId, lock);
                return lock;
            }
            else
            {
                GenericLock lock = new GenericLock(resourceId, maxLockLevel, logger);
                globalLocks.put(resourceId, lock);
                return lock;
            }
        }
    }

    /**
     * Creates {@link org.apache.commons.transaction.locking.GenericLock} based
     * {@link org.apache.commons.transaction.locking.MultiLevelLock2} instances
     * dependend on the specified isolation identity object.
     */
    public OJBLock createIsolationLevel(Object resourceId, Object isolationId, LoggerFacade logger)
    {
        OJBLock result = null;
        switch(((Integer) isolationId).intValue())
        {
            case LockManager.IL_READ_UNCOMMITTED:
                result = new ReadUncommittedLock(resourceId, logger);
                break;
            case LockManager.IL_READ_COMMITTED:
                result = new ReadCommitedLock(resourceId, logger);
                break;
            case LockManager.IL_REPEATABLE_READ:
                result = new RepeadableReadsLock(resourceId, logger);
                break;
            case LockManager.IL_SERIALIZABLE:
                result = new SerializeableLock(resourceId, logger);
                break;
            case LockManager.IL_OPTIMISTIC:
                throw new LockRuntimeException("Optimistic locking must be handled on top of this class");
            default:
                throw new LockRuntimeException("Unknown lock isolation level specified");
        }
        return result;
    }

    /**
     * Helper method to map the specified common lock level (e.g like
     * {@link #COMMON_READ_LOCK}, {@link #COMMON_UPGRADE_LOCK, ...}) based
     * on the isolation level to the internal used lock level value by the
     * {@link org.apache.commons.transaction.locking.MultiLevelLock2} implementation.
     *
     * @param isolationId
     * @param lockLevel
     * @return
     */
    int mapLockLevelDependendOnIsolationLevel(Integer isolationId, int lockLevel)
    {
        int result = 0;
        switch(isolationId.intValue())
        {
            case LockManager.IL_READ_UNCOMMITTED:
                result = ReadUncommittedLock.mapLockLevel(lockLevel);
                break;
            case LockManager.IL_READ_COMMITTED:
                result = ReadCommitedLock.mapLockLevel(lockLevel);
                break;
            case LockManager.IL_REPEATABLE_READ:
                result = RepeadableReadsLock.mapLockLevel(lockLevel);
                break;
            case LockManager.IL_SERIALIZABLE:
                result = SerializeableLock.mapLockLevel(lockLevel);
                break;
            case LockManager.IL_OPTIMISTIC:
                throw new LockRuntimeException("Optimistic locking must be handled on top of this class");
            default:
                throw new LockRuntimeException("Unknown lock isolation level specified");
        }
        return result;
    }



    //===================================================
    // inner class, commons-tx lock
    //===================================================
    /**
     * Abstract base class to implement the different {@link org.apache.commons.transaction.locking.GenericLock}
     * extension classes representing the OJB isolation levels (e.g. READ_COMMITTED, REPEADABLE_READ,...)
     */
    abstract static class OJBLock extends GenericLock
    {
        public OJBLock(Object resourceId, int maxLockLevel, LoggerFacade logger)
        {
            super(resourceId, maxLockLevel, logger);
        }

        /**
         * Need to override this method to make it accessible in
         * {@link CommonsOJBLockManager}.
         *
         * @see GenericLock#tryLock(Object, int, int, boolean)
         */
        protected boolean tryLock(Object ownerId, int targetLockLevel, int compatibility, boolean preferred)
        {
            return super.tryLock(ownerId, targetLockLevel, compatibility, preferred);
        }

        /**
         * Convenience method.
         */
        abstract boolean hasRead(Object ownerId);

        /**
         * Convenience method.
         */
        abstract boolean hasWrite(Object ownerId);

        /**
         * Convenience method.
         */
        abstract boolean hasUpgrade(Object ownerId);

        /**
         * Convenience method.
         */
        abstract boolean readLock(Object ownerId, long timeout) throws InterruptedException;

        /**
         * Convenience method.
         */
        abstract boolean writeLock(Object ownerId, long timeout) throws InterruptedException;

        /**
         * Convenience method.
         */
        abstract boolean upgradeLock(Object ownerId, long timeout) throws InterruptedException;
    }



    //===================================================
    // inner class, commons-tx lock
    //===================================================
    /**
     * Implementation of isolation level {@link LockManager#IL_READ_UNCOMMITTED}.
     */
    static class ReadUncommittedLock extends RepeadableReadsLock
    {
        public ReadUncommittedLock(Object resourceId, LoggerFacade logger)
        {
            super(resourceId, logger);
        }

        protected boolean isCompatible(int targetLockLevel, int currentLockLevel)
        {
            if(currentLockLevel == READ_LOCK || targetLockLevel == READ_LOCK)
            {
                return true;
            }
            else
            {
                return super.isCompatible(targetLockLevel, currentLockLevel);
            }
        }
    }

    //===================================================
    // inner class, commons-tx lock
    //===================================================
    /**
     * Implementation of isolation level {@link LockManager#IL_READ_COMMITTED}.
     */
    static final class ReadCommitedLock extends RepeadableReadsLock
    {
        public ReadCommitedLock(Object resourceId, LoggerFacade logger)
        {
            super(resourceId, logger);
        }

        protected boolean isCompatible(int targetLockLevel, int currentLockLevel)
        {
            if(currentLockLevel == READ_LOCK)
            {
                return true;
            }
            else
            {
                return super.isCompatible(targetLockLevel, currentLockLevel);
            }
        }
    }

    //===================================================
    // inner class, commons-tx lock
    //===================================================
    /**
     * Implementation of isolation level {@link LockManager#IL_REPEATABLE_READ}.
     */
    static class RepeadableReadsLock extends OJBLock
    {
        static final int NO_LOCK = 0;
        static final int READ_LOCK = 1;
        static final int UPGRADE_LOCK = 2;
        static final int WRITE_LOCK = 3;

        public RepeadableReadsLock(Object resourceId, LoggerFacade logger)
        {
            super(resourceId, WRITE_LOCK, logger);
        }

        static int mapLockLevel(int commonLockLevel)
        {
            int result = 0;
            switch(commonLockLevel)
            {
                case COMMON_READ_LOCK:
                    result = READ_LOCK;
                    break;
                case COMMON_UPGRADE_LOCK:
                    result = UPGRADE_LOCK;
                    break;
                case COMMON_WRITE_LOCK:
                    result = WRITE_LOCK;
                    break;
                default:
                    throw new LockRuntimeException("Unknown common lock type: " + commonLockLevel);
            }
            return result;
        }

        public boolean readLock(Object ownerId, long timeout) throws InterruptedException
        {
            return acquire(ownerId, READ_LOCK, false, GenericLock.COMPATIBILITY_REENTRANT, false, timeout);
        }

        public boolean writeLock(Object ownerId, long timeout) throws InterruptedException
        {
            return acquire(ownerId, WRITE_LOCK, true, GenericLock.COMPATIBILITY_REENTRANT, false, timeout);
        }

        public boolean upgradeLock(Object ownerId, long timeout) throws InterruptedException
        {
            return acquire(ownerId, UPGRADE_LOCK, true, GenericLock.COMPATIBILITY_REENTRANT, true, timeout);
        }

        public boolean hasRead(Object ownerId)
        {
            return has(ownerId, READ_LOCK);
        }

        public boolean hasWrite(Object ownerId)
        {
            return has(ownerId, WRITE_LOCK);
        }

        public boolean hasUpgrade(Object ownerId)
        {
            return has(ownerId, UPGRADE_LOCK);
        }
    }


    //===================================================
    // inner class, commons-tx lock
    //===================================================
    /**
     * Implementation of isolation level {@link LockManager#IL_SERIALIZABLE}.
     */
    static final class SerializeableLock extends ReadUncommittedLock
    {
        public SerializeableLock(Object resourceId, LoggerFacade logger)
        {
            super(resourceId, logger);
        }

        protected boolean isCompatible(int targetLockLevel, int currentLockLevel)
        {
            return currentLockLevel > NO_LOCK ? false : true;
        }
    }
}
TOP

Related Classes of org.apache.ojb.broker.locking.CommonsOJBLockManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.