View Javadoc

1   /**
2    * Copyright 2005-2011 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kew.routeheader;
17  
18  
19  import static org.junit.Assert.assertEquals;
20  import static org.junit.Assert.assertNotNull;
21  import static org.junit.Assert.assertTrue;
22  import static org.junit.Assert.fail;
23  
24  import java.sql.Timestamp;
25  
26  import org.junit.Test;
27  import org.kuali.rice.core.api.config.property.Config;
28  import org.kuali.rice.core.api.config.property.ConfigContext;
29  import org.kuali.rice.kew.api.WorkflowDocument;
30  import org.kuali.rice.kew.api.WorkflowDocumentFactory;
31  import org.kuali.rice.kew.api.exception.LockingException;
32  import org.kuali.rice.kew.doctype.bo.DocumentType;
33  import org.kuali.rice.kew.routeheader.service.RouteHeaderService;
34  import org.kuali.rice.kew.service.KEWServiceLocator;
35  import org.kuali.rice.kew.test.KEWTestCase;
36  import org.kuali.rice.kew.api.KewApiConstants;
37  import org.kuali.rice.test.BaselineTestCase;
38  import org.springframework.transaction.TransactionStatus;
39  import org.springframework.transaction.support.TransactionCallback;
40  
41  
42  @BaselineTestCase.BaselineMode(BaselineTestCase.Mode.NONE)
43  public class RouteHeaderServiceTest extends KEWTestCase {
44  
45      private Object lock = new Object();
46      private RouteHeaderService routeHeaderService;
47  
48      protected void setUpAfterDataLoad() throws Exception {
49          super.setUpAfterDataLoad();
50          routeHeaderService = KEWServiceLocator.getRouteHeaderService();
51      }
52      
53      /**
54       * Tests the saving of a document with large XML content.  This verifies that large CLOBs (> 4000 bytes)
55       * can be saved by OJB.  This can cause paticular issues with Oracle and OJB has to unwrap the native jdbc
56       * Connections and Statements from the pooled connection.  We need to make sure this is working for our
57       * pooling software of choice.
58       */
59      @Test
60      public void testLargeDocumentContent() throws Exception {
61          StringBuffer buffer = new StringBuffer();
62          buffer.append("<content>");
63          for (int index = 0; index < 10000; index++) {
64              buffer.append("abcdefghijklmnopqrstuvwxyz");
65          }
66          buffer.append("</content>");
67          DocumentRouteHeaderValue document = new DocumentRouteHeaderValue();
68          document.setDocContent(buffer.toString());
69          document.setDocRouteStatus(KewApiConstants.ROUTE_HEADER_INITIATED_CD);
70          document.setDocRouteLevel(0);
71          document.setStatusModDate(new Timestamp(System.currentTimeMillis()));
72          document.setCreateDate(new Timestamp(System.currentTimeMillis()));
73          document.setInitiatorWorkflowId("1");
74          DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByName("TestDocumentType");
75          assertNotNull(documentType);
76          document.setDocumentTypeId(documentType.getDocumentTypeId());
77          routeHeaderService.saveRouteHeader(document);
78          assertNotNull("Document was saved, it should have an ID now.", document.getDocumentId());
79          
80          // now reload from database and verify it's the right size
81          document = routeHeaderService.getRouteHeader(document.getDocumentId());
82          String docContent = document.getDocContent();
83          assertEquals("Doc content should be the same size as original string buffer.", buffer.length(), docContent.length());
84          assertTrue("Should be greater than about 5000 bytes.", docContent.getBytes().length > 5000);
85      }
86  
87      @Test public void testGetApplicationIdByDocumentId() throws Exception {
88      	WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "TestDocumentType2");
89      	String documentId = document.getDocumentId();
90      	String applicationId = routeHeaderService.getApplicationIdByDocumentId(documentId);
91      	assertEquals("applicationId should be KEWNEW", "KEWNEW", applicationId);
92  
93      	// now check TestDocumentType
94      	document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "TestDocumentType");
95      	documentId = document.getDocumentId();
96      	applicationId = routeHeaderService.getApplicationIdByDocumentId(documentId);
97      	assertEquals("applicationId should be KEW", "KEW", applicationId);
98      }
99  
100     @Test public void testLockRouteHeader() throws Exception {
101 	//fail("TestLockRouteHeader needs to be fixed.  It is currently deadlocking the tests!!!!");
102     	if (ConfigContext.getCurrentContextConfig().getProperty("datasource.ojb.platform").equals("Mckoi")) {
103     		return;
104     	}
105 
106     	WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("rkirkend"), "TestDocumentType");
107     	document.saveDocumentData();
108     	final String documentId = document.getDocumentId();
109         Locker locker = null;
110         synchronized (lock) {
111             locker = new Locker(documentId);
112             locker.start();
113             lock.wait();
114         }
115         // document should be locked by the other thread at this point
116         try {
117             routeHeaderService.lockRouteHeader(documentId, false);
118             fail("The route header should be locked.");
119         } catch (LockingException e) {
120             // should have been thrown!
121         }
122         synchronized (lock) {
123             lock.notify();
124         }
125         locker.join();
126         // document should be unlocked now
127         routeHeaderService.lockRouteHeader(documentId, false);
128         assertTrue("Locker thread should have completed.", locker.isCompleted());
129 
130         // now configure a lock timeout for 2 seconds
131         ConfigContext.getCurrentContextConfig().putProperty(Config.DOCUMENT_LOCK_TIMEOUT, "2");
132         synchronized (lock) {
133             locker = new Locker(documentId);
134             locker.start();
135             lock.wait();
136         }
137         // document should be locked by the other thread at this point
138         long millisStart = System.currentTimeMillis();
139         try {
140         	routeHeaderService.lockRouteHeader(documentId, true);
141         	fail("The route header should be locked.");
142         }  catch (LockingException e) {
143         	// should have been thrown!
144         }
145 
146         long millisEnd = System.currentTimeMillis();
147         long timeLocked = (millisEnd - millisStart);
148 
149         synchronized(lock) {
150         	lock.notify();
151         }
152         locker.join();
153 
154         // assert that the time locked was close to 2000 milliseconds += 250 of a millisecond
155 //        assertTrue("Time locked should have been around 2000 milliseconds but was " + timeLocked, timeLocked > (2000-250) && timeLocked < (2000+250));
156         
157         // document should be unlocked again
158         routeHeaderService.lockRouteHeader(document.getDocumentId(), false);
159         assertTrue("Locker thread should have completed.", locker.isCompleted());
160     }
161 
162     private class Locker extends Thread {
163         private String documentId;
164         private boolean isCompleted = false;
165         public Locker(String documentId) {
166             this.documentId = documentId;
167         }
168         public void run() {
169             getTransactionTemplate().execute(new TransactionCallback() {
170                 public Object doInTransaction(TransactionStatus status) {
171                 	synchronized (lock) {
172                         routeHeaderService.lockRouteHeader(documentId, true);
173                         try {
174                             lock.notify();
175                             lock.wait();
176                         } catch (InterruptedException e) {
177                             fail("Shouldn't have been interrupted");
178                         }
179                     }
180                     return null;
181                 }
182             });
183             isCompleted = true;
184         }
185         public boolean isCompleted() {
186             return isCompleted;
187         }
188     }
189 
190 }