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 26 import java.io.Serializable; 27 import java.lang.reflect.InvocationTargetException; 28 import java.lang.reflect.Method; 29 import java.math.BigDecimal; 30 import java.math.BigInteger; 31 import java.net.InetAddress; 32 import java.net.UnknownHostException; 33 import java.rmi.Remote; 34 import java.rmi.RemoteException; 35 import java.time.LocalTime; 36 import java.util.ArrayList; 37 import java.util.Arrays; 38 39 import java.util.EnumSet; 40 import java.util.HashSet; 41 import java.util.HashMap; 42 import java.util.Objects; 43 import java.util.PropertyPermission; 44 import java.util.Set; 45 import java.util.concurrent.atomic.LongAdder; 46 47 import javax.rmi.CORBA.Util; 48 import javax.rmi.PortableRemoteObject; 49 50 import org.omg.CORBA_2_3.ORB; 51 import org.omg.CORBA_2_3.portable.OutputStream; 52 import org.omg.CORBA_2_3.portable.InputStream; 53 54 import org.testng.Assert; 55 import org.testng.annotations.AfterClass; 56 import org.testng.annotations.BeforeClass; 57 import org.testng.annotations.Test; 58 import org.testng.annotations.DataProvider; 59 import org.testng.TestNG; 60 61 /* 62 * @test 63 * @library /test/lib 64 * @build jdk.test.lib.* 65 * @compile ObjectStreamTest.java ObjectStreamTest$_Echo_Stub.java 66 * ObjectStreamTest$_Server_Tie.java 67 * @modules java.base/java.io:open 68 * java.corba/com.sun.corba.se.impl.io:+open 69 * java.corba/com.sun.corba.se.impl.activation 70 * @summary Tests of ReflectionFactory use in IIOP Serialization 71 * @run testng/othervm ObjectStreamTest 72 * @run testng/othervm/policy=security.policy ObjectStreamTest 73 */ 74 75 @Test 76 public class ObjectStreamTest { 77 78 enum Colors {RED, GREEN, YELLOW} 79 80 static Set<Colors> colorSet = new HashSet<>(); 81 82 static { 83 colorSet.add(Colors.RED); 84 colorSet.add(Colors.GREEN); 85 } 86 87 @DataProvider(name = "Objects") 88 static Object[][] patterns() { 89 BigInteger bigInteger = new BigInteger("8943892002309239"); 90 InetAddress inetAddr; 91 try { 92 inetAddr = java.net.InetAddress.getByAddress(new byte[]{127, 0, 0, 1}); 93 } catch (UnknownHostException ignored) { 94 inetAddr = null; 95 // ignored 96 } 97 HashMap<String, Object> hashMap = new HashMap<>(); 98 hashMap.put("BigInteger", bigInteger); 99 hashMap.put("InetAddress", inetAddr); 100 hashMap.put("String", "bString"); 101 Object[][] patterns = new Object[][]{ 102 {"aString"}, 103 {Integer.valueOf(5)}, 104 {new SimpleObject(4, 4.0f)}, 105 {Arrays.asList("a", "b", "c")}, 106 {new String[]{"x", "y", "z"}}, 107 {new ArrayList<Object>(1)}, // uses readObject/writeObject 108 {new StringBuffer("abc")}, // Has serialPersistentFields 109 {new StringBuilder("abc")}, 110 {Colors.RED}, 111 {inetAddr}, 112 {LocalTime.MIDNIGHT}, // uses writeReplace/readResolve 113 {new LongAdder()}, // uses writeReplace/readResolve 114 {EnumSet.allOf(Colors.class)}, // used writeReplace/readResolve 115 {bigInteger}, 116 {new BigDecimal(bigInteger)}, 117 {hashMap}, 118 {new PropertyPermission("abc", "read")}, // has serialPersistentFields 119 }; 120 return patterns; 121 } 122 123 124 /** 125 * Check ObjectStreamClass facts match between core serialization and CORBA. 126 * 127 * @param value 128 */ 129 @Test(dataProvider = "Objects") 130 void factCheck(Serializable value) { 131 Class<?> clazz = value.getClass(); 132 java.io.ObjectStreamClass sOSC = java.io.ObjectStreamClass.lookup(clazz); 133 java.io.ObjectStreamField[] sFields = sOSC.getFields(); 134 com.sun.corba.se.impl.io.ObjectStreamClass cOSC = corbaLookup(clazz); 135 com.sun.corba.se.impl.io.ObjectStreamField[] cFields = cOSC.getFields(); 136 137 Assert.assertEquals(sFields.length, cFields.length, "Different number of fields"); 138 for (int i = 0; i < sFields.length; i++) { 139 Assert.assertEquals(sFields[i].getName(), cFields[i].getName(), 140 "different field names " + cFields[i].getName()); 141 Assert.assertEquals(sFields[i].getType(), cFields[i].getType(), 142 "different field types " + cFields[i].getName()); 143 Assert.assertEquals(sFields[i].getTypeString(), cFields[i].getTypeString(), 144 "different field typestrings " + cFields[i].getName()); 145 } 146 147 Assert.assertEquals(baseMethod("hasReadObjectMethod", sOSC, (Class<?>[]) null), 148 corbaMethod("hasReadObject", cOSC, (Class<?>[]) null), 149 "hasReadObject: " + value.getClass()); 150 151 Assert.assertEquals(baseMethod("hasWriteObjectMethod", sOSC, (Class<?>[]) null), 152 corbaMethod("hasWriteObject", cOSC, (Class<?>[]) null), 153 "hasWriteObject: " + value.getClass()); 154 155 Assert.assertEquals(baseMethod("hasWriteReplaceMethod", sOSC, (Class<?>[]) null), 156 corbaMethod("hasWriteReplaceMethod", cOSC, (Class<?>[]) null), 157 "hasWriteReplace: " + value.getClass()); 158 159 Assert.assertEquals(baseMethod("hasReadResolveMethod", sOSC, (Class<?>[]) null), 160 corbaMethod("hasReadResolveMethod", cOSC, (Class<?>[]) null), 161 "hasReadResolve: " + value.getClass()); 162 163 Assert.assertEquals(baseMethod("getSerialVersionUID", sOSC, (Class<?>[]) null), 164 corbaMethod("getSerialVersionUID", cOSC, (Class<?>[]) null), 165 "getSerialVersionUID: " + value.getClass()); 166 167 } 168 169 170 /** 171 * Test that objects written using Util.writeAny can be serialized 172 * and deserialized using Util.readAny to equivalent objects. 173 */ 174 @Test(dataProvider = "Objects", enabled = true, dependsOnMethods = {"factCheck"}) 175 void WriteValueObjectStreamTest01(Serializable value) throws Exception { 176 ORB orb = (ORB) ORB.init(new String[0], null); 177 178 OutputStream out = (OutputStream) orb.create_output_stream(); 179 Util.writeAny(out, value); 180 181 InputStream in = (InputStream) out.create_input_stream(); 182 Object actual = Util.readAny(in); 183 184 checkEquals(actual, value); 185 } 186 187 /** 188 * Test that objects can be echoed to a server and come back equivalent. 189 */ 190 @Test(dataProvider = "Objects", enabled = true, dependsOnMethods = {"factCheck"}) 191 void echoObjects(Serializable value) throws Exception { 192 Echo echo = getEchoStub(); 193 Object actual = echo.echo(value); 194 checkEquals(actual, value); 195 } 196 197 198 /** 199 * Initialize the ORB and the singleton Echo server stub. 200 * @return the stub for the Echo server. 201 * @throws RemoteException if an error occurs 202 */ 203 synchronized Echo getEchoStub() throws RemoteException { 204 if (echoStub == null) { 205 ORB orb = (ORB) ORB.init(new String[0], null); 206 Echo server = new Server(); 207 echoStub = (javax.rmi.CORBA.Stub) PortableRemoteObject.toStub(server); 208 echoStub.connect(orb); 209 } 210 return (Echo)echoStub; 211 } 212 213 /** 214 * The stub for the Echo Server class. Initialized on first use. 215 */ 216 private javax.rmi.CORBA.Stub echoStub; 217 218 /** 219 * After all the tests run shutdown the orb. 220 */ 221 @AfterClass 222 void shutdownOrb() { 223 ORB orb = (ORB) ORB.init(new String[0], null); 224 orb.shutdown(true); 225 } 226 227 /** 228 * Check if the value and result are equals, with some tests depending on the type. 229 * @param expected the expected value 230 * @param actual the actual value 231 */ 232 static void checkEquals(Object actual, Object expected) { 233 Class<?> cl = expected.getClass(); 234 Assert.assertEquals(actual.getClass(), cl, 235 "type of value not equal to class of result"); 236 try { 237 if (cl.isArray() || !(cl.getDeclaredMethod("equals", cl) == null)) { 238 Assert.assertEquals(actual, expected, "echo'd object not equal"); 239 } else { 240 Assert.assertEquals(toString(actual), toString(expected), 241 "toString values not equal"); 242 } 243 } catch (NoSuchMethodException ex) { 244 Assert.assertEquals(toString(actual), toString(expected), 245 "toString values not equal"); 246 } 247 } 248 249 /** 250 * Convert an object to a String, and correctly for arrays. 251 * @param obj an object 252 * @return the tostring for the object. 253 */ 254 static String toString(Object obj) { 255 return obj.getClass().isArray() 256 ? Arrays.toString((Object[]) obj) 257 : Objects.toString(obj); 258 } 259 260 /** 261 * SimpleObject to test round trip. 262 */ 263 static class SimpleObject implements Serializable { 264 private static final long serialVersionUID = 5217577841494640354L; 265 266 private int i = 0; 267 private float f = 0.0f; 268 269 SimpleObject(int i, float f) { 270 this.i = i; 271 this.f = f; 272 } 273 274 @Override 275 public boolean equals(Object o) { 276 if (this == o) return true; 277 if (o == null || getClass() != o.getClass()) return false; 278 279 SimpleObject that = (SimpleObject) o; 280 281 if (i != that.i) return false; 282 return Float.compare(that.f, f) == 0; 283 284 } 285 286 @Override 287 public int hashCode() { 288 int result = i; 289 result = 31 * result + (f != +0.0f ? Float.floatToIntBits(f) : 0); 290 return result; 291 } 292 293 @Override 294 public String toString() { 295 return "SimpleObject{" + 296 "i=" + i + 297 ", f=" + f + 298 '}'; 299 } 300 } 301 302 303 /** 304 * Lookup the CORBA ObjectStreamClass instance for a class. 305 * @param clazz the class 306 * @return the CORBA ObjectStreamClass instance for the class 307 */ 308 static com.sun.corba.se.impl.io.ObjectStreamClass corbaLookup(Class<?> clazz) { 309 Class<?> oscClass = com.sun.corba.se.impl.io.ObjectStreamClass.class; 310 311 try { 312 Method meth = oscClass.getDeclaredMethod("lookup", Class.class); 313 meth.setAccessible(true); 314 return (com.sun.corba.se.impl.io.ObjectStreamClass) meth.invoke(null, clazz); 315 } catch (NoSuchMethodException noMeth) { 316 throw new RuntimeException("missing method", noMeth); 317 } catch (IllegalAccessException | InvocationTargetException rex) { 318 throw new RuntimeException("invocation failed", rex); 319 } 320 } 321 322 /** 323 * Lookup aand invoke method on a serializable object via the CORBA ObjectStreamClass. 324 * @param methodName method name 325 * @param osc CORBA ObjectStreamClass 326 * @param argClasses method arguments 327 * @return the value returned from invoking the method 328 */ 329 static Object corbaMethod(String methodName, 330 com.sun.corba.se.impl.io.ObjectStreamClass osc, 331 Class<?>... argClasses) { 332 Class<?> oscClass = com.sun.corba.se.impl.io.ObjectStreamClass.class; 333 334 try { 335 Method meth = oscClass.getDeclaredMethod(methodName, argClasses); 336 meth.setAccessible(true); 337 return meth.invoke(osc); 338 339 } catch (NoSuchMethodException noMeth) { 340 throw new RuntimeException("missing method" + osc.getName() 341 + "::" + methodName, noMeth); 342 } catch (IllegalAccessException | InvocationTargetException rex) { 343 throw new RuntimeException("invocation failed", rex); 344 } 345 } 346 347 348 /** 349 * Lookup aand invoke method on a serializable object via java.io.ObjectStreamClass. 350 * @param methodName method name 351 * @param osc java.io.ObjectStreamClass 352 * @param argClasses method arguments 353 * @return the value returned from invoking the method 354 */ 355 static Object baseMethod(String methodName, java.io.ObjectStreamClass osc, 356 Class<?>... argClasses) { 357 Class<?> oscClass = java.io.ObjectStreamClass.class; 358 359 try { 360 Method meth = oscClass.getDeclaredMethod(methodName, argClasses); 361 meth.setAccessible(true); 362 return meth.invoke(osc); 363 364 } catch (NoSuchMethodException noMeth) { 365 throw new RuntimeException("missing method: " + osc.getName() 366 + "::" + methodName, noMeth); 367 } catch (IllegalAccessException | InvocationTargetException rex) { 368 throw new RuntimeException("invocation failed", rex); 369 } 370 } 371 372 /** 373 * Simple echo interface to check IIOP serialization/deserialization. 374 */ 375 interface Echo extends Remote { 376 Object echo(Object obj) throws RemoteException; 377 } 378 379 static class Server extends PortableRemoteObject implements Echo { 380 381 public Server() throws RemoteException { 382 super(); 383 } 384 385 public Object echo(Object obj) { 386 return obj; 387 } 388 } 389 390 // Main can be used to run the tests from the command line with only testng.jar. 391 @SuppressWarnings("raw_types") 392 @Test(enabled = false) 393 public static void main(String[] args) { 394 Class<?>[] testclass = {ObjectStreamTest.class}; 395 TestNG testng = new TestNG(); 396 testng.setTestClasses(testclass); 397 testng.run(); 398 } 399 400 }