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
020package org.apache.james.mailrepository.lib;
021
022import java.util.Hashtable;
023
024/**
025 * Provides Lock functionality
026 */
027public class Lock {
028    /**
029     * An internal hash table of keys to locks
030     */
031    private final Hashtable<Object, Object> locks = new Hashtable<Object, Object>();
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(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(Object key) {
052        Object o = locks.get(key);
053
054        return null == o || o == this.getCallerId();
055
056    }
057
058    /**
059     * Lock on a given object.
060     * 
061     * @param key
062     *            the Object on which to lock
063     * @return true if the locking was successful, false otherwise
064     */
065    public boolean lock(Object key) {
066        Object theLock;
067
068        synchronized (this) {
069            theLock = locks.get(key);
070
071            if (null == theLock) {
072                locks.put(key, getCallerId());
073                return true;
074            } else return getCallerId() == theLock;
075        }
076    }
077
078    /**
079     * Release the lock on a given object.
080     * 
081     * @param key
082     *            the Object on which the lock is held
083     * @return true if the unlocking was successful, false otherwise
084     */
085    public boolean unlock(Object key) {
086        Object theLock;
087        synchronized (this) {
088            theLock = locks.get(key);
089
090            if (null == theLock) {
091                return true;
092            } else if (getCallerId() == theLock) {
093                locks.remove(key);
094                return true;
095            } else {
096                return false;
097            }
098        }
099    }
100
101    /**
102     * Private helper method to abstract away caller ID.
103     * 
104     * @return the id of the caller (i.e. the Thread reference)
105     */
106    private Object getCallerId() {
107        return Thread.currentThread();
108    }
109}