1 /* 2 * Copyright (c) 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 package tests; 24 25 import java.io.ByteArrayInputStream; 26 import java.io.ByteArrayOutputStream; 27 import java.io.File; 28 import java.io.FileOutputStream; 29 import java.io.IOException; 30 import java.io.InputStream; 31 import java.io.OutputStream; 32 import java.io.PrintStream; 33 import java.io.PrintWriter; 34 import java.io.StringWriter; 35 import java.nio.file.Files; 36 import java.nio.file.Path; 37 import java.nio.file.Paths; 38 import java.nio.file.StandardCopyOption; 39 import java.util.ArrayList; 40 import java.util.Arrays; 41 import java.util.Collections; 42 import java.util.HashSet; 43 import java.util.List; 44 import java.util.Objects; 45 import java.util.Set; 46 import java.util.jar.JarEntry; 47 import java.util.jar.JarInputStream; 48 import java.util.jar.JarOutputStream; 49 import java.util.stream.Collectors; 50 import java.util.stream.Stream; 51 import java.util.zip.ZipEntry; 52 53 import javax.tools.JavaCompiler; 54 import javax.tools.StandardJavaFileManager; 55 import javax.tools.StandardLocation; 56 import javax.tools.ToolProvider; 57 58 /** 59 * 60 * A generator for jmods, jars and images. 61 */ 62 public class JImageGenerator { 63 64 public static final String LOAD_ALL_CLASSES_TEMPLATE = "package PACKAGE;\n" 65 + "\n" 66 + "import java.net.URI;\n" 67 + "import java.nio.file.FileSystems;\n" 68 + "import java.nio.file.Files;\n" 69 + "import java.nio.file.Path;\n" 70 + "import java.util.function.Function;\n" 71 + "\n" 72 + "public class CLASS {\n" 73 + " private static long total_time;\n" 74 + " private static long num_classes;\n" 75 + " public static void main(String[] args) throws Exception {\n" 76 + " Function<Path, String> formatter = (path) -> {\n" 77 + " String clazz = path.toString().substring(\"modules/\".length()+1, path.toString().lastIndexOf(\".\"));\n" 78 + " clazz = clazz.substring(clazz.indexOf(\"/\") + 1);\n" 79 + " return clazz.replaceAll(\"/\", \"\\\\.\");\n" 80 + " };\n" 81 + " Files.walk(FileSystems.getFileSystem(URI.create(\"jrt:/\")).getPath(\"/modules/\")).\n" 82 + " filter((p) -> {\n" 83 + " return Files.isRegularFile(p) && p.toString().endsWith(\".class\")\n" 84 + " && !p.toString().endsWith(\"module-info.class\");\n" 85 + " }).\n" 86 + " map(formatter).forEach((clazz) -> {\n" 87 + " try {\n" 88 + " long t = System.currentTimeMillis();\n" 89 + " Class.forName(clazz, false, Thread.currentThread().getContextClassLoader());\n" 90 + " total_time+= System.currentTimeMillis()-t;\n" 91 + " num_classes+=1;\n" 92 + " } catch (IllegalAccessError ex) {\n" 93 + " // Security exceptions can occur, this is not what we are testing\n" 94 + " System.err.println(\"Access error, OK \" + clazz);\n" 95 + " } catch (Exception ex) {\n" 96 + " System.err.println(\"ERROR \" + clazz);\n" 97 + " throw new RuntimeException(ex);\n" 98 + " }\n" 99 + " });\n" 100 + " double res = (double) total_time / num_classes;\n" 101 + " // System.out.println(\"Total time \" + total_time + \" num classes \" + num_classes + \" average \" + res);\n" 102 + " }\n" 103 + "}\n"; 104 105 private static final String OUTPUT_OPTION = "--output"; 106 private static final String POST_PROCESS_OPTION = "--post-process-path"; 107 private static final String MAIN_CLASS_OPTION = "--main-class"; 108 private static final String CLASS_PATH_OPTION = "--class-path"; 109 private static final String MODULE_PATH_OPTION = "--module-path"; 110 private static final String ADD_MODULES_OPTION = "--add-modules"; 111 private static final String LIMIT_MODULES_OPTION = "--limit-modules"; 112 private static final String PLUGIN_MODULE_PATH = "--plugin-module-path"; 113 114 private static final String CMDS_OPTION = "--cmds"; 115 private static final String CONFIG_OPTION = "--config"; 116 private static final String HASH_MODULES_OPTION = "--hash-modules"; 117 private static final String LIBS_OPTION = "--libs"; 118 private static final String MODULE_VERSION_OPTION = "--module-version"; 119 120 private JImageGenerator() {} 121 122 private static String optionsPrettyPrint(String... args) { 123 return Stream.of(args).collect(Collectors.joining(" ")); 124 } 125 126 public static File getJModsDir(File jdkHome) { 127 File jdkjmods = new File(jdkHome, "jmods"); 128 if (!jdkjmods.exists()) { 129 return null; 130 } 131 return jdkjmods; 132 } 133 134 public static Path addFiles(Path module, InMemoryFile... resources) throws IOException { 135 Path tempFile = Files.createTempFile("jlink-test", ""); 136 try (JarInputStream in = new JarInputStream(Files.newInputStream(module)); 137 JarOutputStream out = new JarOutputStream(new FileOutputStream(tempFile.toFile()))) { 138 ZipEntry entry; 139 while ((entry = in.getNextEntry()) != null) { 140 String name = entry.getName(); 141 out.putNextEntry(new ZipEntry(name)); 142 copy(in, out); 143 out.closeEntry(); 144 } 145 for (InMemoryFile r : resources) { 146 addFile(r, out); 147 } 148 } 149 Files.move(tempFile, module, StandardCopyOption.REPLACE_EXISTING); 150 return module; 151 } 152 153 private static void copy(InputStream in, OutputStream out) throws IOException { 154 int len; 155 byte[] buf = new byte[4096]; 156 while ((len = in.read(buf)) > 0) { 157 out.write(buf, 0, len); 158 } 159 } 160 161 public static JModTask getJModTask() { 162 return new JModTask(); 163 } 164 165 public static JLinkTask getJLinkTask() { 166 return new JLinkTask(); 167 } 168 169 public static JImageTask getJImageTask() { 170 return new JImageTask(); 171 } 172 173 private static void addFile(InMemoryFile resource, JarOutputStream target) throws IOException { 174 String fileName = resource.getPath(); 175 fileName = fileName.replace("\\", "/"); 176 String[] ss = fileName.split("/"); 177 Path p = Paths.get(""); 178 for (int i = 0; i < ss.length; ++i) { 179 if (i < ss.length - 1) { 180 if (!ss[i].isEmpty()) { 181 p = p.resolve(ss[i]); 182 JarEntry entry = new JarEntry(p.toString() + "/"); 183 target.putNextEntry(entry); 184 target.closeEntry(); 185 } 186 } else { 187 p = p.resolve(ss[i]); 188 JarEntry entry = new JarEntry(p.toString()); 189 target.putNextEntry(entry); 190 copy(resource.getBytes(), target); 191 target.closeEntry(); 192 } 193 } 194 } 195 196 public static Path createNewFile(Path root, String pathName, String extension) { 197 Path out = root.resolve(pathName + extension); 198 int i = 1; 199 while (Files.exists(out)) { 200 out = root.resolve(pathName + "-" + (++i) + extension); 201 } 202 return out; 203 } 204 205 public static Path generateSources(Path output, String moduleName, List<InMemorySourceFile> sources) throws IOException { 206 Path moduleDir = output.resolve(moduleName); 207 Files.createDirectory(moduleDir); 208 for (InMemorySourceFile source : sources) { 209 Path fileDir = moduleDir; 210 if (!source.packageName.isEmpty()) { 211 String dir = source.packageName.replace('.', File.separatorChar); 212 fileDir = moduleDir.resolve(dir); 213 Files.createDirectories(fileDir); 214 } 215 Files.write(fileDir.resolve(source.className + ".java"), source.source.getBytes()); 216 } 217 return moduleDir; 218 } 219 220 public static Path generateSourcesFromTemplate(Path output, String moduleName, String... classNames) throws IOException { 221 List<InMemorySourceFile> sources = new ArrayList<>(); 222 for (String className : classNames) { 223 String packageName = getPackageName(className); 224 String simpleName = getSimpleName(className); 225 String content = LOAD_ALL_CLASSES_TEMPLATE 226 .replace("CLASS", simpleName); 227 if (packageName.isEmpty()) { 228 content = content.replace("package PACKAGE;", packageName); 229 } else { 230 content = content.replace("PACKAGE", packageName); 231 } 232 sources.add(new InMemorySourceFile(packageName, simpleName, content)); 233 } 234 return generateSources(output, moduleName, sources); 235 } 236 237 public static void generateModuleInfo(Path moduleDir, List<String> packages, String... dependencies) throws IOException { 238 StringBuilder moduleInfoBuilder = new StringBuilder(); 239 Path file = moduleDir.resolve("module-info.java"); 240 String moduleName = moduleDir.getFileName().toString(); 241 moduleInfoBuilder.append("module ").append(moduleName).append("{\n"); 242 for (String dep : dependencies) { 243 moduleInfoBuilder.append("requires ").append(dep).append(";\n"); 244 } 245 for (String pkg : packages) { 246 if (!pkg.trim().isEmpty()) { 247 moduleInfoBuilder.append("exports ").append(pkg).append(";\n"); 248 } 249 } 250 moduleInfoBuilder.append("}"); 251 Files.write(file, moduleInfoBuilder.toString().getBytes()); 252 } 253 254 public static void compileSuccess(Path source, Path destination, String... options) throws IOException { 255 if (!compile(source, destination, options)) { 256 throw new AssertionError("Compilation failed."); 257 } 258 } 259 260 public static boolean compile(Path source, Path destination, String... options) throws IOException { 261 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 262 try (StandardJavaFileManager jfm = compiler.getStandardFileManager(null, null, null)) { 263 List<Path> sources 264 = Files.find(source, Integer.MAX_VALUE, 265 (file, attrs) -> file.toString().endsWith(".java")) 266 .collect(Collectors.toList()); 267 268 Files.createDirectories(destination); 269 jfm.setLocationFromPaths(StandardLocation.CLASS_OUTPUT, Collections.singleton(destination)); 270 271 List<String> opts = Arrays.asList(options); 272 JavaCompiler.CompilationTask task 273 = compiler.getTask(null, jfm, null, opts, null, 274 jfm.getJavaFileObjectsFromPaths(sources)); 275 List<String> list = new ArrayList<>(opts); 276 list.addAll(sources.stream() 277 .map(Path::toString) 278 .collect(Collectors.toList())); 279 System.err.println("javac options: " + optionsPrettyPrint(list.toArray(new String[list.size()]))); 280 return task.call(); 281 } 282 } 283 284 public static Path createJarFile(Path jarfile, Path dir) throws IOException { 285 return createJarFile(jarfile, dir, Paths.get(".")); 286 } 287 288 public static Path createJarFile(Path jarfile, Path dir, Path file) throws IOException { 289 // create the target directory 290 Path parent = jarfile.getParent(); 291 if (parent != null) 292 Files.createDirectories(parent); 293 294 List<Path> entries = Files.find(dir.resolve(file), Integer.MAX_VALUE, 295 (p, attrs) -> attrs.isRegularFile()) 296 .map(dir::relativize) 297 .collect(Collectors.toList()); 298 299 try (OutputStream out = Files.newOutputStream(jarfile); 300 JarOutputStream jos = new JarOutputStream(out)) { 301 for (Path entry : entries) { 302 // map the file path to a name in the JAR file 303 Path normalized = entry.normalize(); 304 String name = normalized 305 .subpath(0, normalized.getNameCount()) // drop root 306 .toString() 307 .replace(File.separatorChar, '/'); 308 309 jos.putNextEntry(new JarEntry(name)); 310 Files.copy(dir.resolve(entry), jos); 311 } 312 } 313 return jarfile; 314 } 315 316 public static Set<String> getModuleContent(Path module) { 317 Result result = JImageGenerator.getJModTask() 318 .jmod(module) 319 .list(); 320 result.assertSuccess(); 321 return Stream.of(result.getMessage().split("\r?\n")) 322 .collect(Collectors.toSet()); 323 } 324 325 public static void checkModule(Path module, Set<String> expected) throws IOException { 326 Set<String> actual = getModuleContent(module); 327 if (!Objects.equals(actual, expected)) { 328 Set<String> unexpected = new HashSet<>(actual); 329 unexpected.removeAll(expected); 330 Set<String> notFound = new HashSet<>(expected); 331 notFound.removeAll(actual); 332 System.err.println("Unexpected files:"); 333 unexpected.forEach(s -> System.err.println("\t" + s)); 334 System.err.println("Not found files:"); 335 notFound.forEach(s -> System.err.println("\t" + s)); 336 throw new AssertionError("Module check failed."); 337 } 338 } 339 340 public static class JModTask { 341 342 private final List<Path> classpath = new ArrayList<>(); 343 private final List<Path> libs = new ArrayList<>(); 344 private final List<Path> cmds = new ArrayList<>(); 345 private final List<Path> config = new ArrayList<>(); 346 private final List<Path> jars = new ArrayList<>(); 347 private final List<Path> jmods = new ArrayList<>(); 348 private final List<String> options = new ArrayList<>(); 349 private Path output; 350 private String hashModules; 351 private String mainClass; 352 private String moduleVersion; 353 354 public JModTask addNativeLibraries(Path cp) { 355 this.libs.add(cp); 356 return this; 357 } 358 359 public JModTask hashModules(String hash) { 360 this.hashModules = hash; 361 return this; 362 } 363 364 public JModTask addCmds(Path cp) { 365 this.cmds.add(cp); 366 return this; 367 } 368 369 public JModTask addClassPath(Path cp) { 370 this.classpath.add(cp); 371 return this; 372 } 373 374 public JModTask addConfig(Path cp) { 375 this.config.add(cp); 376 return this; 377 } 378 379 public JModTask addJars(Path jars) { 380 this.jars.add(jars); 381 return this; 382 } 383 384 public JModTask addJmods(Path jmods) { 385 this.jmods.add(jmods); 386 return this; 387 } 388 389 public JModTask jmod(Path output) { 390 this.output = output; 391 return this; 392 } 393 394 public JModTask moduleVersion(String moduleVersion) { 395 this.moduleVersion = moduleVersion; 396 return this; 397 } 398 399 public JModTask mainClass(String mainClass) { 400 this.mainClass = mainClass; 401 return this; 402 } 403 404 public JModTask option(String o) { 405 this.options.add(o); 406 return this; 407 } 408 409 private String modulePath() { 410 // This is expect FIRST jmods THEN jars, if you change this, some tests could fail 411 String jmods = toPath(this.jmods); 412 String jars = toPath(this.jars); 413 return jmods + File.pathSeparator + jars; 414 } 415 416 private String toPath(List<Path> paths) { 417 return paths.stream() 418 .map(Path::toString) 419 .collect(Collectors.joining(File.pathSeparator)); 420 } 421 422 private String[] optionsJMod(String cmd) { 423 List<String> options = new ArrayList<>(); 424 options.add(cmd); 425 if (!cmds.isEmpty()) { 426 options.add(CMDS_OPTION); 427 options.add(toPath(cmds)); 428 } 429 if (!config.isEmpty()) { 430 options.add(CONFIG_OPTION); 431 options.add(toPath(config)); 432 } 433 if (hashModules != null) { 434 options.add(HASH_MODULES_OPTION); 435 options.add(hashModules); 436 } 437 if (mainClass != null) { 438 options.add(MAIN_CLASS_OPTION); 439 options.add(mainClass); 440 } 441 if (!libs.isEmpty()) { 442 options.add(LIBS_OPTION); 443 options.add(toPath(libs)); 444 } 445 if (!classpath.isEmpty()) { 446 options.add(CLASS_PATH_OPTION); 447 options.add(toPath(classpath)); 448 } 449 if (!jars.isEmpty() || !jmods.isEmpty()) { 450 options.add(MODULE_PATH_OPTION); 451 options.add(modulePath()); 452 } 453 if (moduleVersion != null) { 454 options.add(MODULE_VERSION_OPTION); 455 options.add(moduleVersion); 456 } 457 options.addAll(this.options); 458 if (output != null) { 459 options.add(output.toString()); 460 } 461 return options.toArray(new String[options.size()]); 462 } 463 464 public Result create() { 465 return cmd("create"); 466 } 467 468 public Result list() { 469 return cmd("list"); 470 } 471 472 public Result call() { 473 return cmd(""); 474 } 475 476 private Result cmd(String cmd) { 477 String[] args = optionsJMod(cmd); 478 System.err.println("jmod options: " + optionsPrettyPrint(args)); 479 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 480 int exitCode = jdk.tools.jmod.Main.run(args, new PrintStream(baos)); 481 String msg = new String(baos.toByteArray()); 482 return new Result(exitCode, msg, output); 483 } 484 } 485 486 public static String getPackageName(String canonicalName) { 487 int index = canonicalName.lastIndexOf('.'); 488 return index > 0 ? canonicalName.substring(0, index) : ""; 489 } 490 491 public static String getSimpleName(String canonicalName) { 492 int index = canonicalName.lastIndexOf('.'); 493 return canonicalName.substring(index + 1); 494 } 495 496 public static class JImageTask { 497 498 private final List<Path> pluginModulePath = new ArrayList<>(); 499 private final List<String> options = new ArrayList<>(); 500 private Path dir; 501 private Path image; 502 503 public JImageTask pluginModulePath(Path p) { 504 this.pluginModulePath.add(p); 505 return this; 506 } 507 508 public JImageTask image(Path image) { 509 this.image = image; 510 return this; 511 } 512 513 public JImageTask dir(Path dir) { 514 this.dir = dir; 515 return this; 516 } 517 518 public JImageTask option(String o) { 519 this.options.add(o); 520 return this; 521 } 522 523 private String toPath(List<Path> paths) { 524 return paths.stream() 525 .map(Path::toString) 526 .collect(Collectors.joining(File.pathSeparator)); 527 } 528 529 private String[] optionsJImage(String cmd) { 530 List<String> options = new ArrayList<>(); 531 options.add(cmd); 532 if (dir != null) { 533 options.add("--dir"); 534 options.add(dir.toString()); 535 } 536 if (!pluginModulePath.isEmpty()) { 537 options.add(PLUGIN_MODULE_PATH); 538 options.add(toPath(pluginModulePath)); 539 } 540 options.addAll(this.options); 541 options.add(image.toString()); 542 return options.toArray(new String[options.size()]); 543 } 544 545 private Result cmd(String cmd, Path returnPath) { 546 String[] args = optionsJImage(cmd); 547 System.err.println("jimage options: " + optionsPrettyPrint(args)); 548 StringWriter writer = new StringWriter(); 549 int exitCode = jdk.tools.jimage.Main.run(args, new PrintWriter(writer)); 550 return new Result(exitCode, writer.toString(), returnPath); 551 } 552 553 public Result extract() { 554 return cmd("extract", dir); 555 } 556 } 557 558 public static class JLinkTask { 559 560 private final List<Path> jars = new ArrayList<>(); 561 private final List<Path> jmods = new ArrayList<>(); 562 private final List<Path> pluginModulePath = new ArrayList<>(); 563 private final List<String> addMods = new ArrayList<>(); 564 private final List<String> limitMods = new ArrayList<>(); 565 private final List<String> options = new ArrayList<>(); 566 private String modulePath; 567 private Path output; 568 private Path existing; 569 570 public JLinkTask modulePath(String modulePath) { 571 this.modulePath = modulePath; 572 return this; 573 } 574 575 public JLinkTask addJars(Path jars) { 576 this.jars.add(jars); 577 return this; 578 } 579 580 public JLinkTask addJmods(Path jmods) { 581 this.jmods.add(jmods); 582 return this; 583 } 584 585 public JLinkTask pluginModulePath(Path p) { 586 this.pluginModulePath.add(p); 587 return this; 588 } 589 590 public JLinkTask addMods(String moduleName) { 591 this.addMods.add(moduleName); 592 return this; 593 } 594 595 public JLinkTask limitMods(String moduleName) { 596 this.limitMods.add(moduleName); 597 return this; 598 } 599 600 public JLinkTask output(Path output) { 601 this.output = output; 602 return this; 603 } 604 605 public JLinkTask existing(Path existing) { 606 this.existing = existing; 607 return this; 608 } 609 610 public JLinkTask option(String o) { 611 this.options.add(o); 612 return this; 613 } 614 615 private String modulePath() { 616 // This is expect FIRST jmods THEN jars, if you change this, some tests could fail 617 String jmods = toPath(this.jmods); 618 String jars = toPath(this.jars); 619 return jmods + File.pathSeparator + jars; 620 } 621 622 private String toPath(List<Path> paths) { 623 return paths.stream() 624 .map(Path::toString) 625 .collect(Collectors.joining(File.pathSeparator)); 626 } 627 628 private String[] optionsJLink() { 629 List<String> options = new ArrayList<>(); 630 if (output != null) { 631 options.add(OUTPUT_OPTION); 632 options.add(output.toString()); 633 } 634 if (!addMods.isEmpty()) { 635 options.add(ADD_MODULES_OPTION); 636 options.add(addMods.stream().collect(Collectors.joining(","))); 637 } 638 if (!limitMods.isEmpty()) { 639 options.add(LIMIT_MODULES_OPTION); 640 options.add(limitMods.stream().collect(Collectors.joining(","))); 641 } 642 if (!jars.isEmpty() || !jmods.isEmpty()) { 643 options.add(MODULE_PATH_OPTION); 644 options.add(modulePath()); 645 } 646 if (modulePath != null) { 647 options.add(MODULE_PATH_OPTION); 648 options.add(modulePath); 649 } 650 if (!pluginModulePath.isEmpty()) { 651 options.add(PLUGIN_MODULE_PATH); 652 options.add(toPath(pluginModulePath)); 653 } 654 options.addAll(this.options); 655 return options.toArray(new String[options.size()]); 656 } 657 658 private String[] optionsPostProcessJLink() { 659 List<String> options = new ArrayList<>(); 660 if (existing != null) { 661 options.add(POST_PROCESS_OPTION); 662 options.add(existing.toString()); 663 } 664 options.addAll(this.options); 665 return options.toArray(new String[options.size()]); 666 } 667 668 public Result call() { 669 String[] args = optionsJLink(); 670 System.err.println("jlink options: " + optionsPrettyPrint(args)); 671 StringWriter writer = new StringWriter(); 672 int exitCode = jdk.tools.jlink.internal.Main.run(args, new PrintWriter(writer)); 673 return new Result(exitCode, writer.toString(), output); 674 } 675 676 public Result callPostProcess() { 677 String[] args = optionsPostProcessJLink(); 678 System.err.println("jlink options: " + optionsPrettyPrint(args)); 679 StringWriter writer = new StringWriter(); 680 int exitCode = jdk.tools.jlink.internal.Main.run(args, new PrintWriter(writer)); 681 return new Result(exitCode, writer.toString(), output); 682 } 683 } 684 685 public static class InMemorySourceFile { 686 public final String packageName; 687 public final String className; 688 public final String source; 689 690 public InMemorySourceFile(String packageName, String simpleName, String source) { 691 this.packageName = packageName; 692 this.className = simpleName; 693 this.source = source; 694 } 695 } 696 697 public static class InMemoryFile { 698 private final String path; 699 private final byte[] bytes; 700 701 public String getPath() { 702 return path; 703 } 704 705 public InputStream getBytes() { 706 return new ByteArrayInputStream(bytes); 707 } 708 709 public InMemoryFile(String path, byte[] bytes) { 710 this.path = path; 711 this.bytes = bytes; 712 } 713 714 public InMemoryFile(String path, InputStream is) throws IOException { 715 this(path, readAllBytes(is)); 716 } 717 } 718 719 public static byte[] readAllBytes(InputStream is) throws IOException { 720 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 721 byte[] buf = new byte[1024]; 722 while (true) { 723 int n = is.read(buf); 724 if (n < 0) { 725 break; 726 } 727 baos.write(buf, 0, n); 728 } 729 return baos.toByteArray(); 730 } 731 }