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    }