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
write(int b)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 
PackAction()62         PackAction() throws IOException {
63             jarFile = new JarFile(new File("golden.jar"));
64         }
65 
66         @Override
run()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 
UnpackAction()81         UnpackAction() throws IOException {
82             jos = new JarOutputStream(new NoOpOutputStream());
83         }
84 
85         @Override
run()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 
test(final Class<? extends Runnable> runnableClass)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 
main(String args[])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 }
160