View Javadoc
1   /**
2    * Copyright 2005-2014 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.krad.datadictionary;
17  
18  import org.junit.Test;
19  import org.kuali.rice.kim.document.IdentityManagementGroupDocument;
20  import org.kuali.rice.kim.document.IdentityManagementKimDocument;
21  import org.kuali.rice.kim.document.IdentityManagementPersonDocument;
22  import org.kuali.rice.krad.bo.AdHocRoutePerson;
23  import org.kuali.rice.krad.bo.AdHocRouteRecipient;
24  import org.kuali.rice.krad.bo.AdHocRouteWorkgroup;
25  import org.kuali.rice.krad.bo.BusinessObject;
26  import org.kuali.rice.krad.datadictionary.exception.ClassValidationException;
27  import org.kuali.rice.krad.document.Document;
28  import org.kuali.rice.krad.document.DocumentBase;
29  import org.kuali.rice.krad.impls.RiceTestTransactionalDocumentDivergent;
30  import org.kuali.rice.krad.impls.RiceTestTransactionalDocumentDivergentParent;
31  import org.kuali.rice.krad.maintenance.MaintenanceDocumentBase;
32  import org.kuali.rice.krad.document.TransactionalDocumentBase;
33  import org.kuali.rice.krad.impls.RiceTestTransactionalDocument2;
34  import org.kuali.rice.krad.impls.RiceTestTransactionalDocument2Parent;
35  import org.kuali.rice.krad.test.TestDictionaryConfig;
36  import org.kuali.rice.krad.test.document.AccountRequestDocument;
37  import org.kuali.rice.krad.test.document.bo.AccountType2;
38  import org.kuali.rice.krad.test.document.bo.AccountType2Parent;
39  import org.kuali.rice.krad.test.document.bo.AccountTypeDivergent;
40  import org.kuali.rice.krad.test.document.bo.AccountTypeDivergentParent;
41  import org.kuali.rice.krad.test.KRADTestCase;
42  
43  import static org.junit.Assert.*;
44  
45  /**
46   * BaseBOClassAndBaseDocumentClassTest tests for the data dictionary's ability to index entries by a "base" superclass
47   *
48   * <p>When running this test, the working directory should be set to two levels down from the root of the project e.g.
49   * it/krad</p>
50   * 
51   * @author Kuali Rice Team (rice.collab@kuali.org)
52   */
53  @TestDictionaryConfig(namespaceCode="KR-NS",dataDictionaryFiles="classpath:org/kuali/rice/krad/test/document")
54  public class BaseBOClassAndBaseDocumentClassTest extends KRADTestCase {
55  	
56  	/**
57  	 * This method tests to make sure that business object entries and document entries can only define regular and "base" classes that are compatible.
58  	 * 
59  	 * @throws Exception
60  	 */
61  	@Test
62  	public void testValidAndInvalidDDEntries() throws Exception {
63  		// Ensure that we can specify a base class that is not the superclass of the document/businessObject class.
64  		assertExpectedOutcomeOfBOEntryConstruction(AdHocRoutePerson.class, DocumentBase.class, true);
65  		assertExpectedOutcomeOfDocEntryConstruction(TransactionalDocumentBase.class, MaintenanceDocumentBase.class, true);
66  		assertExpectedOutcomeOfBOEntryConstruction(TransactionalDocumentBase.class, AdHocRouteRecipient.class, true);
67  		assertExpectedOutcomeOfDocEntryConstruction(AccountRequestDocument.class, IdentityManagementKimDocument.class, true);
68  		
69  		// Ensure that we can specify a base class that is the superclass of the document/businessObject class.
70  		assertExpectedOutcomeOfBOEntryConstruction(AdHocRoutePerson.class, AdHocRouteRecipient.class, true);
71  		assertExpectedOutcomeOfDocEntryConstruction(TransactionalDocumentBase.class, DocumentBase.class, true);
72  		assertExpectedOutcomeOfBOEntryConstruction(AdHocRouteWorkgroup.class, AdHocRouteRecipient.class, true);
73  		assertExpectedOutcomeOfDocEntryConstruction(IdentityManagementPersonDocument.class, IdentityManagementKimDocument.class, true);
74  		
75  		// Ensure that we can specify a document/businessObject class that is a superclass of the base class.
76  		assertExpectedOutcomeOfBOEntryConstruction(AdHocRouteRecipient.class, AdHocRoutePerson.class, true);
77  		assertExpectedOutcomeOfDocEntryConstruction(IdentityManagementKimDocument.class, IdentityManagementGroupDocument.class, true);
78  		
79  		// Ensure that we can specify the same class for both the document/businessObject class and the base class
80  		// (as permitted by the use of Class.isAssignableFrom in the BO and doc entry validations).
81  		assertExpectedOutcomeOfBOEntryConstruction(AdHocRoutePerson.class, AdHocRoutePerson.class, true);
82  		assertExpectedOutcomeOfDocEntryConstruction(MaintenanceDocumentBase.class, MaintenanceDocumentBase.class, true);
83  	}
84  	
85  	/**
86  	 * This method tests the DataDictionary's ability to grab entries based on a "base" class.
87  	 * 
88  	 * @throws Exception
89  	 */
90  	@Test
91  	public void testRetrieveDDEntriesByBaseClass() throws Exception {
92  		// Test the ability to retrieve a BusinessObjectEntry by "base" class, using both the full name and the simple name.
93          Object[][] tests = {
94              { "AccountType2Parent", "AccountType2",
95                 AccountType2.class, AccountType2Parent.class, "accountTypeCode2", "Account Type 2" },
96              { "org.kuali.rice.krad.test.document.bo.AccountType2Parent", "org.kuali.rice.krad.test.document.bo.AccountType2",
97                 AccountType2.class, AccountType2Parent.class, "accountTypeCode2", "Account Type 2" },
98              { "AccountTypeDivergentParent", "AccountTypeDivergent",
99                 AccountTypeDivergent.class, AccountTypeDivergentParent.class, "accountTypeCode Divergent", "Account Type Divergent" },
100             { "org.kuali.rice.krad.test.document.bo.AccountTypeDivergentParent", "org.kuali.rice.krad.test.document.bo.AccountTypeDivergent",
101                AccountTypeDivergent.class, AccountTypeDivergentParent.class, "accountTypeCode Divergent", "Account Type Divergent" }
102         };
103 		for (Object[] test: tests) {
104 			// Attempt to retrieve a BusinessObjectEntry that is indexed under the "base" class.
105 			assertBusinessObjectEntry(dd.getBusinessObjectEntry((String) test[0]), (Class) test[2], (Class) test[3],
106                     (String) test[4], (String) test[5]);
107 			// Now check to ensure that the same BusinessObjectEntry can still be retrieved by specifying the actual BO class name.
108             assertBusinessObjectEntry(dd.getBusinessObjectEntry((String) test[1]), (Class) test[2], (Class) test[3],
109                     (String) test[4], (String) test[5]);
110             // Attempt to retrieve a DataObjectEntry that is indexed under the "base" class.
111             assertDataObjectEntry(dd.getDataObjectEntry((String) test[0]), (Class) test[2], (Class) test[3],
112                     (String) test[4], (String) test[5]);
113             // Now check to ensure that the same DataObjectEntry can still be retrieved by specifying the actual BO class name.
114             assertDataObjectEntry(dd.getDataObjectEntry((String) test[1]), (Class) test[2], (Class) test[3],
115                     (String) test[4], (String) test[5]);
116 		}
117 
118 		// Test the ability to retrieve a DocumentEntry by "base" class, using both the full name and the simple name.
119         tests = new Object[][] {
120             { "RiceTestTransactionalDocument2Parent", "RiceTestTransactionalDocument2",
121                RiceTestTransactionalDocument2.class, RiceTestTransactionalDocument2Parent.class },
122             { "org.kuali.rice.krad.impls.RiceTestTransactionalDocument2Parent", "org.kuali.rice.krad.impls.RiceTestTransactionalDocument2",
123                RiceTestTransactionalDocument2.class, RiceTestTransactionalDocument2Parent.class },
124             { "RiceTestTransactionalDocumentDivergentParent", "RiceTestTransactionalDocumentDivergent",
125                RiceTestTransactionalDocumentDivergent.class, RiceTestTransactionalDocumentDivergentParent.class },
126             { "org.kuali.rice.krad.impls.RiceTestTransactionalDocumentDivergentParent", "org.kuali.rice.krad.impls.RiceTestTransactionalDocumentDivergent",
127                RiceTestTransactionalDocumentDivergent.class, RiceTestTransactionalDocumentDivergentParent.class }
128         };
129         for (Object[] test: tests) {
130 			// Attempt to retrieve a DocumentEntry indexed under the "base" class
131             assertDocumentEntry(dd.getDocumentEntry((String) test[0]), (Class) test[2], (Class) test[3]);
132 			// Now check to ensure that the same DocumentEntry can still be retrieved by specifying the actual document class name.
133             assertDocumentEntry(dd.getDocumentEntry((String) test[1]), (Class) test[2], (Class) test[3]);
134 		}
135 		
136 		// Test the ability to retrieve a BusinessObjectEntry by JSTL key, where the "base" class's simple name is the JSTL key if it is defined. However,
137 		// the getDictionaryObjectEntry could still find the object even if the JSTL key map doesn't have it, since it checks the other maps for the
138 		// entry if it cannot be found in the entriesByJstlKey map.
139 		DataDictionaryEntry ddEntry = dd.getDictionaryObjectEntry("AccountType2");
140 		assertNotNull("The AccountType2 DD entry from the entriesByJstlKey map should not be null", ddEntry);
141 		assertTrue("The DD entry should have been a BusinessObjectEntry", ddEntry instanceof BusinessObjectEntry);
142 		assertBusinessObjectEntryIsAccountType2((BusinessObjectEntry) ddEntry);
143 	}
144 	
145 	/**
146 	 * A convenience method for testing the construction of a BusinessObjectEntry that has the given BO class and "base" class.
147 	 * 
148 	 * @param boClass The businessObjectClass of the entry.
149 	 * @param boBaseClass The "base" class of the entry.
150 	 * @param shouldSucceed Indicates whether the construction task should succeed or fail.
151 	 * @throws Exception
152 	 */
153 	private void assertExpectedOutcomeOfBOEntryConstruction(Class<?> boClass,
154 			Class<?> boBaseClass, boolean shouldSucceed) throws Exception {
155 		// Construct the entry and set the necessary properties.
156 		BusinessObjectEntry boEntry = new BusinessObjectEntry();
157 		boEntry.setDataObjectClass(boClass);
158 		boEntry.setBaseBusinessObjectClass((Class<? extends BusinessObject>) boBaseClass);
159 		boEntry.setObjectLabel(boClass.getSimpleName());
160 		// Now attempt to validate these properties.
161 		try {
162 			boEntry.completeValidation();
163 			// If the above operation succeeds, check whether or not the operation was meant to succeed.
164 			if (!shouldSucceed) {
165 				fail("The BO entry should have thrown a ClassValidationException during the validation process");
166 			}
167 		}
168 		catch (ClassValidationException e) {
169 			// If the above operation fails, check whether or not the operation was meant to fail.
170 			if (shouldSucceed) {
171 				fail("The BO entry should not have thrown a ClassValidationException during the validation process");
172 			}
173 		}
174 	}
175 	
176 	/**
177 	 * A convenience method for testing the construction of a DocumentEntry that has the given doc class and "base" class.
178 	 * 
179 	 * @param docClass The documentClass of the entry.
180 	 * @param docBaseClass The "base" class of the entry.
181 	 * @param shouldSucceed Indicates whether the construction task should succeed or fail.
182 	 * @throws Exception
183 	 */
184 	private void assertExpectedOutcomeOfDocEntryConstruction(Class<? extends Document> docClass,
185 			Class<? extends Document> docBaseClass, boolean shouldSucceed) throws Exception {
186 		// Construct the entry and set the necessary properties.
187 		DocumentEntry docEntry = new TransactionalDocumentEntry();
188 		docEntry.setDocumentClass(docClass);
189 		docEntry.setBaseDocumentClass(docBaseClass);
190 		// Now attempt to validate these properties.
191 		try {
192 			docEntry.completeValidation();
193 			// If the above operation succeeds, check whether or not the operation was meant to succeed.
194 			if (!shouldSucceed) {
195 				fail("The doc entry should have thrown a ClassValidationException during the validation process");
196 			}
197 		}
198 		catch (ClassValidationException e) {
199 			// If the above operation fails, check whether or not the operation was meant to fail.
200 			if (shouldSucceed) {
201 				fail("The doc entry should not have thrown a ClassValidationException during the validation process");
202 			}
203 		}
204 	}
205 	
206 	/**
207 	 * A convenience method for checking if a BusinessObjectEntry represents the AccountType2 DD entry.
208 	 * 
209 	 * @param boEntry The BusinessObjectEntry to test.
210 	 * @throws Exception
211 	 */
212 	private void assertBusinessObjectEntryIsAccountType2(BusinessObjectEntry boEntry) throws Exception {
213         assertBusinessObjectEntry(boEntry, AccountType2.class, AccountType2Parent.class, "accountTypeCode2",
214                 "Account Type 2");
215 	}
216 
217     /**
218      * A convenience method for checking if a BusinessObjectEntry represents the correct DD entry.
219      *
220      * @param boEntry The BusinessObjectEntry to test.
221      * @throws Exception
222      */
223     private void assertBusinessObjectEntry(BusinessObjectEntry boEntry, Class boClass, Class boBaseClass, String title, String label) throws Exception {
224         assertNotNull("The DD entry should not be null", boEntry);
225         assertEquals("The DD entry does not represent the " + boClass.getName() + " entry", boClass,
226                 boEntry.getBusinessObjectClass());
227         assertEquals("The DD entry does not have the expected base class", boBaseClass, boEntry.getBaseBusinessObjectClass());
228         assertEquals("The DD entry does not have the expected title attribute", title, boEntry.getTitleAttribute());
229         assertEquals("The DD entry does not have the expected object label", label, boEntry.getObjectLabel());
230     }
231 
232     /**
233      * A convenience method for checking if a DataObjectentry represents the correct Data Dictionary entry.
234      *
235      */
236     private void assertDataObjectEntry(DataObjectEntry doEntry, Class doClass, Class doBaseClass, String title, String label) throws Exception {
237         assertNotNull("The DD entry should not be null", doEntry);
238         assertEquals("The DD entry does not represent the " + doClass.getName() + " entry", doClass,
239                 doEntry.getDataObjectClass());
240         assertEquals("The DD entry does not have the expected base class", doBaseClass, doEntry.getBaseDataObjectClass());
241         assertEquals("The DD entry does not have the expected title attribute", title, doEntry.getTitleAttribute());
242         assertEquals("The DD entry does not have the expected object label", label, doEntry.getObjectLabel());
243     }
244 
245     /**
246      * A convenience method for checking if a DocumentEntry represents the correct DD entry.
247      *
248      * @param docEntry The DocumentEntry to test.
249      * @throws Exception
250      */
251     private void assertDocumentEntry(DocumentEntry docEntry, Class docClass, Class baseDocClass) throws Exception {
252         assertNotNull("The RiceTestTransactionalDocument2 DD entry should not be null", docEntry);
253         assertEquals("The DD entry does not represent the RiceTestTransactionalDocument2 entry",
254                 docClass, docEntry.getDocumentClass());
255         assertEquals("The DD entry does not have the expected base class", baseDocClass, docEntry.getBaseDocumentClass());
256     }
257 }