src/share/classes/sun/tools/jar/Main.java

Print this page

        

@@ -24,13 +24,14 @@
  */
 
 package sun.tools.jar;
 
 import java.io.*;
-import java.nio.file.Path;
-import java.nio.file.Files;
+import java.nio.file.*;
+import java.nio.file.attribute.*;
 import java.util.*;
+import java.util.concurrent.*;
 import java.util.zip.*;
 import java.util.jar.*;
 import java.util.jar.Manifest;
 import java.text.MessageFormat;
 import sun.misc.JarIndex;

@@ -71,11 +72,13 @@
      * vflag: verbose
      * flag0: no zip compression (store only)
      * Mflag: DO NOT generate a manifest file (just ZIP)
      * iflag: generate jar index
      */
-    boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag;
+    boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag, mtflag;
+
+    int threadNum;
 
     static final String MANIFEST_DIR = "META-INF/";
     static final String VERSION = "1.0";
 
     private static ResourceBundle rsrc;

@@ -195,12 +198,12 @@
                         // on stdout along with file data
                         // error("Warning: -v option ignored");
                         vflag = false;
                     }
                 }
-                expand(null, files, false);
-                create(new BufferedOutputStream(out, 4096), manifest);
+                //expand(null, files, false);
+                create(files, new BufferedOutputStream(out, 4096), manifest);
                 if (in != null) {
                     in.close();
                 }
                 out.close();
             } else if (uflag) {

@@ -251,11 +254,14 @@
                         in.close();
                     }
                 }
             } else if (xflag) {
                 replaceFSC(files);
-                if (fname != null && files != null) {
+
+                if (mtflag && fname != null) {
+                    extract2(fname, files);
+                } else if (fname != null && files != null) {
                     extract(fname, files);
                 } else {
                     InputStream in = (fname == null)
                         ? new FileInputStream(FileDescriptor.in)
                         : new FileInputStream(fname);

@@ -359,10 +365,16 @@
                     iflag = true;
                     break;
                 case 'e':
                      ename = args[count++];
                      break;
+                case 'T':
+                     mtflag = true;
+                     threadNum = flags.charAt(++i) - '0';
+                     if (threadNum <= 0)
+                         threadNum = 1;
+                     break;
                 default:
                     error(formatMsg("error.illegal.option",
                                 String.valueOf(flags.charAt(i))));
                     usageError();
                     return false;

@@ -457,14 +469,103 @@
                 ok = false;
             }
         }
     }
 
+    //void expand2(File[] files, ArrayList elist, ExecutorService es) {
+    void expand2(File[] files, Queue elist, ExecutorService es) {
+        if (files == null) {
+            return;
+        }
+        for (File f :files) {
+            if (f.isFile()) {
+                if (entries.add(f)) {
+                    if (f.length() > MAXBUFSIZE) {
+                        elist.add(f);
+                    } else {
+                        DefWork job = new DefWork(f);                    
+                        elist.add(es.submit(job, job));
+                    }
+                }
+            } else if (f.isDirectory()) {
+                if (entries.add(f)) {
+                    elist.add(f);
+                    expand2(f.listFiles(), elist, es);
+                }
+            } else {
+                error(formatMsg("error.nosuch.fileordir", String.valueOf(f)));
+                ok = false;
+            }
+        }
+    }
+
+    private static int MAXBUFSIZE = 1024 * 1024 * 50;
+    private ThreadLocal<Deflater> tlDef = new ThreadLocal<>();
+    private ThreadLocal<CRC32> tlCrc = new ThreadLocal<>();
+    private ThreadLocal<byte[]> tlBuf = new ThreadLocal<>();
+
+    private class DefByteArrayOutputStream extends ByteArrayOutputStream {
+        DefByteArrayOutputStream(int size) {
+            super(size);
+        }
+        byte[] getByteArray() {
+            return buf;
+        }    
+    }
+
+    private class DefWork implements Runnable {
+        File f;
+        DefByteArrayOutputStream dbaos;
+        long size;
+        long csize;
+        long crc;
+        IOException x;
+    
+        DefWork(File f) {
+            this.f = f;
+        }
+    
+        public void run() {
+            long len = f.length();
+            dbaos = new DefByteArrayOutputStream((int)len);
+            Deflater def = tlDef.get();
+            if (def == null)
+                def = new Deflater(Deflater.DEFAULT_COMPRESSION, true);
+            CRC32 crc32 = tlCrc.get();
+            if (crc32 == null)
+                crc32 = new CRC32();
+            byte[] buf = tlBuf.get();
+            if (buf == null)
+                buf = new byte[8192];
+            DeflaterOutputStream dos = new DeflaterOutputStream(dbaos, def);
+            try (InputStream in = new FileInputStream(f)) {
+                int n;
+                while ((n = in.read(buf)) != -1) {
+                    dos.write(buf, 0, n);
+                    crc32.update(buf, 0, n);
+                }
+                dos.close(); 
+            } catch (IOException x) {
+                x.printStackTrace();
+                this.x = x;
+            }
+            size  = def.getBytesRead();
+            csize = def.getBytesWritten();
+            crc = crc32.getValue();
+            def.reset();
+            tlDef.set(def);
+            crc32.reset();
+            tlCrc.set(crc32);
+            tlBuf.set(buf);
+        }
+    }
+
+
     /**
      * Creates a new JAR file.
      */
