< prev index next >

src/jdk.dev/share/classes/jdk/tools/jimage/JImageTask.java

Print this page

        

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this

@@ -23,145 +23,102 @@
  * questions.
  */
 
 package jdk.tools.jimage;
 
-import java.io.BufferedOutputStream;
-import java.io.DataOutputStream;
 import java.io.File;
 import java.io.IOException;
-import java.io.OutputStream;
 import java.io.PrintWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.FileChannel;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.text.MessageFormat;
-import java.util.ArrayList;
+import static java.nio.file.StandardOpenOption.READ;
+import static java.nio.file.StandardOpenOption.WRITE;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Locale;
-import java.util.MissingResourceException;
-import java.util.ResourceBundle;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
 import jdk.internal.jimage.BasicImageReader;
-import jdk.internal.jimage.BasicImageWriter;
 import jdk.internal.jimage.ImageHeader;
+import static jdk.internal.jimage.ImageHeader.MAGIC;
+import static jdk.internal.jimage.ImageHeader.MAJOR_VERSION;
+import static jdk.internal.jimage.ImageHeader.MINOR_VERSION;
 import jdk.internal.jimage.ImageLocation;
-import jdk.internal.jimage.PackageModuleMap;
+import jdk.internal.jimage.ImageModuleData;
+import jdk.internal.jimage.ImageResourcesTree;
+import jdk.tools.jimage.TaskHelper.BadArgs;
+import jdk.tools.jimage.TaskHelper.HiddenOption;
+import jdk.tools.jimage.TaskHelper.Option;
+import jdk.tools.jimage.TaskHelper.OptionsHelper;
 
 class JImageTask {
-    static class BadArgs extends Exception {
-        static final long serialVersionUID = 8765093759964640723L;  // ## re-generate
-        final String key;
-        final Object[] args;
-        boolean showUsage;
 
-        BadArgs(String key, Object... args) {
-            super(JImageTask.getMessage(key, args));
-            this.key = key;
-            this.args = args;
-        }
-
-        BadArgs showUsage(boolean b) {
-            showUsage = b;
-            return this;
-        }
-    }
-
-    static abstract class Option {
-        final boolean hasArg;
-        final String[] aliases;
-
-        Option(boolean hasArg, String... aliases) {
-            this.hasArg = hasArg;
-            this.aliases = aliases;
-        }
-
-        boolean isHidden() {
-            return false;
-        }
-
-        boolean matches(String opt) {
-            for (String a : aliases) {
-                if (a.equals(opt)) {
-                    return true;
-                } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        boolean ignoreRest() {
-            return false;
-        }
-
-        abstract void process(JImageTask task, String opt, String arg) throws BadArgs;
-    }
-
-    static abstract class HiddenOption extends Option {
-        HiddenOption(boolean hasArg, String... aliases) {
-            super(hasArg, aliases);
-        }
-
-        @Override
-        boolean isHidden() {
-            return true;
-        }
-    }
-
-    static Option[] recognizedOptions = {
-        new Option(true, "--dir") {
+    static final Option<?>[] recognizedOptions = {
+        new Option<JImageTask>(true, "--dir") {
             @Override
-            void process(JImageTask task, String opt, String arg) throws BadArgs {
+            protected void process(JImageTask task, String opt, String arg) throws BadArgs {
                  task.options.directory = arg;
             }
         },
-        new HiddenOption(false, "--fullversion") {
+        new HiddenOption<JImageTask>(false, "--fullversion") {
             @Override
-            void process(JImageTask task, String opt, String arg) {
+            protected void process(JImageTask task, String opt, String arg) {
                 task.options.fullVersion = true;
             }
         },
-        new Option(false, "--help") {
+        new Option<JImageTask>(false, "--help") {
             @Override
-            void process(JImageTask task, String opt, String arg) {
+            protected void process(JImageTask task, String opt, String arg) {
                 task.options.help = true;
             }
         },
-        new Option(false, "--verbose") {
+
+        new Option<JImageTask>(true, "--flags") {
+            @Override
+            protected void process(JImageTask task, String opt, String arg) {
+                task.options.flags = arg;
+            }
+        },
+
+        new Option<JImageTask>(false, "--verbose") {
             @Override
-            void process(JImageTask task, String opt, String arg) throws BadArgs {
+            protected void process(JImageTask task, String opt, String arg) throws BadArgs {
                  task.options.verbose = true;
             }
         },
-        new Option(false, "--version") {
+        new Option<JImageTask>(false, "--version") {
             @Override
-            void process(JImageTask task, String opt, String arg) {
+            protected void process(JImageTask task, String opt, String arg) {
                 task.options.version = true;
             }
         },
     };
+    private static final TaskHelper taskHelper
+            = new TaskHelper("jdk.tools.jimage.resources.jimage");
+    private static final OptionsHelper<JImageTask> optionsHelper
+            = taskHelper.newOptionsHelper(JImageTask.class, recognizedOptions);
 
-    static class Options {
+    static class OptionsValues {
         Task task = Task.LIST;
         String directory = ".";
         boolean fullVersion;
         boolean help;
+        String flags;
         boolean verbose;
         boolean version;
         List<File> jimages = new LinkedList<>();
     }
 
     private static final String PROGNAME = "jimage";
-    private final Options options = new Options();
+    private final OptionsValues options = new OptionsValues();
 
     enum Task {
-        RECREATE,
         EXTRACT,
         INFO,
         LIST,
+        RECREATE,
+        SET,
         VERIFY
     };
 
     private String pad(String string, int width, boolean justifyRight) {
         int length = string.length();

@@ -208,129 +165,63 @@
     private static final int EXIT_SYSERR = 3;    // System error or resource exhaustion.
     private static final int EXIT_ABNORMAL = 4;  // Terminated abnormally.
 
     int run(String[] args) {
         if (log == null) {
-            log = new PrintWriter(System.out);
+            setLog(new PrintWriter(System.out));
         }
 
         try {
-            handleOptions(args);
+            List<String> unhandled = optionsHelper.handleOptions(this, args);
+            if(!unhandled.isEmpty()) {
+                options.task = Enum.valueOf(Task.class, unhandled.get(0).toUpperCase());
+                for(int i = 1; i < unhandled.size(); i++) {
+                    options.jimages.add(new File(unhandled.get(i)));
+                }
+            }
             if (options.help) {
-                showHelp();
+                optionsHelper.showHelp(PROGNAME, "recreate only options:");
             }
             if (options.version || options.fullVersion) {
-                showVersion(options.fullVersion);
+                taskHelper.showVersion(options.fullVersion);
             }
             boolean ok = run();
             return ok ? EXIT_OK : EXIT_ERROR;
         } catch (BadArgs e) {
-            reportError(e.key, e.args);
+            taskHelper.reportError(e.key, e.args);
             if (e.showUsage) {
-                log.println(getMessage("main.usage.summary", PROGNAME));
+                log.println(taskHelper.getMessage("main.usage.summary", PROGNAME));
             }
             return EXIT_CMDERR;
         } catch (Exception x) {
             x.printStackTrace();
             return EXIT_ABNORMAL;
         } finally {
             log.flush();
         }
     }
 
-    static final String MODULES_ENTRY = PackageModuleMap.MODULES_ENTRY;
-    static final String PACKAGES_ENTRY = "/" + PackageModuleMap.PACKAGES_ENTRY;
-
     private void recreate() throws IOException, BadArgs {
         File directory = new File(options.directory);
-        Path dirPath = directory.toPath();
-        int chop = dirPath.toString().length() + 1;
-
         if (!directory.isDirectory()) {
-            throw new BadArgs("err.not.a.dir", directory.getAbsolutePath());
+            throw taskHelper.newBadArgs("err.not.a.dir", directory.getAbsolutePath());
         }
-
+        Path dirPath = directory.toPath();
         if (options.jimages.isEmpty()) {
-            throw new BadArgs("err.jimage.not.specified");
+            throw taskHelper.newBadArgs("err.jimage.not.specified");
         } else if (options.jimages.size() != 1) {
-            throw new BadArgs("err.only.one.jimage");
-        }
-
-        File jimage = options.jimages.get(0);
-        final List<File> files = new ArrayList<>();
-        final BasicImageWriter writer = new BasicImageWriter();
-        final Long longZero = 0L;
-
-        // Note: code sensitive to Netbeans parser crashing.
-        long total = Files.walk(dirPath).reduce(longZero, (Long offset, Path path) -> {
-                    long size = 0;
-                    String pathString = path.toString();
-
-                    if (pathString.length() < chop || pathString.startsWith(".")) {
-                        return 0L;
+            throw taskHelper.newBadArgs("err.only.one.jimage");
                     }
 
-                    File file = path.toFile();
-
-                    if (file.isFile()) {
-                        String name = pathString.substring(chop).replace(File.separatorChar, '/');
-
-                        if (options.verbose) {
-                            log.println(name);
-                        }
+        Path jimage = options.jimages.get(0).toPath();
 
-                        if (name.endsWith(MODULES_ENTRY) || name.endsWith(PACKAGES_ENTRY)) {
-                            try {
-                                try (Stream<String> lines = Files.lines(path)) {
-                                    size = lines.peek(s -> writer.addString(s)).count() * 4;
-                                }
-                            } catch (IOException ex) {
-                                // Caught again when writing file.
-                                size = 0;
-                            }
+        if (jimage.toFile().createNewFile()) {
+            ExtractedImage img = new ExtractedImage(dirPath, log, options.verbose);
+            img.recreateJImage(jimage);
                         } else {
-                            size = file.length();
+            throw taskHelper.newBadArgs("err.jimage.already.exists", jimage.getFileName());
                         }
-
-                        writer.addLocation(name, offset, 0L, size);
-                        files.add(file);
-                    }
-
-                    return offset + size;
-                },
-                (Long offsetL, Long offsetR) -> { return longZero; } );
-
-        if (jimage.createNewFile()) {
-            try (OutputStream os = Files.newOutputStream(jimage.toPath());
-                    BufferedOutputStream bos = new BufferedOutputStream(os);
-                    DataOutputStream out = new DataOutputStream(bos)) {
-
-                byte[] index = writer.getBytes();
-                out.write(index, 0, index.length);
-
-                for (File file : files) {
-                    try {
-                        Path path = file.toPath();
-                        String name = path.toString().replace(File.separatorChar, '/');
-
-                        if (name.endsWith(MODULES_ENTRY) || name.endsWith(PACKAGES_ENTRY)) {
-                            for (String line: Files.readAllLines(path)) {
-                                int off = writer.addString(line);
-                                out.writeInt(off);
-                            }
-                        } else {
-                            Files.copy(path, out);
-                        }
-                    } catch (IOException ex) {
-                        throw new BadArgs("err.cannot.read.file", file.getName());
-                    }
-                }
-            }
-        } else {
-            throw new BadArgs("err.jimage.already.exists", jimage.getName());
-        }
-
     }
 
     private void title(File file, BasicImageReader reader) {
         log.println("jimage: " + file.getName());
     }

@@ -349,36 +240,40 @@
     private interface JImageAction {
         public void apply(File file, BasicImageReader reader) throws IOException, BadArgs;
     }
 
     private interface ResourceAction {
-        public void apply(BasicImageReader reader, String name, ImageLocation location) throws IOException, BadArgs;
+        public void apply(BasicImageReader reader, String name,
+                ImageLocation location) throws IOException, BadArgs;
     }
 
-    private void extract(BasicImageReader reader, String name, ImageLocation location) throws IOException, BadArgs {
+    private void extract(BasicImageReader reader, String name,
+            ImageLocation location) throws IOException, BadArgs {
         File directory = new File(options.directory);
         byte[] bytes = reader.getResource(location);
         File resource =  new File(directory, name);
         File parent = resource.getParentFile();
 
         if (parent.exists()) {
             if (!parent.isDirectory()) {
-                throw new BadArgs("err.cannot.create.dir", parent.getAbsolutePath());
+                throw taskHelper.newBadArgs("err.cannot.create.dir", parent.getAbsolutePath());
             }
         } else if (!parent.mkdirs()) {
-            throw new BadArgs("err.cannot.create.dir", parent.getAbsolutePath());
+            throw taskHelper.newBadArgs("err.cannot.create.dir", parent.getAbsolutePath());
         }
 
-        if (name.endsWith(MODULES_ENTRY) || name.endsWith(PACKAGES_ENTRY)) {
-            List<String> names = reader.getNames(bytes);
-            Files.write(resource.toPath(), names);
+        if (name.endsWith(ImageModuleData.META_DATA_EXTENSION)) {
+            ImageModuleData imageModuleData = new ImageModuleData(reader, bytes);
+            List<String> lines = imageModuleData.fromModulePackages();
+            Files.write(resource.toPath(), lines);
         } else {
+            if (!ImageResourcesTree.isTreeInfoResource(name)) {
             Files.write(resource.toPath(), bytes);
         }
     }
+    }
 
-    private static final int NAME_WIDTH = 40;
     private static final int NUMBER_WIDTH = 12;
     private static final int OFFSET_WIDTH = NUMBER_WIDTH;
     private static final int SIZE_WIDTH = NUMBER_WIDTH;
     private static final int COMPRESSEDSIZE_WIDTH = NUMBER_WIDTH;
 

@@ -395,16 +290,18 @@
         } else {
             log.println(entry);
         }
     }
 
-    private void info(File file, BasicImageReader reader) {
+    private void info(File file, BasicImageReader reader) throws IOException {
         ImageHeader header = reader.getHeader();
 
         log.println(" Major Version:  " + header.getMajorVersion());
         log.println(" Minor Version:  " + header.getMinorVersion());
-        log.println(" Location Count: " + header.getLocationCount());
+        log.println(" Flags:          " + Integer.toHexString(header.getMinorVersion()));
+        log.println(" Resource Count: " + header.getResourceCount());
+        log.println(" Table Length:   " + header.getTableLength());
         log.println(" Offsets Size:   " + header.getOffsetsSize());
         log.println(" Redirects Size: " + header.getRedirectSize());
         log.println(" Locations Size: " + header.getLocationsSize());
         log.println(" Strings Size:   " + header.getStringsSize());
         log.println(" Index Size:     " + header.getIndexSize());

@@ -412,19 +309,42 @@
 
     private void list(BasicImageReader reader, String name, ImageLocation location) {
         print(reader, name);
     }
 
-    void verify(BasicImageReader reader, String name, ImageLocation location) {
-        if (name.endsWith(".class")) {
-            byte[] bytes;
+    void set(File file, BasicImageReader reader) throws BadArgs {
             try {
-                bytes = reader.getResource(location);
+            ImageHeader oldHeader = reader.getHeader();
+
+            int value = 0;
+            try {
+                value = Integer.valueOf(options.flags);
+            } catch (NumberFormatException ex) {
+                throw taskHelper.newBadArgs("err.flags.not.int", options.flags);
+            }
+
+            ImageHeader newHeader = new ImageHeader(MAGIC, MAJOR_VERSION, MINOR_VERSION,
+                    value,
+                    oldHeader.getResourceCount(), oldHeader.getTableLength(),
+                    oldHeader.getLocationsSize(), oldHeader.getStringsSize());
+
+            ByteBuffer buffer = ByteBuffer.allocate(ImageHeader.getHeaderSize());
+            buffer.order(ByteOrder.nativeOrder());
+            newHeader.writeTo(buffer);
+            buffer.rewind();
+
+            try (FileChannel channel = FileChannel.open(file.toPath(), READ, WRITE)) {
+                channel.write(buffer, 0);
+            }
             } catch (IOException ex) {
-                log.println(ex);
-                bytes = null;
+            throw taskHelper.newBadArgs("err.cannot.update.file", file.getName());
             }
+    }
+
+     void verify(BasicImageReader reader, String name, ImageLocation location) {
+        if (name.endsWith(".class")) {
+            byte[] bytes = reader.getResource(location);
 
             if (bytes == null || bytes.length <= 4 ||
                 (bytes[0] & 0xFF) != 0xCA ||
                 (bytes[1] & 0xFF) != 0xFE ||
                 (bytes[2] & 0xFF) != 0xBA ||

@@ -433,164 +353,64 @@
                 print(reader, name);
             }
         }
     }
 
-    private void iterate(JImageAction jimageAction, ResourceAction resourceAction) throws IOException, BadArgs {
+    private void iterate(JImageAction jimageAction,
+            ResourceAction resourceAction) throws IOException, BadArgs {
         for (File file : options.jimages) {
             if (!file.exists() || !file.isFile()) {
-                throw new BadArgs("err.not.a.jimage", file.getName());
+                throw taskHelper.newBadArgs("err.not.a.jimage", file.getName());
             }
 
             String path = file.getCanonicalPath();
             BasicImageReader reader = BasicImageReader.open(path);
 
             if (jimageAction != null) {
                 jimageAction.apply(file, reader);
             }
 
             if (resourceAction != null) {
-                String[] entryNames = reader.getEntryNames(true);
+                String[] entryNames = reader.getEntryNames();
 
                 for (String name : entryNames) {
+                    if (!ImageResourcesTree.isTreeInfoResource(name)) {
                     ImageLocation location = reader.findLocation(name);
                     resourceAction.apply(reader, name, location);
                 }
             }
        }
     }
+    }
 
     private boolean run() throws IOException, BadArgs {
         switch (options.task) {
-            case RECREATE:
-                recreate();
-                break;
             case EXTRACT:
                 iterate(null, this::extract);
                 break;
             case INFO:
                 iterate(this::info, null);
                 break;
             case LIST:
                 iterate(this::listTitle, this::list);
                 break;
+            case RECREATE:
+                recreate();
+                break;
+            case SET:
+                iterate(this::set, null);
+                break;
             case VERIFY:
                 iterate(this::title, this::verify);
                 break;
             default:
-                throw new BadArgs("err.invalid.task", options.task.name()).showUsage(true);
+                throw taskHelper.newBadArgs("err.invalid.task", options.task.name()).showUsage(true);
         }
         return true;
     }
 
     private PrintWriter log;
     void setLog(PrintWriter out) {
         log = out;
-    }
-    public void handleOptions(String[] args) throws BadArgs {
-        // process options
-        int first = 0;
-
-        if (args.length == 0) {
-            return;
-        }
-
-        String arg = args[first];
-
-        if (!arg.startsWith("-")) {
-            try {
-                options.task = Enum.valueOf(Task.class, arg.toUpperCase());
-                first++;
-            } catch (IllegalArgumentException e) {
-                throw new BadArgs("err.invalid.task", arg).showUsage(true);
-            }
-        }
-
-        for (int i = first; i < args.length; i++) {
-            arg = args[i];
-
-            if (arg.charAt(0) == '-') {
-                Option option = getOption(arg);
-                String param = null;
-
-                if (option.hasArg) {
-                    if (arg.startsWith("--") && arg.indexOf('=') > 0) {
-                        param = arg.substring(arg.indexOf('=') + 1, arg.length());
-                    } else if (i + 1 < args.length) {
-                        param = args[++i];
-                    }
-
-                    if (param == null || param.isEmpty() || param.charAt(0) == '-') {
-                        throw new BadArgs("err.missing.arg", arg).showUsage(true);
-                    }
-                }
-
-                option.process(this, arg, param);
-
-                if (option.ignoreRest()) {
-                    i = args.length;
-                }
-            } else {
-                File file = new File(arg);
-                options.jimages.add(file);
-            }
-        }
-    }
-
-    private Option getOption(String name) throws BadArgs {
-        for (Option o : recognizedOptions) {
-            if (o.matches(name)) {
-                return o;
-            }
-        }
-        throw new BadArgs("err.unknown.option", name).showUsage(true);
-    }
-
-    private void reportError(String key, Object... args) {
-        log.println(getMessage("error.prefix") + " " + getMessage(key, args));
-    }
-
-    private void warning(String key, Object... args) {
-        log.println(getMessage("warn.prefix") + " " + getMessage(key, args));
-    }
-
-    private void showHelp() {
-        log.println(getMessage("main.usage", PROGNAME));
-        for (Option o : recognizedOptions) {
-            String name = o.aliases[0].substring(1); // there must always be at least one name
-            name = name.charAt(0) == '-' ? name.substring(1) : name;
-            if (o.isHidden() || name.equals("h")) {
-                continue;
-            }
-            log.println(getMessage("main.opt." + name));
-        }
-    }
-
-    private void showVersion(boolean full) {
-        log.println(version(full ? "full" : "release"));
-    }
-
-    private String version(String key) {
-        return System.getProperty("java.version");
-    }
-
-    static String getMessage(String key, Object... args) {
-        try {
-            return MessageFormat.format(ResourceBundleHelper.bundle.getString(key), args);
-        } catch (MissingResourceException e) {
-            throw new InternalError("Missing message: " + key);
-        }
-    }
-
-    private static class ResourceBundleHelper {
-        static final ResourceBundle bundle;
-
-        static {
-            Locale locale = Locale.getDefault();
-            try {
-                bundle = ResourceBundle.getBundle("jdk.tools.jimage.resources.jimage", locale);
-            } catch (MissingResourceException e) {
-                throw new InternalError("Cannot find jimage resource bundle for locale " + locale);
-            }
-        }
+        taskHelper.setLog(log);
     }
 }
< prev index next >