| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
| CommonsOJBLockManager |
|
| 1.878787878787879;1.879 | ||||
| CommonsOJBLockManager$OJBLock |
|
| 1.878787878787879;1.879 | ||||
| CommonsOJBLockManager$ReadCommitedLock |
|
| 1.878787878787879;1.879 | ||||
| CommonsOJBLockManager$ReadUncommittedLock |
|
| 1.878787878787879;1.879 | ||||
| CommonsOJBLockManager$RepeadableReadsLock |
|
| 1.878787878787879;1.879 | ||||
| CommonsOJBLockManager$SerializeableLock |
|
| 1.878787878787879;1.879 |
| 1 | package org.apache.ojb.broker.locking; | |
| 2 | ||
| 3 | /* Copyright 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 org.apache.commons.transaction.locking.GenericLock; | |
| 19 | import org.apache.commons.transaction.locking.GenericLockManager; | |
| 20 | import org.apache.commons.transaction.locking.LockException; | |
| 21 | import org.apache.commons.transaction.locking.MultiLevelLock; | |
| 22 | import org.apache.commons.transaction.util.LoggerFacade; | |
| 23 | ||
| 24 | /** | |
| 25 | * Extension of {@link org.apache.commons.transaction.locking.GenericLockManager} to | |
| 26 | * support all locking isolation level defined in OJB locking api and a provider of | |
| 27 | * specific {@link org.apache.commons.transaction.locking.GenericLock} implementation classes | |
| 28 | * representing the isolation levels specified in {@link org.apache.ojb.broker.locking.LockManager}, like | |
| 29 | * {@link org.apache.ojb.broker.locking.LockManager#IL_READ_COMMITTED}, ... . | |
| 30 | * <p/> | |
| 31 | * The specific lock classes will be returned on call of | |
| 32 | * {@link #createIsolationLevel(Object, Object, org.apache.commons.transaction.util.LoggerFacade)} | |
| 33 | * dependend on the specified isolation level. | |
| 34 | * | |
| 35 | * @author <a href="mailto:arminw@apache.org">Armin Waibel</a> | |
| 36 | * @version $Id: CommonsOJBLockManager.java,v 1.1 2007-08-24 22:17:41 ewestfal Exp $ | |
| 37 | */ | |
| 38 | class CommonsOJBLockManager extends GenericLockManager | |
| 39 | { | |
| 40 | static final int COMMON_READ_LOCK = 101; | |
| 41 | static final int COMMON_WRITE_LOCK = 107; | |
| 42 | static final int COMMON_UPGRADE_LOCK = 113; | |
| 43 | ||
| 44 | public CommonsOJBLockManager(LoggerFacade logger, long timeoutMSecs, long checkThreshholdMSecs) | |
| 45 | throws IllegalArgumentException | |
| 46 | { | |
| 47 | super(1, logger, timeoutMSecs, checkThreshholdMSecs); | |
| 48 | } | |
| 49 | ||
| 50 | /** | |
| 51 | * @see org.apache.commons.transaction.locking.GenericLockManager#tryLock(Object, Object, int, boolean) | |
| 52 | */ | |
| 53 | public boolean tryLock(Object ownerId, Object resourceId, int targetLockLevel, boolean reentrant) | |
| 54 | { | |
| 55 | return tryLock(ownerId, resourceId, targetLockLevel, reentrant, null); | |
| 56 | } | |
| 57 | ||
| 58 | /** | |
| 59 | * Tries to acquire a lock on a resource. <br> | |
| 60 | * <br> | |
| 61 | * This method does not block, but immediatly returns. If a lock is not | |
| 62 | * available <code>false</code> will be returned. | |
| 63 | * | |
| 64 | * @param ownerId a unique id identifying the entity that wants to acquire this | |
| 65 | * lock | |
| 66 | * @param resourceId the resource to get the level for | |
| 67 | * @param targetLockLevel the lock level to acquire | |
| 68 | * @param reentrant <code>true</code> if this request shall not be influenced by | |
| 69 | * other locks held by the same owner | |
| 70 | * @param isolationId the isolation level identity key. See {@link CommonsOJBLockManager}. | |
| 71 | * @return <code>true</code> if the lock has been acquired, <code>false</code> otherwise | |
| 72 | */ | |
| 73 | public boolean tryLock(Object ownerId, Object resourceId, int targetLockLevel, boolean reentrant, Object isolationId) | |
| 74 | { | |
| 75 | timeoutCheck(ownerId); | |
| 76 | ||
| 77 | OJBLock lock = atomicGetOrCreateLock(resourceId, isolationId); | |
| 78 | boolean acquired = lock.tryLock(ownerId, targetLockLevel, | |
| 79 | reentrant ? GenericLock.COMPATIBILITY_REENTRANT : GenericLock.COMPATIBILITY_NONE, | |
| 80 | false); | |
| 81 | ||
| 82 | if(acquired) | |
| 83 | { | |
| 84 | addOwner(ownerId, lock); | |
| 85 | } | |
| 86 | return acquired; | |
| 87 | } | |
| 88 | ||
| 89 | /** | |
| 90 | * @see org.apache.commons.transaction.locking.GenericLockManager#lock(Object, Object, int, int, boolean, long) | |
| 91 | */ | |
| 92 | public void lock(Object ownerId, Object resourceId, int targetLockLevel, int compatibility, | |
| 93 | boolean preferred, long timeoutMSecs) throws LockException | |
| 94 | { | |
| 95 | lock(ownerId, resourceId, targetLockLevel, compatibility, preferred, timeoutMSecs, null); | |
| 96 | } | |
| 97 | ||
| 98 | /** | |
| 99 | * Most flexible way to acquire a lock on a resource. <br> | |
| 100 | * <br> | |
| 101 | * This method blocks and waits for the lock in case it is not avaiable. If | |
| 102 | * there is a timeout or a deadlock or the thread is interrupted a | |
| 103 | * LockException is thrown. | |
| 104 | * | |
| 105 | * @param ownerId a unique id identifying the entity that wants to acquire this | |
| 106 | * lock | |
| 107 | * @param resourceId the resource to get the level for | |
| 108 | * @param targetLockLevel the lock level to acquire | |
| 109 | * @param compatibility {@link GenericLock#COMPATIBILITY_NONE}if no additional compatibility is | |
| 110 | * desired (same as reentrant set to false) , | |
| 111 | * {@link GenericLock#COMPATIBILITY_REENTRANT}if lock level by the same | |
| 112 | * owner shall not affect compatibility (same as reentrant set to | |
| 113 | * true), or {@link GenericLock#COMPATIBILITY_SUPPORT}if lock levels that | |
| 114 | * are the same as the desired shall not affect compatibility, or | |
| 115 | * finally {@link GenericLock#COMPATIBILITY_REENTRANT_AND_SUPPORT}which is | |
| 116 | * a combination of reentrant and support | |
| 117 | * @param preferred in case this lock request is incompatible with existing ones | |
| 118 | * and we wait, it shall be granted before other waiting requests | |
| 119 | * that are not preferred | |
| 120 | * @param timeoutMSecs specifies the maximum wait time in milliseconds | |
| 121 | * @param isolationId the isolation level identity key. See {@link CommonsOJBLockManager}. | |
| 122 | * @throws LockException will be thrown when the lock can not be acquired | |
| 123 | */ | |
| 124 | public void lock(Object ownerId, Object resourceId, int targetLockLevel, int compatibility, | |
| 125 | boolean preferred, long timeoutMSecs, Object isolationId) throws LockException | |
| 126 | { | |
| 127 | timeoutCheck(ownerId); | |
| 128 | GenericLock lock = atomicGetOrCreateLock(resourceId, isolationId); | |
| 129 | super.doLock(lock, ownerId, resourceId, targetLockLevel, compatibility, preferred, timeoutMSecs); | |
| 130 | } | |
| 131 | ||
| 132 | /** | |
| 133 | * @see org.apache.commons.transaction.locking.GenericLockManager#atomicGetOrCreateLock(Object) | |
| 134 | */ | |
| 135 | public MultiLevelLock atomicGetOrCreateLock(Object resourceId) | |
| 136 | { | |
| 137 | return atomicGetOrCreateLock(resourceId, null); | |
| 138 | } | |
| 139 | ||
| 140 | /** | |
| 141 | * Either gets an existing lock on the specified resource or creates one if none exists. | |
| 142 | * This methods guarantees to do this atomically. | |
| 143 | * | |
| 144 | * @param resourceId the resource to get or create the lock on | |
| 145 | * @param isolationId the isolation level identity key. See {@link CommonsOJBLockManager}. | |
| 146 | * @return the lock for the specified resource | |
| 147 | */ | |
| 148 | public OJBLock atomicGetOrCreateLock(Object resourceId, Object isolationId) | |
| 149 | { | |
| 150 | synchronized(globalLocks) | |
| 151 | { | |
| 152 | MultiLevelLock lock = getLock(resourceId); | |
| 153 | if(lock == null) | |
| 154 | { | |
| 155 | lock = createLock(resourceId, isolationId); | |
| 156 | } | |
| 157 | return (OJBLock) lock; | |
| 158 | } | |
| 159 | } | |
| 160 | ||
| 161 | /** | |
| 162 | * @see org.apache.commons.transaction.locking.GenericLockManager#createLock(Object) | |
| 163 | */ | |
| 164 | protected GenericLock createLock(Object resourceId) | |
| 165 | { | |
| 166 | return createLock(resourceId, null); | |
| 167 | } | |
| 168 | ||
| 169 | protected GenericLock createLock(Object resourceId, Object isolationId) | |
| 170 | { | |
| 171 | synchronized(globalLocks) | |
| 172 | { | |
| 173 | if(isolationId != null) | |
| 174 | { | |
| 175 | GenericLock lock = createIsolationLevel(resourceId, isolationId, logger); | |
| 176 | globalLocks.put(resourceId, lock); | |
| 177 | return lock; | |
| 178 | } | |
| 179 | else | |
| 180 | { | |
| 181 | GenericLock lock = new GenericLock(resourceId, maxLockLevel, logger); | |
| 182 | globalLocks.put(resourceId, lock); | |
| 183 | return lock; | |
| 184 | } | |
| 185 | } | |
| 186 | } | |
| 187 | ||
| 188 | /** | |
| 189 | * Creates {@link org.apache.commons.transaction.locking.GenericLock} based | |
| 190 | * {@link org.apache.commons.transaction.locking.MultiLevelLock2} instances | |
| 191 | * dependend on the specified isolation identity object. | |
| 192 | */ | |
| 193 | public OJBLock createIsolationLevel(Object resourceId, Object isolationId, LoggerFacade logger) | |
| 194 | { | |
| 195 | OJBLock result = null; | |
| 196 | switch(((Integer) isolationId).intValue()) | |
| 197 | { | |
| 198 | case LockManager.IL_READ_UNCOMMITTED: | |
| 199 | result = new ReadUncommittedLock(resourceId, logger); | |
| 200 | break; | |
| 201 | case LockManager.IL_READ_COMMITTED: | |
| 202 | result = new ReadCommitedLock(resourceId, logger); | |
| 203 | break; | |
| 204 | case LockManager.IL_REPEATABLE_READ: | |
| 205 | result = new RepeadableReadsLock(resourceId, logger); | |
| 206 | break; | |
| 207 | case LockManager.IL_SERIALIZABLE: | |
| 208 | result = new SerializeableLock(resourceId, logger); | |
| 209 | break; | |
| 210 | case LockManager.IL_OPTIMISTIC: | |
| 211 | throw new LockRuntimeException("Optimistic locking must be handled on top of this class"); | |
| 212 | default: | |
| 213 | throw new LockRuntimeException("Unknown lock isolation level specified"); | |
| 214 | } | |
| 215 | return result; | |
| 216 | } | |
| 217 | ||
| 218 | /** | |
| 219 | * Helper method to map the specified common lock level (e.g like | |
| 220 | * {@link #COMMON_READ_LOCK}, {@link #COMMON_UPGRADE_LOCK, ...}) based | |
| 221 | * on the isolation level to the internal used lock level value by the | |
| 222 | * {@link org.apache.commons.transaction.locking.MultiLevelLock2} implementation. | |
| 223 | * | |
| 224 | * @param isolationId | |
| 225 | * @param lockLevel | |
| 226 | * @return | |
| 227 | */ | |
| 228 | int mapLockLevelDependendOnIsolationLevel(Integer isolationId, int lockLevel) | |
| 229 | { | |
| 230 | int result = 0; | |
| 231 | switch(isolationId.intValue()) | |
| 232 | { | |
| 233 | case LockManager.IL_READ_UNCOMMITTED: | |
| 234 | result = ReadUncommittedLock.mapLockLevel(lockLevel); | |
| 235 | break; | |
| 236 | case LockManager.IL_READ_COMMITTED: | |
| 237 | result = ReadCommitedLock.mapLockLevel(lockLevel); | |
| 238 | break; | |
| 239 | case LockManager.IL_REPEATABLE_READ: | |
| 240 | result = RepeadableReadsLock.mapLockLevel(lockLevel); | |
| 241 | break; | |
| 242 | case LockManager.IL_SERIALIZABLE: | |
| 243 | result = SerializeableLock.mapLockLevel(lockLevel); | |
| 244 | break; | |
| 245 | case LockManager.IL_OPTIMISTIC: | |
| 246 | throw new LockRuntimeException("Optimistic locking must be handled on top of this class"); | |
| 247 | default: | |
| 248 | throw new LockRuntimeException("Unknown lock isolation level specified"); | |
| 249 | } | |
| 250 | return result; | |
| 251 | } | |
| 252 | ||
| 253 | ||
| 254 | ||
| 255 | //=================================================== | |
| 256 | // inner class, commons-tx lock | |
| 257 | //=================================================== | |
| 258 | /** | |
| 259 | * Abstract base class to implement the different {@link org.apache.commons.transaction.locking.GenericLock} | |
| 260 | * extension classes representing the OJB isolation levels (e.g. READ_COMMITTED, REPEADABLE_READ,...) | |
| 261 | */ | |
| 262 | abstract static class OJBLock extends GenericLock | |
| 263 | { | |
| 264 | public OJBLock(Object resourceId, int maxLockLevel, LoggerFacade logger) | |
| 265 | { | |
| 266 | super(resourceId, maxLockLevel, logger); | |
| 267 | } | |
| 268 | ||
| 269 | /** | |
| 270 | * Need to override this method to make it accessible in | |
| 271 | * {@link CommonsOJBLockManager}. | |
| 272 | * | |
| 273 | * @see GenericLock#tryLock(Object, int, int, boolean) | |
| 274 | */ | |
| 275 | protected boolean tryLock(Object ownerId, int targetLockLevel, int compatibility, boolean preferred) | |
| 276 | { | |
| 277 | return super.tryLock(ownerId, targetLockLevel, compatibility, preferred); | |
| 278 | } | |
| 279 | ||
| 280 | /** | |
| 281 | * Convenience method. | |
| 282 | */ | |
| 283 | abstract boolean hasRead(Object ownerId); | |
| 284 | ||
| 285 | /** | |
| 286 | * Convenience method. | |
| 287 | */ | |
| 288 | abstract boolean hasWrite(Object ownerId); | |
| 289 | ||
| 290 | /** | |
| 291 | * Convenience method. | |
| 292 | */ | |
| 293 | abstract boolean hasUpgrade(Object ownerId); | |
| 294 | ||
| 295 | /** | |
| 296 | * Convenience method. | |
| 297 | */ | |
| 298 | abstract boolean readLock(Object ownerId, long timeout) throws InterruptedException; | |
| 299 | ||
| 300 | /** | |
| 301 | * Convenience method. | |
| 302 | */ | |
| 303 | abstract boolean writeLock(Object ownerId, long timeout) throws InterruptedException; | |
| 304 | ||
| 305 | /** | |
| 306 | * Convenience method. | |
| 307 | */ | |
| 308 | abstract boolean upgradeLock(Object ownerId, long timeout) throws InterruptedException; | |
| 309 | } | |
| 310 | ||
| 311 | ||
| 312 | ||
| 313 | //=================================================== | |
| 314 | // inner class, commons-tx lock | |
| 315 | //=================================================== | |
| 316 | /** | |
| 317 | * Implementation of isolation level {@link LockManager#IL_READ_UNCOMMITTED}. | |
| 318 | */ | |
| 319 | static class ReadUncommittedLock extends RepeadableReadsLock | |
| 320 | { | |
| 321 | public ReadUncommittedLock(Object resourceId, LoggerFacade logger) | |
| 322 | { | |
| 323 | super(resourceId, logger); | |
| 324 | } | |
| 325 | ||
| 326 | protected boolean isCompatible(int targetLockLevel, int currentLockLevel) | |
| 327 | { | |
| 328 | if(currentLockLevel == READ_LOCK || targetLockLevel == READ_LOCK) | |
| 329 | { | |
| 330 | return true; | |
| 331 | } | |
| 332 | else | |
| 333 | { | |
| 334 | return super.isCompatible(targetLockLevel, currentLockLevel); | |
| 335 | } | |
| 336 | } | |
| 337 | } | |
| 338 | ||
| 339 | //=================================================== | |
| 340 | // inner class, commons-tx lock | |
| 341 | //=================================================== | |
| 342 | /** | |
| 343 | * Implementation of isolation level {@link LockManager#IL_READ_COMMITTED}. | |
| 344 | */ | |
| 345 | static final class ReadCommitedLock extends RepeadableReadsLock | |
| 346 | { | |
| 347 | public ReadCommitedLock(Object resourceId, LoggerFacade logger) | |
| 348 | { | |
| 349 | super(resourceId, logger); | |
| 350 | } | |
| 351 | ||
| 352 | protected boolean isCompatible(int targetLockLevel, int currentLockLevel) | |
| 353 | { | |
| 354 | if(currentLockLevel == READ_LOCK) | |
| 355 | { | |
| 356 | return true; | |
| 357 | } | |
| 358 | else | |
| 359 | { | |
| 360 | return super.isCompatible(targetLockLevel, currentLockLevel); | |
| 361 | } | |
| 362 | } | |
| 363 | } | |
| 364 | ||
| 365 | //=================================================== | |
| 366 | // inner class, commons-tx lock | |
| 367 | //=================================================== | |
| 368 | /** | |
| 369 | * Implementation of isolation level {@link LockManager#IL_REPEATABLE_READ}. | |
| 370 | */ | |
| 371 | static class RepeadableReadsLock extends OJBLock | |
| 372 | { | |
| 373 | static final int NO_LOCK = 0; | |
| 374 | static final int READ_LOCK = 1; | |
| 375 | static final int UPGRADE_LOCK = 2; | |
| 376 | static final int WRITE_LOCK = 3; | |
| 377 | ||
| 378 | public RepeadableReadsLock(Object resourceId, LoggerFacade logger) | |
| 379 | { | |
| 380 | super(resourceId, WRITE_LOCK, logger); | |
| 381 | } | |
| 382 | ||
| 383 | static int mapLockLevel(int commonLockLevel) | |
| 384 | { | |
| 385 | int result = 0; | |
| 386 | switch(commonLockLevel) | |
| 387 | { | |
| 388 | case COMMON_READ_LOCK: | |
| 389 | result = READ_LOCK; | |
| 390 | break; | |
| 391 | case COMMON_UPGRADE_LOCK: | |
| 392 | result = UPGRADE_LOCK; | |
| 393 | break; | |
| 394 | case COMMON_WRITE_LOCK: | |
| 395 | result = WRITE_LOCK; | |
| 396 | break; | |
| 397 | default: | |
| 398 | throw new LockRuntimeException("Unknown common lock type: " + commonLockLevel); | |
| 399 | } | |
| 400 | return result; | |
| 401 | } | |
| 402 | ||
| 403 | public boolean readLock(Object ownerId, long timeout) throws InterruptedException | |
| 404 | { | |
| 405 | return acquire(ownerId, READ_LOCK, false, GenericLock.COMPATIBILITY_REENTRANT, false, timeout); | |
| 406 | } | |
| 407 | ||
| 408 | public boolean writeLock(Object ownerId, long timeout) throws InterruptedException | |
| 409 | { | |
| 410 | return acquire(ownerId, WRITE_LOCK, true, GenericLock.COMPATIBILITY_REENTRANT, false, timeout); | |
| 411 | } | |
| 412 | ||
| 413 | public boolean upgradeLock(Object ownerId, long timeout) throws InterruptedException | |
| 414 | { | |
| 415 | return acquire(ownerId, UPGRADE_LOCK, true, GenericLock.COMPATIBILITY_REENTRANT, true, timeout); | |
| 416 | } | |
| 417 | ||
| 418 | public boolean hasRead(Object ownerId) | |
| 419 | { | |
| 420 | return has(ownerId, READ_LOCK); | |
| 421 | } | |
| 422 | ||
| 423 | public boolean hasWrite(Object ownerId) | |
| 424 | { | |
| 425 | return has(ownerId, WRITE_LOCK); | |
| 426 | } | |
| 427 | ||
| 428 | public boolean hasUpgrade(Object ownerId) | |
| 429 | { | |
| 430 | return has(ownerId, UPGRADE_LOCK); | |
| 431 | } | |
| 432 | } | |
| 433 | ||
| 434 | ||
| 435 | //=================================================== | |
| 436 | // inner class, commons-tx lock | |
| 437 | //=================================================== | |
| 438 | /** | |
| 439 | * Implementation of isolation level {@link LockManager#IL_SERIALIZABLE}. | |
| 440 | */ | |
| 441 | static final class SerializeableLock extends ReadUncommittedLock | |
| 442 | { | |
| 443 | public SerializeableLock(Object resourceId, LoggerFacade logger) | |
| 444 | { | |
| 445 | super(resourceId, logger); | |
| 446 | } | |
| 447 | ||
| 448 | protected boolean isCompatible(int targetLockLevel, int currentLockLevel) | |
| 449 | { | |
| 450 | return currentLockLevel > NO_LOCK ? false : true; | |
| 451 | } | |
| 452 | } | |
| 453 | } |