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