1 /* 2 * Copyright (c) 2003, 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. 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.rmi.RemoteException; 25 import java.rmi.Naming; 26 import java.rmi.server.UnicastRemoteObject; 27 import java.rmi.registry.LocateRegistry; 28 import java.rmi.registry.Registry; 29 import java.util.Random; 30 import java.util.ArrayList; 31 import java.util.Date; 32 import java.util.logging.Logger; 33 import java.util.logging.Level; 34 35 /** 36 * The AppleUserImpl class implements the behavior of the remote 37 * "apple user" objects exported by the server. The application server 38 * passes each of its remote "apple" objects to an apple user, and an 39 * AppleUserThread is created for each apple. 40 */ 41 public class AppleUserImpl 42 extends UnicastRemoteObject 43 implements AppleUser 44 { 45 private static Logger logger = Logger.getLogger("reliability.appleuser"); 46 private static int threadNum = 0; 47 private static long testDuration = 0; 48 private static int maxLevel = 7; 49 private static Thread server = null; 50 private static Exception status = null; 51 private static Random random = new Random(); 52 53 public AppleUserImpl() throws RemoteException { 54 } 55 56 /** 57 * Allows the other server process to indicate that it is ready 58 * to start "juicing". 59 */ 60 public synchronized void startTest() throws RemoteException { 61 this.notifyAll(); 62 } 63 64 /** 65 * Allows the other server process to report an exception to this 66 * process and thereby terminate the test. 67 */ 68 public void reportException(Exception status) throws RemoteException { 69 synchronized (AppleUserImpl.class) { 70 this.status = status; 71 AppleUserImpl.class.notifyAll(); 72 } 73 } 74 75 /** 76 * "Use" supplied apple object. Create an AppleUserThread to 77 * stress it out. 78 */ 79 public synchronized void useApple(Apple apple) throws RemoteException { 80 String threadName = Thread.currentThread().getName(); 81 logger.log(Level.FINEST, 82 threadName + ": AppleUserImpl.useApple(): BEGIN"); 83 84 AppleUserThread t = 85 new AppleUserThread("AppleUserThread-" + (++threadNum), apple); 86 t.start(); 87 88 logger.log(Level.FINEST, 89 threadName + ": AppleUserImpl.useApple(): END"); 90 } 91 92 /** 93 * The AppleUserThread class repeatedly invokes calls on its associated 94 * Apple object to stress the RMI system. 95 */ 96 class AppleUserThread extends Thread { 97 98 Apple apple; 99 100 public AppleUserThread(String name, Apple apple) { 101 super(name); 102 this.apple = apple; 103 } 104 105 public void run() { 106 int orangeNum = 0; 107 long stopTime = System.currentTimeMillis() + testDuration; 108 Logger logger = Logger.getLogger("reliability.appleuserthread"); 109 110 try { 111 do { // loop until stopTime is reached 112 113 /* 114 * Notify apple with some apple events. This tests 115 * serialization of arrays. 116 */ 117 int numEvents = Math.abs(random.nextInt() % 5); 118 AppleEvent[] events = new AppleEvent[numEvents]; 119 for (int i = 0; i < events.length; ++ i) { 120 events[i] = new AppleEvent(orangeNum % 3); 121 } 122 apple.notify(events); 123 124 /* 125 * Request a new orange object be created in 126 * the application server. 127 */ 128 Orange orange = apple.newOrange( 129 "Orange(" + getName() + ")-" + (++orangeNum)); 130 131 /* 132 * Create a large message of random ints to pass to orange. 133 */ 134 int msgLength = 1000 + Math.abs(random.nextInt() % 3000); 135 int[] message = new int[msgLength]; 136 for (int i = 0; i < message.length; ++ i) { 137 message[i] = random.nextInt(); 138 } 139 140 /* 141 * Invoke recursive call on the orange. Base case 142 * of recursion inverts messgage. 143 */ 144 OrangeEchoImpl echo = new OrangeEchoImpl( 145 "OrangeEcho(" + getName() + ")-" + orangeNum); 146 int[] response = orange.recurse(echo, message, 147 2 + Math.abs(random.nextInt() % (maxLevel + 1))); 148 149 /* 150 * Verify message was properly inverted and not corrupted 151 * through all the recursive method invocations. 152 */ 153 if (response.length != message.length) { 154 throw new RuntimeException( 155 "ERROR: CORRUPTED RESPONSE: " + 156 "wrong length of returned array " + "(should be " + 157 message.length + ", is " + response.length + ")"); 158 } 159 for (int i = 0; i < message.length; ++ i) { 160 if (~message[i] != response[i]) { 161 throw new RuntimeException( 162 "ERROR: CORRUPTED RESPONSE: " + 163 "at element " + i + "/" + message.length + 164 " of returned array (should be " + 165 Integer.toHexString(~message[i]) + ", is " + 166 Integer.toHexString(response[i]) + ")"); 167 } 168 } 169 170 try { 171 Thread.sleep(Math.abs(random.nextInt() % 10) * 1000); 172 } catch (InterruptedException e) { 173 } 174 175 } while (System.currentTimeMillis() < stopTime); 176 177 } catch (Exception e) { 178 status = e; 179 } 180 synchronized (AppleUserImpl.class) { 181 AppleUserImpl.class.notifyAll(); 182 } 183 } 184 } 185 186 private static void usage() { 187 System.out.println("Usage: AppleUserImpl [-hours <hours> | " + 188 "-seconds <seconds>]"); 189 System.out.println(" [-maxLevel <maxLevel>]"); 190 System.out.println(" hours The number of hours to run the juicer."); 191 System.out.println(" The default is 0 hours."); 192 System.out.println(" seconds The number of seconds to run the juicer."); 193 System.out.println(" The default is 0 seconds."); 194 System.out.println(" maxLevel The maximum number of levels to "); 195 System.out.println(" recurse on each call."); 196 System.out.println(" The default is 7 levels."); 197 //TestLibrary.bomb("Bad argument"); 198 } 199 200 /** 201 * Entry point for the "juicer" server process. Create and export 202 * an apple user implementation in an rmiregistry running on localhost. 203 */ 204 public static void main(String[] args) 205 206 { 207 //TestLibrary.suggestSecurityManager("java.rmi.RMISecurityManager"); 208 long startTime = 0; 209 String durationString = null; 210 211 // parse command line args 212 try { 213 for (int i = 0; i < args.length ; i++ ) { 214 String arg = args[i]; 215 if (arg.equals("-hours")) { 216 if (durationString != null) { 217 usage(); 218 } 219 i++; 220 int hours = Integer.parseInt(args[i]); 221 durationString = hours + " hours"; 222 testDuration = hours * 60 * 60 * 1000; 223 } else if (arg.equals("-seconds")) { 224 if (durationString != null) { 225 usage(); 226 } 227 i++; 228 long seconds = Long.parseLong(args[i]); 229 durationString = seconds + " seconds"; 230 testDuration = seconds * 1000; 231 } else if (arg.equals("-maxLevel")) { 232 i++; 233 maxLevel = Integer.parseInt(args[i]); 234 } else { 235 usage(); 236 } 237 } 238 if (durationString == null) { 239 durationString = testDuration + " milliseconds"; 240 } 241 } catch (Throwable t) { 242 usage(); 243 } 244 245 AppleUserImpl user = null; 246 try { 247 user = new AppleUserImpl(); 248 } catch (RemoteException e) { 249 //TestLibrary.bomb("Failed to create AppleUser", e); 250 } 251 252 synchronized (user) { 253 int port = -1; 254 // create new registry and bind new AppleUserImpl in registry 255 try { 256 Registry registry = TestLibrary.createRegistryOnEphemeralPort(); 257 port = TestLibrary.getRegistryPort(registry); 258 Naming.rebind("rmi://localhost:" + port + "/AppleUser",user); 259 } catch (RemoteException e) { 260 //TestLibrary.bomb("Failed to bind AppleUser", e); 261 } catch (java.net.MalformedURLException e) { 262 //TestLibrary.bomb("Failed to bind AppleUser", e); 263 } 264 265 // start the other server if available 266 try { 267 Class app = Class.forName("ApplicationServer"); 268 java.lang.reflect.Constructor appConstructor = 269 app.getDeclaredConstructor(new Class[] {Integer.TYPE}); 270 server = new Thread((Runnable) appConstructor.newInstance(port)); 271 } catch (ClassNotFoundException e) { 272 // assume the other server is running in a separate process 273 logger.log(Level.INFO, "Application server must be " + 274 "started in separate process"); 275 } catch (Exception ie) { 276 //TestLibrary.bomb("Could not instantiate server", ie); 277 } 278 279 // wait for other server to call startTest method 280 try { 281 logger.log(Level.INFO, "Waiting for application server " + 282 "process to start"); 283 user.wait(); 284 } catch (InterruptedException ie) { 285 //TestLibrary.bomb("AppleUserImpl interrupted", ie); 286 } 287 } 288 289 startTime = System.currentTimeMillis(); 290 logger.log(Level.INFO, "Test starting"); 291 292 // wait for exception to be reported or first thread to complete 293 try { 294 logger.log(Level.INFO, "Waiting " + durationString + " for " + 295 "test to complete or exception to be thrown"); 296 297 synchronized (AppleUserImpl.class) { 298 AppleUserImpl.class.wait(); 299 } 300 301 if (status != null) { 302 //TestLibrary.bomb("juicer server reported an exception", status); 303 } else { 304 logger.log(Level.INFO, "TEST PASSED"); 305 } 306 } catch (Exception e) { 307 logger.log(Level.INFO, "TEST FAILED"); 308 //TestLibrary.bomb("unexpected exception", e); 309 } finally { 310 logger.log(Level.INFO, "Test finished"); 311 long actualDuration = System.currentTimeMillis() - startTime; 312 logger.log(Level.INFO, "Test duration was " + 313 (actualDuration/1000) + " seconds " + 314 "(" + (actualDuration/3600000) + " hours)"); 315 } 316 } 317 }