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.net;
19
20import java.io.File;
21import java.io.FileOutputStream;
22import java.io.IOException;
23import java.io.InputStream;
24import java.net.MalformedURLException;
25import java.net.URL;
26import java.net.URLClassLoader;
27import java.net.URLStreamHandler;
28import java.net.URLStreamHandlerFactory;
29import java.util.Enumeration;
30import java.util.NoSuchElementException;
31import java.util.StringTokenizer;
32import java.util.Vector;
33import java.util.jar.Attributes;
34import java.util.jar.JarFile;
35import java.util.jar.JarOutputStream;
36import java.util.jar.Manifest;
37
38import junit.framework.TestCase;
39import tests.support.Support_Configuration;
40import tests.support.Support_Jetty;
41import tests.support.resource.Support_Resources;
42
43public class URLClassLoaderTest extends TestCase {
44
45    private static final String PREFIX = "http://localhost:";
46
47    private static final String ROOT = "resources/net.resources/HTTP/html/testres231";
48
49    private static String serverURL = null;
50
51    URLClassLoader ucl;
52
53    static {
54        int port = 0;
55        try {
56            port = Support_Jetty.startHttpServerWithDocRoot(ROOT);
57        } catch (Exception e) {
58            fail("Exception during setup jetty : " + e.getMessage());
59        }
60        serverURL = PREFIX + port + "/";
61    }
62
63    class BogusClassLoader extends ClassLoader {
64        public URL getResource(String res) {
65            try {
66                return new URL("http://test/BogusClassLoader");
67            } catch (MalformedURLException e) {
68                return null;
69            }
70        }
71    }
72
73    public class URLClassLoaderExt extends URLClassLoader {
74
75        public URLClassLoaderExt(URL[] urls) {
76            super(urls);
77        }
78
79        public Class<?> findClass(String cl) throws ClassNotFoundException {
80            return super.findClass(cl);
81        }
82    }
83
84    /**
85     * @tests java.net.URLClassLoader#URLClassLoader(java.net.URL[])
86     */
87    public void test_Constructor$Ljava_net_URL() throws Exception {
88        URL[] u = new URL[0];
89        ucl = new URLClassLoader(u);
90        assertNotNull(ucl);
91        assertSame("Failed to set parent", URLClassLoader
92                .getSystemClassLoader(), ucl.getParent());
93
94        URLClassLoader loader = new URLClassLoader(new URL[] { null });
95        try {
96            Class.forName("test", false, loader);
97            fail("Should throw NullPointerException");
98        } catch (NullPointerException e) {
99            // Expected
100        }
101    }
102
103    /**
104     * @tests java.net.URLClassLoader#URLClassLoader(java.net.URL[],
105     *java.lang.ClassLoader)
106     */
107    public void test_Constructor$Ljava_net_URLLjava_lang_ClassLoader() {
108        ClassLoader cl = new BogusClassLoader();
109        URL[] u = new URL[0];
110        ucl = new URLClassLoader(u, cl);
111        URL res = ucl.getResource("J");
112        assertNotNull(res);
113        assertEquals("Failed to set parent", "/BogusClassLoader", res.getFile());
114    }
115
116    /**
117     * @tests java.net.URLClassLoader#findResources(java.lang.String)
118     */
119    public void test_findResourcesLjava_lang_String() throws IOException {
120        String[] resValues = { "This is a test resource file.",
121                "This is a resource from a subdir" };
122        URL[] urls = new URL[2];
123        urls[0] = new URL(serverURL);
124        urls[1] = new URL(serverURL + "/subdir1/");
125        ucl = new URLClassLoader(urls);
126        Enumeration res = ucl.findResources("RESOURCE.TXT");
127        assertNotNull("Failed to locate resources", res);
128
129        int i = 0;
130        while (res.hasMoreElements()) {
131            StringBuffer sb = new StringBuffer();
132            InputStream is = ((URL) res.nextElement()).openStream();
133            int c;
134            while ((c = is.read()) != -1) {
135                sb.append((char) c);
136            }
137            assertEquals("Returned incorrect resource/or in wrong order",
138                    resValues[i++], sb.toString());
139        }
140        assertEquals("Incorrect number of resources returned: " + i, 2, i);
141
142        // Regression for HARMONY-6510
143        res = ucl.findResources(null);
144        assertNotNull(res);
145        assertFalse(res.hasMoreElements());
146    }
147
148    /**
149     * @tests java.net.URLClassLoader#getURLs()
150     */
151    public void test_getURLs() throws MalformedURLException {
152        URL[] urls = new URL[4];
153        urls[0] = new URL("http://" + Support_Configuration.HomeAddress);
154        urls[1] = new URL("http://" + Support_Configuration.TestResources + "/");
155        urls[2] = new URL("ftp://" + Support_Configuration.TestResources + "/");
156        urls[3] = new URL("jar:file:c://" + Support_Configuration.TestResources
157                + "!/");
158        ucl = new URLClassLoader(urls);
159        URL[] ucUrls = ucl.getURLs();
160        for (int i = 0; i < urls.length; i++) {
161            assertEquals("Returned incorrect URL[]", urls[i], ucUrls[i]);
162        }
163    }
164
165    /**
166     * @tests java.net.URLClassLoader#newInstance(java.net.URL[])
167     */
168    public void test_newInstance$Ljava_net_URL() throws MalformedURLException,
169            ClassNotFoundException {
170        // Verify that loaded class' have correct permissions
171        URL[] urls = new URL[1];
172        urls[0] = new URL(serverURL + "/UCL/UCL.jar");
173        ucl = URLClassLoader.newInstance(urls);
174        Class cl = ucl.loadClass("ucl.ResClass");
175
176        URL res = cl.getClassLoader().getResource("XX.class");
177        assertNotNull("Failed to load class", cl);
178        assertNotNull(
179                "Loaded class unable to access resource from same codeSource",
180                res);
181        cl = null;
182        urls[0] = new URL("jar:" + serverURL + "/UCL/UCL.jar!/");
183        ucl = URLClassLoader.newInstance(urls);
184        cl = ucl.loadClass("ucl.ResClass");
185        assertNotNull("Failed to load class from explicit jar URL", cl);
186    }
187
188    /**
189     * @tests java.net.URLClassLoader#newInstance(java.net.URL[],
190     *java.lang.ClassLoader)
191     */
192    public void test_newInstance$Ljava_net_URLLjava_lang_ClassLoader() {
193        ClassLoader cl = new BogusClassLoader();
194        URL[] u = new URL[0];
195        ucl = URLClassLoader.newInstance(u, cl);
196        URL res = ucl.getResource("J");
197        assertNotNull(res);
198        assertEquals("Failed to set parent", "/BogusClassLoader", res.getFile());
199    }
200
201    /**
202     * @tests java.net.URLClassLoader#URLClassLoader(java.net.URL[],
203     *java.lang.ClassLoader, java.net.URLStreamHandlerFactory)
204     */
205    public void test_Constructor$Ljava_net_URLLjava_lang_ClassLoaderLjava_net_URLStreamHandlerFactory() {
206        class TestFactory implements URLStreamHandlerFactory {
207            public URLStreamHandler createURLStreamHandler(String protocol) {
208                return null;
209            }
210        }
211        ClassLoader cl = new BogusClassLoader();
212        URL[] u = new URL[0];
213        ucl = new URLClassLoader(u, cl, new TestFactory());
214        URL res = ucl.getResource("J");
215        assertNotNull(res);
216        assertEquals("Failed to set parent", "/BogusClassLoader", res.getFile());
217    }
218
219    /**
220     * @throws ClassNotFoundException
221     * @throws IOException
222     * @tests java.net.URLClassLoader#findClass(java.lang.String)
223     */
224    public void test_findClassLjava_lang_String()
225            throws ClassNotFoundException, IOException {
226        File resources = Support_Resources.createTempFolder();
227        String resPath = resources.toString();
228        if (resPath.charAt(0) == '/' || resPath.charAt(0) == '\\') {
229            resPath = resPath.substring(1);
230        }
231        Support_Resources.copyFile(resources, "JarIndex", "hyts_11.jar");
232        Support_Resources.copyFile(resources, "JarIndex", "hyts_12.jar");
233        Support_Resources.copyFile(resources, "JarIndex", "hyts_13.jar");
234        Support_Resources.copyFile(resources, "JarIndex", "hyts_14.jar");
235
236        URL[] urls = new URL[1];
237        urls[0] = new URL("file:/" + resPath + "/JarIndex/hyts_11.jar");
238        URLClassLoader ucl = URLClassLoader.newInstance(urls, null);
239
240        URL resURL = ucl.findResource("Test.txt");
241        URL reference = new URL("jar:file:/" + resPath.replace('\\', '/')
242                + "/JarIndex/hyts_14.jar!/Test.txt");
243        assertEquals("Resource not found: " + resURL + " ref: " + reference,
244                reference, resURL);
245
246        assertNotNull(Class.forName("cpack.CNothing", true, ucl));
247
248        Support_Resources.copyFile(resources, "JarIndex", "hyts_21.jar");
249        Support_Resources.copyFile(resources, "JarIndex", "hyts_22.jar");
250        Support_Resources.copyFile(resources, "JarIndex", "hyts_23.jar");
251        urls[0] = new URL("file:/" + resPath + "/JarIndex/hyts_21.jar");
252        ucl = URLClassLoader.newInstance(urls, null);
253        Enumeration en = ucl.findResources("bpack/");
254
255        boolean resourcesFound;
256        try {
257            resourcesFound = true;
258            URL url1 = (URL) en.nextElement();
259            URL url2 = (URL) en.nextElement();
260            resourcesFound = resourcesFound
261                    && url1.equals(new URL("jar:file:/"
262                    + resPath.replace('\\', '/')
263                    + "/JarIndex/hyts_22.jar!/bpack/"));
264            resourcesFound = resourcesFound
265                    && url2.equals(new URL("jar:file:/"
266                    + resPath.replace('\\', '/')
267                    + "/JarIndex/hyts_23.jar!/bpack/"));
268            if (en.hasMoreElements()) {
269                resourcesFound = false;
270            }
271        } catch (NoSuchElementException e) {
272            resourcesFound = false;
273        }
274        assertTrue("Resources not found (1)", resourcesFound);
275
276        assertNotNull(Class.forName("bpack.Homer", true, ucl));
277
278        try {
279            Class.forName("bpack.Bart", true, ucl);
280            fail("should throw ClassNotFoundException");
281        } catch (ClassNotFoundException e) {
282            // Expected
283        }
284
285        try {
286            Class.forName("Main4", true, ucl);
287            fail("should throw ClassNotFoundException");
288        } catch (ClassNotFoundException e) {
289            // Expected
290        }
291
292        Support_Resources.copyFile(resources, "JarIndex", "hyts_22-new.jar");
293        urls[0] = new URL("file:/" + resPath + "/JarIndex/hyts_22-new.jar");
294        ucl = URLClassLoader.newInstance(urls, null);
295        assertNotNull("Cannot find resource", ucl.findResource("cpack/"));
296        Support_Resources.copyFile(resources, "JarIndex", "hyts_11.jar");
297        urls[0] = new URL("file:/" + resPath + "/JarIndex/hyts_31.jar");
298        ucl = URLClassLoader.newInstance(urls, null);
299
300        try {
301            Class.forName("cpack.Mock", true, ucl);
302            fail("should throw ClassNotFoundException");
303        } catch (ClassNotFoundException e) {
304            // Expected
305        }
306
307        // testing circular reference
308        Support_Resources.copyFile(resources, "JarIndex", "hyts_41.jar");
309        Support_Resources.copyFile(resources, "JarIndex", "hyts_42.jar");
310        urls[0] = new URL("file:/" + resPath + "/JarIndex/hyts_41.jar");
311        ucl = URLClassLoader.newInstance(urls, null);
312        en = ucl.findResources("bpack/");
313        resourcesFound = resourcesFound
314                && ((URL) en.nextElement()).equals(new URL("jar:file:/"
315                + resPath.replace('\\', '/')
316                + "/JarIndex/hyts_42.jar!/bpack/"));
317        assertTrue("Resources not found (2)", resourcesFound);
318        assertFalse("No more resources expected", en.hasMoreElements());
319
320        // Regression test for HARMONY-2357.
321        try {
322            URLClassLoaderExt cl = new URLClassLoaderExt(new URL[557]);
323            cl.findClass("0");
324            fail("should throw NullPointerException");
325        } catch (NullPointerException npe) {
326            // Expected
327        }
328
329        // Regression test for HARMONY-2871.
330        URLClassLoader cl = new URLClassLoader(new URL[] { new URL(
331                "file:/foo.jar") });
332
333        try {
334            Class.forName("foo.Foo", false, cl);
335        } catch (Exception ex) {
336            // Ignored
337        }
338
339        try {
340            Class.forName("foo.Foo", false, cl);
341            fail("should throw ClassNotFoundException");
342        } catch (ClassNotFoundException cnfe) {
343            // Expected
344        }
345    }
346
347    /**
348     * @tests java.net.URLClassLoader#findResource(java.lang.String)
349     */
350    public void test_findResourceLjava_lang_String()
351            throws MalformedURLException {
352        URL[] urls = new URL[2];
353        urls[0] = new URL(serverURL);
354        urls[1] = new URL(serverURL);
355        ucl = new URLClassLoader(urls);
356        URL res = ucl.findResource("RESOURCE.TXT");
357        assertNotNull("Failed to locate resource", res);
358
359        StringBuffer sb = new StringBuffer();
360        try {
361            java.io.InputStream is = res.openStream();
362
363            int c;
364            while ((c = is.read()) != -1) {
365                sb.append((char) c);
366            }
367            is.close();
368        } catch (IOException e) {
369        }
370        assertTrue("Returned incorrect resource", !sb.toString().equals(
371                "This is a test resource file"));
372    }
373
374    public void testFindResource_H3461() throws Exception {
375        File userDir = new File(System.getProperty("user.dir"));
376        File dir = new File(userDir, "encode#me");
377        File f, f2;
378        URLClassLoader loader;
379        URL dirUrl;
380
381        if (!dir.exists()) {
382            dir.mkdir();
383        }
384        dir.deleteOnExit();
385        dirUrl = dir.toURI().toURL();
386        loader = new URLClassLoader(new URL[] { dirUrl });
387
388        f = File.createTempFile("temp", ".dat", dir);
389        f.deleteOnExit();
390        f2 = File.createTempFile("bad#name#", ".dat", dir);
391        f2.deleteOnExit();
392
393        assertNotNull(
394                "Unable to load resource from path with problematic name",
395                loader.getResource(f.getName()));
396        assertEquals("URL was not correctly encoded", f2.toURI().toURL(),
397                loader.getResource(f2.getName()));
398    }
399
400    public void test_findResource() throws Exception {
401        File resources = Support_Resources.createTempFolder();
402        String resPath = resources.toString();
403        if (resPath.charAt(0) == '/' || resPath.charAt(0) == ' ') {
404            resPath = resPath.substring(1);
405        }
406        Support_Resources.copyFile(resources, "JarIndex", "hyts_21.jar");
407        Support_Resources.copyFile(resources, "JarIndex", "hyts_22.jar");
408        Support_Resources.copyFile(resources, "JarIndex", "hyts_23.jar");
409
410        URLClassLoader urlClassloader = URLClassLoader.newInstance(
411                new URL[] { new URL("file:/" + resPath
412                        + "/JarIndex/hyts_21.jar") }, null);
413        Enumeration en = urlClassloader.findResources("bpack/");
414        assertTrue(en.hasMoreElements());
415        URL expected = new URL("jar:file:/" + resPath.replace('\\', '/')
416                + "/JarIndex/hyts_22.jar!/bpack/");
417        assertEquals(expected, (URL) en.nextElement());
418        assertEquals(expected, urlClassloader.findResource("bpack/"));
419    }
420
421    /**
422     * @tests java.net.URLClassLoader#getResource(java.lang.String)
423     */
424    public void test_getResourceLjava_lang_String()
425            throws MalformedURLException {
426        URL url1 = new URL("file:///");
427        URLClassLoader loader = new URLClassLoader(new URL[] { url1 }, null);
428        long start = System.currentTimeMillis();
429        // try without the leading /
430        URL result = loader.getResource("dir1/file1");
431        long end = System.currentTimeMillis();
432        long time = end - start;
433        if (time < 100) {
434            time = 100;
435        }
436
437        start = System.currentTimeMillis();
438        // try with the leading forward slash
439        result = loader.getResource("/dir1/file1");
440        end = System.currentTimeMillis();
441        long uncTime = end - start;
442        assertTrue("too long. UNC path formed? UNC time: " + uncTime
443                + " regular time: " + time, uncTime <= (time * 4));
444    }
445
446    /**
447     * Regression for Harmony-2237
448     */
449    public void test_getResource() throws Exception {
450        URLClassLoader urlLoader = getURLClassLoader();
451        assertNull(urlLoader.findResource("XXX")); //$NON-NLS-1$
452    }
453
454    private static URLClassLoader getURLClassLoader() {
455        String classPath = System.getProperty("java.class.path");
456        StringTokenizer tok = new StringTokenizer(classPath, File.pathSeparator);
457        Vector<URL> urlVec = new Vector<URL>();
458        String resPackage = Support_Resources.RESOURCE_PACKAGE;
459        try {
460            while (tok.hasMoreTokens()) {
461                String path = tok.nextToken();
462                String url;
463                if (new File(path).isDirectory())
464                    url = "file:" + path + resPackage + "subfolder/";
465                else
466                    url = "jar:file:" + path + "!" + resPackage + "subfolder/";
467                urlVec.addElement(new URL(url));
468            }
469        } catch (MalformedURLException e) {
470            // do nothing
471        }
472        URL[] urls = new URL[urlVec.size()];
473        for (int i = 0; i < urlVec.size(); i++) {
474            urls[i] = urlVec.elementAt(i);
475        }
476        URLClassLoader loader = new URLClassLoader(urls, null);
477        return loader;
478    }
479
480    /**
481     * Regression test for HARMONY-2255
482     */
483    public void test_getResourceAsStream() {
484        InputStream in = this.getClass()
485                .getResourceAsStream("test%.properties");
486        assertNotNull(in);
487        in = this.getClass().getResourceAsStream("test%25.properties");
488        assertNull(in);
489    }
490
491    /**
492     * Regression test for HARMONY-6074
493     */
494    public void test_findClassLjava_lang_String_Jar_Class_Path() throws Exception {
495        File resources = Support_Resources.createTempFolder();
496        String resPath = resources.toString();
497        if (resPath.charAt(0) == '/' || resPath.charAt(0) == '\\') {
498            resPath = resPath.substring(1);
499        }
500
501        Support_Resources.copyFile(resources, "JarIndex", "hyts_11.jar");
502        Support_Resources.copyFile(resources, "JarIndex", "hyts_13.jar");
503
504        JarFile jarFile = new JarFile(resources.getAbsolutePath() + "/JarIndex/hyts_11.jar");
505        Manifest mf = jarFile.getManifest();
506        Attributes attrs = mf.getMainAttributes();
507        attrs.putValue("Class-Path", "file:/" + resPath + "/JarIndex/hyts_13.jar");
508
509        File mainJar = new File(resources.getAbsolutePath() + "/JarIndex/main.jar");
510        JarOutputStream jos = new JarOutputStream(new FileOutputStream(mainJar), mf);
511        jos.flush();
512        jos.close();
513        assertTrue(mainJar.exists());
514
515        URL[] urls = new URL[1];
516        urls[0] = new URL("file:/" + resPath + "/JarIndex/main.jar");
517        ucl = URLClassLoader.newInstance(urls, null);
518        assertNotNull(Class.forName("Main2", true, ucl));
519    }
520
521}
522