001: package org.apache.ojb.otm.lock;
002:
003: /* Copyright 2003-2005 The Apache Software Foundation
004: *
005: * Licensed under the Apache License, Version 2.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * 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:
018: import java.util.ArrayList;
019: import java.util.Collection;
020: import java.util.Collections;
021: import java.util.HashMap;
022: import java.util.Iterator;
023:
024: import org.apache.ojb.broker.Identity;
025: import org.apache.ojb.otm.OTMKit;
026: import org.apache.ojb.otm.core.Transaction;
027: import org.apache.ojb.otm.lock.wait.LockWaitStrategy;
028:
029: /**
030: *
031: * Represents the locks held for an object. The basic assertion is that at any given point
032: * in time, there can be multiple readers, but just one writer.
033: *
034: * @author <a href="mailto:rraghuram@hotmail.com">Raghu Rajah</a>
035: *
036: */
037: public class ObjectLock {
038: //////////////////////////////////
039: // IVars
040: //////////////////////////////////
041:
042: private Identity _oid;
043: private LockEntry _writer;
044: private HashMap _readers = new HashMap();
045:
046: ////////////////////////////////////////
047: // Constructor
048: ////////////////////////////////////////
049:
050: public ObjectLock(Identity oid) {
051: _oid = oid;
052: }
053:
054: ////////////////////////////////////////
055: // Operations
056: ////////////////////////////////////////
057:
058: public Identity getTargetIdentity() {
059: return _oid;
060: }
061:
062: public Transaction getWriter() {
063: return (_writer == null) ? null : _writer.getTx();
064: }
065:
066: public boolean isReader(Transaction tx) {
067: return _readers.containsKey(tx);
068: }
069:
070: public boolean doesReaderExists() {
071: return (_readers.size() > 0);
072: }
073:
074: public Collection getReaders() {
075: return Collections.unmodifiableCollection(_readers.keySet());
076: }
077:
078: public void readLock(Transaction tx) {
079: if (!isReader(tx)) {
080: new LockEntry(tx);
081: }
082: }
083:
084: public void writeLock(Transaction tx) throws LockingException {
085: if (getWriter() != tx) {
086: LockEntry lock = (LockEntry) _readers.get(tx);
087:
088: if (lock == null) {
089: lock = new LockEntry(tx);
090: }
091: lock.writeLock();
092: }
093: }
094:
095: public void releaseLock(Transaction tx) {
096: LockEntry lock = (LockEntry) _readers.get(tx);
097:
098: if (lock != null) {
099: lock.release();
100: }
101: }
102:
103: public void waitForTx(Transaction tx) throws LockingException {
104: OTMKit kit = tx.getKit();
105: LockWaitStrategy waitStrategy = kit.getLockWaitStrategy();
106: waitStrategy.waitForLock(this , tx);
107: }
108:
109: public boolean isFree() {
110: return ((_writer == null) && _readers.isEmpty());
111: }
112:
113: /////////////////////////////////////////
114: // Inner classes
115: /////////////////////////////////////////
116:
117: private class LockEntry {
118: public Transaction _tx;
119: public ArrayList _listeners;
120:
121: public LockEntry(Transaction tx) {
122: _tx = tx;
123: _listeners = null;
124: _readers.put(_tx, LockEntry.this );
125: }
126:
127: /**
128: *
129: * Returns the LockListeners for this entry.
130: *
131: * @return ArrayList of LockListeners
132: *
133: */
134: public ArrayList getListeners() {
135: return _listeners;
136: }
137:
138: /**
139: *
140: * Returns the transaction held by this LockEntry.
141: *
142: * @return Transaction
143: *
144: */
145: public Transaction getTx() {
146: return _tx;
147: }
148:
149: /**
150: *
151: * Add a listener to the list of LockListeners. LockListener is notified, when this
152: * LockEntry is released.
153: *
154: * @param listener the LockListener
155: *
156: */
157: public void addListener(LockListener listener) {
158: if (listener != null) {
159: if (_listeners == null) {
160: _listeners = new ArrayList();
161: }
162:
163: _listeners.add(listener);
164: }
165: }
166:
167: /**
168: *
169: * Make this lock a writer. If a writer is already present, the call will block until
170: * the lock is released by the writer.
171: *
172: */
173: public void writeLock() throws LockingException {
174: while (true) {
175: if (_writer != null && _writer._tx != _tx) {
176: waitForTx(_tx);
177: }
178:
179: synchronized (ObjectLock.this ) {
180: if (_writer == null || _writer._tx == _tx) {
181: _writer = this ;
182: return;
183: }
184: }
185: }
186: }
187:
188: public void release() {
189: synchronized (ObjectLock.this ) {
190: if (_writer == this ) {
191: _writer = null;
192: }
193: }
194:
195: _readers.remove(_tx);
196:
197: if (_listeners != null) {
198: for (Iterator iterator = _listeners.iterator(); iterator
199: .hasNext();) {
200: LockListener listener = (LockListener) iterator
201: .next();
202: listener.lockReleased(_tx, _oid);
203: }
204: }
205: }
206: }
207: }
|