1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package org.apache.harmony.luni.tests.java.util;
19
20import java.io.File;
21import java.net.MalformedURLException;
22import java.net.URL;
23import java.net.URLClassLoader;
24import java.util.Iterator;
25import java.util.NoSuchElementException;
26import java.util.ServiceConfigurationError;
27import java.util.ServiceLoader;
28
29import junit.framework.TestCase;
30import tests.resources.ServiceLoader.AbstractService;
31import tests.resources.ServiceLoader.Service;
32import tests.resources.ServiceLoader.ServiceDuplicateIn2File;
33import tests.resources.ServiceLoader.ServiceFinalClass;
34import tests.resources.ServiceLoader.ServiceForAllCommentTest;
35import tests.resources.ServiceLoader.ServiceForEmptyTest;
36import tests.resources.ServiceLoader.ServiceForIllegalNameTest;
37import tests.resources.ServiceLoader.ServiceForWrongNameTest;
38import tests.resources.ServiceLoader.ServiceIn2File;
39import tests.resources.ServiceLoader.ServiceIn2FileWithEmptyConfig;
40import tests.resources.ServiceLoader.ServiceMoreThanOne;
41import tests.resources.ServiceLoader.ServiceWithDuplicateSons;
42import tests.support.resource.Support_Resources;
43
44/**
45 * Test cases for java.util.ServiceLoader
46 */
47public class ServiceLoaderTest extends TestCase {
48
49    private static URL jarFile = null;
50
51    /**
52     * @throws MalformedURLException
53     * @tests {@link java.util.ServiceLoader#reload()}.
54     */
55    @SuppressWarnings("nls")
56    public void test_reload() throws MalformedURLException {
57        class SubURLClassLoader extends URLClassLoader {
58            /**
59             * @param urls
60             */
61            public SubURLClassLoader(URL[] urls) {
62                super(urls);
63            }
64
65            @Override
66            public void addURL(URL url) {
67                super.addURL(url);
68            }
69        }
70        SubURLClassLoader ucl = new SubURLClassLoader(new URL[] { new URL(
71                "file:/no/such/file") });
72        ServiceLoader<Service> serviceLoader = ServiceLoader.load(
73                Service.class, ucl);
74        Iterator<Service> itr = serviceLoader.iterator();
75        assertFalse(itr.hasNext());
76        // change the ucl to install a jar file
77        ucl.addURL(jarFile);
78        // before reload, the Iterator is unchanged
79        itr = serviceLoader.iterator();
80        assertNotSame(itr, serviceLoader.iterator());
81        assertFalse(itr.hasNext());
82        // after reload, the Iterator update
83        serviceLoader.reload();
84        itr = serviceLoader.iterator();
85        assertTrue(itr.hasNext());
86        assertEquals("ImplementationOfService", itr.next().myNameIs());
87        assertFalse(itr.hasNext());
88    }
89
90    /**
91     * @tests {@link java.util.ServiceLoader#iterator()}.
92     */
93    @SuppressWarnings( { "nls", "unchecked" })
94    public void test_iterator() {
95        URLClassLoader ucl = new URLClassLoader(new URL[] { jarFile });
96        Iterator itr = ServiceLoader.load(Service.class, ucl).iterator();
97        assertTrue(itr.hasNext());
98        assertEquals("ImplementationOfService", ((Service) itr.next())
99                .myNameIs());
100        assertFalse(itr.hasNext());
101        try {
102            itr.remove();
103            fail("Should throw UnsupportedOperationException");
104        } catch (UnsupportedOperationException e) {
105            // expected
106        }
107
108        itr = ServiceLoader.load(ServiceForWrongNameTest.class, ucl).iterator();
109        assertTrue(itr.hasNext());
110        try {
111            itr.next();
112            fail("Should throw ServiceConfigurationError");
113        } catch (ServiceConfigurationError e) {
114            // expected
115        }
116        try {
117            itr.remove();
118            fail("Should throw UnsupportedOperationException");
119        } catch (UnsupportedOperationException e) {
120            // expected
121        }
122
123        // null test
124        itr = ServiceLoader.load(null).iterator();
125        nullIteratorTester(itr);
126
127        itr = ServiceLoader.load(null, null).iterator();
128        nullIteratorTester(itr);
129
130        itr = ServiceLoader.load(null, ClassLoader.getSystemClassLoader())
131                .iterator();
132        nullIteratorTester(itr);
133
134        itr = ServiceLoader.load(Service.class, null).iterator();
135        assertFalse(itr.hasNext());
136        try {
137            itr.next();
138            fail("Should throw NoSuchElementException");
139        } catch (NoSuchElementException e) {
140            // expected
141        }
142        try {
143            itr.remove();
144            fail("Should throw UnsupportedOperationException");
145        } catch (UnsupportedOperationException e) {
146            // expected
147        }
148    }
149
150    @SuppressWarnings( { "nls", "unchecked" })
151    private void nullIteratorTester(Iterator itr) {
152        assertNotNull(itr);
153        try {
154            itr.hasNext();
155            fail("Should throw NullPointerException");
156        } catch (NullPointerException e) {
157            // expected
158        }
159
160        try {
161            itr.next();
162            fail("Should throw NullPointerException");
163        } catch (NullPointerException e) {
164            // expected
165        }
166
167        try {
168            itr.remove();
169            fail("Should throw UnsupportedOperationException");
170        } catch (UnsupportedOperationException e) {
171            // expected
172        }
173    }
174
175    /**
176     * @throws MalformedURLException
177     * @tests {@link java.util.ServiceLoader#load(java.lang.Class, java.lang.ClassLoader)}.
178     */
179    @SuppressWarnings( { "nls", "unchecked" })
180    public void test_loadLjava_lang_ClassLjava_lang_ClassLoader()
181            throws MalformedURLException {
182        URLClassLoader ucl = new URLClassLoader(new URL[] { jarFile });
183        // normal config file
184        ServiceLoader serviceLoader = ServiceLoader.load(Service.class, ucl);
185        Iterator itr = serviceLoader.iterator();
186        assertTrue(itr.hasNext());
187        assertEquals("ImplementationOfService", ((Service) itr.next())
188                .myNameIs());
189        assertFalse(itr.hasNext());
190
191        // class that can not cast correctly
192        serviceLoader = ServiceLoader.load(ServiceFinalClass.class, ucl);
193        itr = serviceLoader.iterator();
194        assertTrue(itr.hasNext());
195        try {
196            itr.next();
197            fail("Should throw ServiceConfigurationError");
198        } catch (ServiceConfigurationError e) {
199            // expected
200        }
201
202        // abstract class with comment in config file
203        serviceLoader = ServiceLoader.load(AbstractService.class, ucl);
204        itr = serviceLoader.iterator();
205        assertTrue(itr.hasNext());
206        assertEquals("ImplementationOfAbstractService", ((AbstractService) itr
207                .next()).myNameIs());
208        assertFalse(itr.hasNext());
209
210        // one service with two implementation class
211        serviceLoader = ServiceLoader.load(ServiceMoreThanOne.class, ucl);
212        itr = serviceLoader.iterator();
213        assertTrue(itr.hasNext());
214        String name = ((ServiceMoreThanOne) itr.next()).myNameIs();
215        if ("ImplementationOfServiceMoreThanOne1".equals(name)) {
216            assertEquals("ImplementationOfServiceMoreThanOne2",
217                    ((ServiceMoreThanOne) itr.next()).myNameIs());
218        } else if ("ImplementationOfServiceMoreThanOne2".equals(name)) {
219            assertEquals("ImplementationOfServiceMoreThanOne1",
220                    ((ServiceMoreThanOne) itr.next()).myNameIs());
221        } else {
222            fail("Should load ImplementationOfServiceMoreThanOne1 or ImplementationOfServiceMoreThanOne2");
223        }
224        assertFalse(itr.hasNext());
225
226        // config file only contains comments
227        serviceLoader = ServiceLoader.load(ServiceForAllCommentTest.class, ucl);
228        itr = serviceLoader.iterator();
229        assertFalse(itr.hasNext());
230        try {
231            itr.next();
232            fail("Should throw NoSuchElementException");
233        } catch (NoSuchElementException e) {
234            // expected
235        }
236
237        // empty config file
238        serviceLoader = ServiceLoader.load(ServiceForEmptyTest.class, ucl);
239        itr = serviceLoader.iterator();
240        assertFalse(itr.hasNext());
241        try {
242            itr.next();
243            fail("Should throw NoSuchElementException");
244        } catch (NoSuchElementException e) {
245            // expected
246        }
247
248        // config file with illegal char
249        serviceLoader = ServiceLoader
250                .load(ServiceForIllegalNameTest.class, ucl);
251        itr = serviceLoader.iterator();
252        try {
253            itr.hasNext();
254            fail("Should throw ServiceConfigurationError");
255        } catch (ServiceConfigurationError e) {
256            // expected
257        }
258
259        // config file with legal string, but the class does not exist
260        serviceLoader = ServiceLoader.load(ServiceForWrongNameTest.class, ucl);
261        itr = serviceLoader.iterator();
262        assertTrue(itr.hasNext());
263        try {
264            itr.next();
265            fail("Should throw ServiceConfigurationError");
266        } catch (ServiceConfigurationError e) {
267            // expected
268        }
269
270        // config file for an internal class
271        serviceLoader = ServiceLoader.load(
272                AbstractService.InternalService.class, ucl);
273        itr = serviceLoader.iterator();
274        assertTrue(itr.hasNext());
275        assertEquals("ImplementationOfAbstractServiceInternalService",
276                ((AbstractService.InternalService) itr.next())
277                        .myInternalNameIs());
278        assertFalse(itr.hasNext());
279
280        // config files in the 2 jar files
281        serviceLoader = ServiceLoader.load(ServiceIn2File.class, ucl);
282        itr = serviceLoader.iterator();
283        assertTrue(itr.hasNext());
284        assertEquals("ImplementationOfServiceIn2File1", ((ServiceIn2File) itr
285                .next()).myNameIs());
286        assertFalse(itr.hasNext());
287        // add the second file
288        URL jarFile2 = prepairJar("hyts_services2.jar");
289        URLClassLoader ucl2 = new URLClassLoader(
290                new URL[] { jarFile, jarFile2 });
291        serviceLoader = ServiceLoader.load(ServiceIn2File.class, ucl2);
292        itr = serviceLoader.iterator();
293        assertTrue(itr.hasNext());
294        name = ((ServiceIn2File) itr.next()).myNameIs();
295        if ("ImplementationOfServiceIn2File1".equals(name)) {
296            assertEquals("ImplementationOfServiceIn2File2",
297                    ((ServiceIn2File) itr.next()).myNameIs());
298        } else if ("ImplementationOfServiceIn2File2".equals(name)) {
299            assertEquals("ImplementationOfServiceIn2File1",
300                    ((ServiceIn2File) itr.next()).myNameIs());
301        } else {
302            fail("Should load ImplementationOfServiceIn2File1 or ImplementationOfServiceIn2File2");
303        }
304        assertFalse(itr.hasNext());
305
306        // same config files in 2 jar files
307        serviceLoader = ServiceLoader.load(ServiceDuplicateIn2File.class, ucl2);
308        itr = serviceLoader.iterator();
309        assertTrue(itr.hasNext());
310        assertEquals("ImplementationOfServiceDuplicateIn2File_1",
311                ((ServiceDuplicateIn2File) itr.next()).myNameIs());
312        assertFalse(itr.hasNext());
313        ucl2 = new URLClassLoader(new URL[] { jarFile2, jarFile });
314        serviceLoader = ServiceLoader.load(ServiceDuplicateIn2File.class, ucl2);
315        itr = serviceLoader.iterator();
316        assertTrue(itr.hasNext());
317        assertEquals("ImplementationOfServiceDuplicateIn2File_2",
318                ((ServiceDuplicateIn2File) itr.next()).myNameIs());
319        assertFalse(itr.hasNext());
320
321        // one config file in one jar, another empty config in another jar.
322        serviceLoader = ServiceLoader.load(ServiceIn2FileWithEmptyConfig.class,
323                ucl);
324        itr = serviceLoader.iterator();
325        assertTrue(itr.hasNext());
326        assertEquals("ImplementationOfServiceIn2FileWithEmptyConfig",
327                ((ServiceIn2FileWithEmptyConfig) itr.next()).myNameIs());
328        assertFalse(itr.hasNext());
329        ucl2 = new URLClassLoader(new URL[] { jarFile, jarFile2 });
330        serviceLoader = ServiceLoader.load(ServiceIn2FileWithEmptyConfig.class,
331                ucl2);
332        itr = serviceLoader.iterator();
333        assertTrue(itr.hasNext());
334        assertEquals("ImplementationOfServiceIn2FileWithEmptyConfig",
335                ((ServiceIn2FileWithEmptyConfig) itr.next()).myNameIs());
336        assertFalse(itr.hasNext());
337
338        // config file with duplicate items
339        serviceLoader = ServiceLoader.load(ServiceWithDuplicateSons.class, ucl);
340        itr = serviceLoader.iterator();
341        assertTrue(itr.hasNext());
342        assertEquals("ImplementationOfServiceWithDuplicateSons",
343                ((ServiceWithDuplicateSons) itr.next()).myNameIs());
344        assertFalse(itr.hasNext());
345
346        // can not load by system classloader
347        serviceLoader = ServiceLoader.load(Service.class, ClassLoader
348                .getSystemClassLoader());
349        assertFalse(serviceLoader.iterator().hasNext());
350
351        // can not load by Thread.currentThread().getContextClassLoader()
352        serviceLoader = ServiceLoader.load(Service.class, Thread
353                .currentThread().getContextClassLoader());
354        assertFalse(serviceLoader.iterator().hasNext());
355
356        serviceLoader = ServiceLoader.load(Service.class, Service.class
357                .getClassLoader());
358        assertFalse(serviceLoader.iterator().hasNext());
359
360        // String is a final class, no sub-class for it
361        serviceLoader = ServiceLoader.load(String.class, ucl);
362        assertFalse(serviceLoader.iterator().hasNext());
363    }
364
365    /**
366     * @tests {@link java.util.ServiceLoader#load(java.lang.Class)}.
367     */
368    @SuppressWarnings( { "nls", "unchecked" })
369    public void test_loadLjava_lang_Class() {
370        ServiceLoader serviceLoader = ServiceLoader.load(Service.class);
371        assertFalse(serviceLoader.iterator().hasNext());
372        // String is a final class, no sub-class for it
373        serviceLoader = ServiceLoader.load(String.class);
374        assertFalse(serviceLoader.iterator().hasNext());
375    }
376
377    /**
378     * @param fileName
379     * @return the URL of the jar file
380     * @throws MalformedURLException
381     */
382    @SuppressWarnings("nls")
383    private static URL prepairJar(String fileName) throws MalformedURLException {
384        File resources = Support_Resources.createTempFolder();
385        String resPath = resources.toString();
386        if (resPath.charAt(0) == '/' || resPath.charAt(0) == '\\') {
387            resPath = resPath.substring(1);
388        }
389        Support_Resources.copyFile(resources, "ServiceLoader", fileName);
390        URL resourceURL = new URL("file:/" + resPath + "/ServiceLoader/"
391                + fileName);
392        return resourceURL;
393    }
394
395    /**
396     * @tests {@link java.util.ServiceLoader#loadInstalled(java.lang.Class)}.
397     */
398    public void test_loadInstalledLjava_lang_Class() {
399        ServiceLoader<Service> serviceLoader = ServiceLoader
400                .loadInstalled(Service.class);
401        assertFalse(serviceLoader.iterator().hasNext());
402
403        serviceLoader = ServiceLoader.loadInstalled(null);
404        Iterator<Service> itr = serviceLoader.iterator();
405        nullIteratorTester(itr);
406    }
407
408    /**
409     * @tests {@link java.util.ServiceLoader#toString()}.
410     */
411    @SuppressWarnings( { "unchecked", "nls" })
412    public void test_toString() {
413        URLClassLoader ucl = new URLClassLoader(new URL[] { jarFile });
414        ServiceLoader serviceLoader = ServiceLoader.load(Service.class, ucl);
415        assertTrue(serviceLoader.toString().length() > 0);
416
417        serviceLoader = ServiceLoader.load(String.class, ucl);
418        assertTrue(serviceLoader.toString().length() > 0);
419
420        serviceLoader = ServiceLoader.load(Service.class);
421        assertTrue(serviceLoader.toString().length() > 0);
422
423        serviceLoader = ServiceLoader.load(String.class);
424        assertTrue(serviceLoader.toString().length() > 0);
425
426        serviceLoader = ServiceLoader.loadInstalled(Service.class);
427        assertTrue(serviceLoader.toString().length() > 0);
428
429        serviceLoader = ServiceLoader.loadInstalled(String.class);
430        assertTrue(serviceLoader.toString().length() > 0);
431
432        serviceLoader = ServiceLoader.load(null, ucl);
433        assertNotNull(serviceLoader);
434        try {
435            serviceLoader.toString();
436            fail("Should throw NullPointerException");
437        } catch (NullPointerException e) {
438            // expected
439        }
440
441        serviceLoader = ServiceLoader.load(null, null);
442        assertNotNull(serviceLoader);
443        try {
444            serviceLoader.toString();
445            fail("Should throw NullPointerException");
446        } catch (NullPointerException e) {
447            // expected
448        }
449
450        serviceLoader = ServiceLoader.load(Service.class, null);
451        assertTrue(serviceLoader.toString().length() > 0);
452
453        serviceLoader = ServiceLoader.load(null);
454        assertNotNull(serviceLoader);
455        try {
456            serviceLoader.toString();
457            fail("Should throw NullPointerException");
458        } catch (NullPointerException e) {
459            // expected
460        }
461
462        serviceLoader = ServiceLoader.loadInstalled(null);
463        assertNotNull(serviceLoader);
464        try {
465            serviceLoader.toString();
466            fail("Should throw NullPointerException");
467        } catch (NullPointerException e) {
468            // expected
469        }
470    }
471
472    /**
473     * @see junit.framework.TestCase#setUp()
474     */
475    @SuppressWarnings("nls")
476    @Override
477    protected void setUp() throws Exception {
478        super.setUp();
479        jarFile = prepairJar("hyts_services.jar");
480    }
481
482    /**
483     * @see junit.framework.TestCase#tearDown()
484     */
485    @Override
486    protected void tearDown() throws Exception {
487        super.tearDown();
488        new File(jarFile.getFile()).delete();
489    }
490
491}
492