changeset 14440:4352ddb02f68

8156914: jlink API minor cleanups Reviewed-by: mchung
author sundar
date Mon, 16 May 2016 14:47:27 +0530
parents bad3f8a33db2
children db250cfb765a b26fa1a6458d
files src/jdk.jlink/share/classes/jdk/tools/jlink/Jlink.java src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java src/jdk.jlink/share/classes/jdk/tools/jlink/builder/ImageBuilder.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageFileCreator.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginConfiguration.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModuleEntryImpl.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModulePoolImpl.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PluginContextImpl.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PoolImpl.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePrevisitor.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Utils.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/DefaultCompressPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeFilesPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludePlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeVMPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/FileCopierPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/OptimizationPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/OrderResourcesPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StringSharingPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripDebugPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripNativeCommandsPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModuleDescriptorPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ZipPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/asm/AsmPlugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/asm/AsmPool.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/asm/AsmPoolImpl.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/asm/AsmPools.java src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/ExecutableImage.java src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/LinkModule.java src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/ModuleEntry.java src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/ModulePool.java src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/Plugin.java src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/PluginContext.java src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/Pool.java src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/TransformerPlugin.java src/jdk.jlink/share/classes/module-info.java test/tools/jlink/DefaultProviderTest.java test/tools/jlink/ImageFileCreatorTest.java test/tools/jlink/ImageFilePoolTest.java test/tools/jlink/IntegrationTest.java test/tools/jlink/JLinkOptimTest.java test/tools/jlink/JLinkOptionsTest.java test/tools/jlink/JLinkPostProcessingTest.java test/tools/jlink/ResourcePoolTest.java test/tools/jlink/SecurityTest.java test/tools/jlink/asmplugin/AddForgetResourcesTest.java test/tools/jlink/asmplugin/AsmPluginTestBase.java test/tools/jlink/asmplugin/BasicTest.java test/tools/jlink/asmplugin/IdentityPluginTest.java test/tools/jlink/asmplugin/NegativeTest.java test/tools/jlink/asmplugin/PackageMappingTest.java test/tools/jlink/asmplugin/SortingTest.java test/tools/jlink/asmplugin/VisitorTest.java test/tools/jlink/customplugin/plugin/CustomPlugin.java test/tools/jlink/customplugin/plugin/HelloPlugin.java test/tools/jlink/plugins/CompressorPluginTest.java test/tools/jlink/plugins/ExcludeFilesPluginTest.java test/tools/jlink/plugins/ExcludePluginTest.java test/tools/jlink/plugins/ExcludeVMPluginTest.java test/tools/jlink/plugins/FileCopierPluginTest.java test/tools/jlink/plugins/LastSorterTest.java test/tools/jlink/plugins/OrderResourcesPluginTest.java test/tools/jlink/plugins/PluginOrderTest.java test/tools/jlink/plugins/PluginsNegativeTest.java test/tools/jlink/plugins/PrevisitorTest.java test/tools/jlink/plugins/StringSharingPluginTest.java test/tools/jlink/plugins/StripDebugPluginTest.java
diffstat 73 files changed, 2074 insertions(+), 1908 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/Jlink.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/Jlink.java	Mon May 16 14:47:27 2016 +0530
@@ -34,11 +34,9 @@
 import java.util.Set;
 import jdk.tools.jlink.internal.JlinkTask;
 import jdk.tools.jlink.plugin.Plugin;
-import jdk.tools.jlink.plugin.PluginContext;
 import jdk.tools.jlink.plugin.PluginException;
 import jdk.tools.jlink.plugin.ExecutableImage;
 import jdk.tools.jlink.builder.ImageBuilder;
-import jdk.tools.jlink.internal.PluginContextImpl;
 import jdk.tools.jlink.internal.PluginRepository;
 
 /**
@@ -71,7 +69,6 @@
         private final List<Plugin> plugins;
         private final ImageBuilder imageBuilder;
         private final String lastSorterPluginName;
-        private final PluginContext pluginContext;
 
         /**
          * Empty plugins configuration.
@@ -86,7 +83,7 @@
          * @param plugins List of plugins.
          */
         public PluginsConfiguration(List<Plugin> plugins) {
-            this(plugins, null, null, null);
+            this(plugins, null, null);
         }
 
         /**
@@ -101,28 +98,10 @@
          */
         public PluginsConfiguration(List<Plugin> plugins,
                 ImageBuilder imageBuilder, String lastSorterPluginName) {
-            this(plugins, imageBuilder, lastSorterPluginName, null);
-        }
-
-        /**
-         * Plugins configuration with a last sorter and an ImageBuilder. No
-         * sorting can occur after the last sorter plugin. The ImageBuilder is
-         * in charge to layout the image content on disk.
-         *
-         * @param plugins List of transformer plugins.
-         * @param imageBuilder Image builder.
-         * @param lastSorterPluginName Name of last sorter plugin, no sorting
-         * @param ctx the plugin context
-         * can occur after it.
-         */
-        public PluginsConfiguration(List<Plugin> plugins,
-                ImageBuilder imageBuilder, String lastSorterPluginName,
-                PluginContext ctx) {
             this.plugins = plugins == null ? Collections.emptyList()
                     : plugins;
             this.imageBuilder = imageBuilder;
             this.lastSorterPluginName = lastSorterPluginName;
-            this.pluginContext = ctx != null? ctx : new PluginContextImpl();
         }
 
         /**
@@ -146,13 +125,6 @@
             return lastSorterPluginName;
         }
 
-        /**
-         * @return the pluginContext
-         */
-        public PluginContext getPluginContext() {
-            return pluginContext;
-        }
-
         @Override
         public String toString() {
             StringBuilder builder = new StringBuilder();
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java	Mon May 16 14:47:27 2016 +0530
@@ -1,3 +1,4 @@
+
 /*
  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -24,8 +25,6 @@
  */
 package jdk.tools.jlink.builder;
 
-import jdk.tools.jlink.plugin.ExecutableImage;
-import jdk.tools.jlink.plugin.PluginException;
 import java.io.BufferedOutputStream;
 import java.io.BufferedWriter;
 import java.io.ByteArrayInputStream;
@@ -47,8 +46,10 @@
 import java.nio.file.attribute.PosixFileAttributeView;
 import java.nio.file.attribute.PosixFilePermission;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Properties;
@@ -56,23 +57,40 @@
 import jdk.tools.jlink.internal.BasicImageWriter;
 import jdk.tools.jlink.internal.plugins.FileCopierPlugin;
 import jdk.tools.jlink.internal.plugins.FileCopierPlugin.SymImageFile;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.Module;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.ExecutableImage;
+import jdk.tools.jlink.plugin.ModulePool;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.PluginException;
 
 /**
  *
  * Default Image Builder. This builder creates the default runtime image layout.
  */
-public class DefaultImageBuilder implements ImageBuilder {
+public final class DefaultImageBuilder implements ImageBuilder {
 
     /**
      * The default java executable Image.
      */
-    static class DefaultExecutableImage extends ExecutableImage {
+    static final class DefaultExecutableImage implements ExecutableImage {
+
+        private final Path home;
+        private final List<String> args;
+        private final Set<String> modules;
 
         public DefaultExecutableImage(Path home, Set<String> modules) {
-            super(home, modules, createArgs(home));
+            this(home, modules, createArgs(home));
+        }
+
+        private DefaultExecutableImage(Path home, Set<String> modules,
+                List<String> args) {
+            Objects.requireNonNull(home);
+            Objects.requireNonNull(args);
+            if (!Files.exists(home)) {
+                throw new IllegalArgumentException("Invalid image home");
+            }
+            this.home = home;
+            this.modules = Collections.unmodifiableSet(modules);
+            this.args = Collections.unmodifiableList(args);
         }
 
         private static List<String> createArgs(Path home) {
@@ -84,6 +102,21 @@
         }
 
         @Override
+        public Path getHome() {
+            return home;
+        }
+
+        @Override
+        public Set<String> getModules() {
+            return modules;
+        }
+
+        @Override
+        public List<String> getExecutionArgs() {
+            return args;
+        }
+
+        @Override
         public void storeLaunchArgs(List<String> args) {
             try {
                 patchScripts(this, args);
@@ -111,17 +144,19 @@
         Files.createDirectories(mdir);
     }
 
-    private void storeFiles(Set<String> modules, Properties release) throws IOException {
+    private void storeFiles(Set<String> modules, Map<String, String> release) throws IOException {
         if (release != null) {
-            addModules(release, modules);
+            Properties props = new Properties();
+            props.putAll(release);
+            addModules(props, modules);
             File r = new File(root.toFile(), "release");
             try (FileOutputStream fo = new FileOutputStream(r)) {
-                release.store(fo, null);
+                props.store(fo, null);
             }
         }
     }
 
-    private void addModules(Properties release, Set<String> modules) throws IOException {
+    private void addModules(Properties props, Set<String> modules) throws IOException {
         StringBuilder builder = new StringBuilder();
         int i = 0;
         for (String m : modules) {
@@ -131,28 +166,32 @@
             }
             i++;
         }
-        release.setProperty("MODULES", builder.toString());
+        props.setProperty("MODULES", builder.toString());
     }
 
     @Override
-    public void storeFiles(Pool files, Properties release) {
+    public void storeFiles(ModulePool files) {
         try {
-            for (ModuleData f : files.getContent()) {
-               if (!f.getType().equals(Pool.ModuleDataType.CLASS_OR_RESOURCE)) {
-                    accept(f);
+            files.entries().forEach(f -> {
+                if (!f.getType().equals(ModuleEntry.Type.CLASS_OR_RESOURCE)) {
+                    try {
+                        accept(f);
+                    } catch (IOException ioExp) {
+                        throw new UncheckedIOException(ioExp);
+                    }
                 }
-            }
-            for (Module m : files.getModules()) {
+            });
+            files.modules().forEach(m -> {
                 // Only add modules that contain packages
                 if (!m.getAllPackages().isEmpty()) {
                     // Skip the fake module used by FileCopierPlugin when copying files.
                     if (m.getName().equals(FileCopierPlugin.FAKE_MODULE)) {
-                       continue;
+                        return;
                     }
                     modules.add(m.getName());
                 }
-            }
-            storeFiles(modules, release);
+            });
+            storeFiles(modules, files.getReleaseProperties());
 
             if (Files.getFileStore(root).supportsFileAttributeView(PosixFileAttributeView.class)) {
                 // launchers in the bin directory need execute permission
@@ -168,8 +207,8 @@
                 Path lib = root.resolve("lib");
                 if (Files.isDirectory(lib)) {
                     Files.find(lib, 2, (path, attrs) -> {
-                        return path.getFileName().toString().equals("jspawnhelper") ||
-                               path.getFileName().toString().equals("jexec");
+                        return path.getFileName().toString().equals("jspawnhelper")
+                                || path.getFileName().toString().equals("jexec");
                     }).forEach(this::setExecutable);
                 }
             }
@@ -180,27 +219,23 @@
         }
     }
 
-    @Override
-    public void storeFiles(Pool files) {
-        storeFiles(files, new Properties());
-    }
-
     /**
      * Generates launcher scripts.
+     *
      * @param imageContent The image content.
      * @param modules The set of modules that the runtime image contains.
      * @throws IOException
      */
-    protected void prepareApplicationFiles(Pool imageContent, Set<String> modules) throws IOException {
+    protected void prepareApplicationFiles(ModulePool imageContent, Set<String> modules) throws IOException {
         // generate launch scripts for the modules with a main class
         for (String module : modules) {
             String path = "/" + module + "/module-info.class";
-            ModuleData res = imageContent.get(path);
-            if (res == null) {
+            Optional<ModuleEntry> res = imageContent.findEntry(path);
+            if (!res.isPresent()) {
                 throw new IOException("module-info.class not found for " + module + " module");
             }
             Optional<String> mainClass;
-            ByteArrayInputStream stream = new ByteArrayInputStream(res.getBytes());
+            ByteArrayInputStream stream = new ByteArrayInputStream(res.get().getBytes());
             mainClass = ModuleDescriptor.read(stream).mainClass();
             if (mainClass.isPresent()) {
                 Path cmd = root.resolve("bin").resolve(module);
@@ -263,9 +298,9 @@
         }
     }
 
-    private void accept(ModuleData file) throws IOException {
+    private void accept(ModuleEntry file) throws IOException {
         String fullPath = file.getPath();
-        String module = "/" + file.getModule()+ "/";
+        String module = "/" + file.getModule() + "/";
         String filename = fullPath.substring(module.length());
         // Remove radical native|config|...
         filename = filename.substring(filename.indexOf('/') + 1);
@@ -404,8 +439,7 @@
 
     public static ExecutableImage getExecutableImage(Path root) {
         if (Files.exists(root.resolve("bin").resolve(getJavaProcessName()))) {
-            return new DefaultImageBuilder.DefaultExecutableImage(root,
-                    retrieveModules(root));
+            return new DefaultExecutableImage(root, retrieveModules(root));
         }
         return null;
     }
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/ImageBuilder.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/ImageBuilder.java	Mon May 16 14:47:27 2016 +0530
@@ -29,7 +29,7 @@
 
 import jdk.tools.jlink.plugin.ExecutableImage;
 import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.ModulePool;
 
 /**
  * Implement this interface to develop your own image layout. First the jimage
@@ -45,7 +45,7 @@
      * @param release the release properties
      * @throws PluginException
      */
-    public default void storeFiles(Pool content, Properties release) {
+    public default void storeFiles(ModulePool content, Properties release) {
         storeFiles(content);
     }
 
@@ -55,7 +55,7 @@
      * @param content Pool of module content.
      * @throws PluginException
      */
-    public default void storeFiles(Pool content) {
+    public default void storeFiles(ModulePool content) {
         throw new UnsupportedOperationException("storeFiles");
     }
 
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageFileCreator.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageFileCreator.java	Mon May 16 14:47:27 2016 +0530
@@ -44,12 +44,11 @@
 import java.util.stream.Stream;
 import jdk.tools.jlink.internal.Archive.Entry;
 import jdk.tools.jlink.internal.Archive.Entry.EntryType;
-import jdk.tools.jlink.internal.PoolImpl.CompressedModuleData;
+import jdk.tools.jlink.internal.ModulePoolImpl.CompressedModuleData;
 import jdk.tools.jlink.plugin.ExecutableImage;
 import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
-import jdk.tools.jlink.plugin.Pool.ModuleDataType;
+import jdk.tools.jlink.plugin.ModulePool;
+import jdk.tools.jlink.plugin.ModuleEntry;
 
 /**
  * An image (native endian.)
@@ -145,7 +144,7 @@
                                     }));
             ByteOrder order = ByteOrder.nativeOrder();
             BasicImageWriter writer = new BasicImageWriter(order);
-            PoolImpl pool = createPools(archives, entriesForModule, order, writer);
+            ModulePoolImpl pool = createPools(archives, entriesForModule, order, writer);
             try (OutputStream fos = Files.newOutputStream(jimageFile);
                     BufferedOutputStream bos = new BufferedOutputStream(fos);
                     DataOutputStream out = new DataOutputStream(bos)) {
@@ -163,9 +162,9 @@
             ByteOrder byteOrder)
             throws IOException {
         BasicImageWriter writer = new BasicImageWriter(byteOrder);
-        PoolImpl allContent = createPools(archives,
+        ModulePoolImpl allContent = createPools(archives,
                 entriesForModule, byteOrder, writer);
-        PoolImpl result = generateJImage(allContent,
+        ModulePoolImpl result = generateJImage(allContent,
              writer, plugins, plugins.getJImageFileOutputStream());
 
         //Handle files.
@@ -176,12 +175,12 @@
         }
     }
 
-    private static PoolImpl generateJImage(PoolImpl allContent,
+    private static ModulePoolImpl generateJImage(ModulePoolImpl allContent,
             BasicImageWriter writer,
             ImagePluginStack pluginSupport,
             DataOutputStream out
     ) throws IOException {
-        PoolImpl resultResources;
+        ModulePoolImpl resultResources;
         try {
             resultResources = pluginSupport.visitResources(allContent);
         } catch (PluginException pe) {
@@ -190,14 +189,14 @@
             throw new IOException(ex);
         }
         Set<String> duplicates = new HashSet<>();
-        long offset = 0;
+        long[] offset = new long[1];
 
-        List<ModuleData> content = new ArrayList<>();
+        List<ModuleEntry> content = new ArrayList<>();
         List<String> paths = new ArrayList<>();
                  // the order of traversing the resources and the order of
         // the module content being written must be the same
-        for (ModuleData res : resultResources.getContent()) {
-            if (res.getType().equals(ModuleDataType.CLASS_OR_RESOURCE)) {
+        resultResources.entries().forEach(res -> {
+            if (res.getType().equals(ModuleEntry.Type.CLASS_OR_RESOURCE)) {
                 String path = res.getPath();
                 content.add(res);
                 long uncompressedSize = res.getLength();
@@ -216,24 +215,24 @@
                     // TODO Need to hang bytes on resource and write
                     // from resource not zip.
                     // Skipping resource throws off writing from zip.
-                    offset += onFileSize;
-                    continue;
+                    offset[0] += onFileSize;
+                    return;
                 }
                 duplicates.add(path);
-                writer.addLocation(path, offset, compressedSize, uncompressedSize);
+                writer.addLocation(path, offset[0], compressedSize, uncompressedSize);
                 paths.add(path);
-                offset += onFileSize;
+                offset[0] += onFileSize;
             }
-        }
+        });
 
-        ImageResourcesTree tree = new ImageResourcesTree(offset, writer, paths);
+        ImageResourcesTree tree = new ImageResourcesTree(offset[0], writer, paths);
 
         // write header and indices
         byte[] bytes = writer.getBytes();
         out.write(bytes, 0, bytes.length);
 
         // write module content
-        for (ModuleData res : content) {
+        for (ModuleEntry res : content) {
             byte[] buf = res.getBytes();
             out.write(buf, 0, buf.length);
         }
@@ -245,26 +244,26 @@
         return resultResources;
     }
 
-    private static Pool.ModuleDataType mapImageFileType(EntryType type) {
+    private static ModuleEntry.Type mapImageFileType(EntryType type) {
         switch(type) {
             case CONFIG: {
-                return Pool.ModuleDataType.CONFIG;
+                return ModuleEntry.Type.CONFIG;
             }
             case NATIVE_CMD: {
-                return Pool.ModuleDataType.NATIVE_CMD;
+                return ModuleEntry.Type.NATIVE_CMD;
             }
             case NATIVE_LIB: {
-                return Pool.ModuleDataType.NATIVE_LIB;
+                return ModuleEntry.Type.NATIVE_LIB;
             }
         }
         return null;
     }
 
-    private static PoolImpl createPools(Set<Archive> archives,
+    private static ModulePoolImpl createPools(Set<Archive> archives,
             Map<String, List<Entry>> entriesForModule,
             ByteOrder byteOrder,
             BasicImageWriter writer) throws IOException {
-        PoolImpl resources = new PoolImpl(byteOrder, new StringTable() {
+        ModulePoolImpl resources = new ModulePoolImpl(byteOrder, new StringTable() {
 
             @Override
             public int addString(String str) {
@@ -291,7 +290,7 @@
                             path = "/" + mn + "/" + path;
                         }
                         try {
-                            resources.add(Pool.newResource(path, bytes));
+                            resources.add(ModuleEntry.create(path, bytes));
                         } catch (Exception ex) {
                             throw new IOException(ex);
                         }
@@ -300,7 +299,7 @@
                     try {
                         // Entry.path() contains the kind of file native, conf, bin, ...
                         // Keep it to avoid naming conflict (eg: native/jvm.cfg and config/jvm.cfg
-                        resources.add(Pool.newImageFile(mn,
+                        resources.add(ModuleEntry.create(mn,
                                 "/" + mn + "/" + entry.path(), mapImageFileType(entry.type()),
                                 entry.stream(), entry.size()));
                     } catch (Exception ex) {
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginConfiguration.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginConfiguration.java	Mon May 16 14:47:27 2016 +0530
@@ -28,22 +28,17 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.Objects;
-import java.util.Properties;
 import jdk.tools.jlink.plugin.ExecutableImage;
 import jdk.tools.jlink.builder.ImageBuilder;
 import jdk.tools.jlink.Jlink;
 import jdk.tools.jlink.plugin.Plugin;
-import jdk.tools.jlink.plugin.PluginContext;
 import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.plugin.Plugin.CATEGORY;
-import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Plugin.Category;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.plugin.PostProcessorPlugin;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 
@@ -52,17 +47,18 @@
  */
 public final class ImagePluginConfiguration {
 
-    private static final List<Plugin.CATEGORY> CATEGORIES_ORDER = new ArrayList<>();
+    private static final List<Plugin.Category> CATEGORIES_ORDER = new ArrayList<>();
 
     static {
-        CATEGORIES_ORDER.add(Plugin.CATEGORY.FILTER);
-        CATEGORIES_ORDER.add(Plugin.CATEGORY.TRANSFORMER);
-        CATEGORIES_ORDER.add(Plugin.CATEGORY.MODULEINFO_TRANSFORMER);
-        CATEGORIES_ORDER.add(Plugin.CATEGORY.SORTER);
-        CATEGORIES_ORDER.add(Plugin.CATEGORY.COMPRESSOR);
-        CATEGORIES_ORDER.add(Plugin.CATEGORY.VERIFIER);
-        CATEGORIES_ORDER.add(Plugin.CATEGORY.PROCESSOR);
-        CATEGORIES_ORDER.add(Plugin.CATEGORY.PACKAGER);
+        CATEGORIES_ORDER.add(Plugin.Category.FILTER);
+        CATEGORIES_ORDER.add(Plugin.Category.TRANSFORMER);
+        CATEGORIES_ORDER.add(Plugin.Category.MODULEINFO_TRANSFORMER);
+        CATEGORIES_ORDER.add(Plugin.Category.SORTER);
+        CATEGORIES_ORDER.add(Plugin.Category.COMPRESSOR);
+        CATEGORIES_ORDER.add(Plugin.Category.METAINFO_ADDER);
+        CATEGORIES_ORDER.add(Plugin.Category.VERIFIER);
+        CATEGORIES_ORDER.add(Plugin.Category.PROCESSOR);
+        CATEGORIES_ORDER.add(Plugin.Category.PACKAGER);
     }
 
     private ImagePluginConfiguration() {
@@ -76,8 +72,8 @@
         if (pluginsConfiguration == null) {
             return new ImagePluginStack();
         }
-        Map<Plugin.CATEGORY, List<Plugin>> plugins = new LinkedHashMap<>();
-        for (Plugin.CATEGORY cat : CATEGORIES_ORDER) {
+        Map<Plugin.Category, List<Plugin>> plugins = new LinkedHashMap<>();
+        for (Plugin.Category cat : CATEGORIES_ORDER) {
             plugins.put(cat, new ArrayList<>());
         }
 
@@ -89,7 +85,7 @@
                         + " added more than once to stack ");
             }
             seen.add(plug.getName());
-            CATEGORY category = Utils.getCategory(plug);
+            Category category = Utils.getCategory(plug);
             if (category == null) {
                 throw new PluginException("Invalid category for "
                         + plug.getName());
@@ -100,10 +96,10 @@
 
         List<TransformerPlugin> transformerPlugins = new ArrayList<>();
         List<PostProcessorPlugin> postProcessingPlugins = new ArrayList<>();
-        for (Entry<Plugin.CATEGORY, List<Plugin>> entry : plugins.entrySet()) {
+        for (Entry<Plugin.Category, List<Plugin>> entry : plugins.entrySet()) {
             // Sort according to plugin constraints
             List<Plugin> orderedPlugins = PluginOrderingGraph.sort(entry.getValue());
-            CATEGORY category = entry.getKey();
+            Category category = entry.getKey();
             for (Plugin p : orderedPlugins) {
                 if (Utils.isPostProcessor(category)) {
                     @SuppressWarnings("unchecked")
@@ -143,14 +139,13 @@
                 }
 
                 @Override
-                public void storeFiles(Pool files) {
+                public void storeFiles(ModulePool files) {
                     throw new PluginException("No directory setup to store files");
                 }
             };
         }
 
-        PluginContext ctxt = pluginsConfiguration.getPluginContext();
         return new ImagePluginStack(builder, transformerPlugins,
-                lastSorter, postProcessingPlugins, ctxt);
+                lastSorter, postProcessingPlugins);
     }
 }
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java	Mon May 16 14:47:27 2016 +0530
@@ -37,20 +37,21 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.Properties;
+import java.util.Optional;
 import java.util.Set;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import jdk.internal.jimage.decompressor.Decompressor;
 import jdk.tools.jlink.plugin.Plugin;
-import jdk.tools.jlink.plugin.PluginContext;
 import jdk.tools.jlink.plugin.ExecutableImage;
 import jdk.tools.jlink.builder.ImageBuilder;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.ModulePool;
+import jdk.tools.jlink.plugin.LinkModule;
+import jdk.tools.jlink.plugin.ModuleEntry;
 import jdk.tools.jlink.plugin.PostProcessorPlugin;
 
 /**
@@ -64,9 +65,9 @@
         ExecutableImage retrieve(ImagePluginStack stack) throws IOException;
     }
 
-    public static final class OrderedResourcePool extends PoolImpl {
+    public static final class OrderedResourcePool extends ModulePoolImpl {
 
-        private final List<ModuleData> orderedList = new ArrayList<>();
+        private final List<ModuleEntry> orderedList = new ArrayList<>();
 
         public OrderedResourcePool(ByteOrder order, StringTable table) {
             super(order, table);
@@ -78,22 +79,22 @@
          * @param resource The Resource to add.
          */
         @Override
-        public void add(ModuleData resource) {
+        public void add(ModuleEntry resource) {
             super.add(resource);
             orderedList.add(resource);
         }
 
-        List<ModuleData> getOrderedList() {
+        List<ModuleEntry> getOrderedList() {
             return Collections.unmodifiableList(orderedList);
         }
     }
 
-    private final static class CheckOrderResourcePool extends PoolImpl {
+    private final static class CheckOrderResourcePool extends ModulePoolImpl {
 
-        private final List<ModuleData> orderedList;
+        private final List<ModuleEntry> orderedList;
         private int currentIndex;
 
-        public CheckOrderResourcePool(ByteOrder order, List<ModuleData> orderedList, StringTable table) {
+        public CheckOrderResourcePool(ByteOrder order, List<ModuleEntry> orderedList, StringTable table) {
             super(order, table);
             this.orderedList = orderedList;
         }
@@ -104,8 +105,8 @@
          * @param resource The Resource to add.
          */
         @Override
-        public void add(ModuleData resource) {
-            ModuleData ordered = orderedList.get(currentIndex);
+        public void add(ModuleEntry resource) {
+            ModuleEntry ordered = orderedList.get(currentIndex);
             if (!resource.equals(ordered)) {
                 throw new PluginException("Resource " + resource.getPath() + " not in the right order");
             }
@@ -166,26 +167,16 @@
     private final List<ResourcePrevisitor> resourcePrevisitors = new ArrayList<>();
 
     private final ImageBuilder imageBuilder;
-    private final Properties release;
 
     public ImagePluginStack() {
         this(null, Collections.emptyList(), null,
-                Collections.emptyList(), null);
+                Collections.emptyList());
     }
 
     public ImagePluginStack(ImageBuilder imageBuilder,
             List<TransformerPlugin> contentPlugins,
             Plugin lastSorter,
             List<PostProcessorPlugin> postprocessingPlugins) {
-        this(imageBuilder, contentPlugins, lastSorter,
-            postprocessingPlugins, null);
-    }
-
-    public ImagePluginStack(ImageBuilder imageBuilder,
-            List<TransformerPlugin> contentPlugins,
-            Plugin lastSorter,
-            List<PostProcessorPlugin> postprocessingPlugins,
-            PluginContext ctxt) {
         Objects.requireNonNull(contentPlugins);
         this.lastSorter = lastSorter;
         for (TransformerPlugin p : contentPlugins) {
@@ -200,7 +191,6 @@
             this.postProcessingPlugins.add(p);
         }
         this.imageBuilder = imageBuilder;
-        this.release = ctxt != null? ctxt.getReleaseProperties() : new Properties();
     }
 
     public void operate(ImageProvider provider) throws Exception {
@@ -231,12 +221,12 @@
      * @return The result of the visit.
      * @throws IOException
      */
-    public PoolImpl visitResources(PoolImpl resources)
+    public ModulePoolImpl visitResources(ModulePoolImpl resources)
             throws Exception {
         Objects.requireNonNull(resources);
         resources.setReadOnly();
         if (resources.isEmpty()) {
-            return new PoolImpl(resources.getByteOrder(),
+            return new ModulePoolImpl(resources.getByteOrder(),
                     resources.getStringTable());
         }
         PreVisitStrings previsit = new PreVisitStrings();
@@ -250,11 +240,11 @@
             resources.getStringTable().addString(s);
         }
 
-        PoolImpl current = resources;
-        List<Pool.ModuleData> frozenOrder = null;
+        ModulePoolImpl current = resources;
+        List<ModuleEntry> frozenOrder = null;
         for (TransformerPlugin p : contentPlugins) {
             current.setReadOnly();
-            PoolImpl output = null;
+            ModulePoolImpl output = null;
             if (p == lastSorter) {
                 if (frozenOrder != null) {
                     throw new Exception("Order of resources is already frozen. Plugin "
@@ -268,7 +258,7 @@
                     output = new CheckOrderResourcePool(current.getByteOrder(),
                             frozenOrder, resources.getStringTable());
                 } else {
-                    output = new PoolImpl(current.getByteOrder(),
+                    output = new ModulePoolImpl(current.getByteOrder(),
                             resources.getStringTable());
                 }
             }
@@ -287,15 +277,15 @@
     }
 
     /**
-     * This pool wrap the original pool and automatically uncompress moduledata
+     * This pool wrap the original pool and automatically uncompress ModuleEntry
      * if needed.
      */
-    private class LastPool extends Pool {
-        private class LastModule implements Module {
+    private class LastPool implements ModulePool {
+        private class LastModule implements LinkModule {
 
-            private final Module module;
+            final LinkModule module;
 
-            LastModule(Module module) {
+            LastModule(LinkModule module) {
                 this.module = module;
             }
 
@@ -305,9 +295,9 @@
             }
 
             @Override
-            public ModuleData get(String path) {
-                ModuleData d = module.get(path);
-                return getUncompressed(d);
+            public Optional<ModuleEntry> findEntry(String path) {
+                Optional<ModuleEntry> d = module.findEntry(path);
+                return d.isPresent()? Optional.of(getUncompressed(d.get())) : Optional.empty();
             }
 
             @Override
@@ -316,7 +306,7 @@
             }
 
             @Override
-            public void add(ModuleData data) {
+            public void add(ModuleEntry data) {
                 throw new PluginException("pool is readonly");
             }
 
@@ -331,19 +321,24 @@
             }
 
             @Override
-            public Collection<ModuleData> getContent() {
-                List<ModuleData> lst = new ArrayList<>();
-                for(ModuleData md : module.getContent()) {
+            public Stream<ModuleEntry> entries() {
+                List<ModuleEntry> lst = new ArrayList<>();
+                module.entries().forEach(md -> {
                     lst.add(getUncompressed(md));
-                }
-                return lst;
+                });
+                return lst.stream();
+            }
+
+            @Override
+            public int getEntryCount() {
+                return module.getEntryCount();
             }
         }
-        private final PoolImpl pool;
+        private final ModulePoolImpl pool;
         Decompressor decompressor = new Decompressor();
-        Collection<ModuleData> content;
+        Collection<ModuleEntry> content;
 
-        LastPool(PoolImpl pool) {
+        LastPool(ModulePoolImpl pool) {
             this.pool = pool;
         }
 
@@ -353,23 +348,14 @@
         }
 
         @Override
-        public void add(ModuleData resource) {
+        public void add(ModuleEntry resource) {
             throw new PluginException("pool is readonly");
         }
 
-        /**
-         * Retrieves the module of the provided name.
-         *
-         * @param name The module name
-         * @return the module or null if the module doesn't exist.
-         */
         @Override
-        public Module getModule(String name) {
-            Module module = pool.getModule(name);
-            if (module != null) {
-                module = new LastModule(module);
-            }
-            return module;
+        public Optional<LinkModule> findModule(String name) {
+            Optional<LinkModule> module = pool.findModule(name);
+            return module.isPresent()? Optional.of(new LastModule(module.get())) : Optional.empty();
         }
 
         /**
@@ -378,45 +364,55 @@
          * @return The collection of modules.
          */
         @Override
-        public Collection<Module> getModules() {
-            List<Module> modules = new ArrayList<>();
-            for (Module m : pool.getModules()) {
+        public Stream<? extends LinkModule> modules() {
+            List<LinkModule> modules = new ArrayList<>();
+            pool.modules().forEach(m -> {
                 modules.add(new LastModule(m));
-            }
-            return modules;
+            });
+            return modules.stream();
+        }
+
+        @Override
+        public int getModuleCount() {
+            return pool.getModuleCount();
         }
 
         /**
          * Get all resources contained in this pool instance.
          *
-         * @return The collection of resources;
+         * @return The stream of resources;
          */
         @Override
-        public Collection<ModuleData> getContent() {
+        public Stream<? extends ModuleEntry> entries() {
             if (content == null) {
                 content = new ArrayList<>();
-                for (ModuleData md : pool.getContent()) {
+                pool.entries().forEach(md -> {
                     content.add(getUncompressed(md));
-                }
+                });
             }
-            return content;
+            return content.stream();
+        }
+
+        @Override
+        public int getEntryCount() {
+            return pool.getEntryCount();
         }
 
         /**
          * Get the resource for the passed path.
          *
          * @param path A resource path
-         * @return A Resource instance or null if the resource is not found
+         * @return A Resource instance if the resource is found
          */
         @Override
-        public ModuleData get(String path) {
+        public Optional<ModuleEntry> findEntry(String path) {
             Objects.requireNonNull(path);
-            Pool.ModuleData res = pool.get(path);
-            return getUncompressed(res);
+            Optional<ModuleEntry> res = pool.findEntry(path);
+            return res.isPresent()? Optional.of(getUncompressed(res.get())) : Optional.empty();
         }
 
         @Override
-        public boolean contains(ModuleData res) {
+        public boolean contains(ModuleEntry res) {
             return pool.contains(res);
         }
 
@@ -426,8 +422,8 @@
         }
 
         @Override
-        public void visit(Visitor visitor, Pool output) {
-            pool.visit(visitor, output);
+        public void transformAndCopy(Function<ModuleEntry, ModuleEntry> visitor, ModulePool output) {
+            pool.transformAndCopy(visitor, output);
         }
 
         @Override
@@ -435,14 +431,19 @@
             return pool.getByteOrder();
         }
 
-        private ModuleData getUncompressed(ModuleData res) {
+        @Override
+        public Map<String, String> getReleaseProperties() {
+            return Collections.unmodifiableMap(pool.getReleaseProperties());
+        }
+
+        private ModuleEntry getUncompressed(ModuleEntry res) {
             if (res != null) {
-                if (res instanceof PoolImpl.CompressedModuleData) {
+                if (res instanceof ModulePoolImpl.CompressedModuleData) {
                     try {
                         byte[] bytes = decompressor.decompressResource(getByteOrder(),
                                 (int offset) -> pool.getStringTable().getString(offset),
                                 res.getBytes());
-                        res = Pool.newResource(res.getPath(),
+                        res = ModuleEntry.create(res.getPath(),
                                 new ByteArrayInputStream(bytes),
                                 bytes.length);
                     } catch (IOException ex) {
@@ -462,20 +463,24 @@
      * @param writer
      * @throws java.lang.Exception
      */
-    public void storeFiles(PoolImpl original, PoolImpl transformed,
+    public void storeFiles(ModulePoolImpl original, ModulePoolImpl transformed,
             BasicImageWriter writer)
             throws Exception {
         Objects.requireNonNull(original);
-        try {
-            // fill release information available from transformed "java.base" module!
-            ModuleDescriptor desc = transformed.getModule("java.base").getDescriptor();
-            desc.osName().ifPresent(s -> release.put("OS_NAME", s));
-            desc.osVersion().ifPresent(s -> release.put("OS_VERSION", s));
-            desc.osArch().ifPresent(s -> release.put("OS_ARCH", s));
-        } catch (Exception ignored) {
-        }
+        Objects.requireNonNull(transformed);
+        Optional<LinkModule> javaBase = transformed.findModule("java.base");
+        javaBase.ifPresent(mod -> {
+            try {
+                Map<String, String> release = transformed.getReleaseProperties();
+                // fill release information available from transformed "java.base" module!
+                ModuleDescriptor desc = mod.getDescriptor();
+                desc.osName().ifPresent(s -> release.put("OS_NAME", s));
+                desc.osVersion().ifPresent(s -> release.put("OS_VERSION", s));
+                desc.osArch().ifPresent(s -> release.put("OS_ARCH", s));
+            } catch (Exception ignored) {}
+        });
 
-        imageBuilder.storeFiles(new LastPool(transformed), release);
+        imageBuilder.storeFiles(new LastPool(transformed));
     }
 
     public ExecutableImage getExecutableImage() throws IOException {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModuleEntryImpl.java	Mon May 16 14:47:27 2016 +0530
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2016, 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
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jlink.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.util.Objects;
+import jdk.tools.jlink.plugin.ModuleEntry;
+
+/**
+ * A LinkModuleEntry is the elementary unit of data inside an image. It is
+ * generally a file. e.g.: a java class file, a resource file, a shared library,
+ * ...
+ * <br>
+ * A LinkModuleEntry is identified by a path of the form:
+ * <ul>
+ * <li>For jimage content: /{module name}/{package1}/.../{packageN}/{file
+ * name}</li>
+ * <li>For other files (shared lib, launchers, config, ...):/{module name}/
+ * {@literal bin|conf|native}/{dir1}>/.../{dirN}/{file name}</li>
+ * </ul>
+ */
+public class ModuleEntryImpl implements ModuleEntry {
+
+    private final Type type;
+    private final String path;
+    private final String module;
+    private final long length;
+    private final InputStream stream;
+    private byte[] buffer;
+
+    /**
+     * Create a new LinkModuleEntry.
+     *
+     * @param module The module name.
+     * @param path The data path identifier.
+     * @param type The data type.
+     * @param stream The data content stream.
+     * @param length The stream length.
+     */
+    public ModuleEntryImpl(String module, String path, Type type, InputStream stream, long length) {
+        Objects.requireNonNull(module);
+        Objects.requireNonNull(path);
+        Objects.requireNonNull(type);
+        Objects.requireNonNull(stream);
+        this.path = path;
+        this.type = type;
+        this.module = module;
+        this.stream = stream;
+        this.length = length;
+    }
+
+    /**
+     * The LinkModuleEntry module name.
+     *
+     * @return The module name.
+     */
+    @Override
+    public final String getModule() {
+        return module;
+    }
+
+    /**
+     * The LinkModuleEntry path.
+     *
+     * @return The module path.
+     */
+    @Override
+    public final String getPath() {
+        return path;
+    }
+
+    /**
+     * The LinkModuleEntry's type.
+     *
+     * @return The data type.
+     */
+    @Override
+    public final Type getType() {
+        return type;
+    }
+
+    /**
+     * The LinkModuleEntry content as an array of byte.
+     *
+     * @return An Array of bytes.
+     */
+    @Override
+    public byte[] getBytes() {
+        if (buffer == null) {
+            try (InputStream is = stream) {
+                buffer = is.readAllBytes();
+            } catch (IOException ex) {
+                throw new UncheckedIOException(ex);
+            }
+        }
+        return buffer;
+    }
+
+    /**
+     * The LinkModuleEntry content length.
+     *
+     * @return The length.
+     */
+    @Override
+    public long getLength() {
+        return length;
+    }
+
+    /**
+     * The LinkModuleEntry stream.
+     *
+     * @return The module data stream.
+     */
+    @Override
+    public InputStream stream() {
+        return stream;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 7;
+        hash = 89 * hash + Objects.hashCode(this.path);
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof ModuleEntryImpl)) {
+            return false;
+        }
+        ModuleEntryImpl f = (ModuleEntryImpl) other;
+        return f.path.equals(path);
+    }
+
+    @Override
+    public String toString() {
+        return getPath();
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModulePoolImpl.java	Mon May 16 14:47:27 2016 +0530
@@ -0,0 +1,421 @@
+/*
+ * Copyright (c) 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
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.internal;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.lang.module.ModuleDescriptor;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Stream;
+import jdk.internal.jimage.decompressor.CompressedResourceHeader;
+import jdk.tools.jlink.plugin.ModulePool;
+import jdk.tools.jlink.plugin.LinkModule;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.internal.plugins.FileCopierPlugin;
+
+/**
+ * Pool of module data.
+ */
+public class ModulePoolImpl implements ModulePool {
+
+    private class ModuleImpl implements LinkModule {
+
+        final Map<String, ModuleEntry> moduleContent = new LinkedHashMap<>();
+        private ModuleDescriptor descriptor;
+        final String name;
+
+        private ModuleImpl(String name) {
+            this.name = name;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public Optional<ModuleEntry> findEntry(String path) {
+            if (!path.startsWith("/")) {
+                path = "/" + path;
+            }
+            if (!path.startsWith("/" + name)) {
+                path = "/" + name + path;
+            }
+            return Optional.ofNullable(moduleContent.get(path));
+        }
+
+        @Override
+        public ModuleDescriptor getDescriptor() {
+            if (descriptor == null) {
+                String p = "/" + name + "/module-info.class";
+                Optional<ModuleEntry> content = findEntry(p);
+                if (!content.isPresent()) {
+                    throw new PluginException("No module-info for " + name
+                            + " module");
+                }
+                ByteBuffer bb = ByteBuffer.wrap(content.get().getBytes());
+                descriptor = ModuleDescriptor.read(bb);
+            }
+            return descriptor;
+        }
+
+        @Override
+        public void add(ModuleEntry data) {
+            if (isReadOnly()) {
+                throw new PluginException("LinkConfiguration is readonly");
+            }
+            Objects.requireNonNull(data);
+            if (!data.getModule().equals(name)) {
+                throw new PluginException("Can't add resource " + data.getPath()
+                        + " to module " + name);
+            }
+            ModulePoolImpl.this.add(data);
+        }
+
+        @Override
+        public Set<String> getAllPackages() {
+            Set<String> pkgs = new HashSet<>();
+            moduleContent.values().stream().filter(m -> m.getType().
+                    equals(ModuleEntry.Type.CLASS_OR_RESOURCE)).forEach(res -> {
+                // Module metadata only contains packages with .class files
+                if (ImageFileCreator.isClassPackage(res.getPath())) {
+                    String[] split = ImageFileCreator.splitPath(res.getPath());
+                    String pkg = split[1];
+                    if (pkg != null && !pkg.isEmpty()) {
+                        pkgs.add(pkg);
+                    }
+                }
+            });
+            return pkgs;
+        }
+
+        @Override
+        public String toString() {
+            return getName();
+        }
+
+        @Override
+        public Stream<? extends ModuleEntry> entries() {
+            return moduleContent.values().stream();
+        }
+
+        @Override
+        public int getEntryCount() {
+            return moduleContent.values().size();
+        }
+    }
+
+    private final Map<String, ModuleEntry> resources = new LinkedHashMap<>();
+    private final Map<String, ModuleImpl> modules = new LinkedHashMap<>();
+    private final ModuleImpl fileCopierModule = new ModuleImpl(FileCopierPlugin.FAKE_MODULE);
+    private Map<String, String> releaseProps = new HashMap<>();
+
+    private final ByteOrder order;
+
+    private boolean isReadOnly;
+    private final StringTable table;
+
+    public ModulePoolImpl() {
+        this(ByteOrder.nativeOrder());
+    }
+
+    public ModulePoolImpl(ByteOrder order) {
+        this(order, new StringTable() {
+
+            @Override
+            public int addString(String str) {
+                return -1;
+            }
+
+            @Override
+            public String getString(int id) {
+                return null;
+            }
+        });
+    }
+
+    public ModulePoolImpl(ByteOrder order, StringTable table) {
+        this.order = order;
+        this.table = table;
+    }
+
+    /**
+     * Add a ModuleEntry.
+     *
+     * @param data The ModuleEntry to add.
+     */
+    @Override
+    public void add(ModuleEntry data) {
+        if (isReadOnly()) {
+            throw new PluginException("LinkConfiguration is readonly");
+        }
+        Objects.requireNonNull(data);
+        if (resources.get(data.getPath()) != null) {
+            throw new PluginException("Resource " + data.getPath()
+                    + " already present");
+        }
+        String modulename = data.getModule();
+        ModuleImpl m = modules.get(modulename);
+        // ## TODO: FileCopierPlugin should not add content to a module
+        // FAKE_MODULE is not really a module to be added in the image
+        if (FileCopierPlugin.FAKE_MODULE.equals(modulename)) {
+            m = fileCopierModule;
+        }
+        if (m == null) {
+            m = new ModuleImpl(modulename);
+            modules.put(modulename, m);
+        }
+        resources.put(data.getPath(), data);
+        m.moduleContent.put(data.getPath(), data);
+    }
+
+    /**
+     * Retrieves the module for the provided name.
+     *
+     * @param name The module name
+     * @return the module of matching name, if found
+     */
+    @Override
+    public Optional<LinkModule> findModule(String name) {
+        Objects.requireNonNull(name);
+        return Optional.ofNullable(modules.get(name));
+    }
+
+    /**
+     * The stream of modules contained in this LinkConfiguration.
+     *
+     * @return The stream of modules.
+     */
+    @Override
+    public Stream<? extends LinkModule> modules() {
+        return modules.values().stream();
+    }
+
+    /**
+     * Return the number of LinkModule count in this LinkConfiguration.
+     *
+     * @return the module count.
+     */
+    @Override
+    public int getModuleCount() {
+        return modules.size();
+    }
+
+    /**
+     * Get all ModuleEntry contained in this LinkConfiguration instance.
+     *
+     * @return The stream of LinkModuleEntries.
+     */
+    @Override
+    public Stream<? extends ModuleEntry> entries() {
+        return resources.values().stream();
+    }
+
+    /**
+     * Return the number of ModuleEntry count in this LinkConfiguration.
+     *
+     * @return the entry count.
+     */
+    @Override
+    public int getEntryCount() {
+        return resources.values().size();
+    }
+
+    /**
+     * Get the ModuleEntry for the passed path.
+     *
+     * @param path A data path
+     * @return A ModuleEntry instance or null if the data is not found
+     */
+    @Override
+    public Optional<ModuleEntry> findEntry(String path) {
+        Objects.requireNonNull(path);
+        return Optional.ofNullable(resources.get(path));
+    }
+
+    /**
+     * Check if the LinkConfiguration contains the given ModuleEntry.
+     *
+     * @param data The module data to check existence for.
+     * @return The module data or null if not found.
+     */
+    @Override
+    public boolean contains(ModuleEntry data) {
+        Objects.requireNonNull(data);
+        return findEntry(data.getPath()).isPresent();
+    }
+
+    /**
+     * Check if the LinkConfiguration contains some content at all.
+     *
+     * @return True, no content, false otherwise.
+     */
+    @Override
+    public boolean isEmpty() {
+        return resources.isEmpty();
+    }
+
+    /**
+     * Visit each ModuleEntry in this LinkConfiguration to transform it and
+     * copy the transformed ModuleEntry to the output LinkConfiguration.
+     *
+     * @param transform The function called for each ModuleEntry found in
+     * the LinkConfiguration. The transform function should return a
+     * ModuleEntry instance which will be added to the output or it should
+     * return null if the passed ModuleEntry is to be ignored for the
+     * output.
+     *
+     * @param output The LinkConfiguration to be filled with Visitor returned
+     * ModuleEntry.
+     */
+    @Override
+    public void transformAndCopy(Function<ModuleEntry, ModuleEntry> transform,
+            ModulePool output) {
+        entries().forEach(resource -> {
+            ModuleEntry res = transform.apply(resource);
+            if (res != null) {
+                output.add(res);
+            }
+        });
+    }
+
+    /**
+     * The ByteOrder currently in use when generating the jimage file.
+     *
+     * @return The ByteOrder.
+     */
+    @Override
+    public ByteOrder getByteOrder() {
+        return order;
+    }
+
+    @Override
+    public Map<String, String> getReleaseProperties() {
+        return isReadOnly()? Collections.unmodifiableMap(releaseProps) : releaseProps;
+    }
+
+    public StringTable getStringTable() {
+        return table;
+    }
+
+    /**
+     * Make this Resources instance read-only. No resource can be added.
+     */
+    public void setReadOnly() {
+        isReadOnly = true;
+    }
+
+    /**
+     * Read only state.
+     *
+     * @return true if readonly false otherwise.
+     */
+    @Override
+    public boolean isReadOnly() {
+        return isReadOnly;
+    }
+
+    /**
+     * A resource that has been compressed.
+     */
+    public static final class CompressedModuleData extends ModuleEntryImpl {
+
+        final long uncompressed_size;
+
+        private CompressedModuleData(String module, String path,
+                InputStream stream, long size,
+                long uncompressed_size) {
+            super(module, path, ModuleEntry.Type.CLASS_OR_RESOURCE, stream, size);
+            this.uncompressed_size = uncompressed_size;
+        }
+
+        public long getUncompressedSize() {
+            return uncompressed_size;
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (!(other instanceof CompressedModuleData)) {
+                return false;
+            }
+            CompressedModuleData f = (CompressedModuleData) other;
+            return f.getPath().equals(getPath());
+        }
+
+        @Override
+        public int hashCode() {
+            return super.hashCode();
+        }
+    }
+
+    public static CompressedModuleData newCompressedResource(ModuleEntry original,
+            ByteBuffer compressed,
+            String plugin, String pluginConfig, StringTable strings,
+            ByteOrder order) {
+        Objects.requireNonNull(original);
+        Objects.requireNonNull(compressed);
+        Objects.requireNonNull(plugin);
+
+        boolean isTerminal = !(original instanceof CompressedModuleData);
+        long uncompressed_size = original.getLength();
+        if (original instanceof CompressedModuleData) {
+            CompressedModuleData comp = (CompressedModuleData) original;
+            uncompressed_size = comp.getUncompressedSize();
+        }
+        int nameOffset = strings.addString(plugin);
+        int configOffset = -1;
+        if (pluginConfig != null) {
+            configOffset = strings.addString(plugin);
+        }
+        CompressedResourceHeader rh
+                = new CompressedResourceHeader(compressed.limit(), original.getLength(),
+                        nameOffset, configOffset, isTerminal);
+        // Merge header with content;
+        byte[] h = rh.getBytes(order);
+        ByteBuffer bb = ByteBuffer.allocate(compressed.limit() + h.length);
+        bb.order(order);
+        bb.put(h);
+        bb.put(compressed);
+        byte[] contentWithHeader = bb.array();
+
+        CompressedModuleData compressedResource
+                = new CompressedModuleData(original.getModule(), original.getPath(),
+                        new ByteArrayInputStream(contentWithHeader),
+                        contentWithHeader.length, uncompressed_size);
+        return compressedResource;
+    }
+
+}
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PluginContextImpl.java	Mon May 16 09:54:01 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2016, 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
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.tools.jlink.internal;
-
-import java.util.Properties;
-
-import jdk.tools.jlink.plugin.PluginContext;
-
-public final class PluginContextImpl implements PluginContext {
-    private final Properties releaseProps = new Properties();
-
-    public Properties getReleaseProperties() {
-        return releaseProps;
-    }
-}
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PoolImpl.java	Mon May 16 09:54:01 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,167 +0,0 @@
-/*
- * Copyright (c) 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
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.tools.jlink.internal;
-
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Objects;
-import jdk.internal.jimage.decompressor.CompressedResourceHeader;
-import jdk.tools.jlink.plugin.Pool;
-
-/**
- * Pool of module data.
- */
-public class PoolImpl extends Pool {
-
-    /**
-     * A resource that has been compressed.
-     */
-    public static final class CompressedModuleData extends ModuleData {
-
-        private final long uncompressed_size;
-
-        private CompressedModuleData(String module, String path,
-                InputStream stream, long size,
-                long uncompressed_size) {
-            super(module, path, ModuleDataType.CLASS_OR_RESOURCE, stream, size);
-            this.uncompressed_size = uncompressed_size;
-        }
-
-        public long getUncompressedSize() {
-            return uncompressed_size;
-        }
-
-        @Override
-        public boolean equals(Object other) {
-            if (!(other instanceof CompressedModuleData)) {
-                return false;
-            }
-            CompressedModuleData f = (CompressedModuleData) other;
-            return f.getPath().equals(getPath());
-        }
-
-        @Override
-        public int hashCode() {
-            return super.hashCode();
-        }
-    }
-
-    private boolean isReadOnly;
-    private final StringTable table;
-
-    public PoolImpl() {
-        this(ByteOrder.nativeOrder(), new StringTable() {
-
-            @Override
-            public int addString(String str) {
-                return -1;
-            }
-            @Override
-            public String getString(int id) {
-                return null;
-            }
-        });
-    }
-
-    public PoolImpl(ByteOrder order) {
-        this(order, new StringTable() {
-
-            @Override
-            public int addString(String str) {
-                return -1;
-            }
-            @Override
-            public String getString(int id) {
-                return null;
-            }
-        });
-    }
-
-    public PoolImpl(ByteOrder order, StringTable table) {
-        super(order);
-        this.table = table;
-    }
-
-    public StringTable getStringTable() {
-        return table;
-    }
-
-    /**
-     * Make this Resources instance read-only. No resource can be added.
-     */
-    public void setReadOnly() {
-        isReadOnly = true;
-    }
-
-    /**
-     * Read only state.
-     *
-     * @return true if readonly false otherwise.
-     */
-    @Override
-    public boolean isReadOnly() {
-        return isReadOnly;
-    }
-
-    public static CompressedModuleData newCompressedResource(ModuleData original,
-            ByteBuffer compressed,
-            String plugin, String pluginConfig, StringTable strings,
-            ByteOrder order) {
-        Objects.requireNonNull(original);
-        Objects.requireNonNull(compressed);
-        Objects.requireNonNull(plugin);
-
-        boolean isTerminal = !(original instanceof CompressedModuleData);
-        long uncompressed_size = original.getLength();
-        if (original instanceof CompressedModuleData) {
-            CompressedModuleData comp = (CompressedModuleData) original;
-            uncompressed_size = comp.getUncompressedSize();
-        }
-        int nameOffset = strings.addString(plugin);
-        int configOffset = -1;
-        if (pluginConfig != null) {
-            configOffset = strings.addString(plugin);
-        }
-        CompressedResourceHeader rh
-                = new CompressedResourceHeader(compressed.limit(), original.getLength(),
-                        nameOffset, configOffset, isTerminal);
-        // Merge header with content;
-        byte[] h = rh.getBytes(order);
-        ByteBuffer bb = ByteBuffer.allocate(compressed.limit() + h.length);
-        bb.order(order);
-        bb.put(h);
-        bb.put(compressed);
-        byte[] contentWithHeader = bb.array();
-
-        CompressedModuleData compressedResource
-                = new CompressedModuleData(original.getModule(), original.getPath(),
-                        new ByteArrayInputStream(contentWithHeader),
-                        contentWithHeader.length, uncompressed_size);
-        return compressedResource;
-    }
-
-}
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePrevisitor.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePrevisitor.java	Mon May 16 14:47:27 2016 +0530
@@ -24,7 +24,7 @@
  */
 package jdk.tools.jlink.internal;
 
-import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.ModulePool;
 
 /**
  * Plugin wishing to pre-visit the resources must implement this interface.
@@ -44,5 +44,5 @@
      * usage.
      * @throws PluginException
      */
-    public void previsit(Pool resources, StringTable strings);
+    public void previsit(ModulePool resources, StringTable strings);
 }
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java	Mon May 16 14:47:27 2016 +0530
@@ -52,7 +52,7 @@
 import jdk.tools.jlink.Jlink;
 import jdk.tools.jlink.Jlink.PluginsConfiguration;
 import jdk.tools.jlink.plugin.Plugin;
-import jdk.tools.jlink.plugin.Plugin.CATEGORY;
+import jdk.tools.jlink.plugin.Plugin.Category;
 import jdk.tools.jlink.builder.DefaultImageBuilder;
 import jdk.tools.jlink.builder.ImageBuilder;
 import jdk.tools.jlink.plugin.PluginException;
@@ -346,7 +346,6 @@
                 }
             }
 
-            PluginContextImpl pluginContext = new PluginContextImpl();
             List<Plugin> pluginsList = new ArrayList<>();
             for (Entry<Plugin, List<Map<String, String>>> entry : pluginToMaps.entrySet()) {
                 Plugin plugin = entry.getKey();
@@ -356,7 +355,7 @@
                 // we call configure once for each occurrence. It is upto the plugin
                 // to 'merge' and/or 'override' arguments.
                 for (Map<String, String> map : argsMaps) {
-                    plugin.configure(Collections.unmodifiableMap(map), pluginContext);
+                    plugin.configure(Collections.unmodifiableMap(map));
                 }
 
                 if (!Utils.isDisabled(plugin)) {
@@ -371,7 +370,7 @@
 
             }
             return new Jlink.PluginsConfiguration(pluginsList,
-                    builder, lastSorter, pluginContext);
+                    builder, lastSorter);
         }
     }
 
@@ -594,7 +593,7 @@
                          + ": " + plugin.getClass().getName());
                     log.println(bundleHelper.getMessage("main.plugin.module")
                          + ": " + plugin.getClass().getModule().getName());
-                    CATEGORY category = Utils.getCategory(plugin);
+                    Category category = Utils.getCategory(plugin);
                     log.println(bundleHelper.getMessage("main.plugin.category")
                          + ": " + category.getName());
                     log.println(bundleHelper.getMessage("main.plugin.state")
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Utils.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Utils.java	Mon May 16 14:47:27 2016 +0530
@@ -30,7 +30,6 @@
 import java.util.List;
 import java.util.function.Function;
 import jdk.tools.jlink.plugin.Plugin;
-import jdk.tools.jlink.plugin.Plugin.PluginType;
 
 public class Utils {
 
@@ -50,25 +49,26 @@
         return arguments;
     };
 
-    public static boolean isPostProcessor(Plugin.CATEGORY category) {
-        return category.equals(Plugin.CATEGORY.VERIFIER)
-                || category.equals(Plugin.CATEGORY.PROCESSOR)
-                || category.equals(Plugin.CATEGORY.PACKAGER);
+    public static boolean isPostProcessor(Plugin.Category category) {
+        return category.equals(Plugin.Category.VERIFIER)
+                || category.equals(Plugin.Category.PROCESSOR)
+                || category.equals(Plugin.Category.PACKAGER);
     }
 
-    public static boolean isPreProcessor(Plugin.CATEGORY category) {
-        return category.equals(Plugin.CATEGORY.COMPRESSOR)
-                || category.equals(Plugin.CATEGORY.FILTER)
-                || category.equals(Plugin.CATEGORY.MODULEINFO_TRANSFORMER)
-                || category.equals(Plugin.CATEGORY.SORTER)
-                || category.equals(Plugin.CATEGORY.TRANSFORMER);
+    public static boolean isPreProcessor(Plugin.Category category) {
+        return category.equals(Plugin.Category.COMPRESSOR)
+                || category.equals(Plugin.Category.FILTER)
+                || category.equals(Plugin.Category.MODULEINFO_TRANSFORMER)
+                || category.equals(Plugin.Category.SORTER)
+                || category.equals(Plugin.Category.TRANSFORMER)
+                || category.equals(Plugin.Category.METAINFO_ADDER);
     }
 
     public static boolean isPostProcessor(Plugin prov) {
         if (prov.getType() != null) {
-            for (PluginType pt : prov.getType()) {
-                if (pt instanceof Plugin.CATEGORY) {
-                    return isPostProcessor((Plugin.CATEGORY) pt);
+            for (Plugin.Category pt : prov.getType()) {
+                if (pt instanceof Plugin.Category) {
+                    return isPostProcessor(pt);
                 }
             }
         }
@@ -77,20 +77,20 @@
 
     public static boolean isPreProcessor(Plugin prov) {
         if (prov.getType() != null) {
-            for (PluginType pt : prov.getType()) {
-                if (pt instanceof Plugin.CATEGORY) {
-                    return isPreProcessor((Plugin.CATEGORY) pt);
+            for (Plugin.Category pt : prov.getType()) {
+                if (pt instanceof Plugin.Category) {
+                    return isPreProcessor(pt);
                 }
             }
         }
         return false;
     }
 
-    public static Plugin.CATEGORY getCategory(Plugin provider) {
+    public static Plugin.Category getCategory(Plugin provider) {
         if (provider.getType() != null) {
-            for (Plugin.PluginType t : provider.getType()) {
-                if (t instanceof Plugin.CATEGORY) {
-                    return (Plugin.CATEGORY) t;
+            for (Plugin.Category t : provider.getType()) {
+                if (t instanceof Plugin.Category) {
+                    return t;
                 }
             }
         }
@@ -140,15 +140,15 @@
     }
 
     public static boolean isFunctional(Plugin prov) {
-        return prov.getState().contains(Plugin.STATE.FUNCTIONAL);
+        return prov.getState().contains(Plugin.State.FUNCTIONAL);
     }
 
     public static boolean isAutoEnabled(Plugin prov) {
-        return prov.getState().contains(Plugin.STATE.AUTO_ENABLED);
+        return prov.getState().contains(Plugin.State.AUTO_ENABLED);
     }
 
     public static boolean isDisabled(Plugin prov) {
-        return prov.getState().contains(Plugin.STATE.DISABLED);
+        return prov.getState().contains(Plugin.State.DISABLED);
     }
 
     // is this a builtin (jdk.jlink) plugin?
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java	Mon May 16 14:47:27 2016 +0530
@@ -30,7 +30,7 @@
 import jdk.tools.jlink.builder.ImageBuilder;
 import jdk.tools.jlink.plugin.Plugin;
 import jdk.tools.jlink.builder.*;
-import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.ModulePool;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/DefaultCompressPlugin.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/DefaultCompressPlugin.java	Mon May 16 14:47:27 2016 +0530
@@ -26,16 +26,13 @@
 
 import java.io.IOException;
 import java.io.UncheckedIOException;
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.internal.PoolImpl;
-import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.internal.ModulePoolImpl;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 import jdk.tools.jlink.internal.ImagePluginStack;
 import jdk.tools.jlink.internal.ResourcePrevisitor;
@@ -62,10 +59,10 @@
     }
 
     @Override
-    public void visit(Pool in, Pool out) {
+    public void visit(ModulePool in, ModulePool out) {
         if (ss != null && zip != null) {
-            Pool output = new ImagePluginStack.OrderedResourcePool(in.getByteOrder(),
-                    ((PoolImpl) in).getStringTable());
+            ModulePool output = new ImagePluginStack.OrderedResourcePool(in.getByteOrder(),
+                    ((ModulePoolImpl) in).getStringTable());
             ss.visit(in, output);
             zip.visit(output, out);
         } else if (ss != null) {
@@ -76,16 +73,16 @@
     }
 
     @Override
-    public void previsit(Pool resources, StringTable strings) {
+    public void previsit(ModulePool resources, StringTable strings) {
         if (ss != null) {
             ss.previsit(resources, strings);
         }
     }
 
     @Override
-    public Set<PluginType> getType() {
-        Set<PluginType> set = new HashSet<>();
-        set.add(CATEGORY.COMPRESSOR);
+    public Set<Category> getType() {
+        Set<Category> set = new HashSet<>();
+        set.add(Category.COMPRESSOR);
         return Collections.unmodifiableSet(set);
     }
 
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeFilesPlugin.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeFilesPlugin.java	Mon May 16 14:47:27 2016 +0530
@@ -32,8 +32,8 @@
 import java.util.Set;
 import java.util.function.Predicate;
 import jdk.tools.jlink.plugin.TransformerPlugin;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleDataType;
+import jdk.tools.jlink.plugin.ModulePool;
+import jdk.tools.jlink.plugin.ModuleEntry;
 import jdk.tools.jlink.internal.Utils;
 
 /**
@@ -51,9 +51,9 @@
     }
 
     @Override
-    public void visit(Pool in, Pool out) {
-        in.visit((file) -> {
-            if (!file.getType().equals(ModuleDataType.CLASS_OR_RESOURCE)) {
+    public void visit(ModulePool in, ModulePool out) {
+        in.transformAndCopy((file) -> {
+            if (!file.getType().equals(ModuleEntry.Type.CLASS_OR_RESOURCE)) {
                 file = predicate.test(file.getPath()) ? file : null;
             }
             return file;
@@ -61,9 +61,9 @@
     }
 
     @Override
-    public Set<PluginType> getType() {
-        Set<PluginType> set = new HashSet<>();
-        set.add(CATEGORY.FILTER);
+    public Set<Category> getType() {
+        Set<Category> set = new HashSet<>();
+        set.add(Category.FILTER);
         return Collections.unmodifiableSet(set);
     }
 
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludePlugin.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludePlugin.java	Mon May 16 14:47:27 2016 +0530
@@ -32,7 +32,8 @@
 import java.util.function.Predicate;
 import jdk.tools.jlink.plugin.PluginException;
 import jdk.tools.jlink.plugin.TransformerPlugin;
-import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.internal.Utils;
 
 /**
@@ -50,9 +51,9 @@
     }
 
     @Override
-    public void visit(Pool in, Pool out) {
-        in.visit((resource) -> {
-            if (resource.getType().equals(Pool.ModuleDataType.CLASS_OR_RESOURCE)) {
+    public void visit(ModulePool in, ModulePool out) {
+        in.transformAndCopy((resource) -> {
+            if (resource.getType().equals(ModuleEntry.Type.CLASS_OR_RESOURCE)) {
                 resource = predicate.test(resource.getPath()) ? resource : null;
             }
             return resource;
@@ -75,9 +76,9 @@
     }
 
     @Override
-    public Set<PluginType> getType() {
-        Set<PluginType> set = new HashSet<>();
-        set.add(CATEGORY.FILTER);
+    public Set<Category> getType() {
+        Set<Category> set = new HashSet<>();
+        set.add(Category.FILTER);
         return Collections.unmodifiableSet(set);
     }
 
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeVMPlugin.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeVMPlugin.java	Mon May 16 14:47:27 2016 +0530
@@ -40,9 +40,10 @@
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 import jdk.tools.jlink.plugin.TransformerPlugin;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleDataType;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.internal.Utils;
+import jdk.tools.jlink.plugin.ModuleEntry;
 import jdk.tools.jlink.plugin.PluginException;
 
 /**
@@ -102,24 +103,24 @@
      * e.g.: /java.base/native/amd64/server/libjvm.so
      * /java.base/native/server/libjvm.dylib
      */
-    private List<Pool.ModuleData> getVMs(Pool in) {
+    private List<ModuleEntry> getVMs(ModulePool in) {
         String jvmlib = jvmlib();
-        List<Pool.ModuleData> ret = in.getModule("java.base").getContent().stream().filter((t) -> {
+        List<ModuleEntry> ret = in.findModule("java.base").get().entries().filter((t) -> {
             return t.getPath().endsWith("/" + jvmlib);
         }).collect(Collectors.toList());
         return ret;
     }
 
     @Override
-    public void visit(Pool in, Pool out) {
+    public void visit(ModulePool in, ModulePool out) {
         String jvmlib = jvmlib();
         TreeSet<Jvm> existing = new TreeSet<>(new JvmComparator());
         TreeSet<Jvm> removed = new TreeSet<>(new JvmComparator());
         if (!keepAll) {
             // First retrieve all available VM names and removed VM
-            List<Pool.ModuleData> jvms = getVMs(in);
+            List<ModuleEntry> jvms = getVMs(in);
             for (Jvm jvm : Jvm.values()) {
-                for (Pool.ModuleData md : jvms) {
+                for (ModuleEntry md : jvms) {
                     if (md.getPath().endsWith("/" + jvm.getName() + "/" + jvmlib)) {
                         existing.add(jvm);
                         if (isRemoved(md)) {
@@ -137,9 +138,9 @@
         }
 
         // Rewrite the jvm.cfg file.
-        in.visit((file) -> {
+        in.transformAndCopy((file) -> {
             if (!keepAll) {
-                if (file.getType().equals(ModuleDataType.NATIVE_LIB)) {
+                if (file.getType().equals(ModuleEntry.Type.NATIVE_LIB)) {
                     if (file.getPath().endsWith(JVM_CFG)) {
                         try {
                             file = handleJvmCfgFile(file, existing, removed);
@@ -155,14 +156,14 @@
 
     }
 
-    private boolean isRemoved(Pool.ModuleData file) {
+    private boolean isRemoved(ModuleEntry file) {
         return !predicate.test(file.getPath());
     }
 
     @Override
-    public Set<PluginType> getType() {
-        Set<PluginType> set = new HashSet<>();
-        set.add(CATEGORY.FILTER);
+    public Set<Category> getType() {
+        Set<Category> set = new HashSet<>();
+        set.add(Category.FILTER);
         return Collections.unmodifiableSet(set);
     }
 
@@ -217,7 +218,7 @@
         }
     }
 
-    private Pool.ModuleData handleJvmCfgFile(Pool.ModuleData orig,
+    private ModuleEntry handleJvmCfgFile(ModuleEntry orig,
             TreeSet<Jvm> existing,
             TreeSet<Jvm> removed) throws IOException {
         if (keepAll) {
@@ -253,7 +254,7 @@
 
         byte[] content = builder.toString().getBytes(StandardCharsets.UTF_8);
 
-        return Pool.newImageFile(orig.getModule(),
+        return ModuleEntry.create(orig.getModule(),
                 orig.getPath(),
                 orig.getType(),
                 new ByteArrayInputStream(content), content.length);
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/FileCopierPlugin.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/FileCopierPlugin.java	Mon May 16 14:47:27 2016 +0530
@@ -41,10 +41,10 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import jdk.tools.jlink.internal.ModuleEntryImpl;
 import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
-import jdk.tools.jlink.plugin.Pool.ModuleDataType;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 import jdk.tools.jlink.internal.Utils;
 
@@ -68,12 +68,12 @@
     /**
      * Symbolic link to another path.
      */
-    public static abstract class SymImageFile extends Pool.ModuleData {
+    public static abstract class SymImageFile extends ModuleEntryImpl {
 
         private final String targetPath;
 
         public SymImageFile(String targetPath, String module, String path,
-                Pool.ModuleDataType type, InputStream stream, long size) {
+                ModuleEntry.Type type, InputStream stream, long size) {
             super(module, path, type, stream, size);
             this.targetPath = targetPath;
         }
@@ -86,7 +86,7 @@
     private static final class SymImageFileImpl extends SymImageFile {
 
         public SymImageFileImpl(String targetPath, Path file, String module,
-                String path, ModuleDataType type) {
+                String path, ModuleEntry.Type type) {
             super(targetPath, module, path, type, newStream(file), length(file));
         }
     }
@@ -110,11 +110,11 @@
     private static final class DirectoryCopy implements FileVisitor<Path> {
 
         private final Path source;
-        private final Pool pool;
+        private final ModulePool pool;
         private final String targetDir;
         private final List<SymImageFile> symlinks = new ArrayList<>();
 
-        DirectoryCopy(Path source, Pool pool, String targetDir) {
+        DirectoryCopy(Path source, ModulePool pool, String targetDir) {
             this.source = source;
             this.pool = pool;
             this.targetDir = targetDir;
@@ -148,7 +148,7 @@
                 }
                 SymImageFileImpl impl = new SymImageFileImpl(symTarget.toString(),
                         file, path, Objects.requireNonNull(file.getFileName()).toString(),
-                        Pool.ModuleDataType.OTHER);
+                        ModuleEntry.Type.OTHER);
                 symlinks.add(impl);
             } else {
                 addFile(pool, file, path);
@@ -172,14 +172,14 @@
         }
     }
 
-    private static void addFile(Pool pool, Path file, String path)
+    private static void addFile(ModulePool pool, Path file, String path)
             throws IOException {
         Objects.requireNonNull(pool);
         Objects.requireNonNull(file);
         Objects.requireNonNull(path);
-        ModuleData impl = Pool.newImageFile(FAKE_MODULE,
+        ModuleEntry impl = ModuleEntry.create(FAKE_MODULE,
                 "/" + FAKE_MODULE + "/other/" + path,
-                Pool.ModuleDataType.OTHER, newStream(file), length(file));
+                ModuleEntry.Type.OTHER, newStream(file), length(file));
         try {
             pool.add(impl);
         } catch (Exception ex) {
@@ -188,9 +188,9 @@
     }
 
     @Override
-    public Set<PluginType> getType() {
-        Set<PluginType> set = new HashSet<>();
-        set.add(CATEGORY.TRANSFORMER);
+    public Set<Category> getType() {
+        Set<Category> set = new HashSet<>();
+        set.add(Category.TRANSFORMER);
         return Collections.unmodifiableSet(set);
     }
 
@@ -239,8 +239,8 @@
     }
 
     @Override
-    public void visit(Pool in, Pool out) {
-        in.visit((file) -> {
+    public void visit(ModulePool in, ModulePool out) {
+        in.transformAndCopy((file) -> {
             return file;
         }, out);
 
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java	Mon May 16 14:47:27 2016 +0530
@@ -33,8 +33,9 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
+import jdk.tools.jlink.plugin.ModuleEntry;
 import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 
 /**
@@ -60,8 +61,8 @@
     }
 
     @Override
-    public Set<PluginType> getType() {
-        return Collections.singleton(CATEGORY.TRANSFORMER);
+    public Set<Category> getType() {
+        return Collections.singleton(Category.TRANSFORMER);
     }
 
     @Override
@@ -75,8 +76,8 @@
     }
 
     @Override
-    public Set<STATE> getState() {
-        return EnumSet.of(STATE.AUTO_ENABLED, STATE.FUNCTIONAL);
+    public Set<State> getState() {
+        return EnumSet.of(State.AUTO_ENABLED, State.FUNCTIONAL);
     }
 
     @Override
@@ -151,8 +152,8 @@
     }
 
     @Override
-    public void visit(Pool in, Pool out) {
-        for (Pool.ModuleData data : in.getContent()) {
+    public void visit(ModulePool in, ModulePool out) {
+        in.entries().forEach(data -> {
             if (("/java.base/" + BMH + ".class").equals(data.getPath())) {
                 // Add BoundMethodHandle unchanged
                 out.add(data);
@@ -162,11 +163,11 @@
                     out.add(data);
                 }
             }
-        }
+        });
     }
 
     @SuppressWarnings("unchecked")
-    private void generateConcreteClass(String types, Pool.ModuleData data, Pool out) {
+    private void generateConcreteClass(String types, ModuleEntry data, ModulePool out) {
         try {
             // Generate class
             Map.Entry<String, byte[]> result = (Map.Entry<String, byte[]>)
@@ -175,9 +176,9 @@
             byte[] bytes = result.getValue();
 
             // Add class to pool
-            Pool.ModuleData ndata = new Pool.ModuleData(data.getModule(),
+            ModuleEntry ndata = ModuleEntry.create(data.getModule(),
                     "/java.base/" + className + ".class",
-                    Pool.ModuleDataType.CLASS_OR_RESOURCE,
+                    ModuleEntry.Type.CLASS_OR_RESOURCE,
                     new ByteArrayInputStream(bytes), bytes.length);
             if (!out.contains(ndata)) {
                 out.add(ndata);
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java	Mon May 16 14:47:27 2016 +0530
@@ -34,6 +34,7 @@
 import java.util.Locale;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.function.Predicate;
 import java.util.regex.Pattern;
@@ -44,9 +45,10 @@
 import jdk.tools.jlink.internal.ResourcePrevisitor;
 import jdk.tools.jlink.internal.StringTable;
 import jdk.tools.jlink.internal.Utils;
+import jdk.tools.jlink.plugin.LinkModule;
+import jdk.tools.jlink.plugin.ModuleEntry;
 import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleDataType;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 
 /**
@@ -112,19 +114,19 @@
     }
 
     @Override
-    public void visit(Pool in, Pool out) {
-        in.visit((resource) -> {
+    public void visit(ModulePool in, ModulePool out) {
+        in.transformAndCopy((resource) -> {
             if (resource.getModule().equals(MODULENAME)) {
                 String path = resource.getPath();
                 resource = predicate.test(path) ? resource: null;
                 if (resource != null &&
-                    resource.getType().equals(ModuleDataType.CLASS_OR_RESOURCE)) {
+                    resource.getType().equals(ModuleEntry.Type.CLASS_OR_RESOURCE)) {
                     byte[] bytes = resource.getBytes();
                     ClassReader cr = new ClassReader(bytes);
                     if (Arrays.stream(cr.getInterfaces())
                         .anyMatch(i -> i.contains(METAINFONAME)) &&
                         stripUnsupportedLocales(bytes, cr)) {
-                        resource = new Pool.ModuleData(MODULENAME, path,
+                        resource = ModuleEntry.create(MODULENAME, path,
                             resource.getType(),
                             new ByteArrayInputStream(bytes), bytes.length);
                     }
@@ -135,9 +137,9 @@
     }
 
     @Override
-    public Set<PluginType> getType() {
-        Set<PluginType> set = new HashSet<>();
-        set.add(CATEGORY.FILTER);
+    public Set<Category> getType() {
+        Set<Category> set = new HashSet<>();
+        set.add(Category.FILTER);
         return Collections.unmodifiableSet(set);
     }
 
@@ -172,12 +174,13 @@
     }
 
     @Override
-    public void previsit(Pool resources, StringTable strings) {
+    public void previsit(ModulePool resources, StringTable strings) {
         final Pattern p = Pattern.compile(".*((Data_)|(Names_))(?<tag>.*)\\.class");
-        Pool.Module module = resources.getModule(MODULENAME);
+        Optional<LinkModule> optMod = resources.findModule(MODULENAME);
 
         // jdk.localedata module validation
-        if (module != null) {
+        if (optMod.isPresent()) {
+            LinkModule module = optMod.get();
             Set<String> packages = module.getAllPackages();
             if (!packages.containsAll(LOCALEDATA_PACKAGES)) {
                 throw new PluginException(PluginsResourceBundle.getMessage(NAME + ".missingpackages") +
@@ -186,7 +189,7 @@
                         .collect(Collectors.joining(",\n\t")));
             }
 
-            available = Stream.concat(module.getContent().stream()
+            available = Stream.concat(module.entries()
                                         .map(md -> p.matcher(md.getPath()))
                                         .filter(m -> m.matches())
                                         .map(m -> m.group("tag").replaceAll("_", "-")),
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/OptimizationPlugin.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/OptimizationPlugin.java	Mon May 16 14:47:27 2016 +0530
@@ -24,7 +24,6 @@
  */
 package jdk.tools.jlink.internal.plugins;
 
-import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
@@ -287,9 +286,9 @@
     }
 
     @Override
-    public Set<PluginType> getType() {
-        Set<PluginType> set = new HashSet<>();
-        set.add(CATEGORY.TRANSFORMER);
+    public Set<Category> getType() {
+        Set<Category> set = new HashSet<>();
+        set.add(Category.TRANSFORMER);
         return Collections.unmodifiableSet(set);
     }
 }
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/OrderResourcesPlugin.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/OrderResourcesPlugin.java	Mon May 16 14:47:27 2016 +0530
@@ -36,9 +36,8 @@
 import java.util.Set;
 import java.util.function.ToIntFunction;
 import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
-import jdk.tools.jlink.plugin.Pool.ModuleDataType;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 import jdk.tools.jlink.internal.Utils;
 
@@ -62,15 +61,15 @@
     }
 
     static class SortWrapper {
-        private final ModuleData resource;
+        private final ModuleEntry resource;
         private final int ordinal;
 
-        SortWrapper(ModuleData resource, int ordinal) {
+        SortWrapper(ModuleEntry resource, int ordinal) {
             this.resource = resource;
             this.ordinal = ordinal;
         }
 
-        ModuleData getResource() {
+        ModuleEntry getResource() {
             return resource;
         }
 
@@ -95,7 +94,7 @@
         return path;
     }
 
-    private int getOrdinal(ModuleData resource) {
+    private int getOrdinal(ModuleEntry resource) {
         String path = resource.getPath();
 
         Integer value = orderedPaths.get(stripModule(path));
@@ -126,23 +125,23 @@
     }
 
     @Override
-    public void visit(Pool in, Pool out) {
-        in.getContent().stream()
+    public void visit(ModulePool in, ModulePool out) {
+        in.entries()
                 .filter(resource -> resource.getType()
-                        .equals(ModuleDataType.CLASS_OR_RESOURCE))
+                        .equals(ModuleEntry.Type.CLASS_OR_RESOURCE))
                 .map((resource) -> new SortWrapper(resource, getOrdinal(resource)))
                 .sorted(OrderResourcesPlugin::compare)
                 .forEach((wrapper) -> out.add(wrapper.getResource()));
-        in.getContent().stream()
+        in.entries()
                 .filter(other -> !other.getType()
-                        .equals(ModuleDataType.CLASS_OR_RESOURCE))
+                        .equals(ModuleEntry.Type.CLASS_OR_RESOURCE))
                 .forEach((other) -> out.add(other));
     }
 
     @Override
-    public Set<PluginType> getType() {
-        Set<PluginType> set = new HashSet<>();
-        set.add(CATEGORY.SORTER);
+    public Set<Category> getType() {
+        Set<Category> set = new HashSet<>();
+        set.add(Category.SORTER);
 
         return Collections.unmodifiableSet(set);
     }
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin.java	Mon May 16 14:47:27 2016 +0530
@@ -24,34 +24,33 @@
  */
 package jdk.tools.jlink.internal.plugins;
 
-import java.lang.module.ModuleDescriptor;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.util.Collections;
 import java.util.EnumSet;
-import java.util.List;
+import java.util.HashMap;
 import java.util.Map;
+import java.util.Properties;
 import java.util.Set;
-import java.util.Properties;
-
+import java.util.function.Function;
 import jdk.tools.jlink.internal.Utils;
-import jdk.tools.jlink.plugin.ExecutableImage;
-import jdk.tools.jlink.plugin.PluginContext;
-import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.PostProcessorPlugin;
+import jdk.tools.jlink.plugin.ModulePool;
+import jdk.tools.jlink.plugin.Plugin.Category;
+import jdk.tools.jlink.plugin.Plugin.State;
+import jdk.tools.jlink.plugin.TransformerPlugin;
 
 /**
  * This plugin adds/deletes information for 'release' file.
  */
-public final class ReleaseInfoPlugin implements PostProcessorPlugin {
+public final class ReleaseInfoPlugin implements TransformerPlugin {
     // option name
     public static final String NAME = "release-info";
     public static final String KEYS = "keys";
+    private final Map<String, String> release = new HashMap<>();
 
     @Override
-    public Set<PluginType> getType() {
-        return Collections.singleton(CATEGORY.PROCESSOR);
+    public Set<Category> getType() {
+        return Collections.singleton(Category.METAINFO_ADDER);
     }
 
     @Override
@@ -65,8 +64,8 @@
     }
 
     @Override
-    public Set<STATE> getState() {
-        return EnumSet.of(STATE.FUNCTIONAL);
+    public Set<State> getState() {
+        return EnumSet.of(State.FUNCTIONAL);
     }
 
     @Override
@@ -80,49 +79,49 @@
     }
 
     @Override
-    public void configure(Map<String, String> config, PluginContext ctx) {
-        Properties release = ctx != null? ctx.getReleaseProperties() : null;
-        if (release != null) {
-            String operation = config.get(NAME);
-            switch (operation) {
-                case "add": {
-                    // leave it to open-ended! source, java_version, java_full_version
-                    // can be passed via this option like:
-                    //
-                    //     --release-info add:build_type=fastdebug,source=openjdk,java_version=9
-                    // and put whatever value that was passed in command line.
+    public void configure(Map<String, String> config) {
+        String operation = config.get(NAME);
+        switch (operation) {
+            case "add": {
+                // leave it to open-ended! source, java_version, java_full_version
+                // can be passed via this option like:
+                //
+                //     --release-info add:build_type=fastdebug,source=openjdk,java_version=9
+                // and put whatever value that was passed in command line.
 
-                    config.keySet().stream().
-                        filter(s -> !NAME.equals(s)).
-                        forEach(s -> release.put(s, config.get(s)));
+                config.keySet().stream().
+                    filter(s -> !NAME.equals(s)).
+                    forEach(s -> release.put(s, config.get(s)));
+            }
+            break;
+
+            case "del": {
+                // --release-info del:keys=openjdk,java_version
+                String[] keys = Utils.listParser.apply(config.get(KEYS));
+                for (String k : keys) {
+                    release.remove(k);
                 }
-                break;
+            }
+            break;
 
-                case "del": {
-                    // --release-info del:keys=openjdk,java_version
-                    String[] keys = Utils.listParser.apply(config.get(KEYS));
-                    for (String k : keys) {
-                        release.remove(k);
-                    }
+            default: {
+                // --release-info <file>
+                Properties props = new Properties();
+                try (FileInputStream fis = new FileInputStream(operation)) {
+                    props.load(fis);
+                } catch (IOException exp) {
+                    throw new RuntimeException(exp);
                 }
-                break;
-
-                default: {
-                    // --release-info <file>
-                    try (FileInputStream fis = new FileInputStream(operation)) {
-                        release.load(fis);
-                    } catch (IOException exp) {
-                        throw new RuntimeException(exp);
-                    }
-                }
-                break;
+                props.forEach((k, v) -> release.put(k.toString(), v.toString()));
             }
+            break;
         }
     }
 
     @Override
-    public List<String> process(ExecutableImage image) {
-        // Nothing to do! Release info copied already during configure!
-        return Collections.emptyList();
+    public void visit(ModulePool in, ModulePool out) {
+        in.transformAndCopy(Function.identity(), out);
+        out.getReleaseProperties().putAll(in.getReleaseProperties());
+        out.getReleaseProperties().putAll(release);
     }
 }
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StringSharingPlugin.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StringSharingPlugin.java	Mon May 16 14:47:27 2016 +0530
@@ -56,11 +56,11 @@
 import jdk.internal.jimage.decompressor.CompressIndexes;
 import jdk.internal.jimage.decompressor.SignatureParser;
 import jdk.internal.jimage.decompressor.StringSharingDecompressor;
-import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.internal.ModulePoolImpl;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.internal.ResourcePrevisitor;
 import jdk.tools.jlink.internal.StringTable;
 import jdk.tools.jlink.internal.Utils;
@@ -228,7 +228,7 @@
             }
         }
 
-        public byte[] transform(ModuleData resource, Pool out,
+        public byte[] transform(ModuleEntry resource, ModulePool out,
                 StringTable strings) throws IOException, Exception {
             byte[] content = resource.getBytes();
             ClassFile cf;
@@ -243,7 +243,7 @@
         }
 
         @SuppressWarnings("fallthrough")
-        private byte[] optimize(ModuleData resource, Pool resources,
+        private byte[] optimize(ModuleEntry resource, ModulePool resources,
                 StringTable strings,
                 Set<Integer> descriptorIndexes, byte[] content) throws Exception {
             DataInputStream stream = new DataInputStream(new ByteArrayInputStream(content));
@@ -348,27 +348,27 @@
     }
 
     @Override
-    public Set<PluginType> getType() {
-        Set<PluginType> set = new HashSet<>();
-        set.add(CATEGORY.COMPRESSOR);
+    public Set<Category> getType() {
+        Set<Category> set = new HashSet<>();
+        set.add(Category.COMPRESSOR);
         return Collections.unmodifiableSet(set);
     }
 
     @Override
-    public void visit(Pool in, Pool result) {
+    public void visit(ModulePool in, ModulePool result) {
         CompactCPHelper visit = new CompactCPHelper();
-        in.visit((resource) -> {
-            ModuleData res = resource;
+        in.transformAndCopy((resource) -> {
+            ModuleEntry res = resource;
             if (predicate.test(resource.getPath()) && resource.getPath().endsWith(".class")) {
                 byte[] compressed = null;
                 try {
-                    compressed = visit.transform(resource, result, ((PoolImpl) in).getStringTable());
+                    compressed = visit.transform(resource, result, ((ModulePoolImpl) in).getStringTable());
                 } catch (Exception ex) {
                     throw new PluginException(ex);
                 }
-                res = PoolImpl.newCompressedResource(resource,
+                res = ModulePoolImpl.newCompressedResource(resource,
                         ByteBuffer.wrap(compressed), getName(), null,
-                        ((PoolImpl) in).getStringTable(), in.getByteOrder());
+                        ((ModulePoolImpl) in).getStringTable(), in.getByteOrder());
             }
             return res;
         }, result);
@@ -405,10 +405,10 @@
     }
 
     @Override
-    public void previsit(Pool resources, StringTable strings) {
+    public void previsit(ModulePool resources, StringTable strings) {
         CompactCPHelper preVisit = new CompactCPHelper();
-        for (ModuleData resource : resources.getContent()) {
-            if (resource.getType().equals(Pool.ModuleDataType.CLASS_OR_RESOURCE)
+        resources.entries().forEach(resource -> {
+            if (resource.getType().equals(ModuleEntry.Type.CLASS_OR_RESOURCE)
                     && resource.getPath().endsWith(".class") && predicate.test(resource.getPath())) {
                 try {
                     preVisit.transform(resource, null, strings);
@@ -416,6 +416,6 @@
                     throw new PluginException(ex);
                 }
             }
-        }
+        });
     }
 }
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripDebugPlugin.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripDebugPlugin.java	Mon May 16 14:47:27 2016 +0530
@@ -29,14 +29,12 @@
 import java.io.UncheckedIOException;
 import java.util.Collections;
 import java.util.HashSet;
-import java.util.Map;
 import java.util.Set;
 import java.util.function.Predicate;
 import jdk.internal.org.objectweb.asm.ClassReader;
 import jdk.internal.org.objectweb.asm.ClassWriter;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
-import jdk.tools.jlink.plugin.Pool.ModuleDataType;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 
 /**
@@ -61,9 +59,9 @@
     }
 
     @Override
-    public Set<PluginType> getType() {
-        Set<PluginType> set = new HashSet<>();
-        set.add(CATEGORY.TRANSFORMER);
+    public Set<Category> getType() {
+        Set<Category> set = new HashSet<>();
+        set.add(Category.TRANSFORMER);
         return Collections.unmodifiableSet(set);
     }
 
@@ -73,11 +71,11 @@
     }
 
     @Override
-    public void visit(Pool in, Pool out) {
+    public void visit(ModulePool in, ModulePool out) {
         //remove *.diz files as well as debug attributes.
-        in.visit((resource) -> {
-            ModuleData res = resource;
-            if (resource.getType().equals(ModuleDataType.CLASS_OR_RESOURCE)) {
+        in.transformAndCopy((resource) -> {
+            ModuleEntry res = resource;
+            if (resource.getType().equals(ModuleEntry.Type.CLASS_OR_RESOURCE)) {
                 String path = resource.getPath();
                 if (path.endsWith(".class")) {
                     if (path.endsWith("module-info.class")) {
@@ -87,7 +85,7 @@
                         ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
                         reader.accept(writer, ClassReader.SKIP_DEBUG);
                         byte[] content = writer.toByteArray();
-                        res = Pool.newResource(path, new ByteArrayInputStream(content), content.length);
+                        res = ModuleEntry.create(path, new ByteArrayInputStream(content), content.length);
                     }
                 }
             } else if (predicate.test(res.getPath())) {
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripNativeCommandsPlugin.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StripNativeCommandsPlugin.java	Mon May 16 14:47:27 2016 +0530
@@ -26,9 +26,9 @@
 
 import java.util.Collections;
 import java.util.HashSet;
-import java.util.Map;
 import java.util.Set;
-import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 
 /**
@@ -45,16 +45,16 @@
     }
 
     @Override
-    public Set<PluginType> getType() {
-        Set<PluginType> set = new HashSet<>();
-        set.add(CATEGORY.FILTER);
+    public Set<Category> getType() {
+        Set<Category> set = new HashSet<>();
+        set.add(Category.FILTER);
         return Collections.unmodifiableSet(set);
     }
 
     @Override
-    public void visit(Pool in, Pool out) {
-        in.visit((file) -> {
-            return file.getType() == Pool.ModuleDataType.NATIVE_CMD ? null : file;
+    public void visit(ModulePool in, ModulePool out) {
+        in.transformAndCopy((file) -> {
+            return file.getType() == ModuleEntry.Type.NATIVE_CMD ? null : file;
         }, out);
     }
 
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModuleDescriptorPlugin.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModuleDescriptorPlugin.java	Mon May 16 14:47:27 2016 +0530
@@ -36,6 +36,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -50,9 +51,10 @@
 
 import static jdk.internal.org.objectweb.asm.Opcodes.*;
 import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 import jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin.Builder.*;
+import jdk.tools.jlink.plugin.ModuleEntry;
 
 /**
  * Jlink plugin to reconstitute module descriptors for installed modules.
@@ -81,8 +83,8 @@
     }
 
     @Override
-    public Set<PluginType> getType() {
-        return Collections.singleton(CATEGORY.TRANSFORMER);
+    public Set<Category> getType() {
+        return Collections.singleton(Category.TRANSFORMER);
     }
 
     @Override
@@ -96,9 +98,9 @@
     }
 
     @Override
-    public Set<STATE> getState() {
-        return enabled ? EnumSet.of(STATE.AUTO_ENABLED, STATE.FUNCTIONAL)
-                       : EnumSet.of(STATE.DISABLED);
+    public Set<State> getState() {
+        return enabled ? EnumSet.of(State.AUTO_ENABLED, State.FUNCTIONAL)
+                       : EnumSet.of(State.DISABLED);
     }
 
     @Override
@@ -110,7 +112,7 @@
 
 
     @Override
-    public void visit(Pool in, Pool out) {
+    public void visit(ModulePool in, ModulePool out) {
         if (!enabled) {
             throw new PluginException(NAME + " was set");
         }
@@ -119,13 +121,14 @@
 
         // generate the byte code to create ModuleDescriptors
         // skip parsing module-info.class and skip name check
-        for (Pool.Module module : in.getModules()) {
-            Pool.ModuleData data = module.get("module-info.class");
-            if (data == null) {
+        in.modules().forEach(module -> {
+            Optional<ModuleEntry> optData = module.findEntry("module-info.class");
+            if (! optData.isPresent()) {
                 // automatic module not supported yet
                 throw new PluginException("module-info.class not found for " +
                                           module.getName() + " module");
             }
+            ModuleEntry data = optData.get();
             assert module.getName().equals(data.getModule());
             try {
                 ByteArrayInputStream bain = new ByteArrayInputStream(data.getBytes());
@@ -141,7 +144,7 @@
                     ModuleInfoRewriter minfoWriter =
                         new ModuleInfoRewriter(bain, mbuilder.conceals());
                     // replace with the overridden version
-                    data = new Pool.ModuleData(data.getModule(),
+                    data = ModuleEntry.create(data.getModule(),
                                                data.getPath(),
                                                data.getType(),
                                                minfoWriter.stream(),
@@ -151,19 +154,17 @@
             } catch (IOException e) {
                 throw new PluginException(e);
             }
-
-        }
+        });
 
         // Generate the new class
         ClassWriter cwriter = builder.build();
-        for (Pool.ModuleData data : in.getContent()) {
+        in.entries().forEach(data -> {
             if (data.getPath().endsWith("module-info.class"))
-                continue;
-
+                return;
             if (builder.isOverriddenClass(data.getPath())) {
                 byte[] bytes = cwriter.toByteArray();
-                Pool.ModuleData ndata =
-                    new Pool.ModuleData(data.getModule(),
+                ModuleEntry ndata =
+                    ModuleEntry.create(data.getModule(),
                                         data.getPath(),
                                         data.getType(),
                                         new ByteArrayInputStream(bytes),
@@ -172,7 +173,7 @@
             } else {
                 out.add(data);
             }
-        }
+        });
     }
 
     /*
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ZipPlugin.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ZipPlugin.java	Mon May 16 14:47:27 2016 +0530
@@ -34,10 +34,9 @@
 import java.util.function.Predicate;
 import java.util.zip.Deflater;
 import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.internal.PoolImpl;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
-import jdk.tools.jlink.plugin.Pool.ModuleDataType;
+import jdk.tools.jlink.internal.ModulePoolImpl;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 import jdk.tools.jlink.internal.Utils;
 
@@ -68,9 +67,9 @@
     }
 
     @Override
-    public Set<PluginType> getType() {
-        Set<PluginType> set = new HashSet<>();
-        set.add(CATEGORY.COMPRESSOR);
+    public Set<Category> getType() {
+        Set<Category> set = new HashSet<>();
+        set.add(Category.COMPRESSOR);
         return Collections.unmodifiableSet(set);
     }
 
@@ -124,16 +123,16 @@
     }
 
     @Override
-    public void visit(Pool in, Pool out) {
-        in.visit((resource) -> {
-            ModuleData res = resource;
-            if (resource.getType().equals(ModuleDataType.CLASS_OR_RESOURCE)
+    public void visit(ModulePool in, ModulePool out) {
+        in.transformAndCopy((resource) -> {
+            ModuleEntry res = resource;
+            if (resource.getType().equals(ModuleEntry.Type.CLASS_OR_RESOURCE)
                     && predicate.test(resource.getPath())) {
                 byte[] compressed;
                 compressed = compress(resource.getBytes());
-                res = PoolImpl.newCompressedResource(resource,
+                res = ModulePoolImpl.newCompressedResource(resource,
                         ByteBuffer.wrap(compressed), getName(), null,
-                        ((PoolImpl) in).getStringTable(), in.getByteOrder());
+                        ((ModulePoolImpl) in).getStringTable(), in.getByteOrder());
             }
             return res;
         }, out);
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/asm/AsmPlugin.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/asm/AsmPlugin.java	Mon May 16 14:47:27 2016 +0530
@@ -26,9 +26,9 @@
 
 import java.util.Objects;
 import jdk.tools.jlink.plugin.TransformerPlugin;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
-import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
+import jdk.tools.jlink.internal.ModulePoolImpl;
 
 /**
  * Extend this class to develop your own plugin in order to transform jimage
@@ -41,17 +41,17 @@
     }
 
     @Override
-    public void visit(Pool allContent, Pool outResources) {
+    public void visit(ModulePool allContent, ModulePool outResources) {
         Objects.requireNonNull(allContent);
         Objects.requireNonNull(outResources);
-        PoolImpl resources = new PoolImpl(allContent.getByteOrder());
-        for(ModuleData md : allContent.getContent()) {
-            if(md.getType().equals(Pool.ModuleDataType.CLASS_OR_RESOURCE)) {
+        ModulePoolImpl resources = new ModulePoolImpl(allContent.getByteOrder());
+        allContent.entries().forEach(md -> {
+            if(md.getType().equals(ModuleEntry.Type.CLASS_OR_RESOURCE)) {
                 resources.add(md);
             } else {
                 outResources.add(md);
             }
-        }
+        });
         AsmPools pools = new AsmPools(resources);
         visit(pools);
         pools.fillOutputResources(outResources);
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/asm/AsmPool.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/asm/AsmPool.java	Mon May 16 14:47:27 2016 +0530
@@ -24,13 +24,12 @@
  */
 package jdk.tools.jlink.internal.plugins.asm;
 
-import java.io.InputStream;
-import java.nio.ByteBuffer;
 import java.util.Collection;
 import java.util.List;
 import jdk.internal.org.objectweb.asm.ClassReader;
 import jdk.internal.org.objectweb.asm.ClassWriter;
-import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 
 /**
  * A pool of ClassReader and other resource files.
@@ -138,14 +137,14 @@
          * @return The ClassReader or null if the class is not found.
          * @throws jdk.tools.jlink.plugin.PluginException
          */
-        public ClassReader getClassReader(Pool.ModuleData res);
+        public ClassReader getClassReader(ModuleEntry res);
 
         /**
          * Returns all the classes contained in the writable pool.
          *
          * @return The collection of classes.
          */
-        public Collection<Pool.ModuleData> getClasses();
+        public Collection<ModuleEntry> getClasses();
     }
 
     /**
@@ -185,14 +184,14 @@
          * @param res The java resource
          * @return The Resource or null if the resource is not found.
          */
-        public ResourceFile getResourceFile(Pool.ModuleData res);
+        public ResourceFile getResourceFile(ModuleEntry res);
 
         /**
          * Returns all the resources contained in the writable pool.
          *
          * @return The array of resources.
          */
-        public Collection<Pool.ModuleData> getResourceFiles();
+        public Collection<ModuleEntry> getResourceFiles();
     }
 
     /**
@@ -206,7 +205,7 @@
          * @return The resource paths ordered in the way to use for storage in the jimage.
          * @throws jdk.tools.jlink.plugin.PluginException
          */
-        public List<String> sort(Pool resources);
+        public List<String> sort(ModulePool resources);
     }
 
     /**
@@ -237,7 +236,7 @@
      *
      * @return The classes.
      */
-    public Collection<Pool.ModuleData> getClasses();
+    public Collection<ModuleEntry> getClasses();
 
     /**
      * Returns the resources contained in the pool. Resources are all the file
@@ -245,7 +244,7 @@
      *
      * @return The array of resource files.
      */
-    public Collection<Pool.ModuleData> getResourceFiles();
+    public Collection<ModuleEntry> getResourceFiles();
 
     /**
      * Retrieves a resource based on the binary name. This name doesn't contain
@@ -266,7 +265,7 @@
      * @param res The resource
      * @return The resource file or null if it doesn't exist.
      */
-    public ResourceFile getResourceFile(Pool.ModuleData res);
+    public ResourceFile getResourceFile(ModuleEntry res);
 
     /**
      * Retrieve a ClassReader from the pool.
@@ -284,7 +283,7 @@
      * @return A reader or null if the class is unknown
      * @throws jdk.tools.jlink.plugin.PluginException
      */
-    public ClassReader getClassReader(Pool.ModuleData res);
+    public ClassReader getClassReader(ModuleEntry res);
 
     /**
      * To visit the set of ClassReaders.
@@ -310,6 +309,6 @@
      * @param output The pool used to fill the jimage.
      * @throws jdk.tools.jlink.plugin.PluginException
      */
-    public void fillOutputResources(Pool output);
+    public void fillOutputResources(ModulePool output);
 
 }
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/asm/AsmPoolImpl.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/asm/AsmPoolImpl.java	Mon May 16 14:47:27 2016 +0530
@@ -41,15 +41,14 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
-import java.util.Optional;
 import java.util.Set;
 import jdk.internal.org.objectweb.asm.ClassReader;
 import jdk.internal.org.objectweb.asm.ClassWriter;
 import jdk.tools.jlink.internal.ImageFileCreator;
-import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.internal.ModulePoolImpl;
+import jdk.tools.jlink.plugin.ModuleEntry;
 import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.ModulePool;
 
 /**
  * A pool of ClassReader and other resource files. This class allows to
@@ -94,7 +93,7 @@
             }
 
             byte[] content = writer.toByteArray();
-            ModuleData res = Pool.newResource(path,
+            ModuleEntry res = ModuleEntry.create(path,
                     new ByteArrayInputStream(content), content.length);
             transformedClasses.put(className, res);
         }
@@ -108,7 +107,7 @@
         public void forgetClass(String className) {
             Objects.requireNonNull(className);
             // do we have a resource?
-            ModuleData res = transformedClasses.get(className);
+            ModuleEntry res = transformedClasses.get(className);
             if (res == null) {
                 res = inputClasses.get(className);
                 if (res == null) {
@@ -130,7 +129,7 @@
         @Override
         public ClassReader getClassReader(String binaryName) {
             Objects.requireNonNull(binaryName);
-            ModuleData res = transformedClasses.get(binaryName);
+            ModuleEntry res = transformedClasses.get(binaryName);
             ClassReader reader = null;
             if (res != null) {
                 reader = getClassReader(res);
@@ -144,16 +143,16 @@
          * @return The array of transformed classes.
          */
         @Override
-        public Collection<ModuleData> getClasses() {
-            List<ModuleData> classes = new ArrayList<>();
-            for (Entry<String, ModuleData> entry : transformedClasses.entrySet()) {
+        public Collection<ModuleEntry> getClasses() {
+            List<ModuleEntry> classes = new ArrayList<>();
+            for (Entry<String, ModuleEntry> entry : transformedClasses.entrySet()) {
                 classes.add(entry.getValue());
             }
             return classes;
         }
 
         @Override
-        public ClassReader getClassReader(ModuleData res) {
+        public ClassReader getClassReader(ModuleEntry res) {
             return newClassReader(res.getBytes());
         }
     }
@@ -176,7 +175,7 @@
         public void addResourceFile(ResourceFile resFile) {
             Objects.requireNonNull(resFile);
             String path = toResourceNamePath(resFile.getPath());
-            ModuleData res = Pool.newResource(path, resFile.getContent());
+            ModuleEntry res = ModuleEntry.create(path, resFile.getContent());
             transformedResources.put(resFile.getPath(), res);
         }
 
@@ -191,7 +190,7 @@
             Objects.requireNonNull(resourceName);
             String path = toResourceNamePath(resourceName);
             // do we have a resource?
-            ModuleData res = transformedResources.get(resourceName);
+            ModuleEntry res = transformedResources.get(resourceName);
             if (res == null) {
                 res = inputResources.get(resourceName);
                 if (res == null) {
@@ -212,7 +211,7 @@
         @Override
         public ResourceFile getResourceFile(String name) {
             Objects.requireNonNull(name);
-            ModuleData res = transformedResources.get(name);
+            ModuleEntry res = transformedResources.get(name);
             ResourceFile resFile = null;
             if (res != null) {
                 resFile = getResourceFile(res);
@@ -226,24 +225,24 @@
          * @return The array of transformed classes.
          */
         @Override
-        public Collection<ModuleData> getResourceFiles() {
-            List<ModuleData> resources = new ArrayList<>();
-            for (Entry<String, ModuleData> entry : transformedResources.entrySet()) {
+        public Collection<ModuleEntry> getResourceFiles() {
+            List<ModuleEntry> resources = new ArrayList<>();
+            for (Entry<String, ModuleEntry> entry : transformedResources.entrySet()) {
                 resources.add(entry.getValue());
             }
             return resources;
         }
 
         @Override
-        public ResourceFile getResourceFile(ModuleData res) {
+        public ResourceFile getResourceFile(ModuleEntry res) {
             return new ResourceFile(toJavaBinaryResourceName(res.getPath()),
                     res.getBytes());
         }
     }
 
-    private final Pool jimageResources;
-    private final Map<String, ModuleData> inputClasses;
-    private final Map<String, ModuleData> inputResources;
+    private final ModulePool jimageResources;
+    private final Map<String, ModuleEntry> inputClasses;
+    private final Map<String, ModuleEntry> inputResources;
     private final Map<String, String> inputClassPackageMapping;
     private final Map<String, String> inputOtherPackageMapping;
 
@@ -254,9 +253,9 @@
 
     private Sorter sorter;
 
-    private final Map<String, ModuleData> transformedClasses
+    private final Map<String, ModuleEntry> transformedClasses
             =            new LinkedHashMap<>();
-    private final Map<String, ModuleData> transformedResources
+    private final Map<String, ModuleEntry> transformedResources
             =            new LinkedHashMap<>();
     private final List<String> forgetResources = new ArrayList<>();
     private final Map<String, String> newPackageMapping = new HashMap<>();
@@ -274,7 +273,7 @@
      * @param pools The resource pools.
      * @param descriptor The module descriptor.
      */
-    AsmPoolImpl(Pool inputResources, String moduleName,
+    AsmPoolImpl(ModulePool inputResources, String moduleName,
             AsmPools pools,
             ModuleDescriptor descriptor) {
         Objects.requireNonNull(inputResources);
@@ -285,11 +284,11 @@
         this.moduleName = moduleName;
         this.pools = pools;
         this.descriptor = descriptor;
-        Map<String, ModuleData> classes = new LinkedHashMap<>();
-        Map<String, ModuleData> resources = new LinkedHashMap<>();
+        Map<String, ModuleEntry> classes = new LinkedHashMap<>();
+        Map<String, ModuleEntry> resources = new LinkedHashMap<>();
         Map<String, String> packageClassToModule = new HashMap<>();
         Map<String, String> packageOtherToModule = new HashMap<>();
-        for (ModuleData res : inputResources.getContent()) {
+        inputResources.entries().forEach(res -> {
             if (res.getPath().endsWith(".class")) {
                 classes.put(toJavaBinaryClassName(res.getPath()), res);
             } else {
@@ -305,7 +304,7 @@
                     packageOtherToModule.put(split[1], res.getModule());
                 }
             }
-        }
+        });
         this.inputClasses = Collections.unmodifiableMap(classes);
         this.inputResources = Collections.unmodifiableMap(resources);
 
@@ -356,7 +355,7 @@
      * @return The array of classes.
      */
     @Override
-    public Collection<ModuleData> getClasses() {
+    public Collection<ModuleEntry> getClasses() {
         return inputClasses.values();
     }
 
@@ -367,7 +366,7 @@
      * @return The array of classes.
      */
     @Override
-    public Collection<ModuleData> getResourceFiles() {
+    public Collection<ModuleEntry> getResourceFiles() {
         return inputResources.values();
     }
 
@@ -385,7 +384,7 @@
     @Override
     public ResourceFile getResourceFile(String binaryName) {
         Objects.requireNonNull(binaryName);
-        ModuleData res = inputResources.get(binaryName);
+        ModuleEntry res = inputResources.get(binaryName);
         ResourceFile resFile = null;
         if (res != null) {
             resFile = getResourceFile(res);
@@ -402,7 +401,7 @@
     @Override
     public ClassReader getClassReader(String binaryName) {
         Objects.requireNonNull(binaryName);
-        ModuleData res = inputClasses.get(binaryName);
+        ModuleEntry res = inputClasses.get(binaryName);
         ClassReader reader = null;
         if (res != null) {
             reader = getClassReader(res);
@@ -411,13 +410,13 @@
     }
 
     @Override
-    public ResourceFile getResourceFile(ModuleData res) {
+    public ResourceFile getResourceFile(ModuleEntry res) {
         return new ResourceFile(toJavaBinaryResourceName(res.getPath()),
                 res.getBytes());
     }
 
     @Override
-    public ClassReader getClassReader(ModuleData res) {
+    public ClassReader getClassReader(ModuleEntry res) {
         return newClassReader(res.getBytes());
     }
 
@@ -505,7 +504,7 @@
     @Override
     public void visitClassReaders(ClassReaderVisitor visitor) {
         Objects.requireNonNull(visitor);
-        for (ModuleData res : getClasses()) {
+        for (ModuleEntry res : getClasses()) {
             ClassReader reader = newClassReader(res.getBytes());
             ClassWriter writer = visitor.visit(reader);
             if (writer != null) {
@@ -523,7 +522,7 @@
     @Override
     public void visitResourceFiles(ResourceFileVisitor visitor) {
         Objects.requireNonNull(visitor);
-        for (ModuleData resource : getResourceFiles()) {
+        for (ModuleEntry resource : getResourceFiles()) {
             ResourceFile resFile
                     = new ResourceFile(toJavaBinaryResourceName(resource.getPath()),
                             resource.getBytes());
@@ -540,18 +539,18 @@
      * been set, it is used to sort the returned resources.     *
      */
     @Override
-    public void fillOutputResources(Pool outputResources) {
+    public void fillOutputResources(ModulePool outputResources) {
         List<String> added = new ArrayList<>();
         // If the sorter is null, use the input order.
         // New resources are added at the end
         // First input classes that have not been removed
-        Pool output = new PoolImpl(outputResources.getByteOrder(),
-                ((PoolImpl)outputResources).getStringTable());
-        for (ModuleData inResource : jimageResources.getContent()) {
+        ModulePool output = new ModulePoolImpl(outputResources.getByteOrder(),
+                ((ModulePoolImpl)outputResources).getStringTable());
+        jimageResources.entries().forEach(inResource -> {
             if (!forgetResources.contains(inResource.getPath())) {
-                ModuleData resource = inResource;
+                ModuleEntry resource = inResource;
                 // Do we have a transformed class with the same name?
-                ModuleData res = transformedResources.
+                ModuleEntry res = transformedResources.
                         get(toJavaBinaryResourceName(inResource.getPath()));
                 if (res != null) {
                     resource = res;
@@ -565,10 +564,10 @@
                 output.add(resource);
                 added.add(resource.getPath());
             }
-        }
+        });
         // Then new resources
-        for (Map.Entry<String, ModuleData> entry : transformedResources.entrySet()) {
-            ModuleData resource = entry.getValue();
+        for (Map.Entry<String, ModuleEntry> entry : transformedResources.entrySet()) {
+            ModuleEntry resource = entry.getValue();
             if (!forgetResources.contains(resource.getPath())) {
                 if (!added.contains(resource.getPath())) {
                     output.add(resource);
@@ -576,8 +575,8 @@
             }
         }
         // And new classes
-        for (Map.Entry<String, ModuleData> entry : transformedClasses.entrySet()) {
-            ModuleData resource = entry.getValue();
+        for (Map.Entry<String, ModuleEntry> entry : transformedClasses.entrySet()) {
+            ModuleEntry resource = entry.getValue();
             if (!forgetResources.contains(resource.getPath())) {
                 if (!added.contains(resource.getPath())) {
                     output.add(resource);
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/asm/AsmPools.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/asm/AsmPools.java	Mon May 16 14:47:27 2016 +0530
@@ -41,11 +41,11 @@
 import java.util.Set;
 import jdk.internal.org.objectweb.asm.ClassReader;
 import jdk.internal.org.objectweb.asm.ClassWriter;
-import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.internal.ModulePoolImpl;
 import jdk.tools.jlink.internal.plugins.asm.AsmPool.Sorter;
+import jdk.tools.jlink.plugin.ModuleEntry;
 import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.ModulePool;
 
 /**
  * A container for pools of ClassReader and other resource files. A pool of all
@@ -97,10 +97,10 @@
             }
 
             @Override
-            public Collection<Pool.ModuleData> getClasses() {
-                List<Pool.ModuleData> all = new ArrayList<>();
+            public Collection<ModuleEntry> getClasses() {
+                List<ModuleEntry> all = new ArrayList<>();
                 visitAllPools((AsmModulePool pool) -> {
-                    for (Pool.ModuleData rf : pool.getTransformedClasses().getClasses()) {
+                    for (ModuleEntry rf : pool.getTransformedClasses().getClasses()) {
                         all.add(rf);
                     }
                 });
@@ -108,7 +108,7 @@
             }
 
             @Override
-            public ClassReader getClassReader(Pool.ModuleData res) {
+            public ClassReader getClassReader(ModuleEntry res) {
                 return visitPools((AsmModulePool pool) -> {
                     return pool.getTransformedClasses().getClassReader(res);
                 });
@@ -140,10 +140,10 @@
             }
 
             @Override
-            public Collection<Pool.ModuleData> getResourceFiles() {
-                List<Pool.ModuleData> all = new ArrayList<>();
+            public Collection<ModuleEntry> getResourceFiles() {
+                List<ModuleEntry> all = new ArrayList<>();
                 visitAllPools((AsmModulePool pool) -> {
-                    for (Pool.ModuleData rf : pool.getTransformedResourceFiles().getResourceFiles()) {
+                    for (ModuleEntry rf : pool.getTransformedResourceFiles().getResourceFiles()) {
                         all.add(rf);
                     }
                 });
@@ -151,7 +151,7 @@
             }
 
             @Override
-            public ResourceFile getResourceFile(Pool.ModuleData res) {
+            public ResourceFile getResourceFile(ModuleEntry res) {
                 return visitPools((AsmModulePool pool) -> {
                     return pool.getTransformedResourceFiles().getResourceFile(res);
                 });
@@ -175,10 +175,10 @@
         }
 
         @Override
-        public Collection<Pool.ModuleData> getClasses() {
-            List<Pool.ModuleData> all = new ArrayList<>();
+        public Collection<ModuleEntry> getClasses() {
+            List<ModuleEntry> all = new ArrayList<>();
             visitAllPools((AsmModulePool pool) -> {
-                for (Pool.ModuleData rf : pool.getClasses()) {
+                for (ModuleEntry rf : pool.getClasses()) {
                     all.add(rf);
                 }
             });
@@ -186,10 +186,10 @@
         }
 
         @Override
-        public Collection<Pool.ModuleData> getResourceFiles() {
-            List<Pool.ModuleData> all = new ArrayList<>();
+        public Collection<ModuleEntry> getResourceFiles() {
+            List<ModuleEntry> all = new ArrayList<>();
             visitAllPools((AsmModulePool pool) -> {
-                for (Pool.ModuleData rf : pool.getResourceFiles()) {
+                for (ModuleEntry rf : pool.getResourceFiles()) {
                     all.add(rf);
                 }
             });
@@ -211,14 +211,14 @@
         }
 
         @Override
-        public ResourceFile getResourceFile(Pool.ModuleData res) {
+        public ResourceFile getResourceFile(ModuleEntry res) {
             return visitPools((AsmModulePool pool) -> {
                 return pool.getResourceFile(res);
             });
         }
 
         @Override
-        public ClassReader getClassReader(Pool.ModuleData res) {
+        public ClassReader getClassReader(ModuleEntry res) {
             return visitPoolsEx((AsmModulePool pool) -> {
                 return pool.getClassReader(res);
             });
@@ -239,7 +239,7 @@
         }
 
         @Override
-        public void fillOutputResources(Pool outputResources) {
+        public void fillOutputResources(ModulePool outputResources) {
             AsmPools.this.fillOutputResources(outputResources);
         }
 
@@ -324,15 +324,15 @@
      *
      * @param inputResources The raw resources to build the pool from.
      */
-    public AsmPools(Pool inputResources) {
+    public AsmPools(ModulePool inputResources) {
         Objects.requireNonNull(inputResources);
-        Map<String, Pool> resPools = new LinkedHashMap<>();
+        Map<String, ModulePool> resPools = new LinkedHashMap<>();
         Map<String, ModuleDescriptor> descriptors = new HashMap<>();
-        for (Pool.ModuleData res : inputResources.getContent()) {
-            Pool p = resPools.get(res.getModule());
+        inputResources.entries().forEach(res -> {
+            ModulePool p = resPools.get(res.getModule());
             if (p == null) {
-                p = new PoolImpl(inputResources.getByteOrder(),
-                        ((PoolImpl)inputResources).getStringTable());
+                p = new ModulePoolImpl(inputResources.getByteOrder(),
+                        ((ModulePoolImpl)inputResources).getStringTable());
                 resPools.put(res.getModule(), p);
             }
             if (res.getPath().endsWith("module-info.class")) {
@@ -341,11 +341,11 @@
                 descriptors.put(res.getModule(), descriptor);
             }
             p.add(res);
-        }
+        });
         poolsArray = new AsmModulePool[resPools.size()];
         int i = 0;
 
-        for (Entry<String, Pool> entry : resPools.entrySet()) {
+        for (Entry<String, ModulePool> entry : resPools.entrySet()) {
             ModuleDescriptor descriptor = descriptors.get(entry.getKey());
             if (descriptor == null) {
                 throw new PluginException("module-info.class not found for " + entry.getKey() + " module");
@@ -405,7 +405,7 @@
      *
      * @param outputResources The pool used to fill the jimage.
      */
-    public void fillOutputResources(Pool outputResources) {
+    public void fillOutputResources(ModulePool outputResources) {
         // First sort modules
         List<String> modules = new ArrayList<>();
         for (String k : pools.keySet()) {
@@ -414,8 +414,8 @@
         if (moduleSorter != null) {
             modules = moduleSorter.sort(modules);
         }
-        Pool output = new PoolImpl(outputResources.getByteOrder(),
-                ((PoolImpl)outputResources).getStringTable());
+        ModulePool output = new ModulePoolImpl(outputResources.getByteOrder(),
+                ((ModulePoolImpl)outputResources).getStringTable());
         for (String mn : modules) {
             AsmPool pool = pools.get(mn);
             pool.fillOutputResources(output);
@@ -423,17 +423,17 @@
         sort(outputResources, output, global.sorter);
     }
 
-    static void sort(Pool outputResources,
-            Pool transientOutput, Sorter sorter) {
+    static void sort(ModulePool outputResources,
+            ModulePool transientOutput, Sorter sorter) {
         if (sorter != null) {
             List<String> order = sorter.sort(transientOutput);
             for (String s : order) {
-                outputResources.add(transientOutput.get(s));
+                outputResources.add(transientOutput.findEntry(s).get());
             }
         } else {
-            for (ModuleData res : transientOutput.getContent()) {
+            transientOutput.entries().forEach(res-> {
                 outputResources.add(res);
-            }
+            });
         }
     }
 
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/ExecutableImage.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/ExecutableImage.java	Mon May 16 14:47:27 2016 +0530
@@ -24,66 +24,41 @@
  */
 package jdk.tools.jlink.plugin;
 
-import java.nio.file.Files;
 import java.nio.file.Path;
-import java.util.Collections;
 import java.util.List;
-import java.util.Objects;
 import java.util.Set;
 
 /**
- * An executable runtime image. Instance of this class contains the information
- * needed to create image processes.
+ * An executable runtime image. Contains the information about the executable
+ * image created.
  */
-public abstract class ExecutableImage {
-
-    private final Path home;
-    private final List<String> args;
-    private final Set<String> modules;
-
-    protected ExecutableImage(Path home, Set<String> modules,
-            List<String> args) {
-        Objects.requireNonNull(home);
-        Objects.requireNonNull(args);
-        if (!Files.exists(home)) {
-            throw new IllegalArgumentException("Invalid image home");
-        }
-        this.home = home;
-        this.modules = Collections.unmodifiableSet(modules);
-        this.args = Collections.unmodifiableList(args);
-    }
+public interface ExecutableImage {
 
     /**
      * Image home directory,
      *
      * @return The home directory.
      */
-    public Path getHome() {
-        return home;
-    }
+    public Path getHome();
 
     /**
      * The names of the modules located in the image.
      *
      * @return The set of modules.
      */
-    public Set<String> getModules() {
-        return modules;
-    }
+    public Set<String> getModules();
 
     /**
      * The list of arguments required to execute the image.
      *
      * @return The list of arguments.
      */
-    public List<String> getExecutionArgs() {
-        return args;
-    }
+    public List<String> getExecutionArgs();
 
     /**
      * Store new arguments required to execute the image.
      *
      * @param args Additional arguments
      */
-    public abstract void storeLaunchArgs(List<String> args);
+    public void storeLaunchArgs(List<String> args);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/LinkModule.java	Mon May 16 14:47:27 2016 +0530
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2016, 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
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.plugin;
+
+import java.lang.module.ModuleDescriptor;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Stream;
+
+/**
+  * Link-time representation of a Java module.
+  */
+public interface LinkModule {
+
+    /**
+     * The module name.
+     *
+     * @return The name.
+     */
+    public String getName();
+
+    /**
+     * Retrieves a LinkModuleEntry from the given path (e.g:
+     * /mymodule/com.foo.bar/MyClass.class)
+     *
+     * @param path The piece of data path.
+     * @return A LinkModuleEntry of the given path, if found.
+     */
+    public Optional<ModuleEntry> findEntry(String path);
+
+    /**
+     * The module descriptor of this module.
+     *
+     * @return The module descriptor.
+     */
+    public ModuleDescriptor getDescriptor();
+
+    /**
+     * Add a LinkModuleEntry to this module.
+     *
+     * @param data The LinkModuleEntry to add.
+     */
+    public void add(ModuleEntry data);
+
+    /**
+     * Retrieves all the packages located in this module.
+     *
+     * @return The set of packages.
+     */
+    public Set<String> getAllPackages();
+
+    /**
+     * Retrieves the stream of LinkModuleEntry.
+     *
+     * @return The LinkModuleEntry stream.
+     */
+    public Stream<? extends ModuleEntry> entries();
+
+    /**
+     * Return the number of LinkModuleEntry count in this LinkModule.
+     *
+     * @return the entry count.
+     */
+    public int getEntryCount();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/ModuleEntry.java	Mon May 16 14:47:27 2016 +0530
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2016, 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
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.plugin;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.Objects;
+import jdk.tools.jlink.internal.ImageFileCreator;
+import jdk.tools.jlink.internal.ModuleEntryImpl;
+
+/**
+ * A LinkModuleEntry is the elementary unit of data inside an image. It is
+ * generally a file. e.g.: a java class file, a resource file, a shared library,
+ * ...
+ * <br>
+ * A LinkModuleEntry is identified by a path of the form:
+ * <ul>
+ * <li>For jimage content: /{module name}/{package1}/.../{packageN}/{file
+ * name}</li>
+ * <li>For other files (shared lib, launchers, config, ...):/{module name}/
+ * {@literal bin|conf|native}/{dir1}>/.../{dirN}/{file name}</li>
+ * </ul>
+ */
+public interface ModuleEntry {
+
+    /**
+     * Type of module data.
+     * <li>
+     * <ul>CLASS_OR_RESOURCE: A java class or resource file.</ul>
+     * <ul>CONFIG: A configuration file.</ul>
+     * <ul>NATIVE_CMD: A native process launcher.</ul>
+     * <ul>NATIVE_LIB: A native library.</ul>
+     * <ul>OTHER: Other kind of file.</ul>
+     * </li>
+     */
+    public enum Type {
+        CLASS_OR_RESOURCE,
+        CONFIG,
+        NATIVE_CMD,
+        NATIVE_LIB,
+        OTHER
+    }
+    /**
+     * The LinkModuleEntry module name.
+     *
+     * @return The module name.
+     */
+    public String getModule();
+
+    /**
+     * The LinkModuleEntry path.
+     *
+     * @return The module path.
+     */
+    public String getPath();
+
+    /**
+     * The LinkModuleEntry's type.
+     *
+     * @return The data type.
+     */
+    public Type getType();
+
+    /**
+     * The LinkModuleEntry content as an array of byte.
+     *
+     * @return An Array of bytes.
+     */
+    public byte[] getBytes();
+
+    /**
+     * The LinkModuleEntry content length.
+     *
+     * @return The length.
+     */
+    public long getLength();
+
+    /**
+     * The LinkModuleEntry stream.
+     *
+     * @return The module data stream.
+     */
+    public InputStream stream();
+
+
+    /**
+     * Create a LinkModuleEntry located inside a jimage file. Such
+     * LinkModuleEntry has a Type being equals to CLASS_OR_RESOURCE.
+     *
+     * @param path The complete resource path (contains the module radical).
+     * @param content The resource content.
+     * @param size The content size.
+     * @return A new LinkModuleEntry.
+     */
+    public static ModuleEntry create(String path, InputStream content, long size) {
+        Objects.requireNonNull(path);
+        Objects.requireNonNull(content);
+        String[] split = ImageFileCreator.splitPath(path);
+        String module = split[0];
+        return new ModuleEntryImpl(module, path, Type.CLASS_OR_RESOURCE, content, size);
+    }
+
+    /**
+     * Create a LinkModuleEntry for a file that will be located inside a jimage
+     * file.
+     *
+     * @param path The resource path.
+     * @param content The resource content.
+     * @return A new LinkModuleEntry.
+     */
+    public static ModuleEntry create(String path, byte[] content) {
+        return create(path, new ByteArrayInputStream(content),
+                content.length);
+    }
+
+    /**
+     * Create a LinkModuleEntry for a file that will be located outside a jimage
+     * file.
+     *
+     * @param module The module in which this files is located.
+     * @param path The file path locator (doesn't contain the module name).
+     * @param type The LinkModuleEntry type.
+     * @param content The file content.
+     * @param size The content size.
+     * @return A new LinkModuleEntry.
+     */
+    public static ModuleEntry create(String module, String path, ModuleEntry.Type type,
+            InputStream content, long size) {
+        Objects.requireNonNull(path);
+        Objects.requireNonNull(content);
+        return new ModuleEntryImpl(module, path, type, content, size);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/ModulePool.java	Mon May 16 14:47:27 2016 +0530
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 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
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.tools.jlink.plugin;
+
+import java.nio.ByteOrder;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+/**
+ * Pool of module data.
+ */
+public interface ModulePool {
+/**
+     * Is this a read-only ModulePool?
+     *
+     * @return true if this is a read-only configuration.
+     */
+    public boolean isReadOnly();
+
+    /**
+     * Add a ModuleEntry.
+     *
+     * @param data The ModuleEntry to add.
+     */
+    public void add(ModuleEntry data);
+    /**
+     * Retrieves the module for the provided name.
+     *
+     * @param name The module name
+     * @return the module of matching name, if found
+     */
+    public Optional<LinkModule> findModule(String name);
+
+    /**
+     * The stream of modules contained in this ModulePool.
+     *
+     * @return The stream of modules.
+     */
+    public Stream<? extends LinkModule> modules();
+
+    /**
+     * Return the number of LinkModule count in this ModulePool.
+     *
+     * @return the module count.
+     */
+    public int getModuleCount();
+
+    /**
+     * Get all ModuleEntry contained in this ModulePool instance.
+     *
+     * @return The stream of LinkModuleEntries.
+     */
+    public Stream<? extends ModuleEntry> entries();
+
+    /**
+     * Return the number of ModuleEntry count in this ModulePool.
+     *
+     * @return the entry count.
+     */
+    public int getEntryCount();
+
+    /**
+     * Get the ModuleEntry for the passed path.
+     *
+     * @param path A data path
+     * @return A ModuleEntry instance or null if the data is not found
+     */
+   public Optional<ModuleEntry> findEntry(String path);
+
+    /**
+     * Check if the ModulePool contains the given ModuleEntry.
+     *
+     * @param data The module data to check existence for.
+     * @return The module data or null if not found.
+     */
+    public boolean contains(ModuleEntry data);
+
+    /**
+     * Check if the ModulePool contains some content at all.
+     *
+     * @return True, no content, false otherwise.
+     */
+    public boolean isEmpty();
+
+    /**
+     * Visit each ModuleEntry in this ModulePool to transform it and copy
+     * the transformed ModuleEntry to the output ModulePool.
+     *
+     * @param transform The function called for each ModuleEntry found in the
+     * ModulePool. The transform function should return a ModuleEntry
+     * instance which will be added to the output or it should return null if
+     * the passed ModuleEntry is to be ignored for the output.
+     *
+     * @param output The ModulePool to be filled with Visitor returned
+     * ModuleEntry.
+     */
+    public void transformAndCopy(Function<ModuleEntry, ModuleEntry> transform, ModulePool output);
+
+    /**
+     * The ByteOrder currently in use when generating the jimage file.
+     *
+     * @return The ByteOrder.
+     */
+    public ByteOrder getByteOrder();
+
+    /**
+     * Release properties such as OS, CPU name, version etc.
+     *
+     * @return the release properties
+     */
+    public Map<String, String> getReleaseProperties();
+}
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/Plugin.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/Plugin.java	Mon May 16 14:47:27 2016 +0530
@@ -26,7 +26,6 @@
 
 import java.util.Collections;
 import java.util.EnumSet;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import jdk.tools.jlink.internal.plugins.PluginsResourceBundle;
@@ -37,14 +36,6 @@
 public interface Plugin {
 
     /**
-     * Type of plugin.
-     */
-    public interface PluginType {
-
-        public String getName();
-    }
-
-    /**
      * Order of categories:
      * <ol>
      * <li>FILTER: Filter in/out resources or files.</li>
@@ -53,28 +44,29 @@
      * <li>MODULEINFO_TRANSFORMER: Transform only module-info.class</li>
      * <li>SORTER: Sort resources within the resource container.</li>
      * <li>COMPRESSOR: Compress resource within the resouce containers.</li>
+     * <li>METAINFO_ADDER: Added meta info (like release, copyright etc.)</li>
      * <li>VERIFIER: Does some image verification.</li>
      * <li>PROCESSOR: Does some post processing on image.</li>
      * <li>PACKAGER: Final processing</li>
      * </ol>
      */
-    public enum CATEGORY implements PluginType {
+    public enum Category {
         FILTER("FILTER"),
         TRANSFORMER("TRANSFORMER"),
         MODULEINFO_TRANSFORMER("MODULEINFO_TRANSFORMER"),
         SORTER("SORTER"),
         COMPRESSOR("COMPRESSOR"),
+        METAINFO_ADDER("METAINFO_ADDER"),
         VERIFIER("VERIFIER"),
         PROCESSOR("PROCESSOR"),
         PACKAGER("PACKAGER");
 
         private final String name;
 
-        CATEGORY(String name) {
+        Category(String name) {
             this.name = name;
         }
 
-        @Override
         public String getName() {
             return name;
         }
@@ -91,7 +83,7 @@
      * {@link #getStateDescription() getStateDescription} method</li>
      * </ul>
      */
-    public enum STATE {
+    public enum State {
         DISABLED,
         AUTO_ENABLED,
         FUNCTIONAL
@@ -101,7 +93,7 @@
      * The Plugin set of types.
      * @return The set of types.
      */
-    public default Set<PluginType> getType() {
+    public default Set<Category> getType() {
         return Collections.emptySet();
     }
 
@@ -109,8 +101,8 @@
      * The Plugin set of states.
      * @return The set of states.
      */
-    public default Set<STATE> getState() {
-        return EnumSet.of(STATE.FUNCTIONAL);
+    public default Set<State> getState() {
+        return EnumSet.of(State.FUNCTIONAL);
     }
 
     /**
@@ -191,7 +183,7 @@
      * @return A status description.
      */
     public default String getStateDescription() {
-        return getState().contains(STATE.FUNCTIONAL)
+        return getState().contains(State.FUNCTIONAL)
                 ? PluginsResourceBundle.getMessage("main.status.ok")
                 : PluginsResourceBundle.getMessage("main.status.not.ok");
     }
@@ -206,18 +198,4 @@
      */
     public default void configure(Map<String, String> config) {
     }
-
-    /**
-     * Configure the plugin based on the passed configuration.
-     * This method is called prior to invoke the plugin.
-     *
-     * @param config The plugin configuration.
-     * @param ctx The plugin context
-     * @throws IllegalArgumentException if a mandatory argument is missing or
-     * if an argument has invalid value.
-     *
-     */
-    public default void configure(Map<String, String> config, PluginContext ctx) {
-        configure(config);
-    }
 }
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/PluginContext.java	Mon May 16 09:54:01 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2016, 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
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.tools.jlink.plugin;
-
-import java.util.Properties;
-
-/**
- * Interface to plugin (container) context.
- */
-public interface PluginContext {
-    /**
-     * Returns 'release' properties
-     */
-    public Properties getReleaseProperties();
-}
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/Pool.java	Mon May 16 09:54:01 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,528 +0,0 @@
-/*
- * Copyright (c) 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
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.tools.jlink.plugin;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UncheckedIOException;
-import java.lang.module.ModuleDescriptor;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import jdk.tools.jlink.internal.ImageFileCreator;
-import jdk.tools.jlink.internal.plugins.FileCopierPlugin;
-
-/**
- * Pool of module data.
- *
- */
-public abstract class Pool {
-
-    /**
-     * Interface to visit the content of a Pool.
-     */
-    public interface Visitor {
-
-        /**
-         * Called for each visited ModuleData.
-         *
-         * @param content A ModuleData
-         * @return A ModuleData instance or null if the passed ModuleData is to
-         * be removed from the image.
-         * @throws PluginException
-         */
-        public ModuleData visit(ModuleData content);
-    }
-
-    /**
-     * Type of module data.
-     * <li>
-     * <ul>CLASS_OR_RESOURCE: A java class or resource file.</ul>
-     * <ul>CONFIG: A configuration file.</ul>
-     * <ul>NATIVE_CMD: A native process launcher.</ul>
-     * <ul>NATIVE_LIB: A native library.</ul>
-     * <ul>OTHER: Other kind of file.</ul>
-     * </li>
-     */
-    public static enum ModuleDataType {
-
-        CLASS_OR_RESOURCE,
-        CONFIG,
-        NATIVE_CMD,
-        NATIVE_LIB,
-        OTHER;
-    }
-
-    /**
-     * A module in the pool.
-     */
-    public interface Module {
-
-        /**
-         * The module name.
-         *
-         * @return The name.
-         */
-        public String getName();
-
-        /**
-         * Retrieves a ModuleData from a path (e.g:
-         * /mymodule/com.foo.bar/MyClass.class)
-         *
-         * @param path The piece of data path.
-         * @return A ModuleData or null if the path doesn't identify a
-         * ModuleData.
-         */
-        public ModuleData get(String path);
-
-        /**
-         * The module descriptor of this module.
-         *
-         * @return The module descriptor.
-         */
-        public ModuleDescriptor getDescriptor();
-
-        /**
-         * Add a ModuleData to this module.
-         *
-         * @param data The ModuleData to add.
-         */
-        public void add(ModuleData data);
-
-        /**
-         * Retrieves all the packages located in this module.
-         *
-         * @return The set of packages.
-         */
-        public Set<String> getAllPackages();
-
-        /**
-         * Retrieves the collection of ModuleData.
-         *
-         * @return The ModuleData collection.
-         */
-        public Collection<ModuleData> getContent();
-
-    }
-
-    private class ModuleImpl implements Module {
-
-        private final Map<String, ModuleData> moduleContent = new LinkedHashMap<>();
-        private ModuleDescriptor descriptor;
-        private final String name;
-
-        private ModuleImpl(String name) {
-            this.name = name;
-        }
-
-        @Override
-        public String getName() {
-            return name;
-        }
-
-        @Override
-        public ModuleData get(String path) {
-            if (!path.startsWith("/")) {
-                path = "/" + path;
-            }
-            if (!path.startsWith("/" + name)) {
-                path = "/" + name + path;
-            }
-            return moduleContent.get(path);
-        }
-
-        @Override
-        public ModuleDescriptor getDescriptor() {
-            if (descriptor == null) {
-                String p = "/" + name + "/module-info.class";
-                ModuleData content = moduleContent.get(p);
-                if (content == null) {
-                    throw new PluginException("No module-info for " + name
-                            + " module");
-                }
-                ByteBuffer bb = ByteBuffer.wrap(content.getBytes());
-                descriptor = ModuleDescriptor.read(bb);
-            }
-            return descriptor;
-        }
-
-        @Override
-        public void add(ModuleData data) {
-            if (isReadOnly()) {
-                throw new PluginException("pool is readonly");
-            }
-            Objects.requireNonNull(data);
-            if (!data.getModule().equals(name)) {
-                throw new PluginException("Can't add resource " + data.getPath()
-                        + " to module " + name);
-            }
-            Pool.this.add(data);
-        }
-
-        @Override
-        public Set<String> getAllPackages() {
-            Set<String> pkgs = new HashSet<>();
-            moduleContent.values().stream().filter(m -> m.getType().
-                    equals(ModuleDataType.CLASS_OR_RESOURCE)).forEach((res) -> {
-                // Module metadata only contains packages with .class files
-                if (ImageFileCreator.isClassPackage(res.getPath())) {
-                    String[] split = ImageFileCreator.splitPath(res.getPath());
-                    String pkg = split[1];
-                    if (pkg != null && !pkg.isEmpty()) {
-                        pkgs.add(pkg);
-                    }
-                }
-            });
-            return pkgs;
-        }
-
-        @Override
-        public String toString() {
-            return getName();
-        }
-
-        @Override
-        public Collection<ModuleData> getContent() {
-            return Collections.unmodifiableCollection(moduleContent.values());
-        }
-    }
-
-    /**
-     * A ModuleData is the elementary unit of data inside an image. It is
-     * generally a file. e.g.: a java class file, a resource file, a shared
-     * library, ...
-     * <br>
-     * A ModuleData is identified by a path of the form:
-     * <ul>
-     * <li>For jimage content: /{module name}/{package1}/.../{packageN}/{file
-     * name}</li>
-     * <li>For other files (shared lib, launchers, config, ...):/{module name}/
-     * {@literal bin|conf|native}/{dir1}/.../{dirN}/{file name}</li>
-     * </ul>
-     */
-    public static class ModuleData {
-
-        private final ModuleDataType type;
-        private final String path;
-        private final String module;
-        private final long length;
-        private final InputStream stream;
-        private byte[] buffer;
-
-        /**
-         * Create a new ModuleData.
-         *
-         * @param module The module name.
-         * @param path The data path identifier.
-         * @param type The data type.
-         * @param stream The data content stream.
-         * @param length The stream length.
-         */
-        public ModuleData(String module, String path, ModuleDataType type,
-                InputStream stream, long length) {
-            Objects.requireNonNull(module);
-            Objects.requireNonNull(path);
-            Objects.requireNonNull(type);
-            Objects.requireNonNull(stream);
-            this.path = path;
-            this.type = type;
-            this.module = module;
-            this.stream = stream;
-            this.length = length;
-        }
-
-        /**
-         * The ModuleData module name.
-         *
-         * @return The module name.
-         */
-        public final String getModule() {
-            return module;
-        }
-
-        /**
-         * The ModuleData path.
-         *
-         * @return The module path.
-         */
-        public final String getPath() {
-            return path;
-        }
-
-        /**
-         * The ModuleData type.
-         *
-         * @return The data type.
-         */
-        public final ModuleDataType getType() {
-            return type;
-        }
-
-        /**
-         * The ModuleData content as an array of byte.
-         *
-         * @return An Array of bytes.
-         */
-        public byte[] getBytes() {
-            if (buffer == null) {
-                try {
-                    buffer = stream.readAllBytes();
-                } catch (IOException ex) {
-                    throw new UncheckedIOException(ex);
-                }
-            }
-            return buffer;
-        }
-
-        /**
-         * The ModuleData content length.
-         *
-         * @return The length.
-         */
-        public long getLength() {
-            return length;
-        }
-
-        /**
-         * The ModuleData stream.
-         *
-         * @return The module data stream.
-         */
-        public InputStream stream() {
-            return stream;
-        }
-
-        @Override
-        public int hashCode() {
-            int hash = 7;
-            hash = 89 * hash + Objects.hashCode(this.path);
-            return hash;
-        }
-
-        @Override
-        public boolean equals(Object other) {
-            if (!(other instanceof ModuleData)) {
-                return false;
-            }
-            ModuleData f = (ModuleData) other;
-            return f.path.equals(path);
-        }
-
-        @Override
-        public String toString() {
-            return getPath();
-        }
-    }
-
-    private final Map<String, ModuleData> resources = new LinkedHashMap<>();
-    private final Map<String, ModuleImpl> modules = new LinkedHashMap<>();
-    private final ModuleImpl fileCopierModule = new ModuleImpl(FileCopierPlugin.FAKE_MODULE);
-
-    private final ByteOrder order;
-
-    protected Pool() {
-        this(ByteOrder.nativeOrder());
-    }
-
-    protected Pool(ByteOrder order) {
-        Objects.requireNonNull(order);
-        this.order = order;
-    }
-
-    /**
-     * Read only state. No data can be added to a ReadOnly Pool.
-     *
-     * @return true if readonly false otherwise.
-     */
-    public abstract boolean isReadOnly();
-
-    /**
-     * Add a ModuleData.
-     *
-     * @param data The ModuleData to add.
-     */
-    public void add(ModuleData data) {
-        if (isReadOnly()) {
-            throw new PluginException("pool is readonly");
-        }
-        Objects.requireNonNull(data);
-        if (resources.get(data.getPath()) != null) {
-            throw new PluginException("Resource " + data.getPath()
-                    + " already present");
-        }
-        String modulename = data.getModule();
-        ModuleImpl m = modules.get(modulename);
-        // ## TODO: FileCopierPlugin should not add content to a module
-        // FAKE_MODULE is not really a module to be added in the image
-        if (FileCopierPlugin.FAKE_MODULE.equals(modulename)) {
-            m = fileCopierModule;
-        }
-        if (m == null) {
-            m = new ModuleImpl(modulename);
-            modules.put(modulename, m);
-        }
-        resources.put(data.getPath(), data);
-        m.moduleContent.put(data.getPath(), data);
-    }
-
-    /**
-     * Retrieves the module for the provided name.
-     *
-     * @param name The module name
-     * @return the module or null if the module doesn't exist.
-     */
-    public Module getModule(String name) {
-        Objects.requireNonNull(name);
-        return modules.get(name);
-    }
-
-    /**
-     * The collection of modules contained in this pool.
-     *
-     * @return The collection of modules.
-     */
-    public Collection<Module> getModules() {
-        return Collections.unmodifiableCollection(modules.values());
-    }
-
-    /**
-     * Get all ModuleData contained in this pool instance.
-     *
-     * @return The collection of resources;
-     */
-    public Collection<ModuleData> getContent() {
-        return Collections.unmodifiableCollection(resources.values());
-    }
-
-    /**
-     * Get the ModuleData for the passed path.
-     *
-     * @param path A data path
-     * @return A ModuleData instance or null if the data is not found
-     */
-    public ModuleData get(String path) {
-        Objects.requireNonNull(path);
-        return resources.get(path);
-    }
-
-    /**
-     * Check if the pool contains this data.
-     *
-     * @param data The module data to check existence for.
-     * @return The module data or null if not found.
-     */
-    public boolean contains(ModuleData data) {
-        Objects.requireNonNull(data);
-        return get(data.getPath()) != null;
-    }
-
-    /**
-     * Check if the Pool contains some content.
-     *
-     * @return True, no content, false otherwise.
-     */
-    public boolean isEmpty() {
-        return resources.isEmpty();
-    }
-
-    /**
-     * Visit the pool.
-     *
-     * @param visitor The Visitor called for each ModuleData found in the pool.
-     * @param output The pool to be filled with Visitor returned ModuleData.
-     */
-    public void visit(Visitor visitor, Pool output) {
-        for (ModuleData resource : getContent()) {
-            ModuleData res = visitor.visit(resource);
-            if (res != null) {
-                output.add(res);
-            }
-        }
-    }
-
-    /**
-     * The ByteOrder currently in use when generating the jimage file.
-     *
-     * @return The ByteOrder.
-     */
-    public ByteOrder getByteOrder() {
-        return order;
-    }
-
-    /**
-     * Create a ModuleData located inside a jimage file. Such ModuleData has a
-     * ModuleDataType being equals to CLASS_OR_RESOURCE.
-     *
-     * @param path The complete resource path (contains the module radical).
-     * @param content The resource content.
-     * @param size The content size.
-     * @return A new ModuleData.
-     */
-    public static ModuleData newResource(String path, InputStream content, long size) {
-        Objects.requireNonNull(path);
-        Objects.requireNonNull(content);
-        String[] split = ImageFileCreator.splitPath(path);
-        String module = split[0];
-        return new ModuleData(module, path, ModuleDataType.CLASS_OR_RESOURCE, content, size);
-    }
-
-    /**
-     * Create a ModuleData for a file that will be located inside a jimage file.
-     *
-     * @param path The resource path.
-     * @param content The resource content.
-     * @return A new ModuleData.
-     */
-    public static ModuleData newResource(String path, byte[] content) {
-        return newResource(path, new ByteArrayInputStream(content),
-                content.length);
-    }
-
-    /**
-     * Create a ModuleData for a file that will be located outside a jimage
-     * file.
-     *
-     * @param module The module in which this files is located.
-     * @param path The file path locator (doesn't contain the module name).
-     * @param type The ModuleData type.
-     * @param content The file content.
-     * @param size The content size.
-     * @return A new ModuleData.
-     */
-    public static ModuleData newImageFile(String module, String path, ModuleDataType type,
-            InputStream content, long size) {
-        Objects.requireNonNull(path);
-        Objects.requireNonNull(content);
-        return new ModuleData(module, path, type, content, size);
-    }
-
-}
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/TransformerPlugin.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/TransformerPlugin.java	Mon May 16 14:47:27 2016 +0530
@@ -40,5 +40,5 @@
      *
      * @throws PluginException
      */
-    public void visit(Pool in, Pool out);
+    public void visit(ModulePool in, ModulePool out);
 }
--- a/src/jdk.jlink/share/classes/module-info.java	Mon May 16 09:54:01 2016 +0100
+++ b/src/jdk.jlink/share/classes/module-info.java	Mon May 16 14:47:27 2016 +0530
@@ -24,9 +24,7 @@
  */
 
 module jdk.jlink {
-    exports jdk.tools.jlink;
     exports jdk.tools.jlink.plugin;
-    exports jdk.tools.jlink.builder;
 
     requires jdk.internal.opt;
     requires jdk.jdeps;
@@ -46,5 +44,5 @@
     provides jdk.tools.jlink.plugin.TransformerPlugin with jdk.tools.jlink.internal.plugins.ExcludeVMPlugin;
     provides jdk.tools.jlink.plugin.TransformerPlugin with jdk.tools.jlink.internal.plugins.IncludeLocalesPlugin;
     provides jdk.tools.jlink.plugin.TransformerPlugin with jdk.tools.jlink.internal.plugins.GenerateJLIClassesPlugin;
-    provides jdk.tools.jlink.plugin.PostProcessorPlugin with jdk.tools.jlink.internal.plugins.ReleaseInfoPlugin;
+    provides jdk.tools.jlink.plugin.TransformerPlugin with jdk.tools.jlink.internal.plugins.ReleaseInfoPlugin;
 }
--- a/test/tools/jlink/DefaultProviderTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/DefaultProviderTest.java	Mon May 16 14:47:27 2016 +0530
@@ -33,7 +33,7 @@
 import jdk.tools.jlink.internal.PluginRepository;
 import jdk.tools.jlink.plugin.Plugin;
 import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 import tests.Helper;
 
@@ -65,26 +65,26 @@
         private boolean enabled = true;
 
         @Override
-        public Set<PluginType> getType() {
-            Set<PluginType> set = new HashSet<>();
-            set.add(CATEGORY.TRANSFORMER);
+        public Set<Category> getType() {
+            Set<Category> set = new HashSet<>();
+            set.add(Category.TRANSFORMER);
             return Collections.unmodifiableSet(set);
         }
 
         @Override
-        public Set<STATE> getState() {
-             return enabled ? EnumSet.of(STATE.AUTO_ENABLED, STATE.FUNCTIONAL)
-                : EnumSet.of(STATE.DISABLED);
+        public Set<State> getState() {
+             return enabled ? EnumSet.of(State.AUTO_ENABLED, State.FUNCTIONAL)
+                : EnumSet.of(State.DISABLED);
         }
 
         @Override
-        public void visit(Pool in, Pool out) {
+        public void visit(ModulePool in, ModulePool out) {
             if (!enabled) {
                 throw new PluginException(NAME + " was set");
             }
 
             DefaultProviderTest.isNewPluginsCalled = true;
-            in.visit((Pool.ModuleData content) -> {
+            in.transformAndCopy(content -> {
                 return content;
             }, out);
         }
--- a/test/tools/jlink/ImageFileCreatorTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/ImageFileCreatorTest.java	Mon May 16 14:47:27 2016 +0530
@@ -39,7 +39,7 @@
 import jdk.tools.jlink.internal.ImagePluginStack;
 import jdk.tools.jlink.plugin.ExecutableImage;
 import jdk.tools.jlink.builder.ImageBuilder;
-import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.ModulePool;
 
 
 /*
@@ -47,6 +47,7 @@
  * @summary ImageFileCreator class test
  * @author Jean-Francois Denise
  * @modules jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.builder
  *          java.base/jdk.internal.jimage
  * @run main/othervm -verbose:gc -Xmx1g ImageFileCreatorTest
  */
@@ -214,7 +215,7 @@
             }
 
             @Override
-            public void storeFiles(Pool content) {
+            public void storeFiles(ModulePool content) {
             }
         };
 
--- a/test/tools/jlink/ImageFilePoolTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/ImageFilePoolTest.java	Mon May 16 14:47:27 2016 +0530
@@ -31,11 +31,12 @@
  */
 
 import java.io.ByteArrayInputStream;
-import jdk.tools.jlink.internal.PoolImpl;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
-import jdk.tools.jlink.plugin.Pool.ModuleDataType;
-import jdk.tools.jlink.plugin.Pool.Visitor;
+import java.util.Optional;
+import java.util.function.Function;
+import jdk.tools.jlink.internal.ModuleEntryImpl;
+import jdk.tools.jlink.internal.ModulePoolImpl;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 
 public class ImageFilePoolTest {
     public static void main(String[] args) throws Exception {
@@ -50,45 +51,45 @@
     private static final String SUFFIX = "END";
 
     private void checkVisitor() throws Exception {
-        Pool input = new PoolImpl();
+        ModulePool input = new ModulePoolImpl();
         for (int i = 0; i < 1000; ++i) {
             String module = "module" + (i / 100);
             input.add(new InMemoryImageFile(module, "/" + module + "/java/class" + i,
-                    ModuleDataType.CONFIG, "class" + i));
+                    ModuleEntry.Type.CONFIG, "class" + i));
         }
-        if (input.getContent().size() != 1000) {
+        if (input.getEntryCount() != 1000) {
             throw new AssertionError();
         }
-        Pool output = new PoolImpl();
+        ModulePool output = new ModulePoolImpl();
         ResourceVisitor visitor = new ResourceVisitor();
-        input.visit(visitor, output);
+        input.transformAndCopy(visitor, output);
         if (visitor.getAmountBefore() == 0) {
             throw new AssertionError("Resources not found");
         }
-        if (visitor.getAmountBefore() != input.getContent().size()) {
+        if (visitor.getAmountBefore() != input.getEntryCount()) {
             throw new AssertionError("Number of visited resources. Expected: " +
-                    visitor.getAmountBefore() + ", got: " + input.getContent().size());
+                    visitor.getAmountBefore() + ", got: " + input.getEntryCount());
         }
-        if (visitor.getAmountAfter() != output.getContent().size()) {
+        if (visitor.getAmountAfter() != output.getEntryCount()) {
             throw new AssertionError("Number of added resources. Expected: " +
-                    visitor.getAmountAfter() + ", got: " + output.getContent().size());
+                    visitor.getAmountAfter() + ", got: " + output.getEntryCount());
         }
-        for (ModuleData outFile : output.getContent()) {
+        output.entries().forEach(outFile -> {
             String path = outFile.getPath().replaceAll(SUFFIX + "$", "");
-            ModuleData inFile = input.get(path);
-            if (inFile == null) {
+            Optional<ModuleEntry> inFile = input.findEntry(path);
+            if (!inFile.isPresent()) {
                 throw new AssertionError("Unknown resource: " + path);
             }
-        }
+        });
     }
 
-    private static class ResourceVisitor implements Visitor {
+    private static class ResourceVisitor implements Function<ModuleEntry, ModuleEntry> {
 
         private int amountBefore;
         private int amountAfter;
 
         @Override
-        public ModuleData visit(ModuleData file) {
+        public ModuleEntry apply(ModuleEntry file) {
             int index = ++amountBefore % 3;
             switch (index) {
                 case 0:
@@ -113,7 +114,7 @@
     }
 
     private void checkNegative() throws Exception {
-        PoolImpl input = new PoolImpl();
+        ModulePoolImpl input = new ModulePoolImpl();
         try {
             input.add(null);
             throw new AssertionError("NullPointerException is not thrown");
@@ -126,30 +127,30 @@
         } catch (NullPointerException e) {
             // expected
         }
-        if (input.get("unknown") != null) {
-            throw new AssertionError("ImageFilePool does not return null for unknown file");
+        if (input.findEntry("unknown").isPresent()) {
+            throw new AssertionError("ImageFileModulePool does not return null for unknown file");
         }
-        if (input.contains(new InMemoryImageFile("", "unknown", ModuleDataType.CONFIG, "unknown"))) {
+        if (input.contains(new InMemoryImageFile("", "unknown", ModuleEntry.Type.CONFIG, "unknown"))) {
             throw new AssertionError("'contain' returns true for unknown file");
         }
-        input.add(new InMemoryImageFile("", "/aaa/bbb", ModuleDataType.CONFIG, ""));
+        input.add(new InMemoryImageFile("", "/aaa/bbb", ModuleEntry.Type.CONFIG, ""));
         try {
-            input.add(new InMemoryImageFile("", "/aaa/bbb", ModuleDataType.CONFIG, ""));
+            input.add(new InMemoryImageFile("", "/aaa/bbb", ModuleEntry.Type.CONFIG, ""));
             throw new AssertionError("Exception expected");
         } catch (Exception e) {
             // expected
         }
         input.setReadOnly();
         try {
-            input.add(new InMemoryImageFile("", "/aaa/ccc", ModuleDataType.CONFIG, ""));
+            input.add(new InMemoryImageFile("", "/aaa/ccc", ModuleEntry.Type.CONFIG, ""));
             throw new AssertionError("Exception expected");
         } catch (Exception e) {
             // expected
         }
     }
 
-    private static class InMemoryImageFile extends ModuleData {
-        public InMemoryImageFile(String module, String path, ModuleDataType type, String content) {
+    private static class InMemoryImageFile extends ModuleEntryImpl {
+        public InMemoryImageFile(String module, String path, ModuleEntry.Type type, String content) {
             super(module, path, type, new ByteArrayInputStream(content.getBytes()), content.getBytes().length);
         }
     }
--- a/test/tools/jlink/IntegrationTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/IntegrationTest.java	Mon May 16 14:47:27 2016 +0530
@@ -39,7 +39,7 @@
 import jdk.tools.jlink.Jlink.PluginsConfiguration;
 import jdk.tools.jlink.builder.DefaultImageBuilder;
 import jdk.tools.jlink.plugin.ExecutableImage;
-import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.plugin.PostProcessorPlugin;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 import jdk.tools.jlink.internal.plugins.DefaultCompressPlugin;
@@ -56,6 +56,8 @@
  * @library ../lib
  * @modules java.base/jdk.internal.jimage
  *          jdk.jdeps/com.sun.tools.classfile
+ *          jdk.jlink/jdk.tools.jlink
+ *          jdk.jlink/jdk.tools.jlink.builder
  *          jdk.jlink/jdk.tools.jlink.internal
  *          jdk.jlink/jdk.tools.jlink.internal.plugins
  *          jdk.jlink/jdk.tools.jmod
@@ -88,9 +90,9 @@
         }
 
         @Override
-        public Set<PluginType> getType() {
-            Set<PluginType> set = new HashSet<>();
-            set.add(CATEGORY.PROCESSOR);
+        public Set<Category> getType() {
+            Set<Category> set = new HashSet<>();
+            set.add(Category.PROCESSOR);
             return Collections.unmodifiableSet(set);
         }
 
@@ -128,18 +130,18 @@
         }
 
         @Override
-        public void visit(Pool in, Pool out) {
+        public void visit(ModulePool in, ModulePool out) {
             System.err.println(NAME + index);
             ordered.add(index);
-            in.visit((file) -> {
+            in.transformAndCopy((file) -> {
                 return file;
             }, out);
         }
 
         @Override
-        public Set<PluginType> getType() {
-            Set<PluginType> set = new HashSet<>();
-            set.add(CATEGORY.TRANSFORMER);
+        public Set<Category> getType() {
+            Set<Category> set = new HashSet<>();
+            set.add(Category.TRANSFORMER);
             return Collections.unmodifiableSet(set);
         }
 
--- a/test/tools/jlink/JLinkOptimTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/JLinkOptimTest.java	Mon May 16 14:47:27 2016 +0530
@@ -23,15 +23,15 @@
 import jdk.internal.org.objectweb.asm.tree.MethodNode;
 import jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode;
 import jdk.tools.jlink.internal.PluginRepository;
-import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.internal.ModulePoolImpl;
 import jdk.tools.jlink.internal.plugins.OptimizationPlugin;
 import jdk.tools.jlink.internal.plugins.asm.AsmModulePool;
 import jdk.tools.jlink.internal.plugins.asm.AsmPlugin;
 import jdk.tools.jlink.internal.plugins.asm.AsmPools;
 import jdk.tools.jlink.internal.plugins.optim.ControlFlow;
 import jdk.tools.jlink.internal.plugins.optim.ControlFlow.Block;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 
 import tests.Helper;
 import tests.JImageGenerator;
@@ -134,9 +134,9 @@
         }
 
         @Override
-        public Set<PluginType> getType() {
-            Set<PluginType> set = new HashSet<>();
-            set.add(CATEGORY.TRANSFORMER);
+        public Set<Category> getType() {
+            Set<Category> set = new HashSet<>();
+            set.add(Category.TRANSFORMER);
             return Collections.unmodifiableSet(set);
         }
     }
@@ -150,13 +150,13 @@
         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
         Path root = fs.getPath("/modules/java.base");
         // Access module-info.class to be reused as fake module-info.class
-        List<ModuleData> javabaseResources = new ArrayList<>();
+        List<ModuleEntry> javabaseResources = new ArrayList<>();
         try (Stream<Path> stream = Files.walk(root)) {
             for (Iterator<Path> iterator = stream.iterator(); iterator.hasNext();) {
                 Path p = iterator.next();
                 if (Files.isRegularFile(p)) {
                     try {
-                        javabaseResources.add(Pool.newResource(p.toString().
+                        javabaseResources.add(ModuleEntry.create(p.toString().
                                 substring("/modules".length()), Files.readAllBytes(p)));
                     } catch (Exception ex) {
                         throw new RuntimeException(ex);
@@ -166,18 +166,18 @@
         }
 
         //forName folding
-        PoolImpl pool = new PoolImpl();
+        ModulePoolImpl pool = new ModulePoolImpl();
         byte[] content = Files.readAllBytes(classes.
                 resolve("optim").resolve("ForNameTestCase.class"));
         byte[] content2 = Files.readAllBytes(classes.
                 resolve("optim").resolve("AType.class"));
         byte[] mcontent = Files.readAllBytes(classes.resolve("module-info.class"));
 
-        pool.add(Pool.newResource("/optimplugin/optim/ForNameTestCase.class", content));
-        pool.add(Pool.newResource("/optimplugin/optim/AType.class", content2));
-        pool.add(Pool.newResource("/optimplugin/module-info.class", mcontent));
+        pool.add(ModuleEntry.create("/optimplugin/optim/ForNameTestCase.class", content));
+        pool.add(ModuleEntry.create("/optimplugin/optim/AType.class", content2));
+        pool.add(ModuleEntry.create("/optimplugin/module-info.class", mcontent));
 
-        for (ModuleData r : javabaseResources) {
+        for (ModuleEntry r : javabaseResources) {
             pool.add(r);
         }
 
@@ -186,10 +186,10 @@
         optional.put(OptimizationPlugin.NAME, OptimizationPlugin.FORNAME_REMOVAL);
         optional.put(OptimizationPlugin.LOG, "forName.log");
         plugin.configure(optional);
-        Pool out = new PoolImpl();
+        ModulePool out = new ModulePoolImpl();
         plugin.visit(pool, out);
 
-        ModuleData result = out.getContent().iterator().next();
+        ModuleEntry result = out.entries().iterator().next();
 
         ClassReader optimReader = new ClassReader(result.getBytes());
         ClassNode optimClass = new ClassNode();
--- a/test/tools/jlink/JLinkOptionsTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/JLinkOptionsTest.java	Mon May 16 14:47:27 2016 +0530
@@ -24,7 +24,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.internal.PluginRepository;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 
@@ -62,7 +62,7 @@
         }
 
         @Override
-        public void visit(Pool in, Pool out) {
+        public void visit(ModulePool in, ModulePool out) {
 
         }
 
--- a/test/tools/jlink/JLinkPostProcessingTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/JLinkPostProcessingTest.java	Mon May 16 14:47:27 2016 +0530
@@ -75,9 +75,9 @@
         }
 
         @Override
-        public Set<PluginType> getType() {
-            Set<PluginType> set = new HashSet<>();
-            set.add(CATEGORY.PROCESSOR);
+        public Set<Category> getType() {
+            Set<Category> set = new HashSet<>();
+            set.add(Category.PROCESSOR);
             return Collections.unmodifiableSet(set);
         }
 
--- a/test/tools/jlink/ResourcePoolTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/ResourcePoolTest.java	Mon May 16 14:47:27 2016 +0530
@@ -37,14 +37,14 @@
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Optional;
 import java.util.Set;
-
-import jdk.tools.jlink.internal.PoolImpl;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.Module;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
-import jdk.tools.jlink.plugin.Pool.ModuleDataType;
-import jdk.tools.jlink.plugin.Pool.Visitor;
+import java.util.function.Function;
+import jdk.tools.jlink.internal.ModulePoolImpl;
+import jdk.tools.jlink.plugin.ModulePool;
+import jdk.tools.jlink.plugin.LinkModule;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 
 public class ResourcePoolTest {
 
@@ -61,54 +61,53 @@
     private static final String SUFFIX = "END";
 
     private void checkResourceVisitor() throws Exception {
-        Pool input = new PoolImpl();
+        ModulePool input = new ModulePoolImpl();
         for (int i = 0; i < 1000; ++i) {
             String module = "/module" + (i / 10);
             String resourcePath = module + "/java/package" + i;
             byte[] bytes = resourcePath.getBytes();
-            input.add(new ModuleData(module, resourcePath,
-                    ModuleDataType.CLASS_OR_RESOURCE,
+            input.add(ModuleEntry.create(module, resourcePath,
+                    ModuleEntry.Type.CLASS_OR_RESOURCE,
                     new ByteArrayInputStream(bytes), bytes.length));
         }
-        Pool output = new PoolImpl();
+        ModulePool output = new ModulePoolImpl();
         ResourceVisitor visitor = new ResourceVisitor();
-        input.visit(visitor, output);
+        input.transformAndCopy(visitor, output);
         if (visitor.getAmountBefore() == 0) {
             throw new AssertionError("Resources not found");
         }
-        if (visitor.getAmountBefore() != input.getContent().size()) {
+        if (visitor.getAmountBefore() != input.getEntryCount()) {
             throw new AssertionError("Number of visited resources. Expected: " +
-                    visitor.getAmountBefore() + ", got: " + input.getContent().size());
+                    visitor.getAmountBefore() + ", got: " + input.getEntryCount());
         }
-        if (visitor.getAmountAfter() != output.getContent().size()) {
+        if (visitor.getAmountAfter() != output.getEntryCount()) {
             throw new AssertionError("Number of added resources. Expected: " +
-                    visitor.getAmountAfter() + ", got: " + output.getContent().size());
+                    visitor.getAmountAfter() + ", got: " + output.getEntryCount());
         }
-        for (ModuleData outResource : output.getContent()) {
+        output.entries().forEach(outResource -> {
             String path = outResource.getPath().replaceAll(SUFFIX + "$", "");
-            ModuleData inResource = input.get(path);
-            if (inResource == null) {
+            if (!input.findEntry(path).isPresent()) {
                 throw new AssertionError("Unknown resource: " + path);
             }
-        }
+        });
     }
 
-    private static class ResourceVisitor implements Visitor {
+    private static class ResourceVisitor implements Function<ModuleEntry, ModuleEntry> {
 
         private int amountBefore;
         private int amountAfter;
 
         @Override
-        public ModuleData visit(ModuleData resource) {
+        public ModuleEntry apply(ModuleEntry resource) {
             int index = ++amountBefore % 3;
             switch (index) {
                 case 0:
                     ++amountAfter;
-                    return new ModuleData(resource.getModule(), resource.getPath() + SUFFIX,
+                    return ModuleEntry.create(resource.getModule(), resource.getPath() + SUFFIX,
                             resource.getType(), resource.stream(), resource.getLength());
                 case 1:
                     ++amountAfter;
-                    return new ModuleData(resource.getModule(), resource.getPath(),
+                    return ModuleEntry.create(resource.getModule(), resource.getPath(),
                             resource.getType(), resource.stream(), resource.getLength());
             }
             return null;
@@ -133,8 +132,8 @@
         samples.add("javax/management/ObjectName");
         test(samples, (resources, module, path) -> {
             try {
-                resources.add(new ModuleData(module, path,
-                        ModuleDataType.CLASS_OR_RESOURCE,
+                resources.add(ModuleEntry.create(module, path,
+                        ModuleEntry.Type.CLASS_OR_RESOURCE,
                         new ByteArrayInputStream(new byte[0]), 0));
             } catch (Exception ex) {
                 throw new RuntimeException(ex);
@@ -142,12 +141,12 @@
         });
         test(samples, (resources, module, path) -> {
             try {
-                resources.add(PoolImpl.
-                        newCompressedResource(new ModuleData(module, path,
-                                ModuleDataType.CLASS_OR_RESOURCE,
+                resources.add(ModulePoolImpl.
+                        newCompressedResource(ModuleEntry.create(module, path,
+                                ModuleEntry.Type.CLASS_OR_RESOURCE,
                                 new ByteArrayInputStream(new byte[0]), 0),
                                 ByteBuffer.allocate(99), "bitcruncher", null,
-                                ((PoolImpl)resources).getStringTable(), ByteOrder.nativeOrder()));
+                                ((ModulePoolImpl)resources).getStringTable(), ByteOrder.nativeOrder()));
             } catch (Exception ex) {
                 throw new RuntimeException(ex);
             }
@@ -158,7 +157,7 @@
         if (samples.isEmpty()) {
             throw new AssertionError("No sample to test");
         }
-        Pool resources = new PoolImpl();
+        ModulePool resources = new ModulePoolImpl();
         Set<String> modules = new HashSet<>();
         for (int i = 0; i < samples.size(); i++) {
             String module = samples.get(i);
@@ -173,70 +172,69 @@
             i++;
             String clazz = samples.get(i);
             String path = "/" + module + "/" + clazz + ".class";
-            ModuleData res = resources.get(path);
-            checkModule(resources, res);
-            if (res == null) {
+            Optional<ModuleEntry> res = resources.findEntry(path);
+            if (!res.isPresent()) {
                 throw new AssertionError("Resource not found " + path);
             }
-            ModuleData res2 = resources.get(clazz);
-            if (res2 != null) {
+            checkModule(resources, res.get());
+            if (resources.findEntry(clazz).isPresent()) {
                 throw new AssertionError("Resource found " + clazz);
             }
         }
-        if (resources.getContent().size() != samples.size() / 2) {
+        if (resources.getEntryCount() != samples.size() / 2) {
             throw new AssertionError("Invalid number of resources");
         }
     }
 
-    private void checkModule(Pool resources, ModuleData res) {
-        Module m = resources.getModule(res.getModule());
-        if (m == null) {
+    private void checkModule(ModulePool resources, ModuleEntry res) {
+        Optional<LinkModule> optMod = resources.findModule(res.getModule());
+        if (!optMod.isPresent()) {
             throw new AssertionError("No module " + res.getModule());
         }
+        LinkModule m = optMod.get();
         if (!m.getName().equals(res.getModule())) {
             throw new AssertionError("Not right module name " + res.getModule());
         }
-        if (m.get(res.getPath()) == null) {
+        if (!m.findEntry(res.getPath()).isPresent()) {
             throw new AssertionError("resource " + res.getPath()
                     + " not in module " + m.getName());
         }
     }
 
     private void checkResourcesAfterCompression() throws Exception {
-        PoolImpl resources1 = new PoolImpl();
-        ModuleData res1 = new ModuleData("module1", "/module1/toto1",
-                ModuleDataType.CLASS_OR_RESOURCE,
+        ModulePoolImpl resources1 = new ModulePoolImpl();
+        ModuleEntry res1 = ModuleEntry.create("module1", "/module1/toto1",
+                ModuleEntry.Type.CLASS_OR_RESOURCE,
                 new ByteArrayInputStream(new byte[0]), 0);
-        ModuleData res2 = new ModuleData("module2", "/module2/toto1",
-                ModuleDataType.CLASS_OR_RESOURCE,
+        ModuleEntry res2 = ModuleEntry.create("module2", "/module2/toto1",
+                ModuleEntry.Type.CLASS_OR_RESOURCE,
                 new ByteArrayInputStream(new byte[0]), 0);
         resources1.add(res1);
         resources1.add(res2);
 
         checkResources(resources1, res1, res2);
-        Pool resources2 = new PoolImpl();
-        ModuleData res3 = new ModuleData("module2", "/module2/toto1",
-                ModuleDataType.CLASS_OR_RESOURCE,
+        ModulePool resources2 = new ModulePoolImpl();
+        ModuleEntry res3 = ModuleEntry.create("module2", "/module2/toto1",
+                ModuleEntry.Type.CLASS_OR_RESOURCE,
                 new ByteArrayInputStream(new byte[7]), 7);
         resources2.add(res3);
-        resources2.add(PoolImpl.newCompressedResource(res1,
+        resources2.add(ModulePoolImpl.newCompressedResource(res1,
                 ByteBuffer.allocate(7), "zip", null, resources1.getStringTable(),
                 ByteOrder.nativeOrder()));
         checkResources(resources2, res1, res2);
     }
 
-    private void checkResources(Pool resources, ModuleData... expected) {
-        Collection<Module> ms = resources.getModules();
+    private void checkResources(ModulePool resources, ModuleEntry... expected) {
         List<String> modules = new ArrayList();
-        for(Module m : ms) {
+        resources.modules().forEach(m -> {
             modules.add(m.getName());
-        }
-        for (ModuleData res : expected) {
+        });
+        for (ModuleEntry res : expected) {
             if (!resources.contains(res)) {
                 throw new AssertionError("Resource not found: " + res);
             }
 
-            if (resources.get(res.getPath()) == null) {
+            if (!resources.findEntry(res.getPath()).isPresent()) {
                 throw new AssertionError("Resource not found: " + res);
             }
 
@@ -244,7 +242,7 @@
                 throw new AssertionError("Module not found: " + res.getModule());
             }
 
-            if (!resources.getContent().contains(res)) {
+            if (!resources.contains(res)) {
                 throw new AssertionError("Resources not found: " + res);
             }
 
@@ -260,17 +258,17 @@
             throw new AssertionError("ReadOnly resources");
         }
 
-        ((PoolImpl) resources).setReadOnly();
+        ((ModulePoolImpl) resources).setReadOnly();
         try {
-            resources.add(new ModuleData("module2",  "/module2/toto1",
-                    ModuleDataType.CLASS_OR_RESOURCE, new ByteArrayInputStream(new byte[0]), 0));
-            throw new AssertionError("Pool is read-only, but an exception is not thrown");
+            resources.add(ModuleEntry.create("module2",  "/module2/toto1",
+                    ModuleEntry.Type.CLASS_OR_RESOURCE, new ByteArrayInputStream(new byte[0]), 0));
+            throw new AssertionError("ModulePool is read-only, but an exception is not thrown");
         } catch (Exception ex) {
             // Expected
         }
     }
 
     interface ResourceAdder {
-        void add(Pool resources, String module, String path);
+        void add(ModulePool resources, String module, String path);
     }
 }
--- a/test/tools/jlink/SecurityTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/SecurityTest.java	Mon May 16 14:47:27 2016 +0530
@@ -25,6 +25,7 @@
  * @test
  * @summary Test JlinkPermission
  * @author Jean-Francois Denise
+ * @modules jdk.jlink/jdk.tools.jlink
  * @run main/othervm SecurityTest
  */
 
--- a/test/tools/jlink/asmplugin/AddForgetResourcesTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/asmplugin/AddForgetResourcesTest.java	Mon May 16 14:47:27 2016 +0530
@@ -55,8 +55,8 @@
 import jdk.tools.jlink.internal.plugins.asm.AsmPool.WritableClassPool;
 import jdk.tools.jlink.internal.plugins.asm.AsmPool.WritableResourcePool;
 import jdk.tools.jlink.internal.plugins.asm.AsmPools;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 
 public class AddForgetResourcesTest extends AsmPluginTestBase {
 
@@ -82,7 +82,7 @@
                 new ComboPlugin()
         };
         for (TestPlugin p : plugins) {
-            Pool out = p.visit(getPool());
+            ModulePool out = p.visit(getPool());
             p.test(getPool(), out);
         }
     }
@@ -124,7 +124,7 @@
             AsmGlobalPool globalPool = pools.getGlobalPool();
             WritableClassPool transformedClasses = globalPool.getTransformedClasses();
             expected = globalPool.getClasses().size();
-            for (ModuleData res : globalPool.getClasses()) {
+            for (ModuleEntry res : globalPool.getClasses()) {
                 ClassReader reader = globalPool.getClassReader(res);
                 String className = reader.getClassName();
                 if (!className.endsWith("module-info")) {
@@ -137,14 +137,14 @@
         }
 
         @Override
-        public void test(Pool inResources, Pool outResources) {
-            Collection<ModuleData> inClasses = extractClasses(inResources);
-            Collection<ModuleData> outClasses = extractClasses(outResources);
+        public void test(ModulePool inResources, ModulePool outResources) {
+            Collection<ModuleEntry> inClasses = extractClasses(inResources);
+            Collection<ModuleEntry> outClasses = extractClasses(outResources);
             if (expected != outClasses.size()) {
                 throw new AssertionError("Classes were not added. Expected: " + expected
                         + ", got: " + outClasses.size());
             }
-            for (ModuleData in : inClasses) {
+            for (ModuleEntry in : inClasses) {
                 String path = in.getPath();
                 if (!outClasses.contains(in)) {
                     throw new AssertionError("Class not found: " + path);
@@ -153,7 +153,7 @@
                     continue;
                 }
                 String modifiedPath = path.replace(".class", SUFFIX + ".class");
-                if (!outClasses.contains(Pool.newResource(modifiedPath, new byte[0]))) {
+                if (!outClasses.contains(ModuleEntry.create(modifiedPath, new byte[0]))) {
                     throw new AssertionError("Class not found: " + modifiedPath);
                 }
             }
@@ -166,7 +166,7 @@
         public void visit() {
             AsmPools pools = getPools();
             AsmGlobalPool globalPool = pools.getGlobalPool();
-            for (ModuleData res : globalPool.getResourceFiles()) {
+            for (ModuleEntry res : globalPool.getResourceFiles()) {
                 String path = res.getPath();
                 String moduleName = getModule(path);
                 AsmModulePool modulePool = pools.getModulePool(moduleName);
@@ -177,20 +177,20 @@
         }
 
         @Override
-        public void test(Pool in, Pool out) throws Exception {
-            Collection<ModuleData> inResources = extractResources(in);
-            Collection<ModuleData> outResources = extractResources(out);
+        public void test(ModulePool in, ModulePool out) throws Exception {
+            Collection<ModuleEntry> inResources = extractResources(in);
+            Collection<ModuleEntry> outResources = extractResources(out);
             if (2 * inResources.size() != outResources.size()) {
                 throw new AssertionError("Classes were not added. Expected: " + (2 * inResources.size())
                         + ", got: " + outResources.size());
             }
-            for (ModuleData r : inResources) {
+            for (ModuleEntry r : inResources) {
                 String path = r.getPath();
                 if (!outResources.contains(r)) {
                     throw new AssertionError("Class not found: " + path);
                 }
                 String modifiedPath = path + SUFFIX;
-                if (!outResources.contains(Pool.newResource(modifiedPath, new byte[0]))) {
+                if (!outResources.contains(ModuleEntry.create(modifiedPath, new byte[0]))) {
                     throw new AssertionError("Class not found: " + modifiedPath);
                 }
             }
@@ -204,7 +204,7 @@
             AsmPools pools = getPools();
             AsmGlobalPool globalPool = pools.getGlobalPool();
             WritableClassPool transformedClasses = globalPool.getTransformedClasses();
-            for (ModuleData res : globalPool.getClasses()) {
+            for (ModuleEntry res : globalPool.getClasses()) {
                 ClassReader reader = globalPool.getClassReader(res);
                 ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
                 reader.accept(new AddMethodClassVisitor(writer), ClassReader.EXPAND_FRAMES);
@@ -213,14 +213,14 @@
         }
 
         @Override
-        public void test(Pool inResources, Pool outResources) throws Exception {
-            Collection<ModuleData> inClasses = extractClasses(inResources);
-            Collection<ModuleData> outClasses = extractClasses(outResources);
+        public void test(ModulePool inResources, ModulePool outResources) throws Exception {
+            Collection<ModuleEntry> inClasses = extractClasses(inResources);
+            Collection<ModuleEntry> outClasses = extractClasses(outResources);
             if (inClasses.size() != outClasses.size()) {
                 throw new AssertionError("Number of classes. Expected: " + (inClasses.size())
                         + ", got: " + outClasses.size());
             }
-            for (ModuleData out : outClasses) {
+            for (ModuleEntry out : outClasses) {
                 String path = out.getPath();
                 if (!inClasses.contains(out)) {
                     throw new AssertionError("Class not found: " + path);
@@ -248,7 +248,7 @@
         public void visit() {
             AsmPools pools = getPools();
             AsmGlobalPool globalPool = pools.getGlobalPool();
-            for (ModuleData res : globalPool.getResourceFiles()) {
+            for (ModuleEntry res : globalPool.getResourceFiles()) {
                 String path = res.getPath();
                 AsmModulePool modulePool = pools.getModulePool(getModule(path));
                 modulePool.getTransformedResourceFiles().addResourceFile(new ResourceFile(removeModule(path),
@@ -257,14 +257,14 @@
         }
 
         @Override
-        public void test(Pool in, Pool out) throws Exception {
-            Collection<ModuleData> inResources = extractResources(in);
-            Collection<ModuleData> outResources = extractResources(out);
+        public void test(ModulePool in, ModulePool out) throws Exception {
+            Collection<ModuleEntry> inResources = extractResources(in);
+            Collection<ModuleEntry> outResources = extractResources(out);
             if (inResources.size() != outResources.size()) {
                 throw new AssertionError("Number of resources. Expected: " + inResources.size()
                         + ", got: " + outResources.size());
             }
-            for (ModuleData r : outResources) {
+            for (ModuleEntry r : outResources) {
                 String path = r.getPath();
                 if (!inResources.contains(r)) {
                     throw new AssertionError("Resource not found: " + path);
@@ -287,7 +287,7 @@
             AsmGlobalPool globalPool = pools.getGlobalPool();
             WritableClassPool transformedClasses = globalPool.getTransformedClasses();
             int i = 0;
-            for (ModuleData res : globalPool.getClasses()) {
+            for (ModuleEntry res : globalPool.getClasses()) {
                 String path = removeModule(res.getPath());
                 String className = path.replace(".class", "");
                 if ((i & 1) == 0 && !className.endsWith("module-info")) {
@@ -300,8 +300,8 @@
         }
 
         @Override
-        public void test(Pool inResources, Pool outResources) throws Exception {
-            Collection<ModuleData> outClasses = extractClasses(outResources);
+        public void test(ModulePool inResources, ModulePool outResources) throws Exception {
+            Collection<ModuleEntry> outClasses = extractClasses(outResources);
             if (expected != outClasses.size()) {
                 throw new AssertionError("Number of classes. Expected: " + expected +
                         ", got: " + outClasses.size());
@@ -318,7 +318,7 @@
             AsmPools pools = getPools();
             AsmGlobalPool globalPool = pools.getGlobalPool();
             int i = 0;
-            for (ModuleData res : globalPool.getResourceFiles()) {
+            for (ModuleEntry res : globalPool.getResourceFiles()) {
                 String path = res.getPath();
                 if (!path.contains("META-INF/services")) {
                     if ((i & 1) == 0) {
@@ -335,8 +335,8 @@
         }
 
         @Override
-        public void test(Pool in, Pool out) throws Exception {
-            Collection<ModuleData> outResources = extractResources(out);
+        public void test(ModulePool in, ModulePool out) throws Exception {
+            Collection<ModuleEntry> outResources = extractResources(out);
             if (expectedAmount != outResources.size()) {
                 throw new AssertionError("Number of classes. Expected: " + expectedAmount
                         + ", got: " + outResources.size());
@@ -354,7 +354,7 @@
             AsmGlobalPool globalPool = pools.getGlobalPool();
             WritableClassPool transformedClasses = globalPool.getTransformedClasses();
             int i = 0;
-            for (ModuleData res : globalPool.getClasses()) {
+            for (ModuleEntry res : globalPool.getClasses()) {
                 ClassReader reader = globalPool.getClassReader(res);
                 String className = reader.getClassName();
                 ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
@@ -374,8 +374,8 @@
         }
 
         @Override
-        public void test(Pool inResources, Pool outResources) throws Exception {
-            Collection<ModuleData> outClasses = extractClasses(outResources);
+        public void test(ModulePool inResources, ModulePool outResources) throws Exception {
+            Collection<ModuleEntry> outClasses = extractClasses(outResources);
             if (expected != outClasses.size()) {
                 throw new AssertionError("Number of classes. Expected: " + expected
                         + ", got: " + outClasses.size());
@@ -392,7 +392,7 @@
             AsmPools pools = getPools();
             AsmGlobalPool globalPool = pools.getGlobalPool();
             int i = 0;
-            for (ModuleData res : globalPool.getResourceFiles()) {
+            for (ModuleEntry res : globalPool.getResourceFiles()) {
                 String path = res.getPath();
                 String moduleName = getModule(path);
                 if (!path.contains("META-INF")) {
@@ -412,8 +412,8 @@
         }
 
         @Override
-        public void test(Pool inResources, Pool out) throws Exception {
-            Collection<ModuleData> outResources = extractResources(out);
+        public void test(ModulePool inResources, ModulePool out) throws Exception {
+            Collection<ModuleEntry> outResources = extractResources(out);
             if (expectedAmount != outResources.size()) {
                 throw new AssertionError("Number of classes. Expected: " + expectedAmount
                         + ", got: " + outResources.size());
@@ -446,7 +446,7 @@
         }
 
         @Override
-        public void test(Pool inResources, Pool outResources) throws Exception {
+        public void test(ModulePool inResources, ModulePool outResources) throws Exception {
             if (!isVisitCalled()) {
                 throw new AssertionError("Resources not visited");
             }
@@ -455,7 +455,7 @@
                 throw new AssertionError("Number of transformed classes not equal to expected");
             }
             // Check that only renamed classes and resource files are in the result.
-            for (ModuleData r : outResources.getContent()) {
+            outResources.entries().forEach(r -> {
                 String resourceName = r.getPath();
                 if (resourceName.endsWith(".class") && !resourceName.endsWith("module-info.class")) {
                     if (!resourceName.endsWith(SUFFIX + ".class")) {
@@ -467,7 +467,7 @@
                         throw new AssertionError("Resource file not renamed " + resourceName);
                     }
                 }
-            }
+            });
         }
 
         private void renameResources() throws IOException {
@@ -476,7 +476,7 @@
             for (Map.Entry<String, List<String>> mod : MODULES.entrySet()) {
                 String moduleName = mod.getKey();
                 AsmModulePool modulePool = pools.getModulePool(moduleName);
-                for (ModuleData res : modulePool.getResourceFiles()) {
+                for (ModuleEntry res : modulePool.getResourceFiles()) {
                     ResourceFile resFile = modulePool.getResourceFile(res);
                     if (resFile.getPath().startsWith("META-INF/services/")) {
                         String newContent = new String(resFile.getContent()) + SUFFIX;
@@ -492,7 +492,7 @@
             AsmPools pools = getPools();
             AsmGlobalPool globalPool = pools.getGlobalPool();
             WritableClassPool transformedClasses = globalPool.getTransformedClasses();
-            for (ModuleData res : globalPool.getClasses()) {
+            for (ModuleEntry res : globalPool.getClasses()) {
                 if (res.getPath().endsWith("module-info.class")) {
                     continue;
                 }
--- a/test/tools/jlink/asmplugin/AsmPluginTestBase.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/asmplugin/AsmPluginTestBase.java	Mon May 16 14:47:27 2016 +0530
@@ -38,23 +38,23 @@
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
-import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.internal.ModulePoolImpl;
 import jdk.tools.jlink.internal.StringTable;
 
 import jdk.tools.jlink.internal.plugins.asm.AsmPlugin;
 import jdk.tools.jlink.internal.plugins.asm.AsmPools;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 
 public abstract class AsmPluginTestBase {
 
     protected static final String TEST_MODULE = "jlink.test";
     protected static final Map<String, List<String>> MODULES;
 
-    private static final Predicate<ModuleData> isClass = r -> r.getPath().endsWith(".class");
+    private static final Predicate<ModuleEntry> isClass = r -> r.getPath().endsWith(".class");
     private final List<String> classes;
     private final List<String> resources;
-    private final Pool pool;
+    private final ModulePool pool;
 
     static {
         Map<String, List<String>> map = new HashMap<>();
@@ -75,7 +75,7 @@
             List<String> classes = new ArrayList<>();
             List<String> resources = new ArrayList<>();
 
-            pool = new PoolImpl();
+            pool = new ModulePoolImpl();
 
             FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
             Path root = fs.getPath("/modules");
@@ -100,7 +100,7 @@
                                     MODULES.get(module).add(toResourceFile(p));
                                 }
                                 resources.add(toPath(p.toString()));
-                                ModuleData res = Pool.newResource(toPath(p.toString()), content);
+                                ModuleEntry res = ModuleEntry.create(toPath(p.toString()), content);
                                 pool.add(res);
                             } catch (Exception ex) {
                                 throw new RuntimeException(ex);
@@ -110,17 +110,17 @@
                 }
             }
             // There is more than 10 classes in java.base...
-            if (classes.size() < 10 || pool.getContent().size() < 10) {
+            if (classes.size() < 10 || pool.getEntryCount() < 10) {
                 throw new AssertionError("Not expected resource or class number");
             }
 
             //Add a fake resource file
             String content = "java.lang.Object";
             String path = "META-INF/services/com.foo.BarProvider";
-            ModuleData resFile = Pool.newResource("/" + TEST_MODULE + "/" +
+            ModuleEntry resFile = ModuleEntry.create("/" + TEST_MODULE + "/" +
                     path, content.getBytes());
             pool.add(resFile);
-            ModuleData fakeInfoFile = Pool.newResource("/" + TEST_MODULE
+            ModuleEntry fakeInfoFile = ModuleEntry.create("/" + TEST_MODULE
                     + "/module-info.class", moduleInfos.get(0));
             pool.add(fakeInfoFile);
             MODULES.get(TEST_MODULE).add(path);
@@ -144,20 +144,20 @@
         return resources;
     }
 
-    public Pool getPool() {
+    public ModulePool getPool() {
         return pool;
     }
 
     public abstract void test() throws Exception;
 
-    public Collection<ModuleData> extractClasses(Pool pool) {
-        return pool.getContent().stream()
+    public Collection<ModuleEntry> extractClasses(ModulePool pool) {
+        return pool.entries()
                 .filter(isClass)
                 .collect(Collectors.toSet());
     }
 
-    public Collection<ModuleData> extractResources(Pool pool) {
-        return pool.getContent().stream()
+    public Collection<ModuleEntry> extractResources(ModulePool pool) {
+        return pool.entries()
                 .filter(isClass.negate())
                 .collect(Collectors.toSet());
     }
@@ -209,9 +209,9 @@
             return pools != null;
         }
 
-        public Pool visit(Pool inResources) throws IOException {
+        public ModulePool visit(ModulePool inResources) throws IOException {
             try {
-                Pool outResources = new PoolImpl(inResources.getByteOrder(), new StringTable() {
+                ModulePool outResources = new ModulePoolImpl(inResources.getByteOrder(), new StringTable() {
                     @Override
                     public int addString(String str) {
                         return -1;
@@ -239,7 +239,7 @@
         }
 
         public abstract void visit();
-        public abstract void test(Pool inResources, Pool outResources) throws Exception;
+        public abstract void test(ModulePool inResources, ModulePool outResources) throws Exception;
 
         @Override
         public String getName() {
--- a/test/tools/jlink/asmplugin/BasicTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/asmplugin/BasicTest.java	Mon May 16 14:47:27 2016 +0530
@@ -45,8 +45,8 @@
 import jdk.internal.org.objectweb.asm.ClassReader;
 import jdk.tools.jlink.internal.plugins.asm.AsmModulePool;
 import jdk.tools.jlink.internal.plugins.asm.AsmPool;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 
 public class BasicTest extends AsmPluginTestBase {
 
@@ -61,7 +61,7 @@
     @Override
     public void test() throws Exception {
         BasicPlugin basicPlugin = new BasicPlugin(getClasses());
-        Pool res = basicPlugin.visit(getPool());
+        ModulePool res = basicPlugin.visit(getPool());
         basicPlugin.test(getPool(), res);
     }
 
@@ -107,13 +107,13 @@
         }
 
         @Override
-        public void test(Pool inResources, Pool outResources) throws Exception {
+        public void test(ModulePool inResources, ModulePool outResources) throws Exception {
             if (!isVisitCalled()) {
                 throw new AssertionError("Resources not visited");
             }
-            if (inResources.getContent().size() != outResources.getContent().size()) {
-                throw new AssertionError("Input size " + inResources.getContent().size() +
-                        " != to " + outResources.getContent().size());
+            if (inResources.getEntryCount() != outResources.getEntryCount()) {
+                throw new AssertionError("Input size " + inResources.getEntryCount() +
+                        " != to " + outResources.getEntryCount());
             }
         }
 
@@ -142,7 +142,7 @@
 
         private void testPools() throws IOException {
             Set<String> remain = new HashSet<>(classes);
-            for (ModuleData res : getPools().getGlobalPool().getClasses()) {
+            for (ModuleEntry res : getPools().getGlobalPool().getClasses()) {
                 ClassReader reader = getPools().getGlobalPool().getClassReader(res);
                 String className = reader.getClassName();
                 // Wrong naming of module-info.class in ASM
--- a/test/tools/jlink/asmplugin/IdentityPluginTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/asmplugin/IdentityPluginTest.java	Mon May 16 14:47:27 2016 +0530
@@ -35,14 +35,15 @@
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
+import java.io.UncheckedIOException;
 
 import jdk.internal.org.objectweb.asm.ClassReader;
 import jdk.internal.org.objectweb.asm.ClassVisitor;
 import jdk.internal.org.objectweb.asm.ClassWriter;
 import jdk.internal.org.objectweb.asm.Opcodes;
 import jdk.tools.jlink.internal.plugins.asm.AsmPool.WritableClassPool;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 
 public class IdentityPluginTest extends AsmPluginTestBase {
 
@@ -56,7 +57,7 @@
 
     public void test() throws Exception {
         IdentityPlugin asm = new IdentityPlugin();
-        Pool resourcePool = asm.visit(getPool());
+        ModulePool resourcePool = asm.visit(getPool());
         asm.test(getPool(), resourcePool);
     }
 
@@ -64,7 +65,7 @@
 
         @Override
         public void visit() {
-            for (ModuleData res : getPools().getGlobalPool().getClasses()) {
+            for (ModuleEntry res : getPools().getGlobalPool().getClasses()) {
                 if (res.getPath().endsWith("module-info.class")) {
                     continue;
                 }
@@ -77,7 +78,7 @@
         }
 
         @Override
-        public void test(Pool inResources, Pool outResources) throws IOException {
+        public void test(ModulePool inResources, ModulePool outResources) throws IOException {
             if (outResources.isEmpty()) {
                 throw new AssertionError("Empty result");
             }
@@ -93,13 +94,17 @@
                     throw new AssertionError("Class not transformed " + className);
                 }
             }
-            for (ModuleData r : outResources.getContent()) {
+            outResources.entries().forEach(r -> {
                 if (r.getPath().endsWith(".class") && !r.getPath().endsWith("module-info.class")) {
-                    ClassReader reader = new ClassReader(new ByteArrayInputStream(r.getBytes()));
-                    ClassWriter w = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
-                    reader.accept(w, ClassReader.EXPAND_FRAMES);
+                    try {
+                        ClassReader reader = new ClassReader(new ByteArrayInputStream(r.getBytes()));
+                        ClassWriter w = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
+                        reader.accept(w, ClassReader.EXPAND_FRAMES);
+                    } catch (IOException exp) {
+                        throw new UncheckedIOException(exp);
+                    }
                 }
-            }
+            });
         }
 
         @Override
--- a/test/tools/jlink/asmplugin/NegativeTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/asmplugin/NegativeTest.java	Mon May 16 14:47:27 2016 +0530
@@ -43,7 +43,7 @@
 import jdk.internal.org.objectweb.asm.ClassWriter;
 import jdk.internal.org.objectweb.asm.Opcodes;
 import jdk.tools.jlink.plugin.Plugin;
-import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.internal.ModulePoolImpl;
 import jdk.tools.jlink.internal.StringTable;
 import jdk.tools.jlink.internal.plugins.asm.AsmGlobalPool;
 import jdk.tools.jlink.internal.plugins.asm.AsmModulePool;
@@ -51,7 +51,7 @@
 import jdk.tools.jlink.internal.plugins.asm.AsmPool.ResourceFile;
 import jdk.tools.jlink.internal.plugins.asm.AsmPools;
 import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.ModulePool;
 
 public class NegativeTest extends AsmPluginTestBase {
     public static void main(String[] args) throws Exception {
@@ -102,7 +102,7 @@
                 }
             }
         };
-        Pool resources = new PoolImpl(ByteOrder.BIG_ENDIAN, new StringTable() {
+        ModulePool resources = new ModulePoolImpl(ByteOrder.BIG_ENDIAN, new StringTable() {
             @Override
             public int addString(String str) {
                 return -1;
@@ -136,7 +136,7 @@
                 action(() -> pools.fillOutputResources(null), "Output resource is null", NullPointerException.class);
             }
         };
-        Pool resources = new PoolImpl(ByteOrder.BIG_ENDIAN, new StringTable() {
+        ModulePool resources = new ModulePoolImpl(ByteOrder.BIG_ENDIAN, new StringTable() {
             @Override
             public int addString(String str) {
                 return -1;
--- a/test/tools/jlink/asmplugin/PackageMappingTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/asmplugin/PackageMappingTest.java	Mon May 16 14:47:27 2016 +0530
@@ -48,8 +48,8 @@
 import jdk.tools.jlink.internal.plugins.asm.AsmPool.ResourceFile;
 import jdk.tools.jlink.internal.plugins.asm.AsmPool.WritableResourcePool;
 import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 
 public class PackageMappingTest extends AsmPluginTestBase {
 
@@ -72,7 +72,7 @@
             new PackageMappingPlugin(newFiles, true)
         };
         for (TestPlugin p : plugins) {
-            Pool pool = p.visit(getPool());
+            ModulePool pool = p.visit(getPool());
             p.test(getPool(), pool);
         }
     }
@@ -105,12 +105,12 @@
         }
 
         @Override
-        public void test(Pool inResources, Pool outResources) {
+        public void test(ModulePool inResources, ModulePool outResources) {
             Set<String> in = getPools().getGlobalPool().getResourceFiles().stream()
-                    .map(ModuleData::getPath)
+                    .map(ModuleEntry::getPath)
                     .collect(Collectors.toSet());
             Set<String> out = extractResources(outResources).stream()
-                    .map(ModuleData::getPath)
+                    .map(ModuleEntry::getPath)
                     .collect(Collectors.toSet());
             in.addAll(PackageMappingTest.this.newFiles);
             if (!Objects.equals(in, out)) {
--- a/test/tools/jlink/asmplugin/SortingTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/asmplugin/SortingTest.java	Mon May 16 14:47:27 2016 +0530
@@ -35,12 +35,13 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
 import java.util.stream.Collectors;
 
 import jdk.tools.jlink.internal.plugins.asm.AsmModulePool;
 import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 
 public class SortingTest extends AsmPluginTestBase {
 
@@ -66,7 +67,7 @@
         List<String> sorted = new ArrayList<>(getResources());
         sorted.sort(null);
         ClassSorterPlugin sorterPlugin = new ClassSorterPlugin(sorted);
-        Pool resourcePool = sorterPlugin.visit(getPool());
+        ModulePool resourcePool = sorterPlugin.visit(getPool());
         sorterPlugin.test(getPool(), resourcePool);
     }
 
@@ -78,7 +79,7 @@
         List<String> sorted = new ArrayList<>(getResources());
         sorted.sort((s1, s2) -> -getModuleName(s1).compareTo(getModuleName(s2)));
         ModuleSorterPlugin sorterPlugin = new ModuleSorterPlugin();
-        Pool resourcePool = sorterPlugin.visit(getPool());
+        ModulePool resourcePool = sorterPlugin.visit(getPool());
         sorterPlugin.test(getPool(), resourcePool);
     }
 
@@ -88,8 +89,8 @@
         public void visit() {
             for (AsmModulePool modulePool : getPools().getModulePools()) {
                 modulePool.setSorter(resources -> {
-                    List<String> sort = resources.getContent().stream()
-                            .map(ModuleData::getPath)
+                    List<String> sort = resources.entries()
+                            .map(ModuleEntry::getPath)
                             .collect(Collectors.toList());
                     sort.sort(null);
                     return sort;
@@ -102,21 +103,21 @@
         }
 
         @Override
-        public void test(Pool inResources, Pool outResources) throws Exception {
+        public void test(ModulePool inResources, ModulePool outResources) throws Exception {
             if (!isVisitCalled()) {
                 throw new AssertionError("Resources not visited");
             }
-            List<String> sortedResourcePaths = outResources.getContent().stream()
-                    .map(ModuleData::getPath)
+            List<String> sortedResourcePaths = outResources.entries()
+                    .map(ModuleEntry::getPath)
                     .collect(Collectors.toList());
 
             List<String> defaultResourceOrder = new ArrayList<>();
-            for (ModuleData r : inResources.getContent()) {
-                if (!inResources.getContent().contains(r)) {
+            inResources.entries().forEach(r -> {
+                if (!inResources.contains(r)) {
                     throw new AssertionError("Resource " + r.getPath() + " not in result pool");
                 }
                 defaultResourceOrder.add(r.getPath());
-            }
+            });
             // Check that default sorting is not equal to sorted one
             if (defaultResourceOrder.equals(sortedResourcePaths)) {
                 throw new AssertionError("Sorting not applied, default ordering");
@@ -147,27 +148,28 @@
         public void visit() {
             getPools().getGlobalPool().setSorter(
                     (resources) -> expectedClassesOrder.stream()
-                            .map(resources::get)
-                            .map(ModuleData::getPath)
+                            .map(resources::findEntry)
+                            .map(Optional::get)
+                            .map(ModuleEntry::getPath)
                             .collect(Collectors.toList()));
         }
 
         @Override
-        public void test(Pool inResources, Pool outResources) throws Exception {
+        public void test(ModulePool inResources, ModulePool outResources) throws Exception {
             if (!isVisitCalled()) {
                 throw new AssertionError("Resources not visited");
             }
-            List<String> sortedResourcePaths = outResources.getContent().stream()
-                    .map(ModuleData::getPath)
+            List<String> sortedResourcePaths = outResources.entries()
+                    .map(ModuleEntry::getPath)
                     .collect(Collectors.toList());
 
             List<String> defaultResourceOrder = new ArrayList<>();
-            for (ModuleData r : getPool().getContent()) {
-                if (!getPool().getContent().contains(r)) {
+            getPool().entries().forEach(r -> {
+                if (!getPool().contains(r)) {
                     throw new AssertionError("Resource " + r.getPath() + " not in result pool");
                 }
                 defaultResourceOrder.add(r.getPath());
-            }
+            });
             // Check that default sorting is not equal to sorted one
             if (defaultResourceOrder.equals(sortedResourcePaths)) {
                 throw new AssertionError("Sorting not applied, default ordering");
--- a/test/tools/jlink/asmplugin/VisitorTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/asmplugin/VisitorTest.java	Mon May 16 14:47:27 2016 +0530
@@ -46,8 +46,8 @@
 import jdk.tools.jlink.internal.plugins.asm.AsmPool.ResourceFile;
 import jdk.tools.jlink.internal.plugins.asm.AsmPool.ResourceFileVisitor;
 import jdk.tools.jlink.internal.plugins.asm.AsmPools;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 
 public class VisitorTest extends AsmPluginTestBase {
 
@@ -69,7 +69,7 @@
         };
         for (TestPlugin p : plugins) {
             System.err.println("Testing: " + p.getName());
-            Pool out = p.visit(getPool());
+            ModulePool out = p.visit(getPool());
             p.test(getPool(), out);
         }
     }
@@ -149,15 +149,15 @@
         }
 
         @Override
-        public void test(Pool in, Pool out) throws Exception {
-            Collection<ModuleData> inClasses = getPool.apply(getPools()).getClasses();
+        public void test(ModulePool in, ModulePool out) throws Exception {
+            Collection<ModuleEntry> inClasses = getPool.apply(getPools()).getClasses();
             if (inClasses.size() != classReaderVisitor.getAmount()) {
                 throw new AssertionError("Testing " + name + ". Number of visited classes. Expected: " +
                         inClasses.size() + ", got: " + classReaderVisitor.getAmount());
             }
-            Collection<ModuleData> outClasses = extractClasses(out);
+            Collection<ModuleEntry> outClasses = extractClasses(out);
             int changedClasses = 0;
-            for (ModuleData r : outClasses) {
+            for (ModuleEntry r : outClasses) {
                 if (r.getPath().endsWith("Changed.class")) {
                     ++changedClasses;
                 }
@@ -192,15 +192,15 @@
         }
 
         @Override
-        public void test(Pool in, Pool out) throws Exception {
-            Collection<ModuleData> inResources = getPool.apply(getPools()).getResourceFiles();
+        public void test(ModulePool in, ModulePool out) throws Exception {
+            Collection<ModuleEntry> inResources = getPool.apply(getPools()).getResourceFiles();
             if (inResources.size() != resourceFileVisitor.getAmount()) {
                 throw new AssertionError("Testing " + name + ". Number of visited resources. Expected: " +
                         inResources.size() + ", got: " + resourceFileVisitor.getAmount());
             }
-            Collection<ModuleData> outResources = extractResources(out);
+            Collection<ModuleEntry> outResources = extractResources(out);
             int changedClasses = 0;
-            for (ModuleData r : outResources) {
+            for (ModuleEntry r : outResources) {
                 if (r.getPath().endsWith("Changed")) {
                     ++changedClasses;
                 }
--- a/test/tools/jlink/customplugin/plugin/CustomPlugin.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/customplugin/plugin/CustomPlugin.java	Mon May 16 14:47:27 2016 +0530
@@ -26,7 +26,9 @@
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
-import jdk.tools.jlink.plugin.Pool;
+import java.util.function.Function;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 
 public class CustomPlugin implements TransformerPlugin {
@@ -37,13 +39,8 @@
     }
 
     @Override
-    public void visit(Pool in, Pool out) {
-        in.visit(new Pool.Visitor() {
-            @Override
-            public Pool.ModuleData visit(Pool.ModuleData content) {
-                return content;
-            }
-        }, out);
+    public void visit(ModulePool in, ModulePool out) {
+        in.transformAndCopy(Function.identity(), out);
     }
 
     @Override
@@ -61,9 +58,9 @@
     }
 
     @Override
-    public Set<PluginType> getType() {
-        Set<PluginType> set = new HashSet<>();
-        set.add(CATEGORY.PROCESSOR);
+    public Set<Category> getType() {
+        Set<Category> set = new HashSet<>();
+        set.add(Category.PROCESSOR);
         return Collections.unmodifiableSet(set);
     }
 }
--- a/test/tools/jlink/customplugin/plugin/HelloPlugin.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/customplugin/plugin/HelloPlugin.java	Mon May 16 14:47:27 2016 +0530
@@ -29,8 +29,8 @@
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 
 /**
@@ -49,23 +49,23 @@
     }
 
     @Override
-    public void visit(Pool inResources, Pool outResources) {
+    public void visit(ModulePool inResources, ModulePool outResources) {
         try {
             System.out.println("Hello!!!!!!!!!!");
             File f = new File(OUTPUT_FILE);
             f.createNewFile();
-            for (ModuleData res : inResources.getContent()) {
+            inResources.entries().forEach(res -> {
                 outResources.add(res);
-            }
+            });
         } catch (IOException ex) {
             throw new UncheckedIOException(ex);
         }
     }
 
     @Override
-    public Set<PluginType> getType() {
-        Set<PluginType> set = new HashSet<>();
-        set.add(CATEGORY.TRANSFORMER);
+    public Set<Category> getType() {
+        Set<Category> set = new HashSet<>();
+        set.add(Category.TRANSFORMER);
         return Collections.unmodifiableSet(set);
     }
 
--- a/test/tools/jlink/plugins/CompressorPluginTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/plugins/CompressorPluginTest.java	Mon May 16 14:47:27 2016 +0530
@@ -53,14 +53,14 @@
 import jdk.internal.jimage.decompressor.ResourceDecompressorFactory;
 import jdk.internal.jimage.decompressor.StringSharingDecompressorFactory;
 import jdk.internal.jimage.decompressor.ZipDecompressorFactory;
-import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.internal.ModulePoolImpl;
 import jdk.tools.jlink.internal.StringTable;
 import jdk.tools.jlink.internal.plugins.DefaultCompressPlugin;
 import jdk.tools.jlink.internal.plugins.StringSharingPlugin;
 import jdk.tools.jlink.internal.plugins.ZipPlugin;
 import jdk.tools.jlink.plugin.Plugin;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 
 public class CompressorPluginTest {
@@ -86,7 +86,7 @@
                     new ZipDecompressorFactory()
                 });
 
-        Pool classes = gatherClasses(javabase);
+        ModulePool classes = gatherClasses(javabase);
         // compress = String sharing
         checkCompress(classes, new StringSharingPlugin(), null,
                 new ResourceDecompressorFactory[]{
@@ -173,8 +173,8 @@
                 Collections.singletonList(".*IOException.class"));
     }
 
-    private Pool gatherResources(Path module) throws Exception {
-        Pool pool = new PoolImpl(ByteOrder.nativeOrder(), new StringTable() {
+    private ModulePool gatherResources(Path module) throws Exception {
+        ModulePool pool = new ModulePoolImpl(ByteOrder.nativeOrder(), new StringTable() {
 
             @Override
             public int addString(String str) {
@@ -191,15 +191,15 @@
                 Path p = iterator.next();
                 if (Files.isRegularFile(p)) {
                     byte[] content = Files.readAllBytes(p);
-                    pool.add(Pool.newResource(p.toString(), content));
+                    pool.add(ModuleEntry.create(p.toString(), content));
                 }
             }
         }
         return pool;
     }
 
-    private Pool gatherClasses(Path module) throws Exception {
-        Pool pool = new PoolImpl(ByteOrder.nativeOrder(), new StringTable() {
+    private ModulePool gatherClasses(Path module) throws Exception {
+        ModulePool pool = new ModulePoolImpl(ByteOrder.nativeOrder(), new StringTable() {
 
             @Override
             public int addString(String str) {
@@ -216,27 +216,27 @@
                 Path p = iterator.next();
                 if (Files.isRegularFile(p) && p.toString().endsWith(".class")) {
                     byte[] content = Files.readAllBytes(p);
-                    pool.add(Pool.newResource(p.toString(), content));
+                    pool.add(ModuleEntry.create(p.toString(), content));
                 }
             }
         }
         return pool;
     }
 
-    private void checkCompress(Pool resources, Plugin prov,
+    private void checkCompress(ModulePool resources, Plugin prov,
             Properties config,
             ResourceDecompressorFactory[] factories) throws Exception {
         checkCompress(resources, prov, config, factories, Collections.emptyList(), Collections.emptyList());
     }
 
-    private void checkCompress(Pool resources, Plugin prov,
+    private void checkCompress(ModulePool resources, Plugin prov,
             Properties config,
             ResourceDecompressorFactory[] factories,
             List<String> includes,
             List<String> excludes) throws Exception {
-        long original = 0;
-        long compressed = 0;
-        for (ModuleData resource : resources.getContent()) {
+        long[] original = new long[1];
+        long[] compressed = new long[1];
+        resources.entries().forEach(resource -> {
             List<Pattern> includesPatterns = includes.stream()
                     .map(Pattern::compile)
                     .collect(Collectors.toList());
@@ -252,7 +252,7 @@
             }
             prov.configure(props);
             final Map<Integer, String> strings = new HashMap<>();
-            PoolImpl inputResources = new PoolImpl(ByteOrder.nativeOrder(), new StringTable() {
+            ModulePoolImpl inputResources = new ModulePoolImpl(ByteOrder.nativeOrder(), new StringTable() {
                 @Override
                 public int addString(String str) {
                     int id = strID;
@@ -267,32 +267,32 @@
                 }
             });
             inputResources.add(resource);
-            Pool compressedResources = applyCompressor(prov, inputResources, resource, includesPatterns, excludesPatterns);
-            original += resource.getLength();
-            compressed += compressedResources.get(resource.getPath()).getLength();
+            ModulePool compressedResources = applyCompressor(prov, inputResources, resource, includesPatterns, excludesPatterns);
+            original[0] += resource.getLength();
+            compressed[0] += compressedResources.findEntry(resource.getPath()).get().getLength();
             applyDecompressors(factories, inputResources, compressedResources, strings, includesPatterns, excludesPatterns);
-        }
+        });
         String compressors = Stream.of(factories)
                 .map(Object::getClass)
                 .map(Class::getSimpleName)
                 .collect(Collectors.joining(", "));
-        String size = "Compressed size: " + compressed + ", original size: " + original;
+        String size = "Compressed size: " + compressed[0] + ", original size: " + original[0];
         System.out.println("Used " + compressors + ". " + size);
-        if (original <= compressed) {
+        if (original[0] <= compressed[0]) {
             throw new AssertionError("java.base not compressed.");
         }
     }
 
-    private Pool applyCompressor(Plugin plugin,
-            PoolImpl inputResources,
-            ModuleData res,
+    private ModulePool applyCompressor(Plugin plugin,
+            ModulePoolImpl inputResources,
+            ModuleEntry res,
             List<Pattern> includesPatterns,
-            List<Pattern> excludesPatterns) throws Exception {
+            List<Pattern> excludesPatterns) {
         TransformerPlugin compressor = (TransformerPlugin) plugin;
-        Pool compressedPool = new PoolImpl(ByteOrder.nativeOrder(), inputResources.getStringTable());
-        compressor.visit(inputResources, compressedPool);
+        ModulePool compressedModulePool = new ModulePoolImpl(ByteOrder.nativeOrder(), inputResources.getStringTable());
+        compressor.visit(inputResources, compressedModulePool);
         String path = res.getPath();
-        ModuleData compressed = compressedPool.get(path);
+        ModuleEntry compressed = compressedModulePool.findEntry(path).get();
         CompressedResourceHeader header
                 = CompressedResourceHeader.readFromResource(ByteOrder.nativeOrder(), compressed.getBytes());
         if (isIncluded(includesPatterns, excludesPatterns, path)) {
@@ -310,29 +310,33 @@
         } else if (header != null) {
             throw new AssertionError("Path should not be compressed: " + path);
         }
-        return compressedPool;
+        return compressedModulePool;
     }
 
     private void applyDecompressors(ResourceDecompressorFactory[] decompressors,
-            Pool inputResources,
-            Pool compressedResources,
+            ModulePool inputResources,
+            ModulePool compressedResources,
             Map<Integer, String> strings,
             List<Pattern> includesPatterns,
-            List<Pattern> excludesPatterns) throws Exception {
-        for (ModuleData compressed : compressedResources.getContent()) {
+            List<Pattern> excludesPatterns) {
+        compressedResources.entries().forEach(compressed -> {
             CompressedResourceHeader header = CompressedResourceHeader.readFromResource(
                     ByteOrder.nativeOrder(), compressed.getBytes());
             String path = compressed.getPath();
-            ModuleData orig = inputResources.get(path);
+            ModuleEntry orig = inputResources.findEntry(path).get();
             if (!isIncluded(includesPatterns, excludesPatterns, path)) {
-                continue;
+                return;
             }
             byte[] decompressed = compressed.getBytes();
             for (ResourceDecompressorFactory factory : decompressors) {
-                ResourceDecompressor decompressor = factory.newDecompressor(new Properties());
-                decompressed = decompressor.decompress(
+                try {
+                    ResourceDecompressor decompressor = factory.newDecompressor(new Properties());
+                    decompressed = decompressor.decompress(
                         strings::get, decompressed,
                         CompressedResourceHeader.getSize(), header.getUncompressedSize());
+                } catch (Exception exp) {
+                    throw new RuntimeException(exp);
+                }
             }
 
             if (decompressed.length != orig.getLength()) {
@@ -345,7 +349,7 @@
                     throw new AssertionError("Decompressed and original differ at index " + i);
                 }
             }
-        }
+        });
     }
 
     private boolean isIncluded(List<Pattern> includesPatterns, List<Pattern> excludesPatterns, String path) {
--- a/test/tools/jlink/plugins/ExcludeFilesPluginTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/plugins/ExcludeFilesPluginTest.java	Mon May 16 14:47:27 2016 +0530
@@ -35,12 +35,11 @@
 import java.nio.file.Files;
 import java.util.HashMap;
 import java.util.Map;
-import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.internal.ModulePoolImpl;
 
 import jdk.tools.jlink.internal.plugins.ExcludeFilesPlugin;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
-import jdk.tools.jlink.plugin.Pool.ModuleDataType;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 
 public class ExcludeFilesPluginTest {
@@ -73,20 +72,20 @@
         prop.put(ExcludeFilesPlugin.NAME, s);
         ExcludeFilesPlugin fplug = new ExcludeFilesPlugin();
         fplug.configure(prop);
-        PoolImpl files = new PoolImpl();
-        PoolImpl fresult = new PoolImpl();
-        ModuleData f = Pool.newImageFile(module, "/" + module + "/" + sample,
-                ModuleDataType.CONFIG, new ByteArrayInputStream(new byte[0]), 0);
+        ModulePoolImpl files = new ModulePoolImpl();
+        ModulePoolImpl fresult = new ModulePoolImpl();
+        ModuleEntry f = ModuleEntry.create(module, "/" + module + "/" + sample,
+                ModuleEntry.Type.CONFIG, new ByteArrayInputStream(new byte[0]), 0);
         files.add(f);
 
         fplug.visit(files, fresult);
 
         if (exclude) {
-            if (fresult.getContent().contains(f)) {
+            if (fresult.contains(f)) {
                 throw new Exception(sample + " should be excluded by " + s);
             }
         } else {
-            if (!fresult.getContent().contains(f)) {
+            if (!fresult.contains(f)) {
                 throw new Exception(sample + " shouldn't be excluded by " + s);
             }
         }
--- a/test/tools/jlink/plugins/ExcludePluginTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/plugins/ExcludePluginTest.java	Mon May 16 14:47:27 2016 +0530
@@ -34,11 +34,11 @@
 import java.nio.file.Files;
 import java.util.HashMap;
 import java.util.Map;
-import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.internal.ModulePoolImpl;
 
 import jdk.tools.jlink.internal.plugins.ExcludePlugin;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 
 public class ExcludePluginTest {
 
@@ -75,17 +75,17 @@
         prop.put(ExcludePlugin.NAME, s);
         ExcludePlugin excludePlugin = new ExcludePlugin();
         excludePlugin.configure(prop);
-        Pool resources = new PoolImpl();
-        ModuleData resource = Pool.newResource(sample, new byte[0]);
+        ModulePool resources = new ModulePoolImpl();
+        ModuleEntry resource = ModuleEntry.create(sample, new byte[0]);
         resources.add(resource);
-        Pool result = new PoolImpl();
+        ModulePool result = new ModulePoolImpl();
         excludePlugin.visit(resources, result);
         if (exclude) {
-            if (result.getContent().contains(resource)) {
+            if (result.contains(resource)) {
                 throw new AssertionError(sample + " should be excluded by " + s);
             }
         } else {
-            if (!result.getContent().contains(resource)) {
+            if (!result.contains(resource)) {
                 throw new AssertionError(sample + " shouldn't be excluded by " + s);
             }
         }
--- a/test/tools/jlink/plugins/ExcludeVMPluginTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/plugins/ExcludeVMPluginTest.java	Mon May 16 14:47:27 2016 +0530
@@ -32,13 +32,12 @@
 import java.io.ByteArrayInputStream;
 import java.util.HashMap;
 import java.util.Map;
-import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.internal.ModulePoolImpl;
 
 import jdk.tools.jlink.internal.plugins.ExcludeVMPlugin;
 import jdk.tools.jlink.plugin.Plugin;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
-import jdk.tools.jlink.plugin.Pool.ModuleDataType;
+import jdk.tools.jlink.plugin.ModulePool;
+import jdk.tools.jlink.plugin.ModuleEntry;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 
 public class ExcludeVMPluginTest {
@@ -165,14 +164,14 @@
     private void doCheckVM(String vm, String[] input, String jvmcfg, String[] expectedOutput, String expectdJvmCfg) throws Exception {
         // Create a pool with jvm.cfg and the input paths.
         byte[] jvmcfgContent = jvmcfg.getBytes();
-        Pool pool = new PoolImpl();
-        pool.add(Pool.newImageFile("java.base", "/java.base/native/jvm.cfg",
-                ModuleDataType.NATIVE_LIB, new ByteArrayInputStream(jvmcfgContent), jvmcfgContent.length));
+        ModulePool pool = new ModulePoolImpl();
+        pool.add(ModuleEntry.create("java.base", "/java.base/native/jvm.cfg",
+                ModuleEntry.Type.NATIVE_LIB, new ByteArrayInputStream(jvmcfgContent), jvmcfgContent.length));
         for (String in : input) {
-            pool.add(Pool.newImageFile("java.base", in,
-                    ModuleDataType.NATIVE_LIB, new ByteArrayInputStream(new byte[0]), 0));
+            pool.add(ModuleEntry.create("java.base", in,
+                    ModuleEntry.Type.NATIVE_LIB, new ByteArrayInputStream(new byte[0]), 0));
         }
-        Pool out = new PoolImpl();
+        ModulePool out = new ModulePoolImpl();
 
         TransformerPlugin p = new ExcludeVMPlugin();
         Map<String, String> config = new HashMap<>();
@@ -182,22 +181,22 @@
         p.configure(config);
         p.visit(pool, out);
 
-        String newContent = new String(out.get("/java.base/native/jvm.cfg").stream().readAllBytes());
+        String newContent = new String(out.findEntry("/java.base/native/jvm.cfg").get().stream().readAllBytes());
 
         if (!expectdJvmCfg.equals(newContent)) {
             throw new Exception("Got content " + newContent + " expected " + expectdJvmCfg);
         }
 
-        if (out.getContent().size() != (expectedOutput.length + 1)) {
-            for (ModuleData m : out.getContent()) {
+        if (out.getEntryCount() != (expectedOutput.length + 1)) {
+            out.entries().forEach(m -> {
                 System.err.println(m.getPath());
-            }
-            throw new Exception("Invalid output size " + out.getContent().size() + " expected " + (expectedOutput.length + 1));
+            });
+            throw new Exception("Invalid output size " + out.getEntryCount() + " expected " + (expectedOutput.length + 1));
         }
 
-        for (ModuleData md : out.getContent()) {
+        out.entries().forEach(md -> {
             if (md.getPath().equals("/java.base/native/jvm.cfg")) {
-                continue;
+                return;
             }
             boolean contained = false;
             for (String o : expectedOutput) {
@@ -207,9 +206,9 @@
                 }
             }
             if (!contained) {
-                throw new Exception(md.getPath() + " not expected");
+                throw new RuntimeException(md.getPath() + " not expected");
             }
-        }
+        });
 
     }
 
--- a/test/tools/jlink/plugins/FileCopierPluginTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/plugins/FileCopierPluginTest.java	Mon May 16 14:47:27 2016 +0530
@@ -26,6 +26,7 @@
  * @summary Test files copy plugin
  * @author Jean-Francois Denise
  * @modules jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.builder
  *          jdk.jlink/jdk.tools.jlink.internal.plugins
  * @run main FileCopierPluginTest
  */
@@ -36,13 +37,12 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
-import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.internal.ModulePoolImpl;
 import jdk.tools.jlink.builder.DefaultImageBuilder;
 
 import jdk.tools.jlink.internal.plugins.FileCopierPlugin;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
-import jdk.tools.jlink.plugin.Pool.ModuleDataType;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 
 public class FileCopierPluginTest {
 
@@ -85,21 +85,20 @@
         Map<String, String> conf = new HashMap<>();
         conf.put(FileCopierPlugin.NAME, builder.toString());
         plug.configure(conf);
-        Pool pool = new PoolImpl();
-        plug.visit(new PoolImpl(), pool);
-        if (pool.getContent().size() != expected) {
+        ModulePool pool = new ModulePoolImpl();
+        plug.visit(new ModulePoolImpl(), pool);
+        if (pool.getEntryCount() != expected) {
             throw new AssertionError("Wrong number of added files");
         }
-        for (ModuleData f : pool.getContent()) {
-            if (!f.getType().equals(ModuleDataType.OTHER)) {
+        pool.entries().forEach(f -> {
+            if (!f.getType().equals(ModuleEntry.Type.OTHER)) {
                 throw new AssertionError("Invalid type " + f.getType()
                         + " for file " + f.getPath());
             }
             if (f.stream() == null) {
                 throw new AssertionError("Null stream for file " + f.getPath());
             }
-
-        }
+        });
         Path root = new File(".").toPath();
         DefaultImageBuilder imgbuilder = new DefaultImageBuilder(root);
         imgbuilder.storeFiles(pool);
--- a/test/tools/jlink/plugins/LastSorterTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/plugins/LastSorterTest.java	Mon May 16 14:47:27 2016 +0530
@@ -26,6 +26,7 @@
  * @summary Test last sorter property
  * @author Jean-Francois Denise
  * @modules jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink
  * @run main/othervm LastSorterTest
  */
 
@@ -40,12 +41,12 @@
 import jdk.tools.jlink.internal.ImagePluginConfiguration;
 import jdk.tools.jlink.internal.PluginRepository;
 import jdk.tools.jlink.internal.ImagePluginStack;
-import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.internal.ModulePoolImpl;
 import jdk.tools.jlink.Jlink;
 import jdk.tools.jlink.Jlink.PluginsConfiguration;
 import jdk.tools.jlink.plugin.Plugin;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 
 public class LastSorterTest {
@@ -80,7 +81,7 @@
         ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(config);
 
         // check order
-        PoolImpl res = fillOutResourcePool();
+        ModulePoolImpl res = fillOutResourceModulePool();
 
         try {
             stack.visitResources(res);
@@ -91,18 +92,18 @@
         }
     }
 
-    private PoolImpl fillOutResourcePool() throws Exception {
-        PoolImpl res = new PoolImpl();
-        res.add(Pool.newResource("/eee/bbb/res1.class", new byte[90]));
-        res.add(Pool.newResource("/aaaa/bbb/res2.class", new byte[90]));
-        res.add(Pool.newResource("/bbb/aa/res1.class", new byte[90]));
-        res.add(Pool.newResource("/aaaa/bbb/res3.class", new byte[90]));
-        res.add(Pool.newResource("/bbb/aa/res2.class", new byte[90]));
-        res.add(Pool.newResource("/fff/bbb/res1.class", new byte[90]));
-        res.add(Pool.newResource("/aaaa/bbb/res1.class", new byte[90]));
-        res.add(Pool.newResource("/bbb/aa/res3.class", new byte[90]));
-        res.add(Pool.newResource("/ccc/bbb/res1.class", new byte[90]));
-        res.add(Pool.newResource("/ddd/bbb/res1.class", new byte[90]));
+    private ModulePoolImpl fillOutResourceModulePool() throws Exception {
+        ModulePoolImpl res = new ModulePoolImpl();
+        res.add(ModuleEntry.create("/eee/bbb/res1.class", new byte[90]));
+        res.add(ModuleEntry.create("/aaaa/bbb/res2.class", new byte[90]));
+        res.add(ModuleEntry.create("/bbb/aa/res1.class", new byte[90]));
+        res.add(ModuleEntry.create("/aaaa/bbb/res3.class", new byte[90]));
+        res.add(ModuleEntry.create("/bbb/aa/res2.class", new byte[90]));
+        res.add(ModuleEntry.create("/fff/bbb/res1.class", new byte[90]));
+        res.add(ModuleEntry.create("/aaaa/bbb/res1.class", new byte[90]));
+        res.add(ModuleEntry.create("/bbb/aa/res3.class", new byte[90]));
+        res.add(ModuleEntry.create("/ccc/bbb/res1.class", new byte[90]));
+        res.add(ModuleEntry.create("/ddd/bbb/res1.class", new byte[90]));
         return res;
     }
 
@@ -124,7 +125,7 @@
         ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(config);
 
         // check order
-        PoolImpl res = fillOutResourcePool();
+        ModulePoolImpl res = fillOutResourceModulePool();
 
         stack.visitResources(res);
     }
@@ -159,7 +160,7 @@
         ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(config);
 
         // check order
-        PoolImpl res = fillOutResourcePool();
+        ModulePoolImpl res = fillOutResourceModulePool();
         try {
             stack.visitResources(res);
             throw new AssertionError("Order was changed after the last sorter, but no exception occurred");
@@ -178,17 +179,17 @@
         }
 
         @Override
-        public void visit(Pool resources, Pool output) {
-            List<ModuleData> paths = new ArrayList<>();
-            for (ModuleData res : resources.getContent()) {
+        public void visit(ModulePool resources, ModulePool output) {
+            List<ModuleEntry> paths = new ArrayList<>();
+            resources.entries().forEach(res -> {
                 if (res.getPath().startsWith(starts)) {
                     paths.add(0, res);
                 } else {
                     paths.add(res);
                 }
-            }
+            });
 
-            for (ModuleData r : paths) {
+            for (ModuleEntry r : paths) {
                 output.add(r);
             }
         }
@@ -199,9 +200,9 @@
         }
 
         @Override
-        public Set<PluginType> getType() {
-            Set<PluginType> set = new HashSet<>();
-            set.add(CATEGORY.TRANSFORMER);
+        public Set<Category> getType() {
+            Set<Category> set = new HashSet<>();
+            set.add(Category.TRANSFORMER);
             return Collections.unmodifiableSet(set);
         }
 
--- a/test/tools/jlink/plugins/OrderResourcesPluginTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/plugins/OrderResourcesPluginTest.java	Mon May 16 14:47:27 2016 +0530
@@ -36,11 +36,12 @@
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
-import jdk.tools.jlink.internal.PoolImpl;
+import java.util.stream.Collectors;
 
+import jdk.tools.jlink.internal.ModulePoolImpl;
 import jdk.tools.jlink.internal.plugins.OrderResourcesPlugin;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 
 public class OrderResourcesPluginTest {
@@ -50,52 +51,52 @@
     }
 
     public void test() throws Exception {
-        ModuleData[] array = {
-                Pool.newResource("/module1/toto1.class", new byte[0]),
-                Pool.newResource("/module2/toto2.class", new byte[0]),
-                Pool.newResource("/module3/toto3.class", new byte[0]),
-                Pool.newResource("/module3/toto3/module-info.class", new byte[0]),
-                Pool.newResource("/zazou/toto.class", new byte[0]),
-                Pool.newResource("/module4/zazou.class", new byte[0]),
-                Pool.newResource("/module5/toto5.class", new byte[0]),
-                Pool.newResource("/module6/toto6/module-info.class", new byte[0])
+        ModuleEntry[] array = {
+                ModuleEntry.create("/module1/toto1.class", new byte[0]),
+                ModuleEntry.create("/module2/toto2.class", new byte[0]),
+                ModuleEntry.create("/module3/toto3.class", new byte[0]),
+                ModuleEntry.create("/module3/toto3/module-info.class", new byte[0]),
+                ModuleEntry.create("/zazou/toto.class", new byte[0]),
+                ModuleEntry.create("/module4/zazou.class", new byte[0]),
+                ModuleEntry.create("/module5/toto5.class", new byte[0]),
+                ModuleEntry.create("/module6/toto6/module-info.class", new byte[0])
         };
 
-        ModuleData[] sorted = {
-                Pool.newResource("/zazou/toto.class", new byte[0]),
-                Pool.newResource("/module3/toto3/module-info.class", new byte[0]),
-                Pool.newResource("/module6/toto6/module-info.class", new byte[0]),
-                Pool.newResource("/module1/toto1.class", new byte[0]),
-                Pool.newResource("/module2/toto2.class", new byte[0]),
-                Pool.newResource("/module3/toto3.class", new byte[0]),
-                Pool.newResource("/module4/zazou.class", new byte[0]),
-                Pool.newResource("/module5/toto5.class", new byte[0])
+        ModuleEntry[] sorted = {
+                ModuleEntry.create("/zazou/toto.class", new byte[0]),
+                ModuleEntry.create("/module3/toto3/module-info.class", new byte[0]),
+                ModuleEntry.create("/module6/toto6/module-info.class", new byte[0]),
+                ModuleEntry.create("/module1/toto1.class", new byte[0]),
+                ModuleEntry.create("/module2/toto2.class", new byte[0]),
+                ModuleEntry.create("/module3/toto3.class", new byte[0]),
+                ModuleEntry.create("/module4/zazou.class", new byte[0]),
+                ModuleEntry.create("/module5/toto5.class", new byte[0])
         };
 
-        ModuleData[] sorted2 = {
-            Pool.newResource("/module5/toto5.class", new byte[0]),
-            Pool.newResource("/module6/toto6/module-info.class", new byte[0]),
-            Pool.newResource("/module4/zazou.class", new byte[0]),
-            Pool.newResource("/module3/toto3.class", new byte[0]),
-            Pool.newResource("/module3/toto3/module-info.class", new byte[0]),
-            Pool.newResource("/module1/toto1.class", new byte[0]),
-            Pool.newResource("/module2/toto2.class", new byte[0]),
-            Pool.newResource("/zazou/toto.class", new byte[0])
+        ModuleEntry[] sorted2 = {
+            ModuleEntry.create("/module5/toto5.class", new byte[0]),
+            ModuleEntry.create("/module6/toto6/module-info.class", new byte[0]),
+            ModuleEntry.create("/module4/zazou.class", new byte[0]),
+            ModuleEntry.create("/module3/toto3.class", new byte[0]),
+            ModuleEntry.create("/module3/toto3/module-info.class", new byte[0]),
+            ModuleEntry.create("/module1/toto1.class", new byte[0]),
+            ModuleEntry.create("/module2/toto2.class", new byte[0]),
+            ModuleEntry.create("/zazou/toto.class", new byte[0])
         };
 
-        Pool resources = new PoolImpl();
-        for (ModuleData r : array) {
+        ModulePool resources = new ModulePoolImpl();
+        for (ModuleEntry r : array) {
             resources.add(r);
         }
 
         {
-            Pool out = new PoolImpl();
+            ModulePool out = new ModulePoolImpl();
             Map<String, String> config = new HashMap<>();
             config.put(OrderResourcesPlugin.NAME, "/zazou/*,*/module-info.class");
             TransformerPlugin p = new OrderResourcesPlugin();
             p.configure(config);
             p.visit(resources, out);
-            check(out.getContent(), sorted);
+            check(out.entries().collect(Collectors.toList()), sorted);
         }
 
         {
@@ -112,26 +113,26 @@
             }
             Files.write(order.toPath(), builder.toString().getBytes());
 
-            Pool out = new PoolImpl();
+            ModulePool out = new ModulePoolImpl();
             Map<String, String> config = new HashMap<>();
             config.put(OrderResourcesPlugin.NAME, "@" + order.getAbsolutePath());
             TransformerPlugin p = new OrderResourcesPlugin();
             p.configure(config);
             p.visit(resources, out);
-            check(out.getContent(), sorted2);
+            check(out.entries().collect(Collectors.toList()), sorted2);
 
         }
     }
 
-    private void check(Collection<ModuleData> outResources,
-            ModuleData[] sorted) {
+    private void check(Collection<ModuleEntry> outResources,
+            ModuleEntry[] sorted) {
         if (outResources.size() != sorted.length) {
             throw new AssertionError("Wrong number of resources:\n"
                     + "expected: " + Arrays.toString(sorted) + ",\n"
                     + "     got: " + outResources);
         }
         int i = 0;
-        for (ModuleData r : outResources) {
+        for (ModuleEntry r : outResources) {
             System.err.println("Resource: " + r);
             if (!sorted[i].getPath().equals(r.getPath())) {
                 throw new AssertionError("Resource not properly sorted, difference at: " + i + "\n"
--- a/test/tools/jlink/plugins/PluginOrderTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/plugins/PluginOrderTest.java	Mon May 16 14:47:27 2016 +0530
@@ -44,8 +44,8 @@
 
 import jdk.tools.jlink.internal.PluginOrderingGraph;
 import jdk.tools.jlink.plugin.Plugin;
-import jdk.tools.jlink.plugin.Plugin.CATEGORY;
-import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.Plugin.Category;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 
 public class PluginOrderTest {
@@ -96,8 +96,8 @@
         set.add("plug2");
         List<Plugin> plugins = new ArrayList<>();
         plugins.add(new Plug("plug2", Collections.emptySet(), Collections.emptySet(),
-                CATEGORY.TRANSFORMER));
-        plugins.add(new Plug("plug1", set, Collections.emptySet(), CATEGORY.TRANSFORMER));
+                Category.TRANSFORMER));
+        plugins.add(new Plug("plug1", set, Collections.emptySet(), Category.TRANSFORMER));
         List<Plugin> ordered = PluginOrderingGraph.sort(plugins);
         if (ordered.get(0) != plugins.get(1) || ordered.get(1) != plugins.get(0)) {
             throw new Exception("Invalid sorting");
@@ -108,32 +108,32 @@
         Set<String> lst1 = new HashSet<>();
         lst1.add("plug2");
         lst1.add("plug3");
-        Plugin p1 = new Plug("plug1", lst1, Collections.emptySet(), CATEGORY.TRANSFORMER);
+        Plugin p1 = new Plug("plug1", lst1, Collections.emptySet(), Category.TRANSFORMER);
 
-        Plugin p2 = new Plug("plug2", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER);
+        Plugin p2 = new Plug("plug2", Collections.emptySet(), Collections.emptySet(), Category.TRANSFORMER);
 
         Set<String> lst3 = new HashSet<>();
         lst3.add("plug4");
         lst3.add("plug6");
-        Plugin p3 = new Plug("plug3", lst3, Collections.emptySet(), CATEGORY.TRANSFORMER);
+        Plugin p3 = new Plug("plug3", lst3, Collections.emptySet(), Category.TRANSFORMER);
 
-        Plugin p4 = new Plug("plug4", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER);
+        Plugin p4 = new Plug("plug4", Collections.emptySet(), Collections.emptySet(), Category.TRANSFORMER);
 
         Set<String> lst5 = new HashSet<>();
         lst5.add("plug3");
         lst5.add("plug1");
         lst5.add("plug2");
         lst5.add("plug6");
-        Plugin p5 = new Plug("plug5", lst5, Collections.emptySet(), CATEGORY.TRANSFORMER);
+        Plugin p5 = new Plug("plug5", lst5, Collections.emptySet(), Category.TRANSFORMER);
 
         Set<String> lst6 = new HashSet<>();
         lst6.add("plug4");
         lst6.add("plug2");
-        Plugin p6 = new Plug("plug6", lst6, Collections.emptySet(), CATEGORY.TRANSFORMER);
+        Plugin p6 = new Plug("plug6", lst6, Collections.emptySet(), Category.TRANSFORMER);
 
-        Plugin p7 = new Plug("plug7", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER);
+        Plugin p7 = new Plug("plug7", Collections.emptySet(), Collections.emptySet(), Category.TRANSFORMER);
 
-        Plugin p8 = new Plug("plug8", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER);
+        Plugin p8 = new Plug("plug8", Collections.emptySet(), Collections.emptySet(), Category.TRANSFORMER);
 
         List<Plugin> plugins = new ArrayList<>();
         plugins.add(p1);
@@ -153,11 +153,11 @@
         set2.add("plug1");
         List<Plugin> plugins = new ArrayList<>();
         plugins.add(new Plug("plug2", set2, Collections.emptySet(),
-                CATEGORY.TRANSFORMER));
+                Category.TRANSFORMER));
 
         Set<String> set1 = new HashSet<>();
         set1.add("plug2");
-        plugins.add(new Plug("plug1", set1, Collections.emptySet(), CATEGORY.TRANSFORMER));
+        plugins.add(new Plug("plug1", set1, Collections.emptySet(), Category.TRANSFORMER));
         PluginOrderingGraph.sort(plugins);
 
     }
@@ -166,31 +166,31 @@
         Set<String> lst1 = new HashSet<>();
         lst1.add("plug2");
         lst1.add("plug3");
-        Plugin p1 = new Plug("plug1", lst1, Collections.emptySet(), CATEGORY.TRANSFORMER);
+        Plugin p1 = new Plug("plug1", lst1, Collections.emptySet(), Category.TRANSFORMER);
 
-        Plugin p2 = new Plug("plug2", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER);
+        Plugin p2 = new Plug("plug2", Collections.emptySet(), Collections.emptySet(), Category.TRANSFORMER);
 
         Set<String> lst3 = new HashSet<>();
         lst3.add("plug4");
         lst3.add("plug6");
-        Plugin p3 = new Plug("plug3", lst3, Collections.emptySet(), CATEGORY.TRANSFORMER);
+        Plugin p3 = new Plug("plug3", lst3, Collections.emptySet(), Category.TRANSFORMER);
 
-        Plugin p4 = new Plug("plug4", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER);
+        Plugin p4 = new Plug("plug4", Collections.emptySet(), Collections.emptySet(), Category.TRANSFORMER);
 
         Set<String> lst5 = new HashSet<>();
         lst5.add("plug3");
         lst5.add("plug1");
         lst5.add("plug2");
-        Plugin p5 = new Plug("plug5", lst5, Collections.emptySet(), CATEGORY.TRANSFORMER);
+        Plugin p5 = new Plug("plug5", lst5, Collections.emptySet(), Category.TRANSFORMER);
 
         Set<String> lst6 = new HashSet<>();
         lst6.add("plug4");
         lst6.add("plug1");
-        Plugin p6 = new Plug("plug6", lst6, Collections.emptySet(), CATEGORY.TRANSFORMER);
+        Plugin p6 = new Plug("plug6", lst6, Collections.emptySet(), Category.TRANSFORMER);
 
-        Plugin p7 = new Plug("plug7", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER);
+        Plugin p7 = new Plug("plug7", Collections.emptySet(), Collections.emptySet(), Category.TRANSFORMER);
 
-        Plugin p8 = new Plug("plug8", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER);
+        Plugin p8 = new Plug("plug8", Collections.emptySet(), Collections.emptySet(), Category.TRANSFORMER);
 
         List<Plugin> plugins = new ArrayList<>();
         plugins.add(p1);
@@ -208,8 +208,8 @@
         Set<String> lst1 = new HashSet<>();
         lst1.add("plug2");
         lst1.add("plug3");
-        Plugin p = new Plug("plug1", lst1, Collections.emptySet(), CATEGORY.TRANSFORMER);
-        Plugin p2 = new Plug("plug2", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER);
+        Plugin p = new Plug("plug1", lst1, Collections.emptySet(), Category.TRANSFORMER);
+        Plugin p2 = new Plug("plug2", Collections.emptySet(), Collections.emptySet(), Category.TRANSFORMER);
 
         Set<String> lst3 = new HashSet<>();
         lst3.add("plug2");
@@ -217,7 +217,7 @@
         Set<String> lst4 = new HashSet<>();
         lst4.add("plug1");
 
-        Plugin p3 = new Plug("plug3", lst4, lst3, CATEGORY.TRANSFORMER);
+        Plugin p3 = new Plug("plug3", lst4, lst3, Category.TRANSFORMER);
         List<Plugin> plugins = new ArrayList<>();
         plugins.add(p);
         plugins.add(p2);
@@ -229,10 +229,10 @@
 
         private final Set<String> isBefore;
         private final Set<String> isAfter;
-        private final CATEGORY category;
+        private final Category category;
         private final String name;
 
-        private Plug(String name, Set<String> isBefore, Set<String> isAfter, CATEGORY category) {
+        private Plug(String name, Set<String> isBefore, Set<String> isAfter, Category category) {
             this.name = name;
             this.isBefore = isBefore;
             this.isAfter = isAfter;
@@ -255,12 +255,12 @@
         }
 
         @Override
-        public void visit(Pool in, Pool out) {
+        public void visit(ModulePool in, ModulePool out) {
 
         }
 
         @Override
-        public Set<PluginType> getType() {
+        public Set<Category> getType() {
             return Collections.singleton(category);
         }
 
--- a/test/tools/jlink/plugins/PluginsNegativeTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/plugins/PluginsNegativeTest.java	Mon May 16 14:47:27 2016 +0530
@@ -26,6 +26,7 @@
  * @summary Negative test for ImagePluginStack.
  * @author Andrei Eremeev
  * @modules jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink
  * @run main/othervm PluginsNegativeTest
  */
 import java.lang.reflect.Layer;
@@ -39,11 +40,12 @@
 import jdk.tools.jlink.internal.ImagePluginConfiguration;
 import jdk.tools.jlink.internal.PluginRepository;
 import jdk.tools.jlink.internal.ImagePluginStack;
-import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.internal.ModulePoolImpl;
 import jdk.tools.jlink.Jlink;
 import jdk.tools.jlink.Jlink.PluginsConfiguration;
 import jdk.tools.jlink.plugin.Plugin;
-import jdk.tools.jlink.plugin.Pool;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 
 public class PluginsNegativeTest {
@@ -96,8 +98,8 @@
         plugins.add(createPlugin("plugin"));
         ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(new PluginsConfiguration(plugins,
                 null, null));
-        PoolImpl inResources = new PoolImpl();
-        inResources.add(Pool.newResource("/aaa/bbb/A", new byte[10]));
+        ModulePoolImpl inResources = new ModulePoolImpl();
+        inResources.add(ModuleEntry.create("/aaa/bbb/A", new byte[10]));
         try {
             stack.visitResources(inResources);
             throw new AssertionError("Exception expected when output resource is empty");
@@ -110,8 +112,8 @@
         plugins.add(createPlugin("plugin"));
         ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(new PluginsConfiguration(plugins,
                 null, null));
-        PoolImpl inResources = new PoolImpl();
-        PoolImpl outResources = (PoolImpl) stack.visitResources(inResources);
+        ModulePoolImpl inResources = new ModulePoolImpl();
+        ModulePoolImpl outResources = (ModulePoolImpl) stack.visitResources(inResources);
         if (!outResources.isEmpty()) {
             throw new AssertionError("Output resource is not empty");
         }
@@ -126,7 +128,7 @@
         }
 
         @Override
-        public void visit(Pool inResources, Pool outResources) {
+        public void visit(ModulePool inResources, ModulePool outResources) {
             // do nothing
         }
 
@@ -136,9 +138,9 @@
         }
 
         @Override
-        public Set<PluginType> getType() {
-            Set<PluginType> set = new HashSet<>();
-            set.add(CATEGORY.TRANSFORMER);
+        public Set<Category> getType() {
+            Set<Category> set = new HashSet<>();
+            set.add(Category.TRANSFORMER);
             return Collections.unmodifiableSet(set);
         }
 
--- a/test/tools/jlink/plugins/PrevisitorTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/plugins/PrevisitorTest.java	Mon May 16 14:47:27 2016 +0530
@@ -26,6 +26,7 @@
  * @summary Test previsitor
  * @author Andrei Eremeev
  * @modules jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink
  * @run main/othervm PrevisitorTest
  */
 import java.nio.ByteOrder;
@@ -36,19 +37,20 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
 
 import jdk.tools.jlink.internal.ImagePluginConfiguration;
 import jdk.tools.jlink.internal.PluginRepository;
 import jdk.tools.jlink.internal.ImagePluginStack;
-import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.internal.ModulePoolImpl;
 import jdk.tools.jlink.internal.ResourcePrevisitor;
 import jdk.tools.jlink.internal.StringTable;
 import jdk.tools.jlink.Jlink;
 import jdk.tools.jlink.plugin.Plugin;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 
 public class PrevisitorTest {
@@ -68,17 +70,17 @@
         plugins.add(createPlugin(CustomPlugin.NAME));
         ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(new Jlink.PluginsConfiguration(plugins,
                 null, null));
-        PoolImpl inResources = new PoolImpl(ByteOrder.nativeOrder(), new CustomStringTable());
-        inResources.add(Pool.newResource("/aaa/bbb/res1.class", new byte[90]));
-        inResources.add(Pool.newResource("/aaa/bbb/res2.class", new byte[90]));
-        inResources.add(Pool.newResource("/aaa/bbb/res3.class", new byte[90]));
-        inResources.add(Pool.newResource("/aaa/ddd/res1.class", new byte[90]));
-        inResources.add(Pool.newResource("/aaa/res1.class", new byte[90]));
-        Pool outResources = stack.visitResources(inResources);
-        Collection<String> input = inResources.getContent().stream()
+        ModulePoolImpl inResources = new ModulePoolImpl(ByteOrder.nativeOrder(), new CustomStringTable());
+        inResources.add(ModuleEntry.create("/aaa/bbb/res1.class", new byte[90]));
+        inResources.add(ModuleEntry.create("/aaa/bbb/res2.class", new byte[90]));
+        inResources.add(ModuleEntry.create("/aaa/bbb/res3.class", new byte[90]));
+        inResources.add(ModuleEntry.create("/aaa/ddd/res1.class", new byte[90]));
+        inResources.add(ModuleEntry.create("/aaa/res1.class", new byte[90]));
+        ModulePool outResources = stack.visitResources(inResources);
+        Collection<String> input = inResources.entries()
                 .map(Object::toString)
                 .collect(Collectors.toList());
-        Collection<String> output = outResources.getContent().stream()
+        Collection<String> output = outResources.entries()
                 .map(Object::toString)
                 .collect(Collectors.toList());
         if (!input.equals(output)) {
@@ -114,19 +116,20 @@
         private boolean isPrevisitCalled = false;
 
         @Override
-        public void visit(Pool inResources, Pool outResources) {
+        public void visit(ModulePool inResources, ModulePool outResources) {
             if (!isPrevisitCalled) {
                 throw new AssertionError("Previsit was not called");
             }
             CustomStringTable table = (CustomStringTable)
-                    ((PoolImpl) inResources).getStringTable();
+                    ((ModulePoolImpl) inResources).getStringTable();
             if (table.size() == 0) {
                 throw new AssertionError("Table is empty");
             }
             Map<String, Integer> count = new HashMap<>();
             for (int i = 0; i < table.size(); ++i) {
                 String s = table.getString(i);
-                if (inResources.get(s) != null) {
+                Optional<ModuleEntry> e = inResources.findEntry(s);
+                if (e.isPresent()) {
                     throw new AssertionError();
                 }
                 count.compute(s, (k, c) -> 1 + (c == null ? 0 : c));
@@ -136,9 +139,9 @@
                     throw new AssertionError("Expected one entry in the table, got: " + v + " for " + k);
                 }
             });
-            for (ModuleData r : inResources.getContent()) {
+            inResources.entries().forEach(r -> {
                 outResources.add(r);
-            }
+            });
         }
 
         @Override
@@ -147,21 +150,21 @@
         }
 
         @Override
-        public void previsit(Pool resources, StringTable strings) {
+        public void previsit(ModulePool resources, StringTable strings) {
             isPrevisitCalled = true;
-            for (ModuleData r : resources.getContent()) {
+            resources.entries().forEach(r -> {
                 String s = r.getPath();
                 int lastIndexOf = s.lastIndexOf('/');
                 if (lastIndexOf >= 0) {
                     strings.addString(s.substring(0, lastIndexOf));
                 }
-            }
+            });
         }
 
         @Override
-        public Set<PluginType> getType() {
-            Set<PluginType> set = new HashSet<>();
-            set.add(CATEGORY.TRANSFORMER);
+        public Set<Category> getType() {
+            Set<Category> set = new HashSet<>();
+            set.add(Category.TRANSFORMER);
             return Collections.unmodifiableSet(set);
         }
     }
--- a/test/tools/jlink/plugins/StringSharingPluginTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/plugins/StringSharingPluginTest.java	Mon May 16 14:47:27 2016 +0530
@@ -38,6 +38,8 @@
  * @run main StringSharingPluginTest
  */
 
+import java.io.IOException;
+import java.io.UncheckedIOException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.file.Files;
@@ -50,11 +52,11 @@
 
 import jdk.internal.jimage.decompressor.CompressedResourceHeader;
 import jdk.internal.jimage.decompressor.StringSharingDecompressor;
-import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.internal.ModulePoolImpl;
 import jdk.tools.jlink.internal.StringTable;
 import jdk.tools.jlink.internal.plugins.StringSharingPlugin;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 import tests.Helper;
 import tests.JImageValidator;
@@ -78,7 +80,7 @@
         Map<String, Integer> map = new HashMap<>();
         Map<Integer, String> reversedMap = new HashMap<>();
 
-        PoolImpl resources = new PoolImpl(ByteOrder.nativeOrder(), new StringTable() {
+        ModulePoolImpl resources = new ModulePoolImpl(ByteOrder.nativeOrder(), new StringTable() {
             @Override
             public int addString(String str) {
                 Integer id = map.get(str);
@@ -104,7 +106,7 @@
                     byte[] content = Files.readAllBytes(p);
                     String path = p.toString().replace('\\', '/');
                     path = path.substring("/modules".length());
-                    ModuleData res = Pool.newResource(path, content);
+                    ModuleEntry res = ModuleEntry.create(path, content);
                     resources.add(res);
                 } catch (Exception ex) {
                     throw new RuntimeException(ex);
@@ -115,19 +117,23 @@
             stream.forEach(c);
         }
         TransformerPlugin plugin = new StringSharingPlugin();
-        PoolImpl result = new PoolImpl(resources.getByteOrder(), resources.getStringTable());
+        ModulePoolImpl result = new ModulePoolImpl(resources.getByteOrder(), resources.getStringTable());
         plugin.visit(resources, result);
 
         if (result.isEmpty()) {
             throw new AssertionError("No result");
         }
 
-        for (ModuleData res : result.getContent()) {
+        result.entries().forEach(res -> {
             if (res.getPath().endsWith(".class")) {
-                byte[] uncompacted = StringSharingDecompressor.normalize(reversedMap::get, res.getBytes(),
+                try {
+                    byte[] uncompacted = StringSharingDecompressor.normalize(reversedMap::get, res.getBytes(),
                         CompressedResourceHeader.getSize());
-                JImageValidator.readClass(uncompacted);
+                    JImageValidator.readClass(uncompacted);
+                } catch (IOException exp) {
+                    throw new UncheckedIOException(exp);
+                }
             }
-        }
+        });
     }
 }
--- a/test/tools/jlink/plugins/StripDebugPluginTest.java	Mon May 16 09:54:01 2016 +0100
+++ b/test/tools/jlink/plugins/StripDebugPluginTest.java	Mon May 16 14:47:27 2016 +0530
@@ -54,10 +54,10 @@
 import com.sun.tools.classfile.Method;
 import java.util.HashMap;
 import java.util.Map;
-import jdk.tools.jlink.internal.PoolImpl;
+import jdk.tools.jlink.internal.ModulePoolImpl;
 import jdk.tools.jlink.internal.plugins.StripDebugPlugin;
-import jdk.tools.jlink.plugin.Pool;
-import jdk.tools.jlink.plugin.Pool.ModuleData;
+import jdk.tools.jlink.plugin.ModuleEntry;
+import jdk.tools.jlink.plugin.ModulePool;
 import jdk.tools.jlink.plugin.TransformerPlugin;
 import tests.Helper;
 
@@ -106,7 +106,7 @@
         path = path.replace('\\', '/');
         StripDebugPlugin debug = new StripDebugPlugin();
         debug.configure(new HashMap<>());
-        ModuleData result1 = stripDebug(debug, Pool.newResource(path,content), path, infoPath, moduleInfo);
+        ModuleEntry result1 = stripDebug(debug, ModuleEntry.create(path,content), path, infoPath, moduleInfo);
 
         if (!path.endsWith("module-info.class")) {
             if (result1.getLength() >= content.length) {
@@ -116,7 +116,7 @@
             checkDebugAttributes(result1.getBytes());
         }
 
-        ModuleData result2 = stripDebug(debug, result1, path, infoPath, moduleInfo);
+        ModuleEntry result2 = stripDebug(debug, result1, path, infoPath, moduleInfo);
         if (result1.getLength() != result2.getLength()) {
             throw new AssertionError("removing debug info twice reduces class size of "
                     + path);
@@ -124,18 +124,18 @@
         checkDebugAttributes(result1.getBytes());
     }
 
-    private ModuleData stripDebug(TransformerPlugin debug, ModuleData classResource,
+    private ModuleEntry stripDebug(TransformerPlugin debug, ModuleEntry classResource,
             String path, String infoPath, byte[] moduleInfo) throws Exception {
-        Pool resources = new PoolImpl();
+        ModulePool resources = new ModulePoolImpl();
         resources.add(classResource);
         if (!path.endsWith("module-info.class")) {
-            ModuleData res2 = Pool.newResource(infoPath, moduleInfo);
+            ModuleEntry res2 = ModuleEntry.create(infoPath, moduleInfo);
             resources.add(res2);
         }
-        Pool results = new PoolImpl();
+        ModulePool results = new ModulePoolImpl();
         debug.visit(resources, results);
         System.out.println(classResource.getPath());
-        return results.get(classResource.getPath());
+        return results.findEntry(classResource.getPath()).get();
     }
 
     private void checkDebugAttributes(byte[] strippedClassFile) throws IOException, ConstantPoolException {