001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.transaction.locking;
018    
019    import org.apache.commons.transaction.util.LoggerFacade;
020    
021    /**
022     * Manager for
023     * {@link org.apache.commons.transaction.locking.ReadWriteUpgradeLock}s on
024     * resources. <br>
025     * <br>
026     * <p>
027     * The idea (as explained by Jim LoVerde) is that only one owner can hold an
028     * upgrade lock, but while that is held, it is possible for read locks to exist
029     * and/or be obtained, and when the request is made to upgrade to a write lock
030     * by the same owner, the lock manager prevents additional read locks until the
031     * write lock can be aquired.
032     * </p>
033     * <p>
034     * In this sense the write lock becomes preferred over all other locks when it gets upgraded from
035     * a upgrate lock. Preferred means that if it has to wait and others wait as well it will be
036     * served before all other none preferred locking requests.
037     * </p>
038     * 
039     * @version $Id: ReadWriteUpgradeLockManager.java 493628 2007-01-07 01:42:48Z joerg $
040     * 
041     * @see ReadWriteUpgradeLock
042     * @since 1.1
043     */
044    public class ReadWriteUpgradeLockManager extends ReadWriteLockManager {
045    
046        /**
047         * Creates a new read/write/upgrade lock manager.
048         * 
049         * @param logger generic logger used for all kind of debug logging
050         * @param timeoutMSecs specifies the maximum time to wait for a lock in milliseconds
051         */
052        public ReadWriteUpgradeLockManager(LoggerFacade logger, long timeoutMSecs) {
053            super(ReadWriteUpgradeLock.WRITE_LOCK, logger, timeoutMSecs);
054        }
055    
056        /**
057         * Tries to acquire a reentrant upgrade lock on a resource. <br>
058         * <br>
059         * This method does not block, but immediatly returns. If a lock is not
060         * available <code>false</code> will be returned.
061         * 
062         * @param ownerId
063         *            a unique id identifying the entity that wants to acquire this
064         *            lock
065         * @param resourceId
066         *            the resource to get the lock for
067         * @return <code>true</code> if the lock has been acquired, <code>false</code> otherwise
068         */
069        public boolean tryUpgradeLock(Object ownerId, Object resourceId) {
070            return tryLock(ownerId, resourceId, ReadWriteUpgradeLock.UPGRADE_LOCK, true);
071        }
072    
073        /**
074         * Tries to acquire an exclusive, reentrant write lock on a resource. <br>
075         * <br>
076         * This method does not block, but immediatly returns. If a lock is not
077         * available <code>false</code> will be returned.
078         * 
079         * @param ownerId
080         *            a unique id identifying the entity that wants to acquire this
081         *            lock
082         * @param resourceId
083         *            the resource to get the lock for
084         * @return <code>true</code> if the lock has been acquired, <code>false</code> otherwise
085         */
086        public boolean tryWriteLock(Object ownerId, Object resourceId) {
087            return tryLock(ownerId, resourceId, ReadWriteUpgradeLock.WRITE_LOCK, true);
088        }
089    
090        /**
091         * Tries to acquire a reentrant upgrade lock on a resource. <br>
092         * <br>
093         * This method blocks and waits for the lock in case it is not avaiable. If
094         * there is a timeout or a deadlock or the thread is interrupted a
095         * LockException is thrown.
096         * 
097         * @param ownerId
098         *            a unique id identifying the entity that wants to acquire this
099         *            lock
100         * @param resourceId
101         *            the resource to get the level for
102         * @throws LockException
103         *             will be thrown when the lock can not be acquired
104         */
105        public void upgradeLock(Object ownerId, Object resourceId) throws LockException {
106            super.lock(ownerId, resourceId, ReadWriteUpgradeLock.UPGRADE_LOCK, true);
107        }
108    
109        /**
110         * Tries to acquire an exclusive, reentrant write lock on a resource. <br>
111         * <br>
112         * This method blocks and waits for the lock in case it is not avaiable. If
113         * there is a timeout or a deadlock or the thread is interrupted a
114         * LockException is thrown.
115         * 
116         * @param ownerId
117         *            a unique id identifying the entity that wants to acquire this
118         *            lock
119         * @param resourceId
120         *            the resource to get the level for
121         * @throws LockException
122         *             will be thrown when the lock can not be acquired
123         */
124        public void writeLock(Object ownerId, Object resourceId) throws LockException {
125            super.lock(ownerId, resourceId, ReadWriteUpgradeLock.WRITE_LOCK, true);
126        }
127    
128        protected GenericLock createLock(Object resourceId) {
129            synchronized (globalLocks) {
130                GenericLock lock = new ReadWriteUpgradeLock(resourceId, logger);
131                globalLocks.put(resourceId, lock);
132                return lock;
133            }
134        }
135    
136    }