1 /*
   2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import java.io.File;
  25 import java.io.FileOutputStream;
  26 import java.io.IOException;
  27 import java.io.OutputStream;
  28 import java.util.TimeZone;
  29 import java.util.concurrent.CountDownLatch;
  30 import java.util.jar.JarFile;
  31 import java.util.jar.JarOutputStream;
  32 import java.util.jar.Pack200;
  33 
  34 /*
  35  * @test
  36  * @bug 8066985
  37  * @summary multithreading packing/unpacking files can result in Timezone set to UTC
  38  * @compile -XDignore.symbol.file Utils.java DefaultTimeZoneTest.java
  39  * @run main/othervm DefaultTimeZoneTest
  40  * @author mcherkas
  41  */
  42 
  43 
  44 public class DefaultTimeZoneTest {
  45 
  46     private static final TimeZone tz = TimeZone.getTimeZone("Europe/Moscow");
  47     private static final int INIT_THREAD_COUNT = Math.min(4, Runtime.getRuntime().availableProcessors());
  48     private static final int MAX_THREAD_COUNT = 4 * INIT_THREAD_COUNT;
  49     private static final long MINUTE = 60 * 1000;
  50 
  51     private static class NoOpOutputStream extends OutputStream {
  52         @Override
  53         public void write(int b) throws IOException {
  54             // no op
  55         }
  56     }
  57 
  58     static class PackAction implements Runnable {
  59         private Pack200.Packer packer = Pack200.newPacker();
  60         private JarFile jarFile;
  61 
  62         PackAction() throws IOException {
  63             jarFile = new JarFile(new File("golden.jar"));
  64         }
  65 
  66         @Override
  67         public void run() {
  68             try {
  69                 packer.pack(jarFile, new NoOpOutputStream());
  70             } catch (IOException e) {
  71                 throw new RuntimeException(e);
  72             }
  73         }
  74     }
  75 
  76     static class UnpackAction implements Runnable {
  77         private Pack200.Unpacker unpacker = Pack200.newUnpacker();
  78         private JarOutputStream jos;
  79         private File packedJar = new File("golden.pack");
  80 
  81         UnpackAction() throws IOException {
  82             jos = new JarOutputStream(new NoOpOutputStream());
  83         }
  84 
  85         @Override
  86         public void run() {
  87             try {
  88                 unpacker.unpack(packedJar, jos);
  89             } catch (IOException e) {
  90                 throw new RuntimeException(e);
  91             } finally {
  92                 try {
  93                     jos.close();
  94                 } catch (IOException e) {
  95                     throw new RuntimeException(e);
  96                 }
  97             }
  98         }
  99     };
 100 
 101     public static void test(final Class<? extends Runnable> runnableClass) throws InterruptedException {
 102         for (int i = INIT_THREAD_COUNT; i <= MAX_THREAD_COUNT; i*=2) {
 103             final CountDownLatch startLatch = new CountDownLatch(i);
 104             final CountDownLatch doneLatch = new CountDownLatch(i);
 105             for (int j = 0; j < i; j++) {
 106                 new Thread() {
 107                     @Override
 108                     public void run() {
 109                         try {
 110                             Runnable r = runnableClass.newInstance();
 111                             startLatch.countDown();
 112                             startLatch.await();
 113                             r.run();
 114                         } catch (Exception e) {
 115                             throw new RuntimeException(e);
 116                         } finally {
 117                             doneLatch.countDown();
 118                         }
 119                     }
 120                 }.start();
 121             }
 122             doneLatch.await();
 123 
 124             if(!TimeZone.getDefault().equals(tz)) {
 125                 throw new RuntimeException("FAIL: default time zone was changed");
 126             }
 127         }
 128     }
 129 
 130     public static void main(String args[]) throws IOException, InterruptedException {
 131         TimeZone.setDefault(tz);
 132 
 133         // make a local copy of our test file
 134         File srcFile = Utils.locateJar("golden.jar");
 135         final File goldenFile = new File("golden.jar");
 136         Utils.copyFile(srcFile, goldenFile);
 137 
 138         // created packed file
 139         final JarFile goldenJarFile = new JarFile(goldenFile);
 140         final File packFile = new File("golden.pack");
 141         Utils.pack(goldenJarFile, packFile);
 142 
 143         // before test let's unpack golden pack to warm up
 144         // a native unpacker. That allow us to avoid JDK-8080438
 145         UnpackAction unpackAction = new UnpackAction();
 146         unpackAction.run();
 147 
 148         long startTime = System.currentTimeMillis();
 149         while(System.currentTimeMillis() - startTime < MINUTE) {
 150             // test packer
 151             test(PackAction.class);
 152 
 153             // test unpacker
 154             test(UnpackAction.class);
 155         }
 156 
 157         Utils.cleanup();
 158     }
 159 }