Basic.java revision 12973:2e63fa2efdb1
1/* 2 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24/* 25 * @test 26 * @bug 6887710 27 * @summary Verify the impact of sun.misc.JarIndex.metaInfFilenames on ServiceLoader 28 * @modules jdk.jartool/sun.tools.jar 29 * jdk.httpserver 30 * jdk.compiler 31 * @run main/othervm Basic 32 */ 33 34import java.io.IOException; 35import java.io.BufferedReader; 36import java.io.File; 37import java.io.FileInputStream; 38import java.io.InputStream; 39import java.io.InputStreamReader; 40import java.io.OutputStream; 41import java.net.InetSocketAddress; 42import java.net.URI; 43import java.net.URL; 44import java.net.URLClassLoader; 45import java.util.Arrays; 46import java.util.Iterator; 47import java.util.ServiceLoader; 48import com.sun.net.httpserver.Headers; 49import com.sun.net.httpserver.HttpExchange; 50import com.sun.net.httpserver.HttpHandler; 51import com.sun.net.httpserver.HttpServer; 52 53/** 54 * Verifies the impact of sun.misc.JarIndex.metaInfFilenames on ServiceLoader 55 * and on finding resources via Class.getResource. 56 * 57 * 1) Compile the test sources: 58 * jarA: 59 * META-INF/services/my.happy.land 60 * com/message/spi/MessageService.java 61 * a/A.java 62 * jarB: 63 * META-INF/JAVA2.DS 64 * META-INF/services/no.name.service 65 * b/B.java 66 * jarC: 67 * META-INF/fonts.mf 68 * META-INF/fonts/Company-corporate.ttf 69 * META-INF/fonts/kidpr.ttf 70 * META-INF/services/com.message.spi.MessageService 71 * my/impl/StandardMessageService.java 72 * 73 * 2) Build three jar files a.jar, b.jar, c.jar 74 * 75 * 3) Create an index in a.jar (jar -i a.jar b.jar c.jar) 76 * with sun.misc.JarIndex.metaInfFilenames=true 77 * 78 * 4) Start a HTTP server serving out the three jars. 79 * 80 * The test then tries to locate services/resources within the jars using 81 * URLClassLoader. Each request to the HTTP server is recorded to ensure 82 * only the correct amount of requests are being made. 83 * 84 */ 85 86public class Basic { 87 static final String slash = File.separator; 88 static final String[] testSources = { 89 "jarA" + slash + "a" + slash + "A.java", 90 "jarA" + slash + "com" + slash + "message" + slash + "spi" + slash + "MessageService.java", 91 "jarB" + slash + "b" + slash + "B.java", 92 "jarC" + slash + "my" + slash + "impl" + slash + "StandardMessageService.java"}; 93 94 static final String testSrc = System.getProperty("test.src"); 95 static final String testSrcDir = testSrc != null ? testSrc : "."; 96 static final String testClasses = System.getProperty("test.classes"); 97 static final String testClassesDir = testClasses != null ? testClasses : "."; 98 99 static JarHttpServer httpServer; 100 101 public static void main(String[] args) throws Exception { 102 103 // Set global url cache to false so that we can track every jar request. 104 (new URL("http://localhost/")).openConnection().setDefaultUseCaches(false); 105 106 buildTest(); 107 108 try { 109 httpServer = new JarHttpServer(testClassesDir); 110 httpServer.start(); 111 112 doTest(httpServer.getAddress()); 113 114 } catch (IOException ioe) { 115 ioe.printStackTrace(); 116 } finally { 117 if (httpServer != null) { httpServer.stop(2); } 118 } 119 } 120 121 static void buildTest() { 122 /* compile the source that will be used to generate the jars */ 123 for (int i=0; i<testSources.length; i++) 124 testSources[i] = testSrcDir + slash + testSources[i]; 125 126 compile("-d" , testClassesDir, 127 "-sourcepath", testSrcDir, 128 testSources[0], testSources[1], testSources[2], testSources[3]); 129 130 /* build the 3 jar files */ 131 jar("-cf", testClassesDir + slash + "a.jar", 132 "-C", testClassesDir, "a", 133 "-C", testClassesDir, "com", 134 "-C", testSrcDir + slash + "jarA", "META-INF"); 135 jar("-cf", testClassesDir + slash + "b.jar", 136 "-C", testClassesDir, "b", 137 "-C", testSrcDir + slash + "jarB", "META-INF"); 138 jar("-cf", testClassesDir + slash + "c.jar", 139 "-C", testClassesDir, "my", 140 "-C", testSrcDir + slash + "jarC", "META-INF"); 141 142 /* Create an index in a.jar for b.jar and c.jar */ 143 createIndex(testClassesDir); 144 } 145 146 /* run jar <args> */ 147 static void jar(String... args) { 148 debug("Running: jar " + Arrays.toString(args)); 149 sun.tools.jar.Main jar = new sun.tools.jar.Main(System.out, System.err, "jar"); 150 if (!jar.run(args)) { 151 throw new RuntimeException("jar failed: args=" + Arrays.toString(args)); 152 } 153 } 154 155 /* run javac <args> */ 156 static void compile(String... args) { 157 debug("Running: javac " + Arrays.toString(args)); 158 if (com.sun.tools.javac.Main.compile(args) != 0) { 159 throw new RuntimeException("javac failed: args=" + Arrays.toString(args)); 160 } 161 } 162 163 static String jar; 164 static { 165 jar = System.getProperty("java.home") + slash+ "bin" + slash + "jar"; 166 } 167 168 /* create the index */ 169 static void createIndex(String workingDir) { 170 // ProcessBuilder is used so that the current directory can be set 171 // to the directory that directly contains the jars. 172 debug("Running jar to create the index"); 173 ProcessBuilder pb = new ProcessBuilder( 174 jar, "-J-Dsun.misc.JarIndex.metaInfFilenames=true", "-i", "a.jar", "b.jar", "c.jar"); 175 pb.directory(new File(workingDir)); 176 //pd.inheritIO(); 177 try { 178 Process p = pb.start(); 179 if(p.waitFor() != 0) 180 throw new RuntimeException("jar indexing failed"); 181 182 if(debug && p != null) { 183 String line = null; 184 BufferedReader reader = 185 new BufferedReader(new InputStreamReader(p.getInputStream())); 186 while((line = reader.readLine()) != null) 187 debug(line); 188 reader = new BufferedReader(new InputStreamReader(p.getErrorStream())); 189 while((line = reader.readLine()) != null) 190 debug(line); 191 } 192 } catch(InterruptedException ie) { throw new RuntimeException(ie); 193 } catch(IOException e) { throw new RuntimeException(e); } 194 } 195 196 static final boolean debug = true; 197 198 static void debug(Object message) { if (debug) System.out.println(message); } 199 200 /* service define in c.jar */ 201 static final String messageService = "com.message.spi.MessageService"; 202 203 /* a service that is not defined in any of the jars */ 204 static final String unknownService = "java.lang.Object"; 205 206 static void doTest(InetSocketAddress serverAddress) throws IOException { 207 URL baseURL = new URL("http://localhost:" + serverAddress.getPort() + "/"); 208 209 int failed = 0; 210 211 // Tests using java.util.SerivceLoader 212 if (!javaUtilServiceLoaderTest(baseURL, messageService, true, false, true)) { 213 System.out.println("Test: ServiceLoader looking for " + messageService + ", failed"); 214 failed++; 215 } 216 if (!javaUtilServiceLoaderTest(baseURL, unknownService, false, false, false)) { 217 System.out.println("Test: ServiceLoader looking for " + unknownService + " failed"); 218 failed++; 219 } 220 221 // Tests using java.lang.Class (similar to the FontManager in javafx) 222 if (!klassLoader(baseURL, "/META-INF/fonts.mf", true, false, true)) { 223 System.out.println("Test: klassLoader looking for /META-INF/fonts.mf failed"); 224 failed++; 225 } 226 if (!klassLoader(baseURL, "/META-INF/unknown.mf", false, false, false)) { 227 System.out.println("Test: klassLoader looking for /META-INF/unknown.mf failed"); 228 failed++; 229 } 230 231 if (failed > 0) 232 throw new RuntimeException("Failed: " + failed + " tests"); 233 } 234 235 static boolean javaUtilServiceLoaderTest(URL baseURL, 236 String serviceClass, 237 boolean expectToFind, 238 boolean expectbDotJar, 239 boolean expectcDotJar) throws IOException { 240 debug("----------------------------------"); 241 debug("Running test with java.util.ServiceLoader looking for " + serviceClass); 242 URLClassLoader loader = getLoader(baseURL); 243 httpServer.reset(); 244 245 Class<?> messageServiceClass = null; 246 try { 247 messageServiceClass = loader.loadClass(serviceClass); 248 } catch (ClassNotFoundException cnfe) { 249 System.err.println(cnfe); 250 throw new RuntimeException("Error in test: " + cnfe); 251 } 252 253 Iterator<?> iterator = (ServiceLoader.load(messageServiceClass, loader)).iterator(); 254 if (expectToFind && !iterator.hasNext()) { 255 debug(messageServiceClass + " NOT found."); 256 return false; 257 } 258 259 while (iterator.hasNext()) { 260 debug("found " + iterator.next() + " " + messageService); 261 } 262 263 debug("HttpServer: " + httpServer); 264 265 if (!expectbDotJar && httpServer.bDotJar > 0) { 266 debug("Unexpeced request sent to the httpserver for b.jar"); 267 return false; 268 } 269 if (!expectcDotJar && httpServer.cDotJar > 0) { 270 debug("Unexpeced request sent to the httpserver for c.jar"); 271 return false; 272 } 273 274 return true; 275 } 276 277 /* Tries to find a resource in a similar way to the font manager in javafx 278 * com.sun.javafx.scene.text.FontManager */ 279 static boolean klassLoader(URL baseURL, 280 String resource, 281 boolean expectToFind, 282 boolean expectbDotJar, 283 boolean expectcDotJar) throws IOException { 284 debug("----------------------------------"); 285 debug("Running test looking for " + resource); 286 URLClassLoader loader = getLoader(baseURL); 287 httpServer.reset(); 288 289 Class<?> ADotAKlass = null; 290 try { 291 ADotAKlass = loader.loadClass("a.A"); 292 } catch (ClassNotFoundException cnfe) { 293 System.err.println(cnfe); 294 throw new RuntimeException("Error in test: " + cnfe); 295 } 296 297 URL u = ADotAKlass.getResource(resource); 298 if (expectToFind && u == null) { 299 System.out.println("Expected to find " + resource + " but didn't"); 300 return false; 301 } 302 303 debug("HttpServer: " + httpServer); 304 305 if (!expectbDotJar && httpServer.bDotJar > 0) { 306 debug("Unexpeced request sent to the httpserver for b.jar"); 307 return false; 308 } 309 if (!expectcDotJar && httpServer.cDotJar > 0) { 310 debug("Unexpeced request sent to the httpserver for c.jar"); 311 return false; 312 } 313 314 return true; 315 } 316 317 static URLClassLoader getLoader(URL baseURL) throws IOException { 318 ClassLoader loader = Basic.class.getClassLoader(); 319 320 while (loader.getParent() != null) 321 loader = loader.getParent(); 322 323 return new URLClassLoader( new URL[]{ 324 new URL(baseURL, "a.jar"), 325 new URL(baseURL, "b.jar"), 326 new URL(baseURL, "c.jar")}, loader ); 327 } 328 329 /** 330 * HTTP Server to server the jar files. 331 */ 332 static class JarHttpServer implements HttpHandler { 333 final String docsDir; 334 final HttpServer httpServer; 335 int aDotJar, bDotJar, cDotJar; 336 337 JarHttpServer(String docsDir) throws IOException { 338 this.docsDir = docsDir; 339 340 httpServer = HttpServer.create(new InetSocketAddress(0), 0); 341 httpServer.createContext("/", this); 342 } 343 344 void start() throws IOException { 345 httpServer.start(); 346 } 347 348 void stop(int delay) { 349 httpServer.stop(delay); 350 } 351 352 InetSocketAddress getAddress() { 353 return httpServer.getAddress(); 354 } 355 356 void reset() { 357 aDotJar = bDotJar = cDotJar = 0; 358 } 359 360 @Override 361 public String toString() { 362 return "aDotJar=" + aDotJar + ", bDotJar=" + bDotJar + ", cDotJar=" + cDotJar; 363 } 364 365 public void handle(HttpExchange t) throws IOException { 366 InputStream is = t.getRequestBody(); 367 Headers map = t.getRequestHeaders(); 368 Headers rmap = t.getResponseHeaders(); 369 URI uri = t.getRequestURI(); 370 371 debug("Server: received request for " + uri); 372 String path = uri.getPath(); 373 if (path.endsWith("a.jar")) 374 aDotJar++; 375 else if (path.endsWith("b.jar")) 376 bDotJar++; 377 else if (path.endsWith("c.jar")) 378 cDotJar++; 379 else 380 System.out.println("Unexpected resource request" + path); 381 382 while (is.read() != -1); 383 is.close(); 384 385 File file = new File(docsDir, path); 386 if (!file.exists()) 387 throw new RuntimeException("Error: request for " + file); 388 long clen = file.length(); 389 t.sendResponseHeaders (200, clen); 390 OutputStream os = t.getResponseBody(); 391 FileInputStream fis = new FileInputStream(file); 392 try { 393 byte[] buf = new byte [16 * 1024]; 394 int len; 395 while ((len=fis.read(buf)) != -1) { 396 os.write (buf, 0, len); 397 } 398 } catch (IOException e) { 399 e.printStackTrace(); 400 } 401 fis.close(); 402 os.close(); 403 } 404 } 405} 406