001/** 002 * Copyright 2005-2016 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.krad.util; 017 018import org.apache.ojb.broker.metadata.ClassDescriptor; 019import org.apache.ojb.broker.metadata.DescriptorRepository; 020import org.apache.ojb.broker.metadata.MetadataManager; 021import org.junit.After; 022import org.junit.Before; 023import org.junit.Test; 024import org.junit.runner.RunWith; 025import org.kuali.rice.core.api.config.property.ConfigContext; 026import org.kuali.rice.core.api.util.ContextClassLoaderBinder; 027import org.kuali.rice.core.framework.config.property.SimpleConfig; 028import org.kuali.rice.kns.datadictionary.BusinessObjectEntry; 029import org.kuali.rice.krad.data.metadata.MetadataRepository; 030import org.kuali.rice.krad.datadictionary.DataDictionary; 031import org.kuali.rice.krad.service.DataDictionaryService; 032import org.mockito.Mock; 033import org.mockito.invocation.InvocationOnMock; 034import org.mockito.runners.MockitoJUnitRunner; 035import org.mockito.stubbing.Answer; 036 037import java.lang.reflect.Field; 038import java.util.HashSet; 039import java.util.Set; 040import java.util.concurrent.Callable; 041 042import static org.junit.Assert.*; 043import static org.mockito.Mockito.*; 044 045/** 046 * Tests LegacyDetectionService 047 */ 048@RunWith(MockitoJUnitRunner.class) 049public class LegacyDetectorTest { 050 051 private static class DummyDataObject {} 052 private static class DummyDataObjectOjb {} 053 054 private Set<Class<?>> nonLegacyClasses = new HashSet<Class<?>>(); 055 056 @Mock private MetadataManager metadataManager; 057 @Mock private MetadataRepository metadataRepository; 058 @Mock private DataDictionaryService dataDictionaryService; 059 @Mock private DataDictionary dataDictionary; 060 061 private MetadataManager existingMetadataManager = null; 062 063 private LegacyDetector detector; 064 065 @Before 066 public void setUp() throws Exception { 067 068 DescriptorRepository descriptorRepository = new DescriptorRepository(); 069 when(metadataManager.getGlobalRepository()).thenReturn(descriptorRepository); 070 this.existingMetadataManager = hackOjb(metadataManager); 071 072 when(metadataRepository.contains(any(Class.class))).thenAnswer(new Answer() { 073 @Override 074 public Object answer(InvocationOnMock invocation) { 075 Class<?> type = (Class<?>)invocation.getArguments()[0]; 076 return nonLegacyClasses.contains(type); 077 } 078 }); 079 080 when(dataDictionaryService.getDataDictionary()).thenReturn(dataDictionary); 081 082 nonLegacyClasses.clear(); 083 084 ConfigContext.init(new SimpleConfig()); 085 ConfigContext.getCurrentContextConfig().removeProperty(KRADConstants.Config.KNS_ENABLED); 086 ConfigContext.getCurrentContextConfig().removeProperty(KRADConstants.Config.ENABLE_LEGACY_DATA_FRAMEWORK); 087 088 this.detector = new LegacyDetector(this.metadataRepository, this.dataDictionaryService); 089 090 addOjbClass(DummyDataObjectOjb.class); 091 } 092 093 @After 094 public void tearDown() throws Exception { 095 unhackOjb(this.existingMetadataManager); 096 } 097 098 @Test 099 public void testKnsDisabledByDefault() { 100 assertFalse(detector.isKnsEnabled()); 101 } 102 103 @Test 104 public void testKnsEnabledByConfig() { 105 ConfigContext.getCurrentContextConfig().putProperty(KRADConstants.Config.KNS_ENABLED, "true"); 106 assertTrue(detector.isKnsEnabled()); 107 } 108 109 @Test 110 public void testKnsDisabledByConfig() { 111 ConfigContext.getCurrentContextConfig().putProperty(KRADConstants.Config.KNS_ENABLED, "false"); 112 assertFalse(detector.isKnsEnabled()); 113 } 114 115 @Test 116 public void testLegacyDataFrameworkDisabledByDefault() { 117 assertFalse(detector.isLegacyDataFrameworkEnabled()); 118 } 119 120 @Test 121 public void testLegacyDataFrameworkEnabledByKnsByDefault() { 122 ConfigContext.getCurrentContextConfig().putProperty(KRADConstants.Config.KNS_ENABLED, "true"); 123 assertTrue(detector.isLegacyDataFrameworkEnabled()); 124 } 125 126 @Test 127 public void testLegacyDataFrameworkDisabledByKnsByDefault() { 128 ConfigContext.getCurrentContextConfig().putProperty(KRADConstants.Config.KNS_ENABLED, "false"); 129 assertFalse(detector.isLegacyDataFrameworkEnabled()); 130 } 131 132 @Test 133 public void testLegacyDataFrameworkEnabledByConfig() { 134 ConfigContext.getCurrentContextConfig().putProperty(KRADConstants.Config.KNS_ENABLED, "false"); 135 ConfigContext.getCurrentContextConfig().putProperty(KRADConstants.Config.ENABLE_LEGACY_DATA_FRAMEWORK, "true"); 136 assertTrue(detector.isLegacyDataFrameworkEnabled()); 137 } 138 139 @Test 140 public void testLegacyDataFrameworkDisabledByConfig() { 141 ConfigContext.getCurrentContextConfig().putProperty(KRADConstants.Config.KNS_ENABLED, "true"); 142 ConfigContext.getCurrentContextConfig().putProperty(KRADConstants.Config.ENABLE_LEGACY_DATA_FRAMEWORK, "false"); 143 assertFalse(detector.isLegacyDataFrameworkEnabled()); 144 } 145 146 @Test 147 public void testDataObjectNotLegacyWhenDisabled() { 148 addOjbClass(DummyDataObject.class); 149 assertFalse(detector.isLegacyDataFrameworkEnabled()); 150 assertFalse(detector.useLegacyForObject(new DummyDataObject())); 151 assertFalse(detector.useLegacy(DummyDataObject.class)); 152 } 153 154 @Test 155 public void testDataObjectNotLegacyWhenNotLoaded() { 156 ConfigContext.getCurrentContextConfig().putProperty(KRADConstants.Config.ENABLE_LEGACY_DATA_FRAMEWORK, "true"); 157 assertTrue(detector.isLegacyDataFrameworkEnabled()); 158 assertFalse(detector.useLegacyForObject(new DummyDataObject())); 159 assertFalse(detector.useLegacy(DummyDataObject.class)); 160 } 161 162 @Test 163 public void testDataObjectIsLegacyWhenEnabledAndLoaded() { 164 ConfigContext.getCurrentContextConfig().putProperty(KRADConstants.Config.ENABLE_LEGACY_DATA_FRAMEWORK, "true"); 165 addOjbClass(DummyDataObject.class); 166 assertTrue(detector.isLegacyDataFrameworkEnabled()); 167 assertTrue(detector.useLegacyForObject(new DummyDataObject())); 168 assertTrue(detector.useLegacy(DummyDataObject.class)); 169 } 170 171 @Test 172 public void testUseLegacy_InContext() { 173 ConfigContext.getCurrentContextConfig().putProperty(KRADConstants.Config.ENABLE_LEGACY_DATA_FRAMEWORK, "true"); 174 detector.beginLegacyContext(); 175 try { 176 // since recent changes, if it's not in OJB, it's not legacy 177 assertFalse(detector.useLegacy(DummyDataObject.class)); 178 assertTrue(detector.useLegacy(DummyDataObjectOjb.class)); 179 } finally { 180 detector.endLegacyContext(); 181 } 182 } 183 184 @Test(expected = IllegalStateException.class) 185 public void testUseLegacy_LegacyFrameworkDisabled() { 186 detector.beginLegacyContext(); 187 try { 188 detector.useLegacy(DummyDataObject.class); 189 } finally { 190 detector.endLegacyContext(); 191 } 192 } 193 194 /** 195 * Verifies that if you pass an instance of java.lang.Class to useLegacyForObject, that it 196 * throws an IllegalArgumentException since you should use the useLegacy method for that 197 */ 198 @Test(expected = IllegalArgumentException.class) 199 public void testUseLegacyForObject_PassingAClassIsBad() { 200 detector.useLegacyForObject(DummyDataObject.class); 201 } 202 203 @Test(expected=IllegalStateException.class) 204 public void testBeginLegacyContext_LegacyFrameworkDisabled() { 205 detector.beginLegacyContext(); 206 } 207 208 @Test(expected=IllegalStateException.class) 209 public void testEndLegacyContext_NoContext() { 210 detector.endLegacyContext(); 211 } 212 213 @Test 214 public void testBeginEndLegacyContext() { 215 ConfigContext.getCurrentContextConfig().putProperty(KRADConstants.Config.ENABLE_LEGACY_DATA_FRAMEWORK, "true"); 216 assertFalse(detector.isInLegacyContext()); 217 detector.beginLegacyContext(); 218 try { 219 assertTrue(detector.isInLegacyContext()); 220 } finally { 221 detector.endLegacyContext(); 222 } 223 assertFalse(detector.isInLegacyContext()); 224 } 225 226 @Test 227 public void testNestedLegacyContext() { 228 ConfigContext.getCurrentContextConfig().putProperty(KRADConstants.Config.ENABLE_LEGACY_DATA_FRAMEWORK, "true"); 229 assertFalse(detector.isInLegacyContext()); 230 detector.beginLegacyContext(); 231 try { 232 assertTrue(detector.isInLegacyContext()); 233 detector.beginLegacyContext(); 234 try { 235 detector.beginLegacyContext(); 236 try { 237 assertTrue(detector.isInLegacyContext()); 238 } finally { 239 detector.endLegacyContext(); 240 } 241 assertTrue(detector.isInLegacyContext()); 242 } finally { 243 detector.endLegacyContext(); 244 } 245 assertTrue(detector.isInLegacyContext()); 246 } finally { 247 detector.endLegacyContext(); 248 } 249 assertFalse(detector.isInLegacyContext()); 250 } 251 252 @Test 253 public void testIllegallyNestedLegacyContext() { 254 ConfigContext.getCurrentContextConfig().putProperty(KRADConstants.Config.ENABLE_LEGACY_DATA_FRAMEWORK, "true"); 255 assertFalse(detector.isInLegacyContext()); 256 detector.beginLegacyContext(); 257 assertTrue(detector.isInLegacyContext()); 258 detector.endLegacyContext(); 259 assertFalse(detector.isInLegacyContext()); 260 try { 261 detector.endLegacyContext(); 262 fail("Should have thrown IllegalStateException"); 263 } catch (IllegalStateException e) { 264 // this should happen! 265 } 266 } 267 268 @Test 269 public void testIsOjbLoadedClass() { 270 assertFalse(detector.isOjbLoadedClass(DummyDataObject.class)); 271 assertTrue(detector.isOjbLoadedClass(DummyDataObjectOjb.class)); 272 } 273 274 /** 275 * Verifies that isLegacyManaged reports that the object is legacy managed if it has a BusinessObjectEntry and 276 * nothing else. 277 */ 278 @Test 279 public void testIsLegacyManaged_withBusinessObjectEntry() { 280 assertFalse(detector.isLegacyManaged(DummyDataObject.class)); 281 when(dataDictionary.getBusinessObjectEntry(DummyDataObject.class.getName())).thenReturn( 282 new BusinessObjectEntry()); 283 assertTrue(detector.isLegacyManaged(DummyDataObject.class)); 284 assertFalse(detector.isLegacyManaged(String.class)); 285 verify(dataDictionary, times(2)).getBusinessObjectEntry(DummyDataObject.class.getName()); 286 verify(dataDictionary, times(3)).getBusinessObjectEntry(anyString()); 287 } 288 289 /** 290 * Verifies that isLegacyManaged reports that the object is legacy managed if it is mapped in OJB. 291 */ 292 @Test 293 public void testIsLegacyManaged_ojbLoaded() { 294 assertFalse(detector.isLegacyManaged(DummyDataObject.class)); 295 // it must be mapped in ojb 296 assertTrue(detector.isLegacyManaged(DummyDataObjectOjb.class)); 297 } 298 299 /** 300 * Ensures false is returned form isOjbLoadedClass if OJB is not on the classpath. 301 */ 302 @Test 303 public void testIsOjbLoadedClass_NoOjbOnClasspath() throws Exception { 304 // set an empty classloader to cause the check to load OJB MetadataManager to fail from inside isOjbLoadedClass 305 ContextClassLoaderBinder.doInContextClassLoader(ClassLoader.getSystemClassLoader().getParent(), 306 new Callable<Object>() { 307 @Override 308 public Object call() throws Exception { 309 assertFalse(detector.isOjbLoadedClass(DummyDataObjectOjb.class)); 310 return null; 311 } 312 }); 313 } 314 315 private void addOjbClass(Class<?> type) { 316 ClassDescriptor classDescriptor = new ClassDescriptor(metadataManager.getGlobalRepository()); 317 classDescriptor.setClassOfObject(type); 318 metadataManager.getGlobalRepository().put(type, classDescriptor); 319 } 320 321 /** 322 * Hacks OJB to put a stubbed MetadataManager into place. 323 */ 324 private MetadataManager hackOjb(MetadataManager mockMetadataManager) throws Exception { 325 Field singletonField = MetadataManager.class.getDeclaredField("singleton"); 326 singletonField.setAccessible(true); 327 MetadataManager existingMetadataManager = (MetadataManager)singletonField.get(null); 328 singletonField.set(null, mockMetadataManager); 329 return existingMetadataManager; 330 } 331 332 private void unhackOjb(MetadataManager existingMetadataManager) throws Exception{ 333 Field singletonField = MetadataManager.class.getDeclaredField("singleton"); 334 singletonField.setAccessible(true); 335 singletonField.set(null, this.existingMetadataManager); 336 337 } 338 339}