-    void create(OutputStream out, Manifest manifest)
+    void create(String[] files, OutputStream out, Manifest manifest)
         throws IOException
     {
         ZipOutputStream zos = new JarOutputStream(out);
         if (flag0) {
             zos.setMethod(ZipOutputStream.STORED);

@@ -485,14 +586,141 @@
             }
             zos.putNextEntry(e);
             manifest.write(zos);
             zos.closeEntry();
         }
+
+        if (!mtflag || flag0) {
+            expand(null, files, false);
         for (File file: entries) {
             addFile(zos, file);
         }
+        } else {
+System.out.println("mtCreate: threadNum=" + threadNum + "...");
+            final ExecutorService es = Executors.newFixedThreadPool(threadNum);
+
+            final File[] fs = new File[files.length];
+            for (int i = 0; i < files.length; i++)
+                fs[i] = new File(files[i]);
+
+
+            final Queue elist = new ConcurrentLinkedQueue();
+            final Object LAST = new Object();
+            es.submit(new Runnable() {
+                public void run() {
+                    expand2(fs, elist, es);
+                    elist.add(LAST);
+                }
+            });
+
+            /*
+            ArrayList elist = new ArrayList();
+            expand2(fs, elist, es);
+            */
+
+            /*
+            expand(null, files, false);
+            ArrayList elist = new ArrayList(entries.size());
+            for (File f: entries) {
+                if (f.isDirectory() || f.length() > MAXBUFSIZE) {
+                    elist.add(f);
+                } else {
+                    DefWork job = new DefWork(f);                    
+                    elist.add(es.submit(job, job));
+                }
+            }
+            */
+
+            //for (Object o : elist) {
+
+            while(true) {
+                Object o = elist.poll();
+                if (o == null)
+                    continue;
+                if (o == LAST)
+                    break;
+
+
+
+                File file = null;
+                DefWork work = null;
+                if (o instanceof File)
+                    file = (File)o;
+                else { 
+                    try {
+                        work = (DefWork)((java.util.concurrent.Future)o).get();
+                    } catch (Exception x) {
+                        x.printStackTrace();
+                        continue;
+                    }
+                    file = work.f;
+                }
+                String name = file.getPath();
+                boolean isDir = file.isDirectory();
+                if (isDir) {
+                    name = name.endsWith(File.separator) ? name :
+                        (name + File.separator);
+                }
+                name = entryName(name);
+
+                if (name.equals("") || name.equals(".") || name.equals(zname)) {
+                    return;
+                } else if ((name.equals(MANIFEST_DIR) || name.equals(MANIFEST_NAME))
+                           && !Mflag) {
+                    if (vflag) {
+                        output(formatMsg("out.ignore.entry", name));
+                    }
+                    return;
+                }
+                long size = isDir ? 0 : file.length();
+                if (vflag) {
+                    //outprint(formatMsg("out.adding", name));
+                    System.out.println(formatMsg("out.adding", name));
+                }
+                ZipEntry e = new ZipEntry(name);
+                e.setTime(file.lastModified());
+                if (size == 0) {
+                    e.setMethod(ZipEntry.STORED);
+                    e.setSize(0);
+                    e.setCrc(0);
+                }
+                if (work != null && work.dbaos != null) {
+                    e.setMethod(ZipEntry.DEFLATED);
+                    e.setSize(work.size);
+                    e.setCompressedSize(work.csize);
+                    e.setCrc(work.crc);
+                    zos.writeNextEntry(e, work.dbaos.getByteArray(), 0, work.dbaos.size());
+                    work.dbaos = null;
+                } else {
+                    zos.putNextEntry(e);
+                    if (!isDir) {
+                        copy(file, zos);
+                    }
+                    zos.closeEntry();
+                }
+                /* report how much compression occurred. */
+                if (vflag) {
+                    size = e.getSize();
+                    long csize = e.getCompressedSize();
+                    //out.print(formatMsg2("out.size", String.valueOf(size),
+                    System.out.println(formatMsg2("out.size", String.valueOf(size),
+                              String.valueOf(csize)));
+                    if (e.getMethod() == ZipEntry.DEFLATED) {
+                        long ratio = 0;
+                        if (size != 0) {
+                            ratio = ((size - csize) * 100) / size;
+                        }
+                        output(formatMsg("out.deflated", String.valueOf(ratio)));
+                    } else {
+                        output(getMsg("out.stored"));
+                    }
+                }
+            }
+            es.shutdown();
+        }
         zos.close();
