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 {@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     */
027    public 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    }