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 static org.junit.Assert.assertEquals;
20  import static org.junit.Assert.assertNotNull;
21  import static org.junit.Assert.assertTrue;
22  
23  import org.apache.commons.lang.StringUtils;
24  import org.custommonkey.xmlunit.XMLAssert;
25  import org.junit.Test;
26  import org.kuali.rice.kew.api.KewApiServiceLocator;
27  import org.kuali.rice.kew.api.WorkflowDocument;
28  import org.kuali.rice.kew.api.WorkflowDocumentFactory;
29  import org.kuali.rice.kew.api.document.DocumentContent;
30  import org.kuali.rice.kew.api.document.DocumentContentUpdate;
31  import org.kuali.rice.kew.api.document.WorkflowAttributeDefinition;
32  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
33  import org.kuali.rice.kew.rule.TestRuleAttribute;
34  import org.kuali.rice.kew.service.KEWServiceLocator;
35  import org.kuali.rice.kew.test.KEWTestCase;
36  import org.kuali.rice.kew.util.KEWConstants;
37  
38  /**
39   * Tests that client interaction with document content behaves approriately.
40   * 
41   * @author Kuali Rice Team (rice.collab@kuali.org)
42   */
43  public class DocumentContentTest extends KEWTestCase {
44  
45      private static final String DOCUMENT_CONTENT = KEWConstants.DOCUMENT_CONTENT_ELEMENT;
46      private static final String ATTRIBUTE_CONTENT = KEWConstants.ATTRIBUTE_CONTENT_ELEMENT;
47      private static final String SEARCHABLE_CONTENT = KEWConstants.SEARCHABLE_CONTENT_ELEMENT;
48      private static final String APPLICATION_CONTENT = KEWConstants.APPLICATION_CONTENT_ELEMENT;
49      
50      @Test public void testDocumentContent() throws Exception {
51          String startContent = "<"+DOCUMENT_CONTENT+">";
52          String endContent = "</"+DOCUMENT_CONTENT+">";
53          String emptyContent1 = startContent+endContent;
54          String emptyContent2 = "<"+DOCUMENT_CONTENT+"/>";
55          
56          WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "TestDocumentType");
57          
58          // test no content prior to server creation
59          assertEquals("Content should be empty.", "", document.getApplicationContent());
60          assertEquals("Content should be empty.", "", document.getAttributeContent());
61          assertEquals("Content should be empty.", "", document.getDocumentContent().getSearchableContent());
62          String fullContent = document.getDocumentContent().getFullContent();
63          assertTrue("Invalid content conversion.", fullContent.equals(emptyContent1) || fullContent.equals(emptyContent2));
64          
65          // test content after server creation
66          document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "TestDocumentType");
67          // this will create the document on the server
68          document.saveDocumentData();
69          assertNotNull(document.getDocumentId());
70          // the document id on the document content should be there now
71          assertEquals("Incorrect document id.", document.getDocumentId(), document.getDocumentContent().getDocumentId());
72          assertEquals("Content should be empty.", "", document.getApplicationContent());
73          assertEquals("Content should be empty.", "", document.getAttributeContent());
74          assertEquals("Content should be empty.", "", document.getDocumentContent().getSearchableContent());
75          fullContent = document.getDocumentContent().getFullContent();
76          assertTrue("Invalid content conversion.", fullContent.equals(emptyContent1) || fullContent.equals(emptyContent2));
77          // verify the content on the actual document stored in the database
78          DocumentRouteHeaderValue routeHeader = KEWServiceLocator.getRouteHeaderService().getRouteHeader(document.getDocumentId());
79          assertTrue("Invalid initial content.", routeHeader.getDocContent().equals(emptyContent1) || routeHeader.getDocContent().equals(emptyContent2));
80          
81          // test simple case, no attributes
82          document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "TestDocumentType");
83          String attributeContent = "<attribute1><id value=\"3\"/></attribute1>";
84          String searchableContent = "<searchable1><data>hello</data></searchable1>";
85          DocumentContentUpdate.Builder contentVO = DocumentContentUpdate.Builder.create(document.getDocumentContent());
86          contentVO.setAttributeContent(constructContent(ATTRIBUTE_CONTENT, attributeContent));
87          contentVO.setSearchableContent(constructContent(SEARCHABLE_CONTENT, searchableContent));
88          document.updateDocumentContent(contentVO.build());
89          // now reload the document
90          document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("ewestfal"), document.getDocumentId());
91          String expectedContent = startContent+constructContent(ATTRIBUTE_CONTENT, attributeContent)+constructContent(SEARCHABLE_CONTENT, searchableContent)+endContent;
92          fullContent = document.getDocumentContent().getFullContent();
93          assertEquals("Invalid content conversion.", StringUtils.deleteWhitespace(expectedContent), StringUtils.deleteWhitespace(fullContent));
94          
95          // now, add an attribute and then clear it, document content should remain the same
96          String testAttributeContent = new TestRuleAttribute().getDocContent();
97          WorkflowAttributeDefinition attributeDefinition = WorkflowAttributeDefinition.Builder.create(TestRuleAttribute.class.getName()).build();
98          document.addAttributeDefinition(attributeDefinition);
99          document.clearAttributeDefinitions();
100         document.saveDocumentData();
101         fullContent = document.getDocumentContent().getFullContent();
102         assertEquals("Invalid content conversion.", StringUtils.deleteWhitespace(expectedContent), StringUtils.deleteWhitespace(fullContent));
103         
104         // now really add an attribute and save the content
105         document.addAttributeDefinition(attributeDefinition);
106         document.saveDocumentData();
107         fullContent = document.getDocumentContent().getFullContent();
108         expectedContent = startContent+
109             constructContent(ATTRIBUTE_CONTENT, attributeContent+testAttributeContent)+
110             constructContent(SEARCHABLE_CONTENT, searchableContent)+
111             endContent;
112         assertEquals("Invalid content conversion.", StringUtils.deleteWhitespace(expectedContent), StringUtils.deleteWhitespace(fullContent));
113 
114         // 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
115         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("ewestfal"), document.getDocumentId());
116         document.addAttributeDefinition(attributeDefinition);
117         document.addAttributeDefinition(attributeDefinition);
118         document.saveDocumentData();
119         fullContent = document.getDocumentContent().getFullContent();
120         expectedContent = startContent+
121             constructContent(ATTRIBUTE_CONTENT, attributeContent+testAttributeContent+testAttributeContent+testAttributeContent)+
122             constructContent(SEARCHABLE_CONTENT, searchableContent)+
123             endContent;
124         assertEquals("Invalid content conversion.", StringUtils.deleteWhitespace(expectedContent), StringUtils.deleteWhitespace(fullContent));
125         
126         // now let's try clearing the attribute content
127         document.clearAttributeContent();
128         expectedContent = startContent+constructContent(SEARCHABLE_CONTENT, searchableContent)+endContent;
129         fullContent = document.getDocumentContent().getFullContent();
130         assertEquals("Invalid content conversion.", StringUtils.deleteWhitespace(expectedContent), StringUtils.deleteWhitespace(fullContent));
131         // now save it and make sure it comes back from the server the same way
132         document.saveDocumentData();
133         fullContent = document.getDocumentContent().getFullContent();
134         assertEquals("Invalid content conversion.", StringUtils.deleteWhitespace(expectedContent), StringUtils.deleteWhitespace(fullContent));
135         
136         // Test backward compatibility with old-school document content, this document content could look something
137         // like <myRadContent>abcd</myRadContent>, when converted to the new form, it should come out like
138         // <documentContent><applicationContent><myRadContent>abcd</myRadContent></applicationContent></documentContent>
139         String myRadContent = "<myRadContent>abcd</myRadContent>";
140         document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "TestDocumentType");
141         DocumentRouteHeaderValue documentValue = KEWServiceLocator.getRouteHeaderService().getRouteHeader(document.getDocumentId());
142         documentValue.setDocContent(myRadContent);
143         KEWServiceLocator.getRouteHeaderService().saveRouteHeader(documentValue);
144         // reload the client document and check that the XML has been auto-magically converted
145         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("ewestfal"), document.getDocumentId());
146         String expected = startContent+constructContent(APPLICATION_CONTENT, myRadContent)+endContent;
147         fullContent = document.getDocumentContent().getFullContent();
148         assertEquals("Backward compatibility failure.", StringUtils.deleteWhitespace(expected), StringUtils.deleteWhitespace(fullContent));
149     }
150     
151     private String constructContent(String type, String content) {
152         if (content == null) {
153             return "";
154         }
155         return "<"+type+">"+content+"</"+type+">";
156     }
157     
158     /**
159      * Tests that document content is reloaded from the database after every call (such as Approve, etc.)
160      * so as to verify that the document content stored on the WorkflowDocument will not go stale in between
161      * calls.
162      */
163     @Test public void testDocumentContentConsistency() throws Exception {
164     	WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "TestDocumentType");
165     	String appContent = "<app>content</app>";
166     	document.setApplicationContent(appContent);
167     	document.saveDocumentData();
168         XMLAssert.assertXMLEqual(appContent, document.getApplicationContent());
169     	
170     	// load the document and modify the content
171     	WorkflowDocument document2 = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("ewestfal"), document.getDocumentId());
172     	XMLAssert.assertXMLEqual(appContent, document2.getApplicationContent());
173     	String appContent2 = "<app>content2</app>";
174     	document2.setApplicationContent(appContent2);
175     	XMLAssert.assertXMLEqual(appContent2, document2.getApplicationContent());
176     	document2.saveDocumentData();
177     	
178     	// the original document should not notice these changes yet
179     	XMLAssert.assertXMLEqual(appContent, document.getApplicationContent());
180     	// but if we saveRoutingData, we should see the new value
181     	document.saveDocumentData();
182     	XMLAssert.assertXMLEqual(appContent2, document.getApplicationContent());
183     	
184     	// also verify that just setting the content, but not saving it, doesn't get persisted
185     	document2.setApplicationContent("<bad>content</bad>");
186     	document2 = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("ewestfal"), document2.getDocumentId());
187     	XMLAssert.assertXMLEqual(appContent2, document.getApplicationContent());
188     }
189     
190     /**
191      * Tests modification of the DocumentContentVO object directly.
192      */
193     @Test public void testManualDocumentContentModification() throws Exception {
194     	WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "TestDocumentType");
195     	document.saveDocumentData();
196     	
197     	// fetch it from WorkflowInfo
198     	DocumentContent content = KewApiServiceLocator.getWorkflowDocumentService().getDocumentContent(document.getDocumentId());
199     	assertTrue("Should contain default content, was " + content.getFullContent(), KEWConstants.DEFAULT_DOCUMENT_CONTENT.equals(content.getFullContent()) ||
200     			KEWConstants.DEFAULT_DOCUMENT_CONTENT2.equals(content.getFullContent()));
201     	
202     	String appContent = "<abcdefg>hijklm n o p</abcdefg>";
203     	DocumentContentUpdate.Builder contentUpdate = DocumentContentUpdate.Builder.create(content);
204     	contentUpdate.setApplicationContent(appContent);
205     	document.updateDocumentContent(contentUpdate.build());
206     	
207     	// test that the content on the document is the same as the content we just set
208     	XMLAssert.assertXMLEqual(appContent, document.getApplicationContent());
209     	
210     	// fetch the document fresh and make sure the content is correct
211     	document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("ewestfal"), document.getDocumentId());
212     	XMLAssert.assertXMLEqual(appContent, document.getApplicationContent());
213     	
214     }
215 }