Coverage Report - org.apache.ojb.otm.lock.ObjectLock
 
Classes in this File Line Coverage Branch Coverage Complexity
ObjectLock
N/A
N/A
1.941
ObjectLock$LockEntry
N/A
N/A
1.941
 
 1  
 package org.apache.ojb.otm.lock;
 2  
 
 3  
 /* Copyright 2003-2005 The Apache Software Foundation
 4  
  *
 5  
  * Licensed under the Apache License, Version 2.0 (the "License");
 6  
  * you may not use this file except in compliance with the License.
 7  
  * You may obtain a copy of the License at
 8  
  *
 9  
  *     http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 
 18  
 import java.util.ArrayList;
 19  
 import java.util.Collection;
 20  
 import java.util.Collections;
 21  
 import java.util.HashMap;
 22  
 import java.util.Iterator;
 23  
 
 24  
 import org.apache.ojb.broker.Identity;
 25  
 import org.apache.ojb.otm.OTMKit;
 26  
 import org.apache.ojb.otm.core.Transaction;
 27  
 import org.apache.ojb.otm.lock.wait.LockWaitStrategy;
 28  
 
 29  
 /**
 30  
  *
 31  
  * Represents the locks held for an object. The basic assertion is that at any given point
 32  
  * in time, there can be multiple readers, but just one writer.
 33  
  *
 34  
  * @author <a href="mailto:rraghuram@hotmail.com">Raghu Rajah</a>
 35  
  *
 36  
  */
 37  
 public class ObjectLock
 38  
 {
 39  
     //////////////////////////////////
 40  
     // IVars
 41  
     //////////////////////////////////
 42  
 
 43  
     private Identity _oid;
 44  
     private LockEntry _writer;
 45  
     private HashMap _readers = new HashMap();
 46  
 
 47  
 
 48  
     ////////////////////////////////////////
 49  
     // Constructor
 50  
     ////////////////////////////////////////
 51  
 
 52  
     public ObjectLock(Identity oid)
 53  
     {
 54  
         _oid = oid;
 55  
     }
 56  
 
 57  
     ////////////////////////////////////////
 58  
     // Operations
 59  
     ////////////////////////////////////////
 60  
 
 61  
     public Identity getTargetIdentity()
 62  
     {
 63  
         return _oid;
 64  
     }
 65  
 
 66  
     public Transaction getWriter()
 67  
     {
 68  
         return (_writer == null)? null: _writer.getTx();
 69  
     }
 70  
 
 71  
     public boolean isReader(Transaction tx)
 72  
     {
 73  
         return _readers.containsKey(tx);
 74  
     }
 75  
 
 76  
     public boolean doesReaderExists()
 77  
     {
 78  
         return (_readers.size() > 0);
 79  
     }
 80  
 
 81  
     public Collection getReaders()
 82  
     {
 83  
         return Collections.unmodifiableCollection(_readers.keySet());
 84  
     }
 85  
 
 86  
     public void readLock(Transaction tx)
 87  
     {
 88  
         if (!isReader(tx))
 89  
         {
 90  
             new LockEntry(tx);
 91  
         }
 92  
     }
 93  
 
 94  
     public void writeLock(Transaction tx)
 95  
         throws LockingException
 96  
     {
 97  
         if (getWriter() != tx)
 98  
         {
 99  
             LockEntry lock = (LockEntry) _readers.get(tx);
 100  
 
 101  
             if (lock == null)
 102  
             {
 103  
                 lock = new LockEntry(tx);
 104  
             }
 105  
             lock.writeLock();
 106  
         }
 107  
     }
 108  
 
 109  
     public void releaseLock(Transaction tx)
 110  
     {
 111  
         LockEntry lock = (LockEntry)_readers.get(tx);
 112  
 
 113  
         if (lock != null)
 114  
         {
 115  
             lock.release();
 116  
         }
 117  
     }
 118  
 
 119  
     public void waitForTx(Transaction tx)
 120  
         throws LockingException
 121  
     {
 122  
         OTMKit kit = tx.getKit();
 123  
         LockWaitStrategy waitStrategy = kit.getLockWaitStrategy();
 124  
         waitStrategy.waitForLock(this, tx);
 125  
     }
 126  
 
 127  
     public boolean isFree()
 128  
     {
 129  
         return ((_writer == null) && _readers.isEmpty());
 130  
     }
 131  
 
 132  
     /////////////////////////////////////////
 133  
     // Inner classes
 134  
     /////////////////////////////////////////
 135  
 
 136  
     private class LockEntry
 137  
     {
 138  
         public Transaction _tx;
 139  
         public ArrayList _listeners;
 140  
 
 141  
         public LockEntry(Transaction tx)
 142  
         {
 143  
             _tx = tx;
 144  
             _listeners = null;
 145  
             _readers.put(_tx, LockEntry.this);
 146  
         }
 147  
 
 148  
         /**
 149  
          *
 150  
          * Returns the LockListeners for this entry.
 151  
          *
 152  
          * @return      ArrayList of LockListeners
 153  
          *
 154  
          */
 155  
         public ArrayList getListeners()
 156  
         {
 157  
             return _listeners;
 158  
         }
 159  
 
 160  
         /**
 161  
          *
 162  
          * Returns the transaction held by this LockEntry.
 163  
          *
 164  
          * @return      Transaction
 165  
          *
 166  
          */
 167  
         public Transaction getTx()
 168  
         {
 169  
             return _tx;
 170  
         }
 171  
 
 172  
         /**
 173  
          *
 174  
          *  Add a listener to the list of LockListeners. LockListener is notified, when this
 175  
          *  LockEntry is released.
 176  
          *
 177  
          *  @param listener         the LockListener
 178  
          *
 179  
          */
 180  
         public void addListener(LockListener listener)
 181  
         {
 182  
             if (listener != null)
 183  
             {
 184  
                 if (_listeners == null)
 185  
                 {
 186  
                     _listeners = new ArrayList();
 187  
                 }
 188  
 
 189  
                 _listeners.add(listener);
 190  
             }
 191  
         }
 192  
 
 193  
         /**
 194  
          *
 195  
          *  Make this lock a writer. If a writer is already present, the call will block until
 196  
          *  the lock is released by the writer.
 197  
          *
 198  
          */
 199  
         public void writeLock() throws LockingException
 200  
         {
 201  
             while (true)
 202  
             {
 203  
                 if (_writer != null && _writer._tx != _tx)
 204  
                 {
 205  
                     waitForTx(_tx);
 206  
                 }
 207  
 
 208  
                 synchronized (ObjectLock.this)
 209  
                 {
 210  
                     if (_writer == null || _writer._tx == _tx)
 211  
                     {
 212  
                         _writer = this;
 213  
                         return;
 214  
                     }
 215  
                 }
 216  
             }
 217  
         }
 218  
 
 219  
         public void release()
 220  
         {
 221  
             synchronized (ObjectLock.this)
 222  
             {
 223  
                 if (_writer == this)
 224  
                 {
 225  
                     _writer = null;
 226  
                 }
 227  
             }
 228  
 
 229  
             _readers.remove(_tx);
 230  
 
 231  
             if (_listeners != null)
 232  
             {
 233  
                 for (Iterator iterator = _listeners.iterator(); iterator.hasNext();)
 234  
                 {
 235  
                   LockListener listener = (LockListener) iterator.next();
 236  
                   listener.lockReleased(_tx, _oid);
 237  
                 }
 238  
             }
 239  
         }
 240  
     }
 241  
 }