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 */
017package org.apache.commons.transaction.locking;
018
019import org.apache.commons.transaction.util.LoggerFacade;
020
021/**
022 * Manager for {@link org.apache.commons.transaction.locking.ReadWriteLock}s on resources.
023 * 
024 * @version $Id: ReadWriteLockManager.java 493628 2007-01-07 01:42:48Z joerg $
025 * @since 1.1
026 */
027public class ReadWriteLockManager extends GenericLockManager {
028
029    /**
030     * Creates a new read/write lock manager.
031     * 
032     * @param logger generic logger used for all kind of debug logging
033     * @param timeoutMSecs specifies the maximum time to wait for a lock in milliseconds
034     */
035    public ReadWriteLockManager(LoggerFacade logger, long timeoutMSecs) {
036        super(ReadWriteLock.WRITE_LOCK, logger, timeoutMSecs);
037    }
038
039    protected ReadWriteLockManager(int maxLockLevel, LoggerFacade logger, long timeoutMSecs)
040            throws IllegalArgumentException {
041        super(maxLockLevel, logger, timeoutMSecs);
042    }
043
044    /**
045     * Tries to acquire a shared, reentrant read lock on a resource. <br>
046     * <br>
047     * This method does not block, but immediatly returns. If a lock is not
048     * available <code>false</code> will be returned.
049     * 
050     * @param ownerId
051     *            a unique id identifying the entity that wants to acquire this
052     *            lock
053     * @param resourceId
054     *            the resource to get the lock for
055     * @return <code>true</code> if the lock has been acquired, <code>false</code> otherwise
056     */
057    public boolean tryReadLock(Object ownerId, Object resourceId) {
058        return tryLock(ownerId, resourceId, ReadWriteLock.READ_LOCK, true);
059    }
060
061    /**
062     * Tries to acquire an exclusive, reentrant write lock on a resource. <br>
063     * <br>
064     * This method does not block, but immediatly returns. If a lock is not
065     * available <code>false</code> will be returned.
066     * 
067     * @param ownerId
068     *            a unique id identifying the entity that wants to acquire this
069     *            lock
070     * @param resourceId
071     *            the resource to get the lock for
072     * @return <code>true</code> if the lock has been acquired, <code>false</code> otherwise
073     */
074    public boolean tryWriteLock(Object ownerId, Object resourceId) {
075        return tryLock(ownerId, resourceId, ReadWriteLock.WRITE_LOCK, true);
076    }
077
078    /**
079     * Determines if a shared, reentrant read lock on a resource 
080     * <em>could</em> be acquired without actually acquiring it. <br>
081     * <br>
082     * This method does not block, but immediatly returns. If a lock is not
083     * available <code>false</code> will be returned.
084     * 
085     * @param ownerId
086     *            a unique id identifying the entity that wants to acquire this
087     *            lock
088     * @param resourceId
089     *            the resource to get the lock for
090     * @return <code>true</code> if the lock could be acquired, <code>false</code> otherwise
091     */
092    public boolean checkReadLock(Object ownerId, Object resourceId) {
093        return checkLock(ownerId, resourceId, ReadWriteLock.READ_LOCK, true);
094    }
095
096    /**
097     * Determines if an exclusive, reentrant write lock on a resource
098     * is held by an owner. <br>
099     * 
100     * @param ownerId
101     *            a unique id identifying the entity that wants to check this
102     *            lock
103     * @param resourceId
104     *            the resource to get the lock for
105     * @return <code>true</code> if the lock is held by the owner, <code>false</code> otherwise
106     */
107    public boolean hasWriteLock(Object ownerId, Object resourceId) {
108        return hasLock(ownerId, resourceId, ReadWriteLock.WRITE_LOCK);
109    }
110
111    /**
112     * Determines if a shared, reentrant read lock on a resource 
113     * is held by an owner. <br>
114     * 
115     * @param ownerId
116     *            a unique id identifying the entity that wants to check this
117     *            lock
118     * @param resourceId
119     *            the resource to get the lock for
120     * @return <code>true</code> if the lock is held by the owner, <code>false</code> otherwise
121     */
122    public boolean hasReadLock(Object ownerId, Object resourceId) {
123        return hasLock(ownerId, resourceId, ReadWriteLock.READ_LOCK);
124    }
125
126    /**
127     * Determines if an exclusive, reentrant write lock on a resource
128     * <em>could</em> be acquired without actually acquiring it. <br>
129     * <br>
130     * This method does not block, but immediatly returns. If a lock is not
131     * available <code>false</code> will be returned.
132     * 
133     * @param ownerId
134     *            a unique id identifying the entity that wants to acquire this
135     *            lock
136     * @param resourceId
137     *            the resource to get the lock for
138     * @return <code>true</code> if the lock could be acquired, <code>false</code> otherwise
139     */
140    public boolean checkWriteLock(Object ownerId, Object resourceId) {
141        return checkLock(ownerId, resourceId, ReadWriteLock.WRITE_LOCK, true);
142    }
143
144    /**
145     * Tries to acquire a shared, reentrant read lock on a resource. <br>
146     * <br>
147     * This method blocks and waits for the lock in case it is not avaiable. If
148     * there is a timeout or a deadlock or the thread is interrupted a
149     * LockException is thrown.
150     * 
151     * @param ownerId
152     *            a unique id identifying the entity that wants to acquire this
153     *            lock
154     * @param resourceId
155     *            the resource to get the lock for
156     * @throws LockException
157     *             will be thrown when the lock can not be acquired
158     */
159    public void readLock(Object ownerId, Object resourceId) throws LockException {
160        lock(ownerId, resourceId, ReadWriteLock.READ_LOCK, GenericLock.COMPATIBILITY_REENTRANT,
161                false, globalTimeoutMSecs);
162    }
163
164    /**
165     * Tries to acquire an exclusive, reentrant write lock on a resource. <br>
166     * <br>
167     * This method blocks and waits for the lock in case it is not avaiable. If
168     * there is a timeout or a deadlock or the thread is interrupted a
169     * LockException is thrown.
170     * 
171     * @param ownerId
172     *            a unique id identifying the entity that wants to acquire this
173     *            lock
174     * @param resourceId
175     *            the resource to get the lock for
176     * @throws LockException
177     *             will be thrown when the lock can not be acquired
178     */
179    public void writeLock(Object ownerId, Object resourceId) throws LockException {
180        lock(ownerId, resourceId, ReadWriteLock.WRITE_LOCK, GenericLock.COMPATIBILITY_REENTRANT,
181                true, globalTimeoutMSecs);
182    }
183
184    protected GenericLock createLock(Object resourceId) {
185        synchronized (globalLocks) {
186            GenericLock lock = new ReadWriteLock(resourceId, logger);
187            globalLocks.put(resourceId, lock);
188            return lock;
189        }
190    }
191
192}