001: package org.apache.ojb.broker.locking;
002:
003: /* Copyright 2002-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 org.apache.commons.lang.SystemUtils;
019: import org.apache.commons.transaction.locking.GenericLock;
020: import org.apache.commons.transaction.locking.GenericLockManager;
021: import org.apache.commons.transaction.locking.LockException;
022: import org.apache.commons.transaction.util.LoggerFacade;
023: import org.apache.ojb.broker.util.logging.Logger;
024: import org.apache.ojb.broker.util.logging.LoggerFactory;
025:
026: /**
027: * A {@link LockManager} implementation based on apache's commons-transaction
028: * locking part.
029: * <p/>
030: * The timeout of locks is currently (OJB 1.0.2) not supported, maybe
031: * in further versions.
032: *
033: * @author <a href="mailto:arminw@apache.org">Armin Waibel</a>
034: * @version $Id: LockManagerCommonsImpl.java,v 1.1.2.2 2005/12/21 22:25:32 tomdz Exp $
035: */
036: public class LockManagerCommonsImpl implements LockManager {
037: private Logger log = LoggerFactory
038: .getLogger(LockManagerCommonsImpl.class);
039:
040: /**
041: * Timeout of the obtained lock.
042: */
043: private long lockTimeout;
044: /**
045: * Time to wait when lock call is blocked.
046: */
047: private long blockTimeout;
048: private LoggerFacade logFacade;
049: private OJBLockManager lm;
050:
051: public LockManagerCommonsImpl() {
052: logFacade = new LoggerFacadeImpl();
053: // default lock timeout
054: this .lockTimeout = DEFAULT_LOCK_TIMEOUT;
055: // default time to wait for a lock
056: this .blockTimeout = DEFAULT_BLOCK_TIMEOUT;
057: lm = new OJBLockManager(logFacade, blockTimeout,
058: GenericLockManager.DEFAULT_CHECK_THRESHHOLD);
059: }
060:
061: private boolean ignore(int isolationLevel) {
062: return isolationLevel == IsolationLevels.IL_OPTIMISTIC
063: || isolationLevel == IsolationLevels.IL_NONE;
064: }
065:
066: public long getLockTimeout() {
067: return lockTimeout;
068: }
069:
070: public void setLockTimeout(long timeout) {
071: this .lockTimeout = timeout;
072: }
073:
074: public long getBlockTimeout() {
075: return blockTimeout;
076: }
077:
078: public void setBlockTimeout(long blockTimeout) {
079: this .blockTimeout = blockTimeout;
080: }
081:
082: public String getLockInfo() {
083: String eol = SystemUtils.LINE_SEPARATOR;
084: StringBuffer msg = new StringBuffer("Class: "
085: + LockManagerCommonsImpl.class.getName() + eol);
086: msg.append("lock timeout: " + getLockTimeout() + " [ms]" + eol);
087: msg.append("block timeout: " + getBlockTimeout() + " [ms]"
088: + eol);
089: msg.append("commons-tx lock-manger info ==> " + eol);
090: msg.append(lm);
091: return msg.toString();
092: }
093:
094: public boolean readLock(Object key, Object resourceId,
095: int isolationLevel) {
096: return ignore(isolationLevel) ? true : lm.readLock(key,
097: resourceId, new Integer(isolationLevel), blockTimeout);
098: }
099:
100: public boolean writeLock(Object key, Object resourceId,
101: int isolationLevel) {
102: return ignore(isolationLevel) ? true : lm.writeLock(key,
103: resourceId, new Integer(isolationLevel), blockTimeout);
104: }
105:
106: public boolean upgradeLock(Object key, Object resourceId,
107: int isolationLevel) {
108: return ignore(isolationLevel) ? true : lm.upgradeLock(key,
109: resourceId, new Integer(isolationLevel), blockTimeout);
110: }
111:
112: public boolean releaseLock(Object key, Object resourceId) {
113: boolean result = true;
114: try {
115: lm.release(key, resourceId);
116: } catch (RuntimeException e) {
117: log.error("Can't release lock for owner key " + key
118: + ", on resource " + resourceId, e);
119: result = false;
120: }
121: return result;
122: }
123:
124: public void releaseLocks(Object key) {
125: try {
126: lm.releaseAll(key);
127: } catch (RuntimeException e) {
128: log
129: .error("Can't release all locks for owner key "
130: + key, e);
131: }
132: }
133:
134: public boolean hasRead(Object key, Object resourceId) {
135: return lm.hasRead(key, resourceId);
136: }
137:
138: public boolean hasWrite(Object key, Object resourceId) {
139: return lm.hasWrite(key, resourceId);
140: }
141:
142: public boolean hasUpgrade(Object key, Object resourceId) {
143: return lm.hasUpgrade(key, resourceId);
144: }
145:
146: //===================================================
147: // inner class, commons-tx lock manager
148: //===================================================
149: /**
150: * Extension class of {@link CommonsOJBLockManager}
151: * which supports additionally convenience methods for read/write/upgrade locks and checks
152: * for these locks.
153: */
154: final class OJBLockManager extends CommonsOJBLockManager {
155: public OJBLockManager(LoggerFacade logger, long timeoutMSecs,
156: long checkThreshholdMSecs)
157: throws IllegalArgumentException {
158: super (logger, timeoutMSecs, checkThreshholdMSecs);
159: }
160:
161: private CommonsOJBLockManager.OJBLock lookupLock(
162: Object resourceId) {
163: return (CommonsOJBLockManager.OJBLock) getLock(resourceId);
164: }
165:
166: boolean readLock(Object key, Object resourceId,
167: Integer isolationLevel, long timeout) {
168: /*
169: arminw: Not sure what's the best way to go
170: - a normal 'lock' call with enabled lock wait time (blocking)
171: - or an immediately returning 'tryLock' call.
172: E.g. assume the user query for 1000 objects and 100 objects has write locks
173: by concurrent threads, then blocking could be counterproductive, because it could
174: be that the app will wait seconds for the first read lock, get it, wait seconds
175: for the next read lock,.... In the worst case app will wait for all 100 locked objects.
176: So I chose the 'tryLock' call for read locks which immediately return.
177: */
178: int lockLevel = mapLockLevelDependendOnIsolationLevel(
179: isolationLevel, COMMON_READ_LOCK);
180: return tryLock(key, resourceId, lockLevel, true,
181: isolationLevel);
182: }
183:
184: boolean writeLock(Object key, Object resourceId,
185: Integer isolationLevel, long timeout) {
186: try {
187: int lockLevel = mapLockLevelDependendOnIsolationLevel(
188: isolationLevel, COMMON_WRITE_LOCK);
189: lock(key, resourceId, lockLevel,
190: GenericLock.COMPATIBILITY_REENTRANT, false,
191: timeout, isolationLevel);
192: return true;
193: } catch (LockException e) {
194: if (log.isEnabledFor(Logger.INFO))
195: log.info("Can't get write lock for " + key, e);
196: return false;
197: }
198: }
199:
200: boolean upgradeLock(Object key, Object resourceId,
201: Integer isolationLevel, long timeout) {
202: try {
203: int lockLevel = mapLockLevelDependendOnIsolationLevel(
204: isolationLevel, COMMON_UPGRADE_LOCK);
205: lock(key, resourceId, lockLevel,
206: GenericLock.COMPATIBILITY_REENTRANT, false,
207: timeout, isolationLevel);
208: return true;
209: } catch (LockException e) {
210: if (log.isEnabledFor(Logger.INFO))
211: log.info("Can't get upgrade lock for " + key, e);
212: return false;
213: }
214: }
215:
216: boolean hasRead(Object key, Object resourceId) {
217: CommonsOJBLockManager.OJBLock lock = lookupLock(resourceId);
218: boolean result = false;
219: if (lock != null) {
220: result = lock.hasRead(key);
221: }
222: return result;
223: }
224:
225: boolean hasWrite(Object key, Object resourceId) {
226: CommonsOJBLockManager.OJBLock lock = lookupLock(resourceId);
227: boolean result = false;
228: if (lock != null) {
229: result = lock.hasWrite(key);
230: }
231: return result;
232: }
233:
234: boolean hasUpgrade(Object key, Object resourceId) {
235: CommonsOJBLockManager.OJBLock lock = lookupLock(resourceId);
236: boolean result = false;
237: if (lock != null) {
238: result = lock.hasUpgrade(key);
239: }
240: return result;
241: }
242: }
243:
244: //===================================================
245: // inner class, logging facade
246: //===================================================
247: /**
248: * Logging facade for apache's commons-transaction.
249: */
250: final class LoggerFacadeImpl implements LoggerFacade {
251:
252: public LoggerFacade createLogger(String name) {
253: return this ;
254: }
255:
256: public void logInfo(String message) {
257: log.info(message);
258: }
259:
260: public void logFine(String message) {
261: log.debug(message);
262: }
263:
264: public boolean isFineEnabled() {
265: return log.isDebugEnabled();
266: }
267:
268: public void logFiner(String message) {
269: log.debug(message);
270: }
271:
272: public boolean isFinerEnabled() {
273: return log.isDebugEnabled();
274: }
275:
276: public void logFinest(String message) {
277: log.debug(message);
278: }
279:
280: public boolean isFinestEnabled() {
281: return log.isDebugEnabled();
282: }
283:
284: public void logWarning(String message) {
285: log.warn(message);
286: }
287:
288: public void logWarning(String message, Throwable t) {
289: log.warn(message, t);
290: }
291:
292: public void logSevere(String message) {
293: log.error(message);
294: }
295:
296: public void logSevere(String message, Throwable t) {
297: log.error(message, t);
298: }
299: }
300: }
|