+
     }
 
     private char toUpperCaseASCII(char c) {
         return (c < 'a' || c > 'z') ? c : (char) (c + 'A' - 'a');
     }

@@ -917,15 +1145,83 @@
         }
         zf.close();
         updateLastModifiedTime(dirs);
     }
 
+    void extract2(String fname, String files[]) throws IOException {
+System.out.println("mtExtract: threadNum=" + threadNum + "...");
+        final ZipFile zf = new ZipFile(fname);
+        final Set<ZipEntry> dirs = newDirSet();
+        Enumeration<? extends ZipEntry> zes = zf.entries();
+
+        class ExtractWork implements Runnable {
+            IOException ioe;
+            ZipEntry e;
+            InputStream is;
+            ExtractWork(InputStream is, ZipEntry e) {
+                this.is = is;
+                this.e = e;
+            }
+            public void run() {
+                try {
+                    dirs.add(extractFile(is, e));                
+                } catch (IOException ioe) {
+                    this.ioe = ioe;
+                }
+            }
+        }
+
+        final ExecutorService es = Executors.newFixedThreadPool(threadNum);
+        final Queue<Future<ExtractWork>> works = new ConcurrentLinkedQueue<>();
+
+        while (zes.hasMoreElements()) {
+            ZipEntry e = zes.nextElement();
+            InputStream is;
+
+            if (files == null) {
+                if (e.isDirectory()) {
+                    dirs.add(extractFile(null, e));
+                } else {
+                    ExtractWork work = new ExtractWork(zf.getInputStream(e), e);
+                    works.add(es.submit(work, work));
+                }
+            } else {
+                String name = e.getName();
+                for (String file : files) {
+                    if (name.startsWith(file)) {
+                        if (e.isDirectory()) {
+                            dirs.add(extractFile(null, e));
+                        } else {
+                            ExtractWork work = new ExtractWork(zf.getInputStream(e), e);
+                            works.add(es.submit(work, work));
+                        }
+                    }
+                }
+            }
+        }
+        Future<ExtractWork> f;
+        while((f = works.poll()) != null) {
+            while (!f.isDone()) {
+                Thread.yield();
+            }
+            try {
+                if (f.get().ioe != null)
+                    throw f.get().ioe;
+            } catch (Exception ire) {}
+        }
+        zf.close();
+        updateLastModifiedTime(dirs);
+        es.shutdown();
+    }
+
+
     /**
      * Extracts next entry from JAR file, creating directories as needed.  If
      * the entry is for a directory which doesn't exist prior to this
      * invocation, returns that entry, otherwise returns null.
      */
+
     ZipEntry extractFile(InputStream is, ZipEntry e) throws IOException {
         ZipEntry rc = null;
         String name = e.getName();
         File f = new File(e.getName().replace('/', File.separatorChar));
         if (e.isDirectory()) {

@@ -940,11 +1236,10 @@
                         f.getPath()));
                 } else {
                     rc = e;
                 }
             }
-
             if (vflag) {
                 output(formatMsg("out.create", name));
             }
         } else {
             if (f.getParent() != null) {