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 }