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.ByteArrayInputStream;
  25 import java.io.ByteArrayOutputStream;
  26 import java.io.IOException;
  27 import java.io.ObjectInputStream;
  28 import java.io.ObjectOutputStream;
  29 import java.util.Base64;
  30 import java.util.Properties;
  31 
  32 /**
  33  * @test
  34  * @bug 8029891
  35  * @summary tests the compatibility of Properties serial form
  36  * @run main PropertiesSerialization read
  37  * @author bchristi
  38  * 
  39  * To update this test in case the serial form of Properties changes, run this
  40  * test with the 'write' flag, and copy the resulting output back into this
  41  * file, replacing the existing String declaration(s).
  42  */
  43 public class PropertiesSerialization {
  44     private static final Properties TEST_PROPS;
  45     static {
  46         TEST_PROPS = new Properties();
  47         TEST_PROPS.setProperty("one", "two");
  48         TEST_PROPS.setProperty("buckle", "shoe");
  49         TEST_PROPS.setProperty("three", "four");
  50         TEST_PROPS.setProperty("shut", "door");
  51     }
  52 
  53     /**
  54      * Base64 encoded string for Properties object
  55      * Java version: 1.8.0
  56      **/
  57     private static final String TEST_SER_BASE64 = 
  58          "rO0ABXNyABRqYXZhLnV0aWwuUHJvcGVydGllczkS0HpwNj6YAgABTAAIZGVmYXVs"
  59        + "dHN0ABZMamF2YS91dGlsL1Byb3BlcnRpZXM7eHIAE2phdmEudXRpbC5IYXNodGFi"
  60        + "bGUTuw8lIUrkuAMAAkYACmxvYWRGYWN0b3JJAAl0aHJlc2hvbGR4cD9AAAAAAAAI"
  61        + "dwgAAAALAAAABHQAA29uZXQAA3R3b3QABHNodXR0AARkb29ydAAGYnVja2xldAAE"
  62        + "c2hvZXQABXRocmVldAAEZm91cnhw";
  63     
  64     public static void main(String[] args) throws IOException,
  65             ClassNotFoundException {
  66         if (args.length == 0) {
  67             System.err.println("Run with 'read' or 'write'");
  68             System.err.println("  read mode:  normal test mode.");
  69             System.err.println("              Confirms that serial stream can");
  70             System.err.println("              be deserialized as expected.");
  71             System.err.println("  write mode: meant for updating the test,");
  72             System.err.println("              should the serial form change.");
  73             System.err.println("              Test output should be pasted");
  74             System.err.println("              back into the test source.");
  75             return;
  76         }
  77 
  78         Properties deserializedObject;
  79         if ("read".equals(args[0])) {
  80             ByteArrayInputStream bais = new
  81               ByteArrayInputStream(Base64.getDecoder().decode(TEST_SER_BASE64));
  82             try (ObjectInputStream ois = new ObjectInputStream(bais)) {
  83                 deserializedObject = (Properties) ois.readObject();
  84             }
  85             if (!TEST_PROPS.equals(deserializedObject)) {
  86                 throw new RuntimeException("deserializedObject not equals()");
  87             }
  88             System.out.println("Test passed");
  89         } else if ("write".equals(args[0])) {
  90             System.out.println("\nTo update the test, paste the following back "
  91                     + "into the test code:\n");
  92             ByteArrayOutputStream baos = new ByteArrayOutputStream();
  93             ObjectOutputStream oos = new ObjectOutputStream(baos);
  94             oos.writeObject(TEST_PROPS);
  95             oos.flush();
  96             oos.close();
  97 
  98             byte[] byteArray = baos.toByteArray();
  99             // Check that the Properties deserializes correctly
 100             ByteArrayInputStream bais = new ByteArrayInputStream(byteArray);
 101             ObjectInputStream ois = new ObjectInputStream(bais);
 102             Properties deser = (Properties)ois.readObject();
 103             if (!TEST_PROPS.equals(deser)) {
 104                 throw new RuntimeException("write: Deserialized != original");
 105             }
 106 
 107             // Now get a Base64 string representation of the serialized bytes.
 108             final String base64 = Base64.getEncoder().encodeToString(byteArray);
 109             // Check that we can deserialize the Base64 string we just computed.
 110             ByteArrayInputStream bais2 =
 111               new ByteArrayInputStream(Base64.getDecoder().decode(base64));
 112             ObjectInputStream ois2 = new ObjectInputStream(bais2);
 113             Properties deser2 = (Properties)ois2.readObject();            
 114             if (!TEST_PROPS.equals(deser2)) {
 115                 throw new RuntimeException("write: Deserialized base64 != "
 116                         + "original");
 117             }
 118             System.out.println(dumpBase64SerialStream(base64));
 119         }
 120     }
 121 
 122     private static final String INDENT = "   ";
 123     /* Based on:
 124      * java/util/logging/HigherResolutionTimeStamps/SerializeLogRecored.java
 125      */
 126     private static String dumpBase64SerialStream(String base64) {
 127         // Generates the Java Pseudo code that can be cut & pasted into
 128         // this test (see Jdk8SerializedLog and Jdk9SerializedLog below)
 129         final StringBuilder sb = new StringBuilder();
 130         sb.append(INDENT).append(" /**").append('\n');
 131         sb.append(INDENT).append("  * Base64 encoded string for Properties object\n");
 132         sb.append(INDENT).append("  * Java version: ").append(System.getProperty("java.version")).append('\n');
 133         sb.append(INDENT).append("  **/").append('\n');
 134         sb.append(INDENT).append(" private static final String TEST_SER_BASE64 = ").append("\n").append(INDENT).append("      ");
 135         final int last = base64.length() - 1;
 136         for (int i=0; i<base64.length();i++) {
 137             if (i%64 == 0) sb.append("\"");
 138             sb.append(base64.charAt(i));
 139             if (i%64 == 63 || i == last) {
 140                 sb.append("\"");
 141                 if (i == last) sb.append(";\n");
 142                 else sb.append("\n").append(INDENT).append("    + ");
 143             }
 144         }
 145         return sb.toString();        
 146     }
 147 }