View Javadoc

1   /*
2    * Copyright 2005-2007 The Kuali Foundation
3    * 
4    * 
5    * Licensed under the Educational Community License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    * 
9    * http://www.opensource.org/licenses/ecl2.php
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.kuali.rice.kew.clientapp;
18  
19  import java.lang.reflect.Field;
20  
21  import org.apache.commons.lang.StringUtils;
22  import org.junit.Test;
23  import org.kuali.rice.kew.dto.DocumentContentDTO;
24  import org.kuali.rice.kew.dto.NetworkIdDTO;
25  import org.kuali.rice.kew.dto.WorkflowAttributeDefinitionDTO;
26  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
27  import org.kuali.rice.kew.rule.TestRuleAttribute;
28  import org.kuali.rice.kew.service.KEWServiceLocator;
29  import org.kuali.rice.kew.service.WorkflowDocument;
30  import org.kuali.rice.kew.service.WorkflowInfo;
31  import org.kuali.rice.kew.test.KEWTestCase;
32  import org.kuali.rice.kew.util.KEWConstants;
33  
34  
35  /**
36   * Tests that client interaction with document content behaves approriately.
37   * 
38   * @author Kuali Rice Team (rice.collab@kuali.org)
39   */
40  public class DocumentContentTest extends KEWTestCase {
41  
42      private static final String DOCUMENT_CONTENT = KEWConstants.DOCUMENT_CONTENT_ELEMENT;
43      private static final String ATTRIBUTE_CONTENT = KEWConstants.ATTRIBUTE_CONTENT_ELEMENT;
44      private static final String SEARCHABLE_CONTENT = KEWConstants.SEARCHABLE_CONTENT_ELEMENT;
45      private static final String APPLICATION_CONTENT = KEWConstants.APPLICATION_CONTENT_ELEMENT;
46      
47      @Test public void testDocumentContent() throws Exception {
48          String startContent = "<"+DOCUMENT_CONTENT+">";
49          String endContent = "</"+DOCUMENT_CONTENT+">";
50          String emptyContent1 = startContent+endContent;
51          String emptyContent2 = "<"+DOCUMENT_CONTENT+"/>";
52          
53          WorkflowDocument document = new WorkflowDocument(new NetworkIdDTO("ewestfal"), "TestDocumentType");
54          
55          // test no content prior to server creation
56          assertEquals("Content should be empty.", "", document.getApplicationContent());
57          assertEquals("Content should be empty.", "", document.getAttributeContent());
58          assertEquals("Content should be empty.", "", document.getDocumentContent().getSearchableContent());
59          String fullContent = document.getDocumentContent().getFullContent();
60          assertTrue("Invalid content conversion.", fullContent.equals(emptyContent1) || fullContent.equals(emptyContent2));
61          
62          // test content after server creation
63          document = new WorkflowDocument(new NetworkIdDTO("ewestfal"), "TestDocumentType");
64          // this will create the document on the server
65          document.saveRoutingData();
66          assertNotNull(document.getRouteHeaderId());
67          // the route header id on the document content should be there now
68          assertEquals("Incorrect document id.", document.getRouteHeaderId(), document.getDocumentContent().getRouteHeaderId());
69          assertEquals("Content should be empty.", "", document.getApplicationContent());
70          assertEquals("Content should be empty.", "", document.getAttributeContent());
71          assertEquals("Content should be empty.", "", document.getDocumentContent().getSearchableContent());
72          fullContent = document.getDocumentContent().getFullContent();
73          assertTrue("Invalid content conversion.", fullContent.equals(emptyContent1) || fullContent.equals(emptyContent2));
74          // verify the content on the actual document stored in the database
75          DocumentRouteHeaderValue routeHeader = KEWServiceLocator.getRouteHeaderService().getRouteHeader(document.getRouteHeaderId());
76          assertTrue("Invalid initial content.", routeHeader.getDocContent().equals(emptyContent1) || routeHeader.getDocContent().equals(emptyContent2));
77          
78          // test simple case, no attributes
79          document = new WorkflowDocument(new NetworkIdDTO("ewestfal"), "TestDocumentType");
80          String attributeContent = "<attribute1><id value=\"3\"/></attribute1>";
81          String searchableContent = "<searchable1><data>hello</data></searchable1>";
82          DocumentContentDTO contentVO = document.getDocumentContent();
83          contentVO.setAttributeContent(constructContent(ATTRIBUTE_CONTENT, attributeContent));
84          contentVO.setSearchableContent(constructContent(SEARCHABLE_CONTENT, searchableContent));
85          document.saveRoutingData();
86          // now reload the document
87          document = new WorkflowDocument(new NetworkIdDTO("ewestfal"), document.getRouteHeaderId());
88          String expectedContent = startContent+constructContent(ATTRIBUTE_CONTENT, attributeContent)+constructContent(SEARCHABLE_CONTENT, searchableContent)+endContent;
89          fullContent = document.getDocumentContent().getFullContent();
90          assertEquals("Invalid content conversion.", StringUtils.deleteWhitespace(expectedContent), StringUtils.deleteWhitespace(fullContent));
91          
92          // now, add an attribute and then clear it, document content should remain the same
93          String testAttributeContent = new TestRuleAttribute().getDocContent();
94          WorkflowAttributeDefinitionDTO attributeDefinition = new WorkflowAttributeDefinitionDTO(TestRuleAttribute.class.getName());
95          document.addAttributeDefinition(attributeDefinition);
96          document.clearAttributeDefinitions();
97          document.saveRoutingData();
98          fullContent = document.getDocumentContent().getFullContent();
99          assertEquals("Invalid content conversion.", StringUtils.deleteWhitespace(expectedContent), StringUtils.deleteWhitespace(fullContent));
100         
101         // now really add an attribute and save the content
102         document.addAttributeDefinition(attributeDefinition);
103         document.saveRoutingData();
104         fullContent = document.getDocumentContent().getFullContent();
105         expectedContent = startContent+
106             constructContent(ATTRIBUTE_CONTENT, attributeContent+testAttributeContent)+
107             constructContent(SEARCHABLE_CONTENT, searchableContent)+
108             endContent;
109         assertEquals("Invalid content conversion.", StringUtils.deleteWhitespace(expectedContent), StringUtils.deleteWhitespace(fullContent));
110 
111         // let's reload the document and try appending a couple of attributes for good measure, this will test appending to existing content on non-materialized document content
112         document = new WorkflowDocument(new NetworkIdDTO("ewestfal"), document.getRouteHeaderId());
113         document.addAttributeDefinition(attributeDefinition);
114         document.addAttributeDefinition(attributeDefinition);
115         document.saveRoutingData();
116         fullContent = document.getDocumentContent().getFullContent();
117         expectedContent = startContent+
118             constructContent(ATTRIBUTE_CONTENT, attributeContent+testAttributeContent+testAttributeContent+testAttributeContent)+
119             constructContent(SEARCHABLE_CONTENT, searchableContent)+
120             endContent;
121         assertEquals("Invalid content conversion.", StringUtils.deleteWhitespace(expectedContent), StringUtils.deleteWhitespace(fullContent));
122         
123         // now let's try clearing the attribute content
124         document.clearAttributeContent();
125         expectedContent = startContent+constructContent(SEARCHABLE_CONTENT, searchableContent)+endContent;
126         fullContent = document.getDocumentContent().getFullContent();
127         assertEquals("Invalid content conversion.", StringUtils.deleteWhitespace(expectedContent), StringUtils.deleteWhitespace(fullContent));
128         // now save it and make sure it comes back from the server the same way
129         document.saveRoutingData();
130         fullContent = document.getDocumentContent().getFullContent();
131         assertEquals("Invalid content conversion.", StringUtils.deleteWhitespace(expectedContent), StringUtils.deleteWhitespace(fullContent));
132         
133         // Test backward compatibility with old-school document content, this document content could look something
134         // like <myRadContent>abcd</myRadContent>, when converted to the new form, it should come out like
135         // <documentContent><applicationContent><myRadContent>abcd</myRadContent></applicationContent></documentContent>
136         String myRadContent = "<myRadContent>abcd</myRadContent>";
137         document = new WorkflowDocument(new NetworkIdDTO("ewestfal"), "TestDocumentType");
138         DocumentRouteHeaderValue documentValue = KEWServiceLocator.getRouteHeaderService().getRouteHeader(document.getRouteHeaderId());
139         documentValue.setDocContent(myRadContent);
140         KEWServiceLocator.getRouteHeaderService().saveRouteHeader(documentValue);
141         // reload the client document and check that the XML has been auto-magically converted
142         document = new WorkflowDocument(new NetworkIdDTO("ewestfal"), document.getRouteHeaderId());
143         String expected = startContent+constructContent(APPLICATION_CONTENT, myRadContent)+endContent;
144         fullContent = document.getDocumentContent().getFullContent();
145         assertEquals("Backward compatibility failure.", StringUtils.deleteWhitespace(expected), StringUtils.deleteWhitespace(fullContent));
146     }
147     
148     private String constructContent(String type, String content) {
149         if (content == null) {
150             return "";
151         }
152         return "<"+type+">"+content+"</"+type+">";
153     }
154     
155     /**
156      * Tests that the lazy loading of document content is functioning properly.
157      */
158     @Test public void testLazyContentLoading() throws Exception {
159     	WorkflowDocument document = new WorkflowDocument(new NetworkIdDTO("ewestfal"), "TestDocumentType");
160         assertFalse("Content should not be loaded yet.", isContentLoaded(document));
161         
162         // save the document, the content should still not be loaded
163         document.setTitle("Test Title");
164         document.saveRoutingData();
165         assertFalse("Content should not be loaded yet.", isContentLoaded(document));
166         
167         // now get the document content, this should result in the content being loaded
168         DocumentContentDTO content = document.getDocumentContent();
169         assertNotNull("Content should be non-null.", content);
170         assertTrue("Content should now be loaded.", isContentLoaded(document));
171         
172         // create a new document, try saving it, and make sure the content has not been loaded
173         document = new WorkflowDocument(new NetworkIdDTO("ewestfal"), "TestDocumentType");
174         document.saveDocument("");
175         assertFalse("Content should not be loaded yet.", isContentLoaded(document));
176         
177         // set some content on the document
178         String applicationContent = "<myTestContent/>";
179         document.setApplicationContent(applicationContent);
180         assertTrue("Content should now be loaded.", isContentLoaded(document));
181         document.saveRoutingData();
182         
183         // reload the document
184         document = new WorkflowDocument(new NetworkIdDTO("ewestfal"), document.getRouteHeaderId());
185         assertFalse("Content should not be loaded yet.", isContentLoaded(document));
186         assertEquals("Invalid application content", applicationContent, document.getApplicationContent());
187         assertTrue("Content should now be loaded.", isContentLoaded(document));
188         
189     }
190     
191     private boolean isContentLoaded(WorkflowDocument document) throws Exception {
192     	Field contentField = document.getClass().getDeclaredField("documentContent");
193     	contentField.setAccessible(true);
194     	return contentField.get(document) != null;
195     }
196     
197     /**
198      * Tests that document content is reloaded from the database after every call (such as Approve, etc.)
199      * so as to verify that the document content stored on the WorkflowDocument will not go stale in between
200      * calls.
201      */
202     @Test public void testDocumentContentConsistency() throws Exception {
203     	WorkflowDocument document = new WorkflowDocument(new NetworkIdDTO("ewestfal"), "TestDocumentType");
204     	String appContent = "<app>content</app>";
205     	document.setApplicationContent(appContent);
206     	document.saveRoutingData();
207     	assertEquals(appContent, document.getApplicationContent());
208     	
209     	// load the document and modify the content
210     	WorkflowDocument document2 = new WorkflowDocument(new NetworkIdDTO("ewestfal"), document.getRouteHeaderId());
211     	assertEquals(appContent, document2.getApplicationContent());
212     	String appContent2 = "<app>content2</app>";
213     	document2.setApplicationContent(appContent2);
214     	assertEquals(appContent2, document2.getApplicationContent());
215     	document2.saveRoutingData();
216     	
217     	// the original document should not notice these changes yet
218     	assertEquals(appContent, document.getApplicationContent());
219     	// but if we saveRoutingData, we should see the new value
220     	document.saveRoutingData();
221     	assertEquals(appContent2, document.getApplicationContent());
222     	
223     	// also verify that just setting the content, but not saving it, doesn't get persisted
224     	document2.setApplicationContent("<bad>content</bad>");
225     	document2 = new WorkflowDocument(new NetworkIdDTO("ewestfal"), document2.getRouteHeaderId());
226     	assertEquals(appContent2, document.getApplicationContent());
227     }
228     
229     /**
230      * Tests modification of the DocumentContentVO object directly.
231      */
232     @Test public void testManualDocumentContentModification() throws Exception {
233     	WorkflowDocument document = new WorkflowDocument(new NetworkIdDTO("ewestfal"), "TestDocumentType");
234     	document.saveRoutingData();
235     	
236     	// fetch it from WorkflowInfo
237     	DocumentContentDTO content = new WorkflowInfo().getDocumentContent(document.getRouteHeaderId());
238     	assertTrue("Should contain default content, was " + content.getFullContent(), KEWConstants.DEFAULT_DOCUMENT_CONTENT.equals(content.getFullContent()) ||
239     			KEWConstants.DEFAULT_DOCUMENT_CONTENT2.equals(content.getFullContent()));
240     	
241     	String appContent = "<abcdefg>hijklm n o p</abcdefg>";
242     	content.setApplicationContent(appContent);
243     	assertFalse(isContentLoaded(document));
244     	document.saveDocumentContent(content);
245     	assertTrue(isContentLoaded(document));
246     	
247     	// test that the content on the document is the same as the content we just set
248     	assertEquals(appContent, document.getApplicationContent());
249     	
250     	// fetch the document fresh and make sure the content is correct
251     	document = new WorkflowDocument(new NetworkIdDTO("ewestfal"), document.getRouteHeaderId());
252     	assertEquals(appContent, document.getApplicationContent());
253     	
254     }
255 }