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 */ 016 package org.kuali.rice.krad.data.provider; 017 018 import org.apache.commons.lang.math.RandomUtils; 019 import org.junit.Before; 020 import org.junit.Test; 021 import org.kuali.rice.krad.data.provider.impl.ProviderRegistryImpl; 022 023 import java.util.ArrayList; 024 import java.util.Arrays; 025 import java.util.Collections; 026 import java.util.List; 027 import java.util.concurrent.BlockingQueue; 028 import java.util.concurrent.Callable; 029 import java.util.concurrent.ExecutorService; 030 import java.util.concurrent.Executors; 031 import java.util.concurrent.LinkedBlockingQueue; 032 import java.util.concurrent.TimeUnit; 033 034 import static junit.framework.Assert.assertEquals; 035 import static org.junit.Assert.assertNull; 036 import static org.junit.Assert.assertSame; 037 import static org.mockito.Matchers.any; 038 import static org.mockito.Matchers.eq; 039 import static org.mockito.Mockito.mock; 040 import static org.mockito.Mockito.when; 041 042 /** 043 * Tests ProviderRegistryImpl 044 */ 045 public class ProviderRegistryImplTest { 046 // various Provider interfaces for testing 047 private static interface CustomProvider extends Provider {} 048 private static interface MultiProvider extends PersistenceProvider, MetadataProvider, CustomProvider {} 049 050 // test types 051 private static class A {} 052 private static class B {} 053 private static Class<A> TYPE_A = A.class; 054 private static Class<B> TYPE_B = B.class; 055 056 private ProviderRegistry registry; 057 058 @Before 059 public void setup() { 060 registry = new ProviderRegistryImpl(); 061 } 062 063 /** 064 * Test empty state 065 */ 066 @Test 067 public void testEmpty() { 068 assertEquals(0, registry.getProviders().size()); 069 assertEquals(0, registry.getMetadataProviders().size()); 070 assertEquals(0, registry.getProvidersForType(MetadataProvider.class).size()); 071 assertEquals(0, registry.getProvidersForType(PersistenceProvider.class).size()); 072 assertEquals(0, registry.getProvidersForType(CustomProvider.class).size()); 073 assertNull(registry.getPersistenceProvider(String.class)); 074 } 075 076 @Test(expected=IllegalArgumentException.class) 077 public void testRegisterProviderIllegalArgument() { 078 registry.registerProvider(null); 079 } 080 081 @Test(expected=IllegalArgumentException.class) 082 public void testUnregisterProviderIllegalArgument() { 083 registry.unregisterProvider(null); 084 } 085 086 @Test(expected=IllegalArgumentException.class) 087 public void testGetProvidersForTypeIllegalArgument() { 088 registry.getProvidersForType(null); 089 } 090 091 @Test(expected=IllegalArgumentException.class) 092 public void testGetPersistenceProviderIllegalArgument() { 093 registry.getPersistenceProvider(null); 094 } 095 096 /** 097 * Registers various Provider implementations and tests getters 098 */ 099 @Test 100 public void testRegisterProviders() { 101 registry.registerProvider(mock(Provider.class)); 102 103 assertEquals(1, registry.getProviders().size()); 104 assertEquals(0, registry.getMetadataProviders().size()); 105 assertEquals(0, registry.getProvidersForType(MetadataProvider.class).size()); 106 assertEquals(0, registry.getProvidersForType(PersistenceProvider.class).size()); 107 assertEquals(0, registry.getProvidersForType(CustomProvider.class).size()); 108 assertNull(registry.getPersistenceProvider(String.class)); 109 110 // create mock metadataprovider that handles any dataobjecttype 111 MetadataProvider mockMetadataProvider = mock(MetadataProvider.class); 112 when(mockMetadataProvider.handles(any(Class.class))).thenReturn(true); 113 114 registry.registerProvider(mockMetadataProvider); 115 116 assertEquals(2, registry.getProviders().size()); 117 assertEquals(1, registry.getMetadataProviders().size()); 118 assertEquals(1, registry.getProvidersForType(MetadataProvider.class).size()); 119 assertEquals(0, registry.getProvidersForType(PersistenceProvider.class).size()); 120 assertEquals(0, registry.getProvidersForType(CustomProvider.class).size()); 121 assertNull(registry.getPersistenceProvider(String.class)); 122 assertSame(mockMetadataProvider, registry.getMetadataProvider(String.class)); 123 124 assertEquals(2, registry.getProviders().size()); 125 assertEquals(1, registry.getMetadataProviders().size()); 126 assertEquals(1, registry.getProvidersForType(MetadataProvider.class).size()); 127 assertEquals(0, registry.getProvidersForType(PersistenceProvider.class).size()); 128 assertEquals(0, registry.getProvidersForType(CustomProvider.class).size()); 129 assertNull(registry.getPersistenceProvider(String.class)); 130 assertSame(mockMetadataProvider, registry.getMetadataProvider(String.class)); 131 132 PersistenceProvider pp = mock(PersistenceProvider.class); 133 when(pp.handles(TYPE_B)).thenReturn(true); 134 registry.registerProvider(pp); 135 136 assertEquals(3, registry.getProviders().size()); 137 assertEquals(1, registry.getMetadataProviders().size()); 138 assertEquals(1, registry.getProvidersForType(MetadataProvider.class).size()); 139 assertEquals(1, registry.getProvidersForType(PersistenceProvider.class).size()); 140 assertEquals(0, registry.getProvidersForType(CustomProvider.class).size()); 141 assertNull(registry.getPersistenceProvider(String.class)); 142 assertSame(pp, registry.getPersistenceProvider(B.class)); 143 assertSame(mockMetadataProvider, registry.getMetadataProvider(String.class)); 144 145 registry.registerProvider(mock(CustomProvider.class)); 146 147 assertEquals(4, registry.getProviders().size()); 148 assertEquals(1, registry.getMetadataProviders().size()); 149 assertEquals(1, registry.getProvidersForType(MetadataProvider.class).size()); 150 assertEquals(1, registry.getProvidersForType(PersistenceProvider.class).size()); 151 assertEquals(1, registry.getProvidersForType(CustomProvider.class).size()); 152 assertNull(registry.getPersistenceProvider(String.class)); 153 assertSame(pp, registry.getPersistenceProvider(B.class)); 154 assertSame(mockMetadataProvider, registry.getMetadataProvider(String.class)); 155 156 registry.registerProvider(mock(MultiProvider.class)); 157 158 assertEquals(5, registry.getProviders().size()); 159 assertEquals(2, registry.getMetadataProviders().size()); 160 assertEquals(2, registry.getProvidersForType(MetadataProvider.class).size()); 161 assertEquals(2, registry.getProvidersForType(PersistenceProvider.class).size()); 162 assertEquals(2, registry.getProvidersForType(CustomProvider.class).size()); 163 assertNull(registry.getPersistenceProvider(String.class)); 164 assertSame(pp, registry.getPersistenceProvider(B.class)); 165 // returns the *first* metadataprovider that handles the given type 166 assertSame(mockMetadataProvider, registry.getMetadataProvider(String.class)); 167 } 168 169 /** 170 * Verifies duplicate providers can't be registered 171 */ 172 @Test 173 public void testRegisterDuplicateProviders() { 174 Provider p = mock(Provider.class); 175 MetadataProvider mp1 = mock(MetadataProvider.class); 176 MetadataProvider mp2 = mock(MetadataProvider.class); 177 178 registry.registerProvider(p); 179 assertEquals(1, registry.getProviders().size()); 180 registry.registerProvider(p); 181 assertEquals(1, registry.getProviders().size()); 182 183 registry.registerProvider(mp1); 184 assertEquals(2, registry.getProviders().size()); 185 assertEquals(1, registry.getMetadataProviders().size()); 186 registry.registerProvider(mp1); 187 assertEquals(2, registry.getProviders().size()); 188 assertEquals(1, registry.getMetadataProviders().size()); 189 190 registry.registerProvider(mp2); 191 assertEquals(3, registry.getProviders().size()); 192 assertEquals(2, registry.getMetadataProviders().size()); 193 registry.registerProvider(mp2); 194 assertEquals(3, registry.getProviders().size()); 195 assertEquals(2, registry.getMetadataProviders().size()); 196 } 197 198 /** 199 * Tests unregistering after registering 200 */ 201 @Test 202 public void testRegisterUnregister() { 203 Provider a = mock(Provider.class); 204 Provider b = mock(Provider.class); 205 Provider c = mock(Provider.class); 206 Provider d = mock(Provider.class); 207 208 registry.registerProvider(a); 209 registry.registerProvider(b); 210 registry.registerProvider(c); 211 registry.registerProvider(d); 212 213 assertEquals(4, registry.getProviders().size()); 214 215 registry.unregisterProvider(c); 216 registry.unregisterProvider(b); 217 registry.unregisterProvider(d); 218 registry.unregisterProvider(a); 219 220 assertEquals(0, registry.getProviders().size()); 221 } 222 223 /** 224 * Verifies ProviderRegistryImpl is threadsafe 225 */ 226 @Test 227 public void testConcurrency() throws InterruptedException { 228 final Class<? extends Provider>[] TYPES = new Class[] { 229 Provider.class, MetadataProvider.class, 230 PersistenceProvider.class, CustomProvider.class 231 }; 232 233 int providers = 50; 234 int threads = providers * 2; // just use live threads for all consumers/producers to ensure no consumer deadlock 235 236 final BlockingQueue<Provider> queue = new LinkedBlockingQueue<Provider>(); 237 ExecutorService threadpool = Executors.newFixedThreadPool(threads); 238 239 Callable<Object>[] producers = new Callable[providers]; 240 Callable<Object>[] consumers = new Callable[providers]; 241 Callable<Object> producer = new Callable<Object>() { 242 @Override 243 public Object call() throws Exception { 244 Provider p = mock(TYPES[RandomUtils.nextInt(5)]); 245 registry.registerProvider(p); 246 queue.add(p); 247 return null; 248 } 249 }; 250 Callable<Object> consumer = new Callable<Object>() { 251 @Override 252 public Object call() throws Exception { 253 Provider p = queue.take(); 254 registry.unregisterProvider(p); 255 return null; 256 } 257 }; 258 259 Arrays.fill(producers, producer); 260 Arrays.fill(consumers, consumer); 261 262 List<Callable<Object>> tasks = new ArrayList<Callable<Object>>(providers * 2); 263 tasks.addAll(Arrays.asList(producers)); 264 tasks.addAll(Arrays.asList(consumers)); 265 Collections.shuffle(tasks); 266 267 System.out.println("Registering and unregistering " + providers + " providers"); 268 threadpool.invokeAll(tasks, 10, TimeUnit.SECONDS); 269 270 // all producers and consumers should have run, we should be back at 0 providers registered 271 assertEquals(0, registry.getProviders().size()); 272 } 273 274 /** 275 * Tests registration and lookup of multiple PersistenceProviders 276 */ 277 @Test 278 public void testRegisterPersistenceProviders() { 279 PersistenceProvider mockA = mock(PersistenceProvider.class); 280 when(mockA.handles(eq(TYPE_A))).thenReturn(true); 281 282 PersistenceProvider mockB = mock(PersistenceProvider.class); 283 when(mockB.handles(eq(TYPE_B))).thenReturn(true); 284 285 PersistenceProvider mockAB = mock(PersistenceProvider.class); 286 when(mockAB.handles(eq(TYPE_A))).thenReturn(true); 287 when(mockAB.handles(eq(TYPE_B))).thenReturn(true); 288 289 registry.registerProvider(mockA); 290 291 assertEquals(1, registry.getProviders().size()); 292 assertEquals(0, registry.getMetadataProviders().size()); 293 assertEquals(1, registry.getProvidersForType(PersistenceProvider.class).size()); 294 assertEquals(0, registry.getProvidersForType(MetadataProvider.class).size()); 295 assertEquals(0, registry.getProvidersForType(CustomProvider.class).size()); 296 assertSame(mockA, registry.getPersistenceProvider(A.class)); 297 298 registry.registerProvider(mockB); 299 300 assertEquals(2, registry.getProviders().size()); 301 assertEquals(0, registry.getMetadataProviders().size()); 302 assertEquals(2, registry.getProvidersForType(PersistenceProvider.class).size()); 303 assertEquals(0, registry.getProvidersForType(MetadataProvider.class).size()); 304 assertEquals(0, registry.getProvidersForType(CustomProvider.class).size()); 305 assertSame(mockA, registry.getPersistenceProvider(A.class)); 306 assertSame(mockB, registry.getPersistenceProvider(B.class)); 307 308 registry.registerProvider(mockAB); 309 310 assertEquals(3, registry.getProviders().size()); 311 assertEquals(0, registry.getMetadataProviders().size()); 312 assertEquals(3, registry.getProvidersForType(PersistenceProvider.class).size()); 313 assertEquals(0, registry.getProvidersForType(MetadataProvider.class).size()); 314 assertEquals(0, registry.getProvidersForType(CustomProvider.class).size()); 315 assertSame(mockA, registry.getPersistenceProvider(A.class)); // still returns mockA 316 assertSame(mockB, registry.getPersistenceProvider(B.class)); 317 } 318 }