001/** 002 * Copyright 2005-2014 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 */ 016package org.kuali.rice.kew.clientapp; 017 018import static org.junit.Assert.assertEquals; 019import static org.junit.Assert.assertNotNull; 020import static org.junit.Assert.assertTrue; 021 022import org.apache.commons.lang.StringUtils; 023import org.custommonkey.xmlunit.XMLAssert; 024import org.junit.Test; 025import org.kuali.rice.kew.api.KewApiServiceLocator; 026import org.kuali.rice.kew.api.WorkflowDocument; 027import org.kuali.rice.kew.api.WorkflowDocumentFactory; 028import org.kuali.rice.kew.api.document.DocumentContent; 029import org.kuali.rice.kew.api.document.DocumentContentUpdate; 030import org.kuali.rice.kew.api.document.attribute.WorkflowAttributeDefinition; 031import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue; 032import org.kuali.rice.kew.rule.TestRuleAttribute; 033import org.kuali.rice.kew.service.KEWServiceLocator; 034import org.kuali.rice.kew.test.KEWTestCase; 035import org.kuali.rice.kew.api.KewApiConstants; 036 037/** 038 * Tests that client interaction with document content behaves approriately. 039 * 040 * @author Kuali Rice Team (rice.collab@kuali.org) 041 */ 042public class DocumentContentTest extends KEWTestCase { 043 044 private static final String DOCUMENT_CONTENT = KewApiConstants.DOCUMENT_CONTENT_ELEMENT; 045 private static final String ATTRIBUTE_CONTENT = KewApiConstants.ATTRIBUTE_CONTENT_ELEMENT; 046 private static final String SEARCHABLE_CONTENT = KewApiConstants.SEARCHABLE_CONTENT_ELEMENT; 047 private static final String APPLICATION_CONTENT = KewApiConstants.APPLICATION_CONTENT_ELEMENT; 048 049 @Test public void testEmptyDocumentContent() throws Exception { 050 DocumentContent content = DocumentContent.Builder.create("1234").build(); 051 assertEquals("<"+DOCUMENT_CONTENT + "></"+DOCUMENT_CONTENT+">", content.getFullContent()); 052 } 053 054 @Test public void testDocumentContent() throws Exception { 055 String startContent = "<"+DOCUMENT_CONTENT+">"; 056 String endContent = "</"+DOCUMENT_CONTENT+">"; 057 String emptyContent1 = startContent+endContent; 058 String emptyContent2 = "<"+DOCUMENT_CONTENT+"/>"; 059 060 WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "TestDocumentType"); 061 062 // test no content prior to server creation 063 assertEquals("Content should be empty.", "", document.getApplicationContent()); 064 assertEquals("Content should be empty.", "", document.getAttributeContent()); 065 assertEquals("Content should be empty.", "", document.getDocumentContent().getSearchableContent()); 066 String fullContent = document.getDocumentContent().getFullContent(); 067 assertTrue("Invalid content conversion.", fullContent.equals(emptyContent1) || fullContent.equals(emptyContent2)); 068 069 // test content after server creation 070 document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "TestDocumentType"); 071 // this will create the document on the server 072 document.saveDocumentData(); 073 assertNotNull(document.getDocumentId()); 074 // the document id on the document content should be there now 075 assertEquals("Incorrect document id.", document.getDocumentId(), document.getDocumentContent().getDocumentId()); 076 assertEquals("Content should be empty.", "", document.getApplicationContent()); 077 assertEquals("Content should be empty.", "", document.getAttributeContent()); 078 assertEquals("Content should be empty.", "", document.getDocumentContent().getSearchableContent()); 079 fullContent = document.getDocumentContent().getFullContent(); 080 assertTrue("Invalid content conversion.", fullContent.equals(emptyContent1) || fullContent.equals(emptyContent2)); 081 // verify the content on the actual document stored in the database 082 DocumentRouteHeaderValue routeHeader = KEWServiceLocator.getRouteHeaderService().getRouteHeader(document.getDocumentId()); 083 assertTrue("Invalid initial content.", routeHeader.getDocContent().equals(emptyContent1) || routeHeader.getDocContent().equals(emptyContent2)); 084 085 // test simple case, no attributes 086 document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "TestDocumentType"); 087 String attributeContent = "<attribute1><id value=\"3\"/></attribute1>"; 088 String searchableContent = "<searchable1><data>hello</data></searchable1>"; 089 DocumentContentUpdate.Builder contentVO = DocumentContentUpdate.Builder.create(document.getDocumentContent()); 090 contentVO.setAttributeContent(constructContent(ATTRIBUTE_CONTENT, attributeContent)); 091 contentVO.setSearchableContent(constructContent(SEARCHABLE_CONTENT, searchableContent)); 092 document.updateDocumentContent(contentVO.build()); 093 document.saveDocumentData(); 094 // now reload the document 095 document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("ewestfal"), document.getDocumentId()); 096 String expectedContent = startContent+constructContent(ATTRIBUTE_CONTENT, attributeContent)+constructContent(SEARCHABLE_CONTENT, searchableContent)+endContent; 097 fullContent = document.getDocumentContent().getFullContent(); 098 assertEquals("Invalid content conversion.", StringUtils.deleteWhitespace(expectedContent), StringUtils.deleteWhitespace(fullContent)); 099 100 // now, add an attribute and then clear it, document content should remain the same 101 String testAttributeContent = new TestRuleAttribute().getDocContent(); 102 WorkflowAttributeDefinition attributeDefinition = WorkflowAttributeDefinition.Builder.create("TestRuleAttribute").build(); 103 document.addAttributeDefinition(attributeDefinition); 104 document.clearAttributeDefinitions(); 105 document.saveDocumentData(); 106 fullContent = document.getDocumentContent().getFullContent(); 107 assertEquals("Invalid content conversion.", StringUtils.deleteWhitespace(expectedContent), StringUtils.deleteWhitespace(fullContent)); 108 109 // now really add an attribute and save the content 110 document.addAttributeDefinition(attributeDefinition); 111 document.saveDocumentData(); 112 fullContent = document.getDocumentContent().getFullContent(); 113 expectedContent = startContent+ 114 constructContent(ATTRIBUTE_CONTENT, attributeContent+testAttributeContent)+ 115 constructContent(SEARCHABLE_CONTENT, searchableContent)+ 116 endContent; 117 assertEquals("Invalid content conversion.", StringUtils.deleteWhitespace(expectedContent), StringUtils.deleteWhitespace(fullContent)); 118 119 // 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 120 document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("ewestfal"), document.getDocumentId()); 121 document.addAttributeDefinition(attributeDefinition); 122 document.addAttributeDefinition(attributeDefinition); 123 document.saveDocumentData(); 124 fullContent = document.getDocumentContent().getFullContent(); 125 expectedContent = startContent+ 126 constructContent(ATTRIBUTE_CONTENT, attributeContent+testAttributeContent+testAttributeContent+testAttributeContent)+ 127 constructContent(SEARCHABLE_CONTENT, searchableContent)+ 128 endContent; 129 assertEquals("Invalid content conversion.", StringUtils.deleteWhitespace(expectedContent), StringUtils.deleteWhitespace(fullContent)); 130 131 // now let's try clearing the attribute content 132 document.clearAttributeContent(); 133 expectedContent = startContent+constructContent(SEARCHABLE_CONTENT, searchableContent)+endContent; 134 fullContent = document.getDocumentContent().getFullContent(); 135 assertEquals("Invalid content conversion.", StringUtils.deleteWhitespace(expectedContent), StringUtils.deleteWhitespace(fullContent)); 136 // now save it and make sure it comes back from the server the same way 137 document.saveDocumentData(); 138 fullContent = document.getDocumentContent().getFullContent(); 139 assertEquals("Invalid content conversion.", StringUtils.deleteWhitespace(expectedContent), StringUtils.deleteWhitespace(fullContent)); 140 141 // Test backward compatibility with old-school document content, this document content could look something 142 // like <myRadContent>abcd</myRadContent>, when converted to the new form, it should come out like 143 // <documentContent><applicationContent><myRadContent>abcd</myRadContent></applicationContent></documentContent> 144 String myRadContent = "<myRadContent>abcd</myRadContent>"; 145 document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "TestDocumentType"); 146 DocumentRouteHeaderValue documentValue = KEWServiceLocator.getRouteHeaderService().getRouteHeader(document.getDocumentId()); 147 documentValue.setDocContent(myRadContent); 148 KEWServiceLocator.getRouteHeaderService().saveRouteHeader(documentValue); 149 // reload the client document and check that the XML has been auto-magically converted 150 document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("ewestfal"), document.getDocumentId()); 151 String expected = startContent+constructContent(APPLICATION_CONTENT, myRadContent)+endContent; 152 fullContent = document.getDocumentContent().getFullContent(); 153 assertEquals("Backward compatibility failure.", StringUtils.deleteWhitespace(expected), StringUtils.deleteWhitespace(fullContent)); 154 } 155 156 private String constructContent(String type, String content) { 157 if (content == null) { 158 return ""; 159 } 160 return "<"+type+">"+content+"</"+type+">"; 161 } 162 163 /** 164 * Tests that document content is reloaded from the database after every call (such as Approve, etc.) 165 * so as to verify that the document content stored on the WorkflowDocument will not go stale in between 166 * calls. 167 */ 168 @Test public void testDocumentContentConsistency() throws Exception { 169 WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "TestDocumentType"); 170 String appContent = "<app>content</app>"; 171 document.setApplicationContent(appContent); 172 document.saveDocumentData(); 173 XMLAssert.assertXMLEqual(appContent, document.getApplicationContent()); 174 175 // load the document and modify the content 176 WorkflowDocument document2 = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("ewestfal"), document.getDocumentId()); 177 XMLAssert.assertXMLEqual(appContent, document2.getApplicationContent()); 178 String appContent2 = "<app>content2</app>"; 179 document2.setApplicationContent(appContent2); 180 XMLAssert.assertXMLEqual(appContent2, document2.getApplicationContent()); 181 document2.saveDocumentData(); 182 183 // the original document should not notice these changes yet 184 XMLAssert.assertXMLEqual(appContent, document.getApplicationContent()); 185 // but if we saveRoutingData, we should see the new value 186 document.saveDocumentData(); 187 XMLAssert.assertXMLEqual(appContent2, document.getApplicationContent()); 188 189 // also verify that just setting the content, but not saving it, doesn't get persisted 190 document2.setApplicationContent("<bad>content</bad>"); 191 document2 = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("ewestfal"), document2.getDocumentId()); 192 XMLAssert.assertXMLEqual(appContent2, document.getApplicationContent()); 193 } 194 195 /** 196 * Tests modification of the DocumentContentVO object directly. 197 */ 198 @Test public void testManualDocumentContentModification() throws Exception { 199 WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "TestDocumentType"); 200 document.saveDocumentData(); 201 202 // fetch it from WorkflowInfo 203 DocumentContent content = KewApiServiceLocator.getWorkflowDocumentService().getDocumentContent(document.getDocumentId()); 204 assertTrue("Should contain default content, was " + content.getFullContent(), KewApiConstants.DEFAULT_DOCUMENT_CONTENT.equals(content.getFullContent()) || 205 KewApiConstants.DEFAULT_DOCUMENT_CONTENT2.equals(content.getFullContent())); 206 207 String appContent = "<abcdefg>hijklm n o p</abcdefg>"; 208 DocumentContentUpdate.Builder contentUpdate = DocumentContentUpdate.Builder.create(content); 209 contentUpdate.setApplicationContent(appContent); 210 document.updateDocumentContent(contentUpdate.build()); 211 document.saveDocumentData(); 212 213 // test that the content on the document is the same as the content we just set 214 XMLAssert.assertXMLEqual(appContent, document.getApplicationContent()); 215 216 // fetch the document fresh and make sure the content is correct 217 document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("ewestfal"), document.getDocumentId()); 218 XMLAssert.assertXMLEqual(appContent, document.getApplicationContent()); 219 220 } 221}