001 /**
002 * Copyright 2005-2011 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.rice.kew.test;
017
018
019 import static org.junit.Assert.fail;
020
021 import org.junit.Test;
022 import org.kuali.rice.core.framework.persistence.ojb.DataAccessUtils;
023 import org.springframework.transaction.TransactionStatus;
024 import org.springframework.transaction.support.TransactionCallback;
025 import org.springmodules.orm.ojb.PersistenceBrokerTemplate;
026
027 /**
028 * @author Kuali Rice Team (rice.collab@kuali.org)
029 */
030 public abstract class OjbBeanTestCase extends KEWTestCase {
031
032 private Object lock = new Object();
033
034 @Test public void testOptimisticLocking() throws Exception {
035 if (isOptimisticallyLocked()) {
036 getTransactionTemplate().execute(new TransactionCallback() {
037 public Object doInTransaction(TransactionStatus status) {
038 try {
039 Object bean = loadBean();
040 modifyBean(bean);
041 synchronized (lock) {
042 modifyConcurrently();
043 try {
044 lock.wait();
045 } catch (InterruptedException e) {
046 throw new RuntimeException(e);
047 }
048 }
049 // transaction from other thread should be commited at this point
050 try {
051 getPersistenceBrokerTemplate().store(bean);
052 fail("The bean was modified by a different transaction, OptimisticLockFailureException should have been thrown.");
053 } catch (Exception e) {
054 if (!DataAccessUtils.isOptimisticLockFailure(e)) {
055 throw e;
056 }
057 }
058 return null;
059 } catch (Exception e) {
060 throw new RuntimeException(e);
061 }
062 }
063 });
064 }
065 }
066
067 private void modifyConcurrently() {
068 Runnable runnable = new Runnable() {
069 public void run() {
070 synchronized (lock) {
071 try {
072 getTransactionTemplate().execute(new TransactionCallback() {
073 public Object doInTransaction(TransactionStatus nestedStatus) {
074 try {
075 Object bean = loadBean();
076 modifyBean(bean);
077 getPersistenceBrokerTemplate().store(bean);
078 return null;
079 } catch (Exception e) {
080 throw new RuntimeException(e);
081 }
082 }
083 });
084 } catch (Throwable t) {
085 t.printStackTrace();
086 fail(t.getMessage());
087 } finally {
088 lock.notify();
089 }
090 }
091 }
092 };
093 new Thread(runnable).start();
094 }
095
096 protected abstract Object loadBean() throws Exception;
097
098 protected abstract void modifyBean(Object bean) throws Exception;
099
100 protected abstract boolean isOptimisticallyLocked();
101
102 protected PersistenceBrokerTemplate getPersistenceBrokerTemplate() {
103 return new PersistenceBrokerTemplate();
104 }
105
106 }