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 }