jdk/test/java/io/Serializable/failureAtomicity/FailureAtomicity.java
changeset 30911 99e027461f4a
child 39480 50a182a81875
equal deleted inserted replaced
30910:1b6a91197762 30911:99e027461f4a
       
     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 /*
       
    25  * @test
       
    26  * @bug 8071474
       
    27  * @summary Better failure atomicity for default read object.
       
    28  * @library /lib/testlibrary
       
    29  * @build jdk.testlibrary.FileUtils
       
    30  * @compile FailureAtomicity.java SerialRef.java
       
    31  * @run main failureAtomicity.FailureAtomicity
       
    32  */
       
    33 
       
    34 package failureAtomicity;
       
    35 
       
    36 import java.io.ByteArrayInputStream;
       
    37 import java.io.ByteArrayOutputStream;
       
    38 import java.io.File;
       
    39 import java.io.IOException;
       
    40 import java.io.InputStream;
       
    41 import java.io.ObjectInputStream;
       
    42 import java.io.ObjectOutputStream;
       
    43 import java.io.ObjectStreamClass;
       
    44 import java.io.UncheckedIOException;
       
    45 import java.lang.reflect.Constructor;
       
    46 import java.net.URL;
       
    47 import java.net.URLClassLoader;
       
    48 import java.nio.file.Files;
       
    49 import java.nio.file.Path;
       
    50 import java.nio.file.Paths;
       
    51 import java.util.ArrayList;
       
    52 import java.util.Arrays;
       
    53 import java.util.List;
       
    54 import java.util.function.BiConsumer;
       
    55 import java.util.stream.Collectors;
       
    56 import javax.tools.JavaCompiler;
       
    57 import javax.tools.JavaFileObject;
       
    58 import javax.tools.StandardJavaFileManager;
       
    59 import javax.tools.StandardLocation;
       
    60 import javax.tools.ToolProvider;
       
    61 import jdk.testlibrary.FileUtils;
       
    62 
       
    63 @SuppressWarnings("unchecked")
       
    64 public class FailureAtomicity {
       
    65     static final Path TEST_SRC = Paths.get(System.getProperty("test.src", "."));
       
    66     static final Path TEST_CLASSES = Paths.get(System.getProperty("test.classes", "."));
       
    67     static final Path fooTemplate = TEST_SRC.resolve("Foo.template");
       
    68     static final Path barTemplate = TEST_SRC.resolve("Bar.template");
       
    69 
       
    70     static final String[] PKGS = { "a.b.c", "x.y.z" };
       
    71 
       
    72     public static void main(String[] args) throws Exception {
       
    73         test_Foo();
       
    74         test_BadFoo();  // 'Bad' => incompatible type; cannot be "fully" deserialized
       
    75         test_FooWithReadObject();
       
    76         test_BadFooWithReadObject();
       
    77 
       
    78         test_Foo_Bar();
       
    79         test_Foo_BadBar();
       
    80         test_BadFoo_Bar();
       
    81         test_BadFoo_BadBar();
       
    82         test_Foo_BarWithReadObject();
       
    83         test_Foo_BadBarWithReadObject();
       
    84         test_BadFoo_BarWithReadObject();
       
    85         test_BadFoo_BadBarWithReadObject();
       
    86         test_FooWithReadObject_Bar();
       
    87         test_FooWithReadObject_BadBar();
       
    88         test_BadFooWithReadObject_Bar();
       
    89         test_BadFooWithReadObject_BadBar();
       
    90     }
       
    91 
       
    92     static final BiConsumer<Object,Object> FOO_FIELDS_EQUAL = (a,b) -> {
       
    93         try {
       
    94             int aPrim = a.getClass().getField("fooPrim").getInt(a);
       
    95             int bPrim = b.getClass().getField("fooPrim").getInt(b);
       
    96             if (aPrim != bPrim)
       
    97                 throw new AssertionError("Not equal: (" + aPrim + "!=" + bPrim
       
    98                                          + "), in [" + a + "] [" + b + "]");
       
    99             Object aRef = a.getClass().getField("fooRef").get(a);
       
   100             Object bRef = b.getClass().getField("fooRef").get(b);
       
   101             if (!aRef.equals(bRef))
       
   102                 throw new RuntimeException("Not equal: (" + aRef + "!=" + bRef
       
   103                                            + "), in [" + a + "] [" + b + "]");
       
   104         } catch (NoSuchFieldException | IllegalAccessException x) {
       
   105             throw new InternalError(x);
       
   106         }
       
   107     };
       
   108     static final BiConsumer<Object,Object> FOO_FIELDS_DEFAULT = (ignore,b) -> {
       
   109         try {
       
   110             int aPrim = b.getClass().getField("fooPrim").getInt(b);
       
   111             if (aPrim != 0)
       
   112                 throw new AssertionError("Expected 0, got:" + aPrim
       
   113                                          + ", in [" + b + "]");
       
   114             Object aRef = b.getClass().getField("fooRef").get(b);
       
   115             if (aRef != null)
       
   116                 throw new RuntimeException("Expected null, got:" + aRef
       
   117                                            + ", in [" + b + "]");
       
   118         } catch (NoSuchFieldException | IllegalAccessException x) {
       
   119             throw new InternalError(x);
       
   120         }
       
   121     };
       
   122     static final BiConsumer<Object,Object> BAR_FIELDS_EQUAL = (a,b) -> {
       
   123         try {
       
   124             long aPrim = a.getClass().getField("barPrim").getLong(a);
       
   125             long bPrim = b.getClass().getField("barPrim").getLong(b);
       
   126             if (aPrim != bPrim)
       
   127                 throw new AssertionError("Not equal: (" + aPrim + "!=" + bPrim
       
   128                                          + "), in [" + a + "] [" + b + "]");
       
   129             Object aRef = a.getClass().getField("barRef").get(a);
       
   130             Object bRef = b.getClass().getField("barRef").get(b);
       
   131             if (!aRef.equals(bRef))
       
   132                 throw new RuntimeException("Not equal: (" + aRef + "!=" + bRef
       
   133                                            + "), in [" + a + "] [" + b + "]");
       
   134         } catch (NoSuchFieldException | IllegalAccessException x) {
       
   135             throw new InternalError(x);
       
   136         }
       
   137     };
       
   138     static final BiConsumer<Object,Object> BAR_FIELDS_DEFAULT = (ignore,b) -> {
       
   139         try {
       
   140             long aPrim = b.getClass().getField("barPrim").getLong(b);
       
   141             if (aPrim != 0L)
       
   142                 throw new AssertionError("Expected 0, got:" + aPrim
       
   143                                          + ", in [" + b + "]");
       
   144             Object aRef = b.getClass().getField("barRef").get(b);
       
   145             if (aRef != null)
       
   146                 throw new RuntimeException("Expected null, got:" + aRef
       
   147                                            + ", in [" + b + "]");
       
   148         } catch (NoSuchFieldException | IllegalAccessException x) {
       
   149             throw new InternalError(x);
       
   150         }
       
   151     };
       
   152 
       
   153     static void test_Foo() {
       
   154         testFoo("Foo", "String", false, false, FOO_FIELDS_EQUAL); }
       
   155     static void test_BadFoo() {
       
   156         testFoo("BadFoo", "byte[]", true, false, FOO_FIELDS_DEFAULT); }
       
   157     static void test_FooWithReadObject() {
       
   158         testFoo("FooWithReadObject", "String", false, true, FOO_FIELDS_EQUAL); }
       
   159     static void test_BadFooWithReadObject() {
       
   160         testFoo("BadFooWithReadObject", "byte[]", true, true, FOO_FIELDS_DEFAULT); }
       
   161 
       
   162     static void testFoo(String testName, String xyzZebraType,
       
   163                         boolean expectCCE, boolean withReadObject,
       
   164                         BiConsumer<Object,Object>... resultCheckers) {
       
   165         System.out.println("\nTesting " + testName);
       
   166         try {
       
   167             Path testRoot = testDir(testName);
       
   168             Path srcRoot = Files.createDirectory(testRoot.resolve("src"));
       
   169             List<Path> srcFiles = new ArrayList<>();
       
   170             srcFiles.add(createSrc(PKGS[0], fooTemplate, srcRoot, "String", withReadObject));
       
   171             srcFiles.add(createSrc(PKGS[1], fooTemplate, srcRoot, xyzZebraType, withReadObject));
       
   172 
       
   173             Path build = Files.createDirectory(testRoot.resolve("build"));
       
   174             javac(build, srcFiles);
       
   175 
       
   176             URLClassLoader loader = new URLClassLoader(new URL[]{ build.toUri().toURL() },
       
   177                                                        FailureAtomicity.class.getClassLoader());
       
   178             Class<?> fooClass = Class.forName(PKGS[0] + ".Foo", true, loader);
       
   179             Constructor<?> ctr = fooClass.getConstructor(
       
   180                     new Class<?>[]{int.class, String.class, String.class});
       
   181             Object abcFoo = ctr.newInstance(5, "chegar", "zebra");
       
   182 
       
   183             try {
       
   184                 toOtherPkgInstance(abcFoo, loader);
       
   185                 if (expectCCE)
       
   186                     throw new AssertionError("Expected CCE not thrown");
       
   187             } catch (ClassCastException e) {
       
   188                 if (!expectCCE)
       
   189                     throw new AssertionError("UnExpected CCE: " + e);
       
   190             }
       
   191 
       
   192             Object deserialInstance = failureAtomicity.SerialRef.obj;
       
   193 
       
   194             System.out.println("abcFoo:           " + abcFoo);
       
   195             System.out.println("deserialInstance: " + deserialInstance);
       
   196 
       
   197             for (BiConsumer<Object, Object> rc : resultCheckers)
       
   198                 rc.accept(abcFoo, deserialInstance);
       
   199         } catch (IOException x) {
       
   200             throw new UncheckedIOException(x);
       
   201         } catch (ReflectiveOperationException x) {
       
   202             throw new InternalError(x);
       
   203         }
       
   204     }
       
   205 
       
   206     static void test_Foo_Bar() {
       
   207         testFooBar("Foo_Bar", "String", "String", false, false, false,
       
   208                    FOO_FIELDS_EQUAL, BAR_FIELDS_EQUAL);
       
   209     }
       
   210     static void test_Foo_BadBar() {
       
   211         testFooBar("Foo_BadBar", "String", "byte[]", true, false, false,
       
   212                    FOO_FIELDS_DEFAULT, BAR_FIELDS_DEFAULT);
       
   213     }
       
   214     static void test_BadFoo_Bar() {
       
   215         testFooBar("BadFoo_Bar", "byte[]", "String", true, false, false,
       
   216                    FOO_FIELDS_DEFAULT, BAR_FIELDS_DEFAULT);
       
   217     }
       
   218     static void test_BadFoo_BadBar() {
       
   219         testFooBar("BadFoo_BadBar", "byte[]", "byte[]", true, false, false,
       
   220                    FOO_FIELDS_DEFAULT, BAR_FIELDS_DEFAULT);
       
   221     }
       
   222     static void test_Foo_BarWithReadObject() {
       
   223         testFooBar("Foo_BarWithReadObject", "String", "String", false, false, true,
       
   224                    FOO_FIELDS_EQUAL, BAR_FIELDS_EQUAL);
       
   225     }
       
   226     static void test_Foo_BadBarWithReadObject() {
       
   227         testFooBar("Foo_BadBarWithReadObject", "String", "byte[]", true, false, true,
       
   228                    FOO_FIELDS_EQUAL, BAR_FIELDS_DEFAULT);
       
   229     }
       
   230     static void test_BadFoo_BarWithReadObject() {
       
   231         testFooBar("BadFoo_BarWithReadObject", "byte[]", "String", true, false, true,
       
   232                    FOO_FIELDS_DEFAULT, BAR_FIELDS_DEFAULT);
       
   233     }
       
   234     static void test_BadFoo_BadBarWithReadObject() {
       
   235         testFooBar("BadFoo_BadBarWithReadObject", "byte[]", "byte[]", true, false, true,
       
   236                    FOO_FIELDS_DEFAULT, BAR_FIELDS_DEFAULT);
       
   237     }
       
   238 
       
   239     static void test_FooWithReadObject_Bar() {
       
   240         testFooBar("FooWithReadObject_Bar", "String", "String", false, true, false,
       
   241                    FOO_FIELDS_EQUAL, BAR_FIELDS_EQUAL);
       
   242     }
       
   243     static void test_FooWithReadObject_BadBar() {
       
   244         testFooBar("FooWithReadObject_BadBar", "String", "byte[]", true, true, false,
       
   245                    FOO_FIELDS_EQUAL, BAR_FIELDS_DEFAULT);
       
   246     }
       
   247     static void test_BadFooWithReadObject_Bar() {
       
   248         testFooBar("BadFooWithReadObject_Bar", "byte[]", "String", true, true, false,
       
   249                    FOO_FIELDS_DEFAULT, BAR_FIELDS_DEFAULT);
       
   250     }
       
   251     static void test_BadFooWithReadObject_BadBar() {
       
   252         testFooBar("BadFooWithReadObject_BadBar", "byte[]", "byte[]", true, true, false,
       
   253                    FOO_FIELDS_DEFAULT, BAR_FIELDS_DEFAULT);
       
   254     }
       
   255 
       
   256     static void testFooBar(String testName, String xyzFooZebraType,
       
   257                            String xyzBarZebraType, boolean expectCCE,
       
   258                            boolean fooWithReadObject, boolean barWithReadObject,
       
   259                            BiConsumer<Object,Object>... resultCheckers) {
       
   260         System.out.println("\nTesting " + testName);
       
   261         try {
       
   262             Path testRoot = testDir(testName);
       
   263             Path srcRoot = Files.createDirectory(testRoot.resolve("src"));
       
   264             List<Path> srcFiles = new ArrayList<>();
       
   265             srcFiles.add(createSrc(PKGS[0], fooTemplate, srcRoot, "String",
       
   266                                    fooWithReadObject, "String"));
       
   267             srcFiles.add(createSrc(PKGS[1], fooTemplate, srcRoot, xyzFooZebraType,
       
   268                                    fooWithReadObject, xyzFooZebraType));
       
   269             srcFiles.add(createSrc(PKGS[0], barTemplate, srcRoot, "String",
       
   270                                    barWithReadObject, "String"));
       
   271             srcFiles.add(createSrc(PKGS[1], barTemplate, srcRoot, xyzBarZebraType,
       
   272                                    barWithReadObject, xyzFooZebraType));
       
   273 
       
   274             Path build = Files.createDirectory(testRoot.resolve("build"));
       
   275             javac(build, srcFiles);
       
   276 
       
   277             URLClassLoader loader = new URLClassLoader(new URL[]{ build.toUri().toURL() },
       
   278                                                        FailureAtomicity.class.getClassLoader());
       
   279             Class<?> fooClass = Class.forName(PKGS[0] + ".Bar", true, loader);
       
   280             Constructor<?> ctr = fooClass.getConstructor(
       
   281                     new Class<?>[]{int.class, String.class, String.class,
       
   282                                    long.class, String.class, String.class});
       
   283             Object abcBar = ctr.newInstance( 5, "chegar", "zebraFoo", 111L, "aBar", "zebraBar");
       
   284 
       
   285             try {
       
   286                 toOtherPkgInstance(abcBar, loader);
       
   287                 if (expectCCE)
       
   288                     throw new AssertionError("Expected CCE not thrown");
       
   289             } catch (ClassCastException e) {
       
   290                 if (!expectCCE)
       
   291                     throw new AssertionError("UnExpected CCE: " + e);
       
   292             }
       
   293 
       
   294             Object deserialInstance = failureAtomicity.SerialRef.obj;
       
   295 
       
   296             System.out.println("abcBar:           " + abcBar);
       
   297             System.out.println("deserialInstance: " + deserialInstance);
       
   298 
       
   299             for (BiConsumer<Object, Object> rc : resultCheckers)
       
   300                 rc.accept(abcBar, deserialInstance);
       
   301         } catch (IOException x) {
       
   302             throw new UncheckedIOException(x);
       
   303         } catch (ReflectiveOperationException x) {
       
   304             throw new InternalError(x);
       
   305         }
       
   306     }
       
   307 
       
   308     static Path testDir(String name) throws IOException {
       
   309         Path testRoot = Paths.get("FailureAtomicity-" + name);
       
   310         if (Files.exists(testRoot))
       
   311             FileUtils.deleteFileTreeWithRetry(testRoot);
       
   312         Files.createDirectory(testRoot);
       
   313         return testRoot;
       
   314     }
       
   315 
       
   316     static String platformPath(String p) { return p.replace("/", File.separator); }
       
   317     static String binaryName(String name) { return name.replace(".", "/"); }
       
   318     static String condRemove(String line, String pattern, boolean hasReadObject) {
       
   319         if (hasReadObject) { return line.replaceAll(pattern, ""); }
       
   320         else { return line; }
       
   321     }
       
   322     static String condReplace(String line, String... zebraFooType) {
       
   323         if (zebraFooType.length == 1) {
       
   324             return line.replaceAll("\\$foo_zebra_type", zebraFooType[0]);
       
   325         } else { return line; }
       
   326     }
       
   327     static String nameFromTemplate(Path template) {
       
   328         return template.getFileName().toString().replaceAll(".template", "");
       
   329     }
       
   330 
       
   331     static Path createSrc(String pkg, Path srcTemplate, Path srcRoot,
       
   332                           String zebraType, boolean hasReadObject,
       
   333                           String... zebraFooType)
       
   334         throws IOException
       
   335     {
       
   336         Path srcDst = srcRoot.resolve(platformPath(binaryName(pkg)));
       
   337         Files.createDirectories(srcDst);
       
   338         Path srcFile = srcDst.resolve(nameFromTemplate(srcTemplate) + ".java");
       
   339 
       
   340         List<String> lines = Files.lines(srcTemplate)
       
   341                 .map(s -> s.replaceAll("\\$package", pkg))
       
   342                 .map(s -> s.replaceAll("\\$zebra_type", zebraType))
       
   343                 .map(s -> condReplace(s, zebraFooType))
       
   344                 .map(s -> condRemove(s, "//\\$has_readObject", hasReadObject))
       
   345                 .collect(Collectors.toList());
       
   346         Files.write(srcFile, lines);
       
   347         return srcFile;
       
   348     }
       
   349 
       
   350     static void javac(Path dest, List<Path> sourceFiles) throws IOException {
       
   351         JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
       
   352         try (StandardJavaFileManager fileManager =
       
   353                      compiler.getStandardFileManager(null, null, null)) {
       
   354             List<File> files = sourceFiles.stream()
       
   355                                           .map(p -> p.toFile())
       
   356                                           .collect(Collectors.toList());
       
   357             Iterable<? extends JavaFileObject> compilationUnits =
       
   358                     fileManager.getJavaFileObjectsFromFiles(files);
       
   359             fileManager.setLocation(StandardLocation.CLASS_OUTPUT,
       
   360                                     Arrays.asList(dest.toFile()));
       
   361             fileManager.setLocation(StandardLocation.CLASS_PATH,
       
   362                                     Arrays.asList(TEST_CLASSES.toFile()));
       
   363             JavaCompiler.CompilationTask task = compiler
       
   364                     .getTask(null, fileManager, null, null, null, compilationUnits);
       
   365             boolean passed = task.call();
       
   366             if (!passed)
       
   367                 throw new RuntimeException("Error compiling " + files);
       
   368         }
       
   369     }
       
   370 
       
   371     static Object toOtherPkgInstance(Object obj, ClassLoader loader)
       
   372         throws IOException, ClassNotFoundException
       
   373     {
       
   374         byte[] bytes = serialize(obj);
       
   375         bytes = replacePkg(bytes);
       
   376         return deserialize(bytes, loader);
       
   377     }
       
   378 
       
   379     @SuppressWarnings("deprecation")
       
   380     static byte[] replacePkg(byte[] bytes) {
       
   381         String str = new String(bytes, 0);
       
   382         str = str.replaceAll(PKGS[0], PKGS[1]);
       
   383         str.getBytes(0, bytes.length, bytes, 0);
       
   384         return bytes;
       
   385     }
       
   386 
       
   387     static byte[] serialize(Object obj) throws IOException {
       
   388         try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
       
   389              ObjectOutputStream out = new ObjectOutputStream(baos);) {
       
   390             out.writeObject(obj);
       
   391             return baos.toByteArray();
       
   392         }
       
   393     }
       
   394 
       
   395     static Object deserialize(byte[] data, ClassLoader l)
       
   396         throws IOException, ClassNotFoundException
       
   397     {
       
   398         return new WithLoaderObjectInputStream(new ByteArrayInputStream(data), l)
       
   399                 .readObject();
       
   400     }
       
   401 
       
   402     static class WithLoaderObjectInputStream extends ObjectInputStream {
       
   403         final ClassLoader loader;
       
   404         WithLoaderObjectInputStream(InputStream is, ClassLoader loader)
       
   405             throws IOException
       
   406         {
       
   407             super(is);
       
   408             this.loader = loader;
       
   409         }
       
   410         @Override
       
   411         protected Class<?> resolveClass(ObjectStreamClass desc)
       
   412             throws IOException, ClassNotFoundException {
       
   413             try {
       
   414                 return super.resolveClass(desc);
       
   415             } catch (ClassNotFoundException x) {
       
   416                 String name = desc.getName();
       
   417                 return Class.forName(name, false, loader);
       
   418             }
       
   419         }
       
   420     }
       
   421 }