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.krad.datadictionary;
17  
18  import org.junit.After;
19  import org.junit.Before;
20  import org.junit.Test;
21  import org.kuali.rice.kim.document.IdentityManagementGroupDocument;
22  import org.kuali.rice.kim.document.IdentityManagementKimDocument;
23  import org.kuali.rice.kim.document.IdentityManagementPersonDocument;
24  import org.kuali.rice.krad.bo.AdHocRoutePerson;
25  import org.kuali.rice.krad.bo.AdHocRouteRecipient;
26  import org.kuali.rice.krad.bo.AdHocRouteWorkgroup;
27  import org.kuali.rice.krad.bo.BusinessObject;
28  import org.kuali.rice.krad.datadictionary.exception.ClassValidationException;
29  import org.kuali.rice.krad.document.Document;
30  import org.kuali.rice.krad.document.DocumentBase;
31  import org.kuali.rice.krad.impls.RiceTestTransactionalDocumentDivergent;
32  import org.kuali.rice.krad.impls.RiceTestTransactionalDocumentDivergentParent;
33  import org.kuali.rice.krad.maintenance.MaintenanceDocumentBase;
34  import org.kuali.rice.krad.document.TransactionalDocumentBase;
35  import org.kuali.rice.krad.impls.RiceTestTransactionalDocument2;
36  import org.kuali.rice.krad.impls.RiceTestTransactionalDocument2Parent;
37  import org.kuali.rice.krad.test.document.AccountRequestDocument;
38  import org.kuali.rice.krad.test.document.bo.AccountType2;
39  import org.kuali.rice.krad.test.document.bo.AccountType2Parent;
40  import org.kuali.rice.krad.test.document.bo.AccountTypeDivergent;
41  import org.kuali.rice.krad.test.document.bo.AccountTypeDivergentParent;
42  import org.kuali.test.KRADTestCase;
43  
44  import static org.junit.Assert.*;
45  
46  /**
47   * This is a test case for the data dictionary's ability to index entries by a "base" superclass. 
48   * 
49   * @author Kuali Rice Team (rice.collab@kuali.org)
50   */
51  public class BaseBOClassAndBaseDocumentClassTest extends KRADTestCase {
52  
53  	DataDictionary dd = null;
54  
55  	/**
56  	 * Performs setup tasks similar to those in ExtensionAttributeTest.
57  	 */
58  	@Before
59  	public void setUp() throws Exception {
60  		super.setUp();
61  
62  		dd = new DataDictionary();
63  
64          dd.addConfigFileLocation("classpath:org/kuali/rice/krad/uif/UifControlDefinitions.xml");
65          dd.addConfigFileLocation("classpath:org/kuali/rice/krad/uif/UifConfigurationDefinitions.xml");
66          dd.addConfigFileLocation("classpath:org/kuali/rice/krad/uif/UifRiceDefinitions.xml");
67          dd.addConfigFileLocation("classpath:org/kuali/rice/krad/uif/UifFieldDefinitions.xml");
68          dd.addConfigFileLocation("classpath:org/kuali/rice/krad/uif/UifLookupDefinitions.xml");
69          dd.addConfigFileLocation("classpath:org/kuali/rice/krad/uif/UifInquiryDefinitions.xml");
70          dd.addConfigFileLocation("classpath:org/kuali/rice/krad/uif/UifGroupDefinitions.xml");
71          dd.addConfigFileLocation("classpath:org/kuali/rice/krad/uif/UifHeaderFooterDefinitions.xml");
72          dd.addConfigFileLocation("classpath:org/kuali/rice/krad/uif/UifLayoutManagerDefinitions.xml");
73          dd.addConfigFileLocation("classpath:org/kuali/rice/krad/uif/UifViewPageDefinitions.xml");
74          dd.addConfigFileLocation("classpath:org/kuali/rice/krad/uif/UifWidgetDefinitions.xml");
75          dd.addConfigFileLocation("classpath:org/kuali/rice/krad/uif/UifMaintenanceDefinitions.xml");
76          dd.addConfigFileLocation("classpath:org/kuali/rice/krad/uif/UifDocumentDefinitions.xml");
77  		//dd.addConfigFileLocation("classpath:org/kuali/rice/krad/bo/datadictionary");
78          dd.addConfigFileLocation("file:" + getUserDir() + "/../../impl/src/main/resources/org/kuali/rice/krad/bo/datadictionary");
79  		dd.addConfigFileLocation("classpath:org/kuali/rice/kns/bo/datadictionary/DataDictionaryBaseTypes.xml");
80  		dd.addConfigFileLocation("classpath:org/kuali/rice/kim/bo/datadictionary/EmploymentStatus.xml");
81  		dd.addConfigFileLocation("classpath:org/kuali/rice/kim/bo/datadictionary/EmploymentType.xml");
82  		dd.addConfigFileLocation("classpath:org/kuali/rice/kim/impl/identity/PersonImpl.xml");
83  		dd.addConfigFileLocation("classpath:org/kuali/rice/kim/bo/datadictionary/KimBaseBeans.xml");
84  		dd.addConfigFileLocation("classpath:org/kuali/rice/kim/impl/group/Group.xml");
85  		dd.addConfigFileLocation("classpath:org/kuali/rice/kim/impl/role/RoleBo.xml");
86  		dd.addConfigFileLocation("classpath:org/kuali/rice/kim/impl/type/KimType.xml");
87  		dd.addConfigFileLocation("classpath:org/kuali/rice/krad/test/document/");
88          dd.addConfigFileLocation("file:" + getBaseDir() + "/../../location/web/src/main/resources/org/kuali/rice/location/web/campus/Campus.xml");
89          dd.addConfigFileLocation("file:" + getBaseDir() + "/../../location/web/src/main/resources/org/kuali/rice/location/web/campus/CampusType.xml");
90          dd.addConfigFileLocation("file:" + getBaseDir() + "/../../location/web/src/main/resources/org/kuali/rice/location/web/country/Country.xml");
91          dd.addConfigFileLocation("file:" + getBaseDir() + "/../../location/web/src/main/resources/org/kuali/rice/location/web/state/State.xml");
92          dd.addConfigFileLocation("file:" + getBaseDir() + "/../../location/web/src/main/resources/org/kuali/rice/location/web/county/County.xml");
93          dd.addConfigFileLocation("file:" + getBaseDir() + "/../../location/web/src/main/resources/org/kuali/rice/location/web/postalcode/PostalCode.xml");
94          dd.addConfigFileLocation("file:" + getBaseDir() + "/../../core-service/web/src/main/resources/org/kuali/rice/coreservice/web/parameter/Parameter.xml");
95          dd.addConfigFileLocation("file:" + getBaseDir() + "/../../core-service/web/src/main/resources/org/kuali/rice/coreservice/web/parameter/ParameterType.xml");
96          dd.addConfigFileLocation("file:" + getBaseDir() + "/../../core-service/web/src/main/resources/org/kuali/rice/coreservice/web/namespace/Namespace.xml");
97          dd.addConfigFileLocation("file:" + getBaseDir() + "/../../core-service/web/src/main/resources/org/kuali/rice/coreservice/web/component/Component.xml");
98          dd.parseDataDictionaryConfigurationFiles( false );
99  	}
100 
101 	/**
102 	 * Performs tearDown tasks similar to those in ExtensionAttributeTest.
103 	 */
104 	@After
105 	public void tearDown() throws Exception {
106 		super.tearDown();
107 		dd = null;
108 	}
109 	
110 	/**
111 	 * This method tests to make sure that business object entries and document entries can only define regular and "base" classes that are compatible.
112 	 * 
113 	 * @throws Exception
114 	 */
115 	@Test
116 	public void testValidAndInvalidDDEntries() throws Exception {
117 		// Ensure that we can specify a base class that is not the superclass of the document/businessObject class.
118 		assertExpectedOutcomeOfBOEntryConstruction(AdHocRoutePerson.class, DocumentBase.class, true);
119 		assertExpectedOutcomeOfDocEntryConstruction(TransactionalDocumentBase.class, MaintenanceDocumentBase.class, true);
120 		assertExpectedOutcomeOfBOEntryConstruction(TransactionalDocumentBase.class, AdHocRouteRecipient.class, true);
121 		assertExpectedOutcomeOfDocEntryConstruction(AccountRequestDocument.class, IdentityManagementKimDocument.class, true);
122 		
123 		// Ensure that we can specify a base class that is the superclass of the document/businessObject class.
124 		assertExpectedOutcomeOfBOEntryConstruction(AdHocRoutePerson.class, AdHocRouteRecipient.class, true);
125 		assertExpectedOutcomeOfDocEntryConstruction(TransactionalDocumentBase.class, DocumentBase.class, true);
126 		assertExpectedOutcomeOfBOEntryConstruction(AdHocRouteWorkgroup.class, AdHocRouteRecipient.class, true);
127 		assertExpectedOutcomeOfDocEntryConstruction(IdentityManagementPersonDocument.class, IdentityManagementKimDocument.class, true);
128 		
129 		// Ensure that we can specify a document/businessObject class that is a superclass of the base class.
130 		assertExpectedOutcomeOfBOEntryConstruction(AdHocRouteRecipient.class, AdHocRoutePerson.class, true);
131 		assertExpectedOutcomeOfDocEntryConstruction(IdentityManagementKimDocument.class, IdentityManagementGroupDocument.class, true);
132 		
133 		// Ensure that we can specify the same class for both the document/businessObject class and the base class
134 		// (as permitted by the use of Class.isAssignableFrom in the BO and doc entry validations).
135 		assertExpectedOutcomeOfBOEntryConstruction(AdHocRoutePerson.class, AdHocRoutePerson.class, true);
136 		assertExpectedOutcomeOfDocEntryConstruction(MaintenanceDocumentBase.class, MaintenanceDocumentBase.class, true);
137 	}
138 	
139 	/**
140 	 * This method tests the DataDictionary's ability to grab entries based on a "base" class.
141 	 * 
142 	 * @throws Exception
143 	 */
144 	@Test
145 	public void testRetrieveDDEntriesByBaseClass() throws Exception {
146 		// Test the ability to retrieve a BusinessObjectEntry by "base" class, using both the full name and the simple name.
147         Object[][] tests = {
148             { "AccountType2Parent", "AccountType2",
149                AccountType2.class, AccountType2Parent.class, "accountTypeCode2", "Account Type 2" },
150             { "org.kuali.rice.krad.test.document.bo.AccountType2Parent", "org.kuali.rice.krad.test.document.bo.AccountType2",
151                AccountType2.class, AccountType2Parent.class, "accountTypeCode2", "Account Type 2" },
152             { "AccountTypeDivergentParent", "AccountTypeDivergent",
153                AccountTypeDivergent.class, AccountTypeDivergentParent.class, "accountTypeCode Divergent", "Account Type Divergent" },
154             { "org.kuali.rice.krad.test.document.bo.AccountTypeDivergentParent", "org.kuali.rice.krad.test.document.bo.AccountTypeDivergent",
155                AccountTypeDivergent.class, AccountTypeDivergentParent.class, "accountTypeCode Divergent", "Account Type Divergent" }
156         };
157 		for (Object[] test: tests) {
158 			// Attempt to retrieve a BusinessObjectEntry that is indexed under the "base" class.
159 			assertBusinessObjectEntry(dd.getBusinessObjectEntry((String) test[0]), (Class) test[2], (Class) test[3], (String) test[4], (String) test[5]);
160 			// Now check to ensure that the same BusinessObjectEntry can still be retrieved by specifying the actual BO class name.
161             assertBusinessObjectEntry(dd.getBusinessObjectEntry((String) test[1]), (Class) test[2], (Class) test[3], (String) test[4], (String) test[5]);
162 		}
163 		
164 		// Test the ability to retrieve a DocumentEntry by "base" class, using both the full name and the simple name.
165         tests = new Object[][] {
166             { "RiceTestTransactionalDocument2Parent", "RiceTestTransactionalDocument2",
167                RiceTestTransactionalDocument2.class, RiceTestTransactionalDocument2Parent.class },
168             { "org.kuali.rice.krad.impls.RiceTestTransactionalDocument2Parent", "org.kuali.rice.krad.impls.RiceTestTransactionalDocument2",
169                RiceTestTransactionalDocument2.class, RiceTestTransactionalDocument2Parent.class },
170             { "RiceTestTransactionalDocumentDivergentParent", "RiceTestTransactionalDocumentDivergent",
171                RiceTestTransactionalDocumentDivergent.class, RiceTestTransactionalDocumentDivergentParent.class },
172             { "org.kuali.rice.krad.impls.RiceTestTransactionalDocumentDivergentParent", "org.kuali.rice.krad.impls.RiceTestTransactionalDocumentDivergent",
173                RiceTestTransactionalDocumentDivergent.class, RiceTestTransactionalDocumentDivergentParent.class }
174         };
175         for (Object[] test: tests) {
176 			// Attempt to retrieve a DocumentEntry indexed under the "base" class
177             assertDocumentEntry(dd.getDocumentEntry((String) test[0]), (Class) test[2], (Class) test[3]);
178 			// Now check to ensure that the same DocumentEntry can still be retrieved by specifying the actual document class name.
179             assertDocumentEntry(dd.getDocumentEntry((String) test[1]), (Class) test[2], (Class) test[3]);
180 		}
181 		
182 		// 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,
183 		// 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
184 		// entry if it cannot be found in the entriesByJstlKey map.
185 		DataDictionaryEntry ddEntry = dd.getDictionaryObjectEntry("AccountType2");
186 		assertNotNull("The AccountType2 DD entry from the entriesByJstlKey map should not be null", ddEntry);
187 		assertTrue("The DD entry should have been a BusinessObjectEntry", ddEntry instanceof BusinessObjectEntry);
188 		assertBusinessObjectEntryIsAccountType2((BusinessObjectEntry) ddEntry);
189 	}
190 	
191 	/**
192 	 * A convenience method for testing the construction of a BusinessObjectEntry that has the given BO class and "base" class.
193 	 * 
194 	 * @param boClass The businessObjectClass of the entry.
195 	 * @param boBaseClass The "base" class of the entry.
196 	 * @param shouldSucceed Indicates whether the construction task should succeed or fail.
197 	 * @throws Exception
198 	 */
199 	private void assertExpectedOutcomeOfBOEntryConstruction(Class<? extends BusinessObject> boClass,
200 			Class<? extends BusinessObject> boBaseClass, boolean shouldSucceed) throws Exception {
201 		// Construct the entry and set the necessary properties.
202 		BusinessObjectEntry boEntry = new BusinessObjectEntry();
203 		boEntry.setBusinessObjectClass(boClass);
204 		boEntry.setBaseBusinessObjectClass(boBaseClass);
205 		boEntry.setObjectLabel(boClass.getSimpleName());
206 		// Now attempt to validate these properties.
207 		try {
208 			boEntry.completeValidation();
209 			// If the above operation succeeds, check whether or not the operation was meant to succeed.
210 			if (!shouldSucceed) {
211 				fail("The BO entry should have thrown a ClassValidationException during the validation process");
212 			}
213 		}
214 		catch (ClassValidationException e) {
215 			// If the above operation fails, check whether or not the operation was meant to fail.
216 			if (shouldSucceed) {
217 				fail("The BO entry should not have thrown a ClassValidationException during the validation process");
218 			}
219 		}
220 	}
221 	
222 	/**
223 	 * A convenience method for testing the construction of a DocumentEntry that has the given doc class and "base" class.
224 	 * 
225 	 * @param docClass The documentClass of the entry.
226 	 * @param docBaseClass The "base" class of the entry.
227 	 * @param shouldSucceed Indicates whether the construction task should succeed or fail.
228 	 * @throws Exception
229 	 */
230 	private void assertExpectedOutcomeOfDocEntryConstruction(Class<? extends Document> docClass,
231 			Class<? extends Document> docBaseClass, boolean shouldSucceed) throws Exception {
232 		// Construct the entry and set the necessary properties.
233 		DocumentEntry docEntry = new TransactionalDocumentEntry();
234 		docEntry.setDocumentClass(docClass);
235 		docEntry.setBaseDocumentClass(docBaseClass);
236 		// Now attempt to validate these properties.
237 		try {
238 			docEntry.completeValidation();
239 			// If the above operation succeeds, check whether or not the operation was meant to succeed.
240 			if (!shouldSucceed) {
241 				fail("The doc entry should have thrown a ClassValidationException during the validation process");
242 			}
243 		}
244 		catch (ClassValidationException e) {
245 			// If the above operation fails, check whether or not the operation was meant to fail.
246 			if (shouldSucceed) {
247 				fail("The doc entry should not have thrown a ClassValidationException during the validation process");
248 			}
249 		}
250 	}
251 	
252 	/**
253 	 * A convenience method for checking if a BusinessObjectEntry represents the AccountType2 DD entry.
254 	 * 
255 	 * @param boEntry The BusinessObjectEntry to test.
256 	 * @throws Exception
257 	 */
258 	private void assertBusinessObjectEntryIsAccountType2(BusinessObjectEntry boEntry) throws Exception {
259         assertBusinessObjectEntry(boEntry, AccountType2.class, AccountType2Parent.class, "accountTypeCode2", "Account Type 2");
260 	}
261 
262     /**
263      * A convenience method for checking if a BusinessObjectEntry represents the correct DD entry.
264      *
265      * @param boEntry The BusinessObjectEntry to test.
266      * @throws Exception
267      */
268     private void assertBusinessObjectEntry(BusinessObjectEntry boEntry, Class boClass, Class boBaseClass, String title, String label) throws Exception {
269         assertNotNull("The DD entry should not be null", boEntry);
270         assertEquals("The DD entry does not represent the " + boClass.getName() + " entry", boClass, boEntry.getBusinessObjectClass());
271         assertEquals("The DD entry does not have the expected base class", boBaseClass, boEntry.getBaseBusinessObjectClass());
272         assertEquals("The DD entry does not have the expected title attribute", title, boEntry.getTitleAttribute());
273         assertEquals("The DD entry does not have the expected object label", label, boEntry.getObjectLabel());
274     }
275 
276     /**
277      * A convenience method for checking if a DocumentEntry represents the correct DD entry.
278      *
279      * @param docEntry The DocumentEntry to test.
280      * @throws Exception
281      */
282     private void assertDocumentEntry(DocumentEntry docEntry, Class docClass, Class baseDocClass) throws Exception {
283         assertNotNull("The RiceTestTransactionalDocument2 DD entry should not be null", docEntry);
284         assertEquals("The DD entry does not represent the RiceTestTransactionalDocument2 entry",
285                 docClass, docEntry.getDocumentClass());
286         assertEquals("The DD entry does not have the expected base class", baseDocClass, docEntry.getBaseDocumentClass());
287     }
288 }