ObjectStreamTest.java revision 15894:6ce43dd8e954
1/* 2 * Copyright (c) 2016, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26import java.io.Serializable; 27import java.lang.reflect.InvocationTargetException; 28import java.lang.reflect.Method; 29import java.math.BigDecimal; 30import java.math.BigInteger; 31import java.net.InetAddress; 32import java.net.UnknownHostException; 33import java.rmi.Remote; 34import java.rmi.RemoteException; 35import java.time.LocalTime; 36import java.util.ArrayList; 37import java.util.Arrays; 38 39import java.util.EnumSet; 40import java.util.HashSet; 41import java.util.HashMap; 42import java.util.Objects; 43import java.util.PropertyPermission; 44import java.util.Set; 45import java.util.concurrent.TimeUnit; 46import java.util.concurrent.atomic.LongAdder; 47 48import javax.naming.CommunicationException; 49import javax.naming.InitialContext; 50import javax.naming.Context; 51import javax.naming.NamingException; 52import javax.rmi.CORBA.Util; 53import javax.rmi.PortableRemoteObject; 54 55import org.omg.CORBA_2_3.ORB; 56import org.omg.CORBA_2_3.portable.OutputStream; 57import org.omg.CORBA_2_3.portable.InputStream; 58 59import jdk.test.lib.JDKToolFinder; 60import jdk.test.lib.JDKToolLauncher; 61 62import org.testng.Assert; 63import org.testng.annotations.AfterSuite; 64import org.testng.annotations.Test; 65import org.testng.annotations.DataProvider; 66import org.testng.TestNG; 67 68/* 69 * @test 70 * @library /test/lib 71 * @build jdk.test.lib.* 72 * @compile ObjectStreamTest.java ObjectStreamTest$_Echo_Stub.java ObjectStreamTest$_Server_Tie.java 73 * @modules java.corba/com.sun.corba.se.impl.io java.base/java.io java.corba/com.sun.corba.se.impl.activation 74 * @summary Tests of ReflectionFactory use in IIOP Serialization 75 * @run testng/othervm 76 * -Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory 77 * -Djava.naming.provider.url=iiop://localhost:1050 ObjectStreamTest 78 * @run testng/othervm/policy=security.policy 79 * -Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory 80 * -Djava.naming.provider.url=iiop://localhost:1050 ObjectStreamTest 81 */ 82 83@Test 84public class ObjectStreamTest { 85 86 enum Colors {RED, GREEN, YELLOW} 87 88 static Set<Colors> colorSet = new HashSet<>(); 89 90 static { 91 colorSet.add(Colors.RED); 92 colorSet.add(Colors.GREEN); 93 } 94 95 /** 96 * The process spawned to run orbd. 97 */ 98 static Process orbdProcess; 99 static Thread orbThread; 100 101 @DataProvider(name = "Objects") 102 static Object[][] patterns() { 103 BigInteger bigInteger = new BigInteger("8943892002309239"); 104 InetAddress inetAddr; 105 try { 106 inetAddr = java.net.InetAddress.getByAddress(new byte[]{127, 0, 0, 1}); 107 } catch (UnknownHostException ignored) { 108 inetAddr = null; 109 // ignored 110 } 111 HashMap<String, Object> hashMap = new HashMap<>(); 112 hashMap.put("BigInteger", bigInteger); 113 hashMap.put("InetAddress", inetAddr); 114 hashMap.put("String", "bString"); 115 Object[][] patterns = new Object[][]{ 116 {"aString"}, 117 {Integer.valueOf(5)}, 118 {new SimpleObject(4, 4.0f)}, 119 {Arrays.asList("a", "b", "c")}, 120 {new String[]{"x", "y", "z"}}, 121 {new ArrayList<Object>(1)}, // uses readObject/writeObject 122 {new StringBuffer("abc")}, // Has serialPersistentFields 123 {new StringBuilder("abc")}, 124 {Colors.RED}, 125 {inetAddr}, 126 {LocalTime.MIDNIGHT}, // uses writeReplace/readResolve 127 {new LongAdder()}, // uses writeReplace/readResolve 128 {EnumSet.allOf(Colors.class)}, // used writeReplace/readResolve 129 {bigInteger}, 130 {new BigDecimal(bigInteger)}, 131 {hashMap}, 132 {new PropertyPermission("abc", "read")}, // has serialPersistentFields 133 }; 134 return patterns; 135 } 136 137 138 /** 139 * Check ObjectStreamClass facts match between core serialization and CORBA. 140 * 141 * @param value 142 */ 143 @Test(dataProvider = "Objects") 144 static void factCheck(Serializable value) { 145 Class<?> clazz = value.getClass(); 146 java.io.ObjectStreamClass sOSC = java.io.ObjectStreamClass.lookup(clazz); 147 java.io.ObjectStreamField[] sFields = sOSC.getFields(); 148 com.sun.corba.se.impl.io.ObjectStreamClass cOSC = corbaLookup(clazz); 149 com.sun.corba.se.impl.io.ObjectStreamField[] cFields = cOSC.getFields(); 150 151 Assert.assertEquals(sFields.length, cFields.length, "Different number of fields"); 152 for (int i = 0; i < sFields.length; i++) { 153 Assert.assertEquals(sFields[i].getName(), cFields[i].getName(), "different field names " + cFields[i].getName()); 154 Assert.assertEquals(sFields[i].getType(), cFields[i].getType(), "different field types " + cFields[i].getName()); 155 Assert.assertEquals(sFields[i].getTypeString(), cFields[i].getTypeString(), "different field typestrings " + cFields[i].getName()); 156 } 157 158 Assert.assertEquals(baseMethod("hasReadObjectMethod", sOSC, (Class<?>[]) null), 159 corbaMethod("hasReadObject", cOSC, (Class<?>[]) null), "hasReadObject: " + value.getClass()); 160 161 Assert.assertEquals(baseMethod("hasWriteObjectMethod", sOSC, (Class<?>[]) null), 162 corbaMethod("hasWriteObject", cOSC, (Class<?>[]) null), "hasWriteObject: " + value.getClass()); 163 164 Assert.assertEquals(baseMethod("hasWriteReplaceMethod", sOSC, (Class<?>[]) null), 165 corbaMethod("hasWriteReplaceMethod", cOSC, (Class<?>[]) null), "hasWriteReplace: " + value.getClass()); 166 167 Assert.assertEquals(baseMethod("hasReadResolveMethod", sOSC, (Class<?>[]) null), 168 corbaMethod("hasReadResolveMethod", cOSC, (Class<?>[]) null), "hasReadResolve: " + value.getClass()); 169 170 Assert.assertEquals(baseMethod("getSerialVersionUID", sOSC, (Class<?>[]) null), 171 corbaMethod("getSerialVersionUID", cOSC, (Class<?>[]) null), "getSerialVersionUID: " + value.getClass()); 172 173 } 174 175 176 /** 177 * Test that objects written using Util.writeAny can be serialized 178 * and deserialized using Util.readAny to equivalent objects. 179 */ 180 @Test(dataProvider = "Objects", enabled = true, dependsOnMethods = {"factCheck"}) 181 static void WriteValueObjectStreamTest01(Serializable value) throws Exception { 182 ORB orb = (ORB) ORB.init(new String[0], null); 183 184 OutputStream out = (OutputStream) orb.create_output_stream(); 185 Util.writeAny(out, value); 186 187 InputStream in = (InputStream) out.create_input_stream(); 188 Object actual = Util.readAny(in); 189 190 checkEquals(actual, value); 191 } 192 193 /** 194 * Test that objects can be echoed to a server and come back equivalent. 195 */ 196 @Test(dataProvider = "Objects", enabled = false, dependsOnMethods = {"factCheck"}) 197 static void echoObjects(Serializable value) throws Exception { 198 Context initialNamingContext = Server.init(); 199 Echo echo = (Echo) PortableRemoteObject.narrow( 200 initialNamingContext.lookup(Server.serverID), Echo.class); 201 Object actual = echo.echo(value); 202 checkEquals(actual, value); 203 } 204 205 /** 206 * Check if the value and result are equals, with some tests depending on the type. 207 * @param expected the expected value 208 * @param actual the actual value 209 */ 210 static void checkEquals(Object actual, Object expected) { 211 Class<?> cl = expected.getClass(); 212 Assert.assertEquals(actual.getClass(), cl, "type of value not equal to class of result"); 213 try { 214 if (cl.isArray() || !(cl.getDeclaredMethod("equals", cl) == null)) { 215 Assert.assertEquals(actual, expected, "echo'd object not equal"); 216 } else { 217 Assert.assertEquals(toString(actual), toString(expected), "toString values not equal"); 218 } 219 } catch (NoSuchMethodException ex) { 220 Assert.assertEquals(toString(actual), toString(expected), "toString values not equal"); 221 } 222 } 223 224 /** 225 * Convert an object to a String, and correctly for arrays. 226 * @param obj an object 227 * @return the tostring for the object. 228 */ 229 static String toString(Object obj) { 230 return obj.getClass().isArray() 231 ? Arrays.toString((Object[]) obj) 232 : Objects.toString(obj); 233 } 234 235 /** 236 * SimpleObject to test round trip. 237 */ 238 static class SimpleObject implements Serializable { 239 private static final long serialVersionUID = 5217577841494640354L; 240 241 private int i = 0; 242 private float f = 0.0f; 243 244 SimpleObject(int i, float f) { 245 this.i = i; 246 this.f = f; 247 } 248 249 @Override 250 public boolean equals(Object o) { 251 if (this == o) return true; 252 if (o == null || getClass() != o.getClass()) return false; 253 254 SimpleObject that = (SimpleObject) o; 255 256 if (i != that.i) return false; 257 return Float.compare(that.f, f) == 0; 258 259 } 260 261 @Override 262 public int hashCode() { 263 int result = i; 264 result = 31 * result + (f != +0.0f ? Float.floatToIntBits(f) : 0); 265 return result; 266 } 267 268 @Override 269 public String toString() { 270 return "SimpleObject{" + 271 "i=" + i + 272 ", f=" + f + 273 '}'; 274 } 275 } 276 277 278 /** 279 * Lookup the CORBA ObjectStreamClass instance for a class. 280 * @param clazz the class 281 * @return the CORBA ObjectStreamClass instance for the class 282 */ 283 static com.sun.corba.se.impl.io.ObjectStreamClass corbaLookup(Class<?> clazz) { 284 Class<?> oscClass = com.sun.corba.se.impl.io.ObjectStreamClass.class; 285 286 try { 287 Method meth = oscClass.getDeclaredMethod("lookup", Class.class); 288 meth.setAccessible(true); 289 return (com.sun.corba.se.impl.io.ObjectStreamClass) meth.invoke(null, clazz); 290 } catch (NoSuchMethodException noMeth) { 291 throw new RuntimeException("missing method", noMeth); 292 } catch (IllegalAccessException | InvocationTargetException rex) { 293 throw new RuntimeException("invocation failed", rex); 294 } 295 } 296 297 /** 298 * Lookup aand invoke method on a serializable object via the CORBA ObjectStreamClass. 299 * @param methodName method name 300 * @param osc CORBA ObjectStreamClass 301 * @param argClasses method arguments 302 * @return the value returned from invoking the method 303 */ 304 static Object corbaMethod(String methodName, com.sun.corba.se.impl.io.ObjectStreamClass osc, Class<?>... argClasses) { 305 Class<?> oscClass = com.sun.corba.se.impl.io.ObjectStreamClass.class; 306 307 try { 308 Method meth = oscClass.getDeclaredMethod(methodName, argClasses); 309 meth.setAccessible(true); 310 return meth.invoke(osc); 311 312 } catch (NoSuchMethodException noMeth) { 313 throw new RuntimeException("missing method" + osc.getName() 314 + "::" + methodName, noMeth); 315 } catch (IllegalAccessException | InvocationTargetException rex) { 316 throw new RuntimeException("invocation failed", rex); 317 } 318 } 319 320 321 /** 322 * Lookup aand invoke method on a serializable object via java.io.ObjectStreamClass. 323 * @param methodName method name 324 * @param osc java.io.ObjectStreamClass 325 * @param argClasses method arguments 326 * @return the value returned from invoking the method 327 */ 328 static Object baseMethod(String methodName, java.io.ObjectStreamClass osc, Class<?>... argClasses) { 329 Class<?> oscClass = java.io.ObjectStreamClass.class; 330 331 try { 332 Method meth = oscClass.getDeclaredMethod(methodName, argClasses); 333 meth.setAccessible(true); 334 return meth.invoke(osc); 335 336 } catch (NoSuchMethodException noMeth) { 337 throw new RuntimeException("missing method: " + osc.getName() 338 + "::" + methodName, noMeth); 339 } catch (IllegalAccessException | InvocationTargetException rex) { 340 throw new RuntimeException("invocation failed", rex); 341 } 342 } 343 344 /** 345 * Simple echo interface to check serialization/deserialization. 346 */ 347 interface Echo extends Remote { 348 Object echo(Object obj) throws RemoteException; 349 } 350 351 static class Server extends PortableRemoteObject implements Echo { 352 353 public static final String serverID = "ObjectStreamTestServer"; 354 355 private static Context initialNamingContext; 356 357 private static Server server; 358 359 public Server() throws RemoteException { 360 super(); 361 } 362 363 public Object echo(Object obj) { 364 return obj; 365 } 366 367 368 public static Context init() { 369 if (initialNamingContext == null) { 370 try { 371 startOrbd(); 372 Thread.sleep(5000L); // Give it 5 seconds 373 } catch (Exception eex) { 374 throw new RuntimeException("Orbd", eex); 375 } 376 for (int i = 0; i < 1; i++) { 377 try { 378 Thread.sleep(1L); 379 initialNamingContext = new InitialContext(); 380 server = new Server(); 381 initialNamingContext.rebind(serverID, server); 382 } catch (CommunicationException | InterruptedException cex) { 383 System.out.printf("retry #%d sec: ex: %s%n", i, cex); 384 } catch (NamingException ex) { 385 throw new RuntimeException("can't initialize naming context", ex); 386 } catch (RemoteException rex) { 387 throw new RuntimeException("can't initialize server", rex); 388 } 389 } 390 } 391 if (initialNamingContext == null) { 392 Assert.fail("Can't initialize the Orb, no naming context"); 393 } 394 return initialNamingContext; 395 } 396 } 397 398 static void startOrbd() throws Exception { 399 System.out.println("\nStarting orbd with NS port 1050 "); 400 JDKToolLauncher orbdLauncher = JDKToolLauncher.create("orbd") 401 .addToolArg("-ORBInitialHost").addToolArg("localhost") 402 .addToolArg("-ORBInitialPort").addToolArg("1050"); 403 404 System.out.println("ObjectStreamTest: Executing: " + Arrays.asList(orbdLauncher.getCommand())); 405 ProcessBuilder pb = new ProcessBuilder(orbdLauncher.getCommand()); 406 407 pb.redirectError(ProcessBuilder.Redirect.INHERIT); 408 orbdProcess = pb.start(); 409 } 410 411 @AfterSuite 412 static void killOrbd() throws Exception { 413 if (orbdProcess != null) { 414 orbdProcess.destroyForcibly(); 415 orbdProcess.waitFor(); 416 System.out.printf("destroyed orbd, pid: %d, exitValue: %d%n", 417 orbdProcess.getPid(), orbdProcess.exitValue()); 418 } 419 } 420 421 422 423 // Main can be used to run the tests from the command line with only testng.jar. 424 @SuppressWarnings("raw_types") 425 @Test(enabled = false) 426 public static void main(String[] args) { 427 Class<?>[] testclass = {ObjectStreamTest.class}; 428 TestNG testng = new TestNG(); 429 testng.setTestClasses(testclass); 430 testng.run(); 431 } 432 433} 434