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