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.setDateModified(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 KUALI", "KUALI", applicationId);
98      }
99  
100     @Test public void testLockRouteHeader() throws Exception {
101     	WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("rkirkend"), "TestDocumentType");
102     	document.saveDocumentData();
103     	final String documentId = document.getDocumentId();
104         Locker locker = null;
105         synchronized (lock) {
106             locker = new Locker(documentId);
107             locker.start();
108             lock.wait();
109         }
110         // document should be locked by the other thread at this point
111         try {
112             routeHeaderService.lockRouteHeader(documentId, false);
113             fail("The route header should be locked.");
114         } catch (LockingException e) {
115             // should have been thrown!
116         }
117         synchronized (lock) {
118             lock.notify();
119         }
120         locker.join();
121         // document should be unlocked now
122         routeHeaderService.lockRouteHeader(documentId, false);
123         assertTrue("Locker thread should have completed.", locker.isCompleted());
124 
125         // now configure a lock timeout for 2 seconds
126         ConfigContext.getCurrentContextConfig().putProperty(Config.DOCUMENT_LOCK_TIMEOUT, "2");
127         synchronized (lock) {
128             locker = new Locker(documentId);
129             locker.start();
130             lock.wait();
131         }
132         // document should be locked by the other thread at this point
133         long millisStart = System.currentTimeMillis();
134         try {
135         	routeHeaderService.lockRouteHeader(documentId, true);
136         	fail("The route header should be locked.");
137         }  catch (LockingException e) {
138         	// should have been thrown!
139         }
140 
141         long millisEnd = System.currentTimeMillis();
142         long timeLocked = (millisEnd - millisStart);
143 
144         synchronized(lock) {
145         	lock.notify();
146         }
147         locker.join();
148 
149         // assert that the time locked was close to 2000 milliseconds += 250 of a millisecond
150 //        assertTrue("Time locked should have been around 2000 milliseconds but was " + timeLocked, timeLocked > (2000-250) && timeLocked < (2000+250));
151         
152         // document should be unlocked again
153         routeHeaderService.lockRouteHeader(document.getDocumentId(), false);
154         assertTrue("Locker thread should have completed.", locker.isCompleted());
155     }
156 
157     private class Locker extends Thread {
158         private String documentId;
159         private boolean isCompleted = false;
160         public Locker(String documentId) {
161             this.documentId = documentId;
162         }
163         public void run() {
164             getTransactionTemplate().execute(new TransactionCallback() {
165                 public Object doInTransaction(TransactionStatus status) {
166                 	synchronized (lock) {
167                         routeHeaderService.lockRouteHeader(documentId, true);
168                         try {
169                             lock.notify();
170                             lock.wait();
171                         } catch (InterruptedException e) {
172                             fail("Shouldn't have been interrupted");
173                         }
174                     }
175                     return null;
176                 }
177             });
178             isCompleted = true;
179         }
180         public boolean isCompleted() {
181             return isCompleted;
182         }
183     }
184 
185 }