View Javadoc
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  package org.apache.commons.vfs2.impl;
18  
19  import java.io.File;
20  import java.io.IOException;
21  import java.net.URL;
22  import java.net.URLConnection;
23  import java.util.Collections;
24  import java.util.Enumeration;
25  
26  import org.apache.commons.vfs2.AbstractProviderTestCase;
27  import org.apache.commons.vfs2.AbstractVfsTestCase;
28  import org.apache.commons.vfs2.Capability;
29  import org.apache.commons.vfs2.FileObject;
30  import org.apache.commons.vfs2.FileSystemException;
31  import org.apache.commons.vfs2.FileSystemManager;
32  import org.apache.commons.vfs2.FileType;
33  import org.junit.Test;
34  
35  /**
36   * VfsClassLoader test cases.
37   */
38  public class VfsClassLoaderTests extends AbstractProviderTestCase {
39  
40      /**
41       * Non-Delegating Class Loader.
42       */
43      public static class MockClassloader extends ClassLoader {
44          MockClassloader() {
45              super(null);
46          }
47  
48          @Override
49          protected Class<?> findClass(final String name) throws ClassNotFoundException {
50              fail("Not intended to be used for class loading.");
51              return null;
52          }
53  
54          /**
55           * This method will not return any hit to VFSClassLoader#testGetResourcesJARs.
56           */
57          @Override
58          public Enumeration<URL> getResources(final String name) throws IOException {
59              return Collections.enumeration(Collections.<URL>emptyList());
60          }
61      }
62  
63      /**
64       * Creates the classloader to use when testing.
65       */
66      private VFSClassLoader createClassLoader() throws FileSystemException {
67          return new VFSClassLoader(getBaseFolder(), getManager());
68      }
69  
70      /**
71       * Returns the capabilities required by the tests of this test case.
72       */
73      @Override
74      protected Capability[] getRequiredCapabilities() {
75          return new Capability[] { Capability.READ_CONTENT, Capability.URI };
76      }
77  
78      /**
79       * Tests retrieving resources (from JAR searchpath).
80       * <p>
81       * This is run for all providers, but only when a local provider is present and jar extension is registered it will
82       * actually carry out all tests.
83       * </p>
84       */
85      @Test
86      public void testGetResourcesJARs() throws Exception {
87          final FileSystemManager manager = getManager();
88          try {
89              // hasProvider("file") cannot be used as it triggers default provider URL
90              manager.toFileObject(new File("."));
91          } catch (final FileSystemException e) {
92              System.out.println("VfsClassLoaderTests no local file provider, skipping.");
93              return;
94          }
95  
96          // build search path without using #getBaseFolder()
97          // because NestedJarTestCase redefines it
98          final File baseDir = AbstractVfsTestCase.getTestDirectoryFile();
99          final FileObject nestedJar = manager.resolveFile(baseDir, "nested.jar");
100         final FileObject testJar = manager.resolveFile(baseDir, "test.jar");
101 
102         // test setup needs to know about .jar extension - i.e. NestedJarTestCase
103         if (!manager.canCreateFileSystem(nestedJar)) {
104             System.out.println("VfsClassLoaderTests no layered .jar provider, skipping.");
105             return;
106         }
107 
108         // verify test setup
109         assertSame("nested.jar is required for testing", nestedJar.getType(), FileType.FILE);
110         assertSame("test.jar is required for testing", testJar.getType(), FileType.FILE);
111 
112         // System class loader (null) might be unpredictable in regards
113         // to returning resources for META-INF/MANIFEST.MF (see VFS-500)
114         // so we use our own which is guaranteed to not return any hit
115         final ClassLoader mockClassloader = new MockClassloader();
116         final FileObject[] search = new FileObject[] { nestedJar, testJar };
117         final VFSClassLoader loader = new VFSClassLoader(search, getManager(), mockClassloader);
118 
119         final Enumeration<URL> urls = loader.getResources("META-INF/MANIFEST.MF");
120         final URL url1 = urls.nextElement();
121         final URL url2 = urls.nextElement();
122 
123         assertTrue("First resource must refer to nested.jar but was " + url1,
124                 url1.toString().endsWith("nested.jar!/META-INF/MANIFEST.MF"));
125         assertTrue("Second resource must refer to test.jar but was " + url2,
126                 url2.toString().endsWith("test.jar!/META-INF/MANIFEST.MF"));
127     }
128 
129     /**
130      * Tests retrieving resources (from local directory with .jar extension).
131      * <p>
132      * This test is repeated with various provider configurations but works on local files, only.
133      * </p>
134      */
135     @Test
136     public void testGetResourcesNoLayerLocal() throws Exception {
137         final FileSystemManager manager = getManager();
138         try {
139             // hasProvider("file") cannot be used as it triggers default provider URL
140             manager.toFileObject(new File("."));
141         } catch (final FileSystemException e) {
142             System.out.println("VfsClassLoaderTests no local file provider, skipping.");
143             return;
144         }
145         final File baseDir = AbstractVfsTestCase.getTestDirectoryFile();
146 
147         // setup test folder
148         final FileObject dir = manager.resolveFile(baseDir, "read-tests/dir1/subdir4.jar");
149         assertSame("subdir4.jar/ is required for testing " + dir, dir.getType(), FileType.FOLDER);
150         assertFalse(manager.canCreateFileSystem(dir));
151 
152         // prepare classloader
153         final FileObject[] search = new FileObject[] { dir };
154         final ClassLoader mockClassloader = new MockClassloader();
155         final VFSClassLoader loader = new VFSClassLoader(search, getManager(), mockClassloader);
156 
157         // verify resource loading
158         final Enumeration<URL> urls = loader.getResources("file1.txt");
159         final URL url1 = urls.nextElement();
160         assertFalse("Only one hit expected", urls.hasMoreElements());
161         assertTrue("not pointing to resource " + url1, url1.toString().endsWith("subdir4.jar/file1.txt"));
162     }
163 
164     /**
165      * Tests loading a class.
166      */
167     @Test
168     public void testLoadClass() throws Exception {
169         final VFSClassLoader loader = createClassLoader();
170 
171         final Class<?> testClass = loader.loadClass("code.ClassToLoad");
172         final Package pack = testClass.getPackage();
173         assertEquals("code", pack.getName());
174         verifyPackage(pack, false);
175 
176         final Object testObject = testClass.newInstance();
177         assertEquals("**PRIVATE**", testObject.toString());
178     }
179 
180     /**
181      * Tests loading a resource.
182      */
183     @Test
184     public void testLoadResource() throws Exception {
185         final VFSClassLoader loader = createClassLoader();
186 
187         final URL resource = loader.getResource("read-tests/file1.txt");
188 
189         assertNotNull(resource);
190         final URLConnection urlCon = resource.openConnection();
191         assertSameURLContent(FILE1_CONTENT, urlCon);
192     }
193 
194     /**
195      * Tests package sealing.
196      */
197     @Test
198     public void testSealing() throws Exception {
199         final VFSClassLoader loader = createClassLoader();
200         final Class<?> testClass = loader.loadClass("code.sealed.AnotherClass");
201         final Package pack = testClass.getPackage();
202         assertEquals("code.sealed", pack.getName());
203         verifyPackage(pack, true);
204     }
205 
206     /**
207      * Verify the package loaded with class loader.
208      */
209     private void verifyPackage(final Package pack, final boolean sealed) {
210         if (getBaseFolder().getFileSystem().hasCapability(Capability.MANIFEST_ATTRIBUTES)) {
211             assertEquals("ImplTitle", pack.getImplementationTitle());
212             assertEquals("ImplVendor", pack.getImplementationVendor());
213             assertEquals("1.1", pack.getImplementationVersion());
214             assertEquals("SpecTitle", pack.getSpecificationTitle());
215             assertEquals("SpecVendor", pack.getSpecificationVendor());
216             assertEquals("1.0", pack.getSpecificationVersion());
217             assertEquals(sealed, pack.isSealed());
218         } else {
219             assertNull(pack.getImplementationTitle());
220             assertNull(pack.getImplementationVendor());
221             assertNull(pack.getImplementationVersion());
222             assertNull(pack.getSpecificationTitle());
223             assertNull(pack.getSpecificationVendor());
224             assertNull(pack.getSpecificationVersion());
225             assertFalse(pack.isSealed());
226         }
227     }
228 }