001    /****************************************************************
002     * Licensed to the Apache Software Foundation (ASF) under one   *
003     * or more contributor license agreements.  See the NOTICE file *
004     * distributed with this work for additional information        *
005     * regarding copyright ownership.  The ASF licenses this file   *
006     * to you under the Apache License, Version 2.0 (the            *
007     * "License"); you may not use this file except in compliance   *
008     * with the License.  You may obtain a copy of the License at   *
009     *                                                              *
010     *   http://www.apache.org/licenses/LICENSE-2.0                 *
011     *                                                              *
012     * Unless required by applicable law or agreed to in writing,   *
013     * software distributed under the License is distributed on an  *
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
015     * KIND, either express or implied.  See the License for the    *
016     * specific language governing permissions and limitations      *
017     * under the License.                                           *
018     ****************************************************************/
019    
020    package org.apache.james.mailrepository.lib;
021    
022    import java.util.Hashtable;
023    
024    /**
025     * Provides Lock functionality
026     */
027    public class Lock {
028        /**
029         * An internal hash table of keys to locks
030         */
031        private Hashtable locks = new Hashtable();
032    
033        /**
034         * Check to see if the object is locked
035         * 
036         * @param key
037         *            the Object on which to check the lock
038         * @return true if the object is locked, false otherwise
039         */
040        public boolean isLocked(final Object key) {
041            return (locks.get(key) != null);
042        }
043    
044        /**
045         * Check to see if we can lock on a given object.
046         * 
047         * @param key
048         *            the Object on which to lock
049         * @return true if the calling thread can lock, false otherwise
050         */
051        public boolean canI(final Object key) {
052            Object o = locks.get(key);
053    
054            if (null == o || o == this.getCallerId()) {
055                return true;
056            }
057    
058            return false;
059        }
060    
061        /**
062         * Lock on a given object.
063         * 
064         * @param key
065         *            the Object on which to lock
066         * @return true if the locking was successful, false otherwise
067         */
068        public boolean lock(final Object key) {
069            Object theLock;
070    
071            synchronized (this) {
072                theLock = locks.get(key);
073    
074                if (null == theLock) {
075                    locks.put(key, getCallerId());
076                    return true;
077                } else if (getCallerId() == theLock) {
078                    return true;
079                } else {
080                    return false;
081                }
082            }
083        }
084    
085        /**
086         * Release the lock on a given object.
087         * 
088         * @param key
089         *            the Object on which the lock is held
090         * @return true if the unlocking was successful, false otherwise
091         */
092        public boolean unlock(final Object key) {
093            Object theLock;
094            synchronized (this) {
095                theLock = locks.get(key);
096    
097                if (null == theLock) {
098                    return true;
099                } else if (getCallerId() == theLock) {
100                    locks.remove(key);
101                    return true;
102                } else {
103                    return false;
104                }
105            }
106        }
107    
108        /**
109         * Private helper method to abstract away caller ID.
110         * 
111         * @return the id of the caller (i.e. the Thread reference)
112         */
113        private Object getCallerId() {
114            return Thread.currentThread();
115        }
116    }