1 // 2 // Copyright (c) ZeroC, Inc. All rights reserved. 3 // 4 5 package com.zeroc.testcontroller; 6 7 import java.io.*; 8 import java.util.*; 9 10 import com.zeroc.Ice.Logger; 11 import com.zeroc.Ice.Communicator; 12 import com.zeroc.IceInternal.Time; 13 14 import android.os.Build; 15 import android.util.Log; 16 import android.app.Application; 17 18 import Test.Common.ProcessControllerRegistryPrx; 19 import Test.Common.ProcessControllerPrx; 20 21 public class ControllerApp extends Application 22 { 23 private final String TAG = "ControllerApp"; 24 private ControllerI _controllerI; 25 private ControllerActivity _activity; 26 private String _ipv4Address; 27 private String _ipv6Address; 28 29 static private class TestSuiteBundle 30 { 31 @SuppressWarnings("unchecked") TestSuiteBundle(String name, ClassLoader loader)32 TestSuiteBundle(String name, ClassLoader loader) throws ClassNotFoundException 33 { 34 _loader = loader; 35 _class = (Class<? extends test.TestHelper>)_loader.loadClass(name); 36 } 37 newInstance()38 test.TestHelper newInstance() 39 throws IllegalAccessException, InstantiationException 40 { 41 if(_class == null) 42 { 43 return null; 44 } 45 return _class.newInstance(); 46 } 47 getClassLoader()48 ClassLoader getClassLoader() 49 { 50 return _loader; 51 } 52 53 private String _name; 54 private ClassLoader _loader; 55 private Class<? extends test.TestHelper> _class; 56 } 57 58 class AndroidLogger implements Logger 59 { 60 private final String _prefix; 61 AndroidLogger(String prefix)62 AndroidLogger(String prefix) 63 { 64 _prefix = prefix; 65 } 66 67 @Override print(String message)68 public void print(String message) 69 { 70 Log.d(TAG, message); 71 } 72 73 @Override trace(String category, String message)74 public void trace(String category, String message) 75 { 76 Log.v(category, message); 77 } 78 79 @Override warning(String message)80 public void warning(String message) 81 { 82 Log.w(TAG, message); 83 } 84 85 @Override error(String message)86 public void error(String message) 87 { 88 Log.e(TAG, message); 89 } 90 91 @Override getPrefix()92 public String getPrefix() 93 { 94 return _prefix; 95 } 96 97 @Override cloneWithPrefix(String s)98 public Logger cloneWithPrefix(String s) 99 { 100 return new AndroidLogger(s); 101 } 102 } 103 104 @Override onCreate()105 public void onCreate() 106 { 107 super.onCreate(); 108 com.zeroc.Ice.Util.setProcessLogger(new AndroidLogger("")); 109 } 110 setIpv4Address(String address)111 synchronized public void setIpv4Address(String address) 112 { 113 _ipv4Address = address; 114 } 115 setIpv6Address(String address)116 synchronized public void setIpv6Address(String address) 117 { 118 int i = address.indexOf("%"); 119 _ipv6Address = i == -1 ? address : address.substring(i); 120 } 121 getAddresses(boolean ipv6)122 public List<String> getAddresses(boolean ipv6) 123 { 124 List<String> addresses = new java.util.ArrayList<String>(); 125 try 126 { 127 java.util.Enumeration<java.net.NetworkInterface> ifaces = java.net.NetworkInterface.getNetworkInterfaces(); 128 while(ifaces.hasMoreElements()) 129 { 130 java.net.NetworkInterface iface = ifaces.nextElement(); 131 java.util.Enumeration<java.net.InetAddress> addrs = iface.getInetAddresses(); 132 while(addrs.hasMoreElements()) 133 { 134 java.net.InetAddress addr = addrs.nextElement(); 135 if((ipv6 && addr instanceof java.net.Inet6Address) || 136 (!ipv6 && !(addr instanceof java.net.Inet6Address))) 137 { 138 addresses.add(addr.getHostAddress()); 139 } 140 } 141 } 142 } 143 catch(java.net.SocketException ex) 144 { 145 } 146 return addresses; 147 } 148 startController(ControllerActivity activity, boolean bluetooth)149 public synchronized void startController(ControllerActivity activity, boolean bluetooth) 150 { 151 _activity = activity; 152 if(_controllerI == null) 153 { 154 _controllerI = new ControllerI(bluetooth); 155 } 156 } 157 println(final String data)158 public synchronized void println(final String data) 159 { 160 _activity.runOnUiThread(new Runnable() 161 { 162 @Override 163 public void run() 164 { 165 synchronized(ControllerApp.this) 166 { 167 _activity.println(data); 168 } 169 } 170 }); 171 } 172 isEmulator()173 public static boolean isEmulator() 174 { 175 return Build.FINGERPRINT.startsWith("generic") || 176 Build.FINGERPRINT.startsWith("unknown") || 177 Build.MODEL.contains("google_sdk") || 178 Build.MODEL.contains("Emulator") || 179 Build.MODEL.contains("Android SDK built for x86") || 180 Build.MANUFACTURER.contains("Genymotion") || 181 (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")) || 182 Build.PRODUCT.equals("google_sdk"); 183 } 184 185 class ControllerI 186 { ControllerI(boolean bluetooth)187 public ControllerI(boolean bluetooth) 188 { 189 com.zeroc.Ice.InitializationData initData = new com.zeroc.Ice.InitializationData(); 190 initData.properties = com.zeroc.Ice.Util.createProperties(); 191 initData.properties.setProperty("Ice.ThreadPool.Server.SizeMax", "10"); 192 initData.properties.setProperty("ControllerAdapter.Endpoints", "tcp"); 193 //initData.properties.setProperty("Ice.Trace.Network", "3"); 194 //initData.properties.setProperty("Ice.Trace.Protocol", "1"); 195 initData.properties.setProperty("ControllerAdapter.AdapterId", java.util.UUID.randomUUID().toString()); 196 initData.properties.setProperty("Ice.Override.ConnectTimeout", "1000"); 197 if(!isEmulator()) 198 { 199 if(bluetooth) 200 { 201 initData.properties.setProperty("Ice.Plugin.IceBT", "com.zeroc.IceBT.PluginFactory"); 202 } 203 initData.properties.setProperty("Ice.Plugin.IceDiscovery", "com.zeroc.IceDiscovery.PluginFactory"); 204 initData.properties.setProperty("IceDiscovery.DomainId", "TestController"); 205 } 206 _communicator = com.zeroc.Ice.Util.initialize(initData); 207 com.zeroc.Ice.ObjectAdapter adapter = _communicator.createObjectAdapter("ControllerAdapter"); 208 ProcessControllerPrx processController = ProcessControllerPrx.uncheckedCast( 209 adapter.add(new ProcessControllerI(), 210 com.zeroc.Ice.Util.stringToIdentity("Android/ProcessController"))); 211 adapter.activate(); 212 ProcessControllerRegistryPrx registry; 213 if(isEmulator()) 214 { 215 registry = ProcessControllerRegistryPrx.uncheckedCast( 216 _communicator.stringToProxy("Util/ProcessControllerRegistry:tcp -h 10.0.2.2 -p 15001")); 217 } 218 else 219 { 220 // Use IceDiscovery to find a process controller registry 221 registry = ProcessControllerRegistryPrx.uncheckedCast( 222 _communicator.stringToProxy("Util/ProcessControllerRegistry")); 223 } 224 registerProcessController(adapter, registry, processController); 225 println("Android/ProcessController"); 226 } 227 228 public void registerProcessController(final com.zeroc.Ice.ObjectAdapter adapter, final ProcessControllerRegistryPrx registry, final ProcessControllerPrx processController)229 registerProcessController(final com.zeroc.Ice.ObjectAdapter adapter, 230 final ProcessControllerRegistryPrx registry, 231 final ProcessControllerPrx processController) 232 { 233 registry.ice_pingAsync().whenCompleteAsync( 234 (r1, e1) -> 235 { 236 if(e1 != null) 237 { 238 handleException(e1, adapter, registry, processController); 239 } 240 else 241 { 242 com.zeroc.Ice.Connection connection = registry.ice_getConnection(); 243 connection.setAdapter(adapter); 244 connection.setACM(OptionalInt.of(5), 245 Optional.of(com.zeroc.Ice.ACMClose.CloseOff), 246 Optional.of(com.zeroc.Ice.ACMHeartbeat.HeartbeatAlways)); 247 connection.setCloseCallback( 248 con -> 249 { 250 println("connection with process controller registry closed"); 251 while (true) { 252 try 253 { 254 Thread.sleep(500); 255 break; 256 } 257 catch(InterruptedException e) 258 { 259 } 260 } 261 registerProcessController(adapter, registry, processController); 262 }); 263 264 registry.setProcessControllerAsync(processController).whenCompleteAsync( 265 (r2, e2) -> 266 { 267 if(e2 != null) 268 { 269 handleException(e2, adapter, registry, processController); 270 } 271 }); 272 } 273 }); 274 } 275 handleException(Throwable ex, final com.zeroc.Ice.ObjectAdapter adapter, final ProcessControllerRegistryPrx registry, final ProcessControllerPrx processController)276 public void handleException(Throwable ex, 277 final com.zeroc.Ice.ObjectAdapter adapter, 278 final ProcessControllerRegistryPrx registry, 279 final ProcessControllerPrx processController) 280 { 281 if(ex instanceof com.zeroc.Ice.ConnectFailedException || ex instanceof com.zeroc.Ice.TimeoutException) 282 { 283 while(true) 284 { 285 try 286 { 287 Thread.sleep(500); 288 break; 289 } 290 catch(InterruptedException e) 291 { 292 } 293 } 294 registerProcessController(adapter, registry, processController); 295 } 296 else 297 { 298 println(ex.toString()); 299 } 300 } 301 destroy()302 public void destroy() 303 { 304 _communicator.destroy(); 305 } 306 307 private ProcessControllerRegistryPrx _registry; 308 private com.zeroc.Ice.Communicator _communicator; 309 } 310 311 class ControllerHelperI extends Thread implements test.TestHelper.ControllerHelper 312 { ControllerHelperI(TestSuiteBundle bundle, String[] args, String exe)313 public ControllerHelperI(TestSuiteBundle bundle, String[] args, String exe) 314 { 315 _bundle = bundle; 316 _args = args; 317 _exe = exe; 318 } 319 communicatorInitialized(Communicator communicator)320 public void communicatorInitialized(Communicator communicator) 321 { 322 com.zeroc.Ice.Properties properties = communicator.getProperties(); 323 if(properties.getProperty("Ice.Plugin.IceSSL").equals("com.zeroc.IceSSL.PluginFactory")) 324 { 325 com.zeroc.IceSSL.Plugin plugin = 326 (com.zeroc.IceSSL.Plugin)communicator.getPluginManager().getPlugin("IceSSL"); 327 String keystore = communicator.getProperties().getProperty("IceSSL.Keystore"); 328 properties.setProperty("IceSSL.Keystore", ""); 329 int resource = keystore.equals("client.bks") ? R.raw.client : R.raw.server; 330 java.io.InputStream certs = getResources().openRawResource(resource); 331 plugin.setKeystoreStream(certs); 332 plugin.setTruststoreStream(certs); 333 communicator.getPluginManager().initializePlugins(); 334 } 335 } 336 run()337 public void run() 338 { 339 try 340 { 341 _helper = _bundle.newInstance(); 342 _helper.setClassLoader(_bundle.getClassLoader()); 343 _helper.setControllerHelper(this); 344 345 _helper.setWriter(new Writer() 346 { 347 @Override 348 public void close() throws IOException 349 { 350 } 351 352 @Override 353 public void flush() throws IOException 354 { 355 } 356 357 @Override 358 public void write(char[] buf, int offset, int count) 359 throws IOException 360 { 361 _out.append(buf, offset, count); 362 } 363 }); 364 365 _helper.run(_args); 366 completed(0); 367 } 368 catch(Exception ex) 369 { 370 ex.printStackTrace(_helper.getWriter()); 371 completed(-1); 372 } 373 } 374 shutdown()375 public void shutdown() 376 { 377 if(_helper != null) 378 { 379 _helper.shutdown(); 380 } 381 } 382 getOutput()383 public String getOutput() 384 { 385 return _out.toString(); 386 } 387 serverReady()388 synchronized public void serverReady() 389 { 390 _ready = true; 391 notifyAll(); 392 } 393 completed(int status)394 synchronized private void completed(int status) 395 { 396 _completed = true; 397 _status = status; 398 notifyAll(); 399 } 400 waitReady(int timeout)401 synchronized private void waitReady(int timeout) 402 throws Test.Common.ProcessFailedException 403 { 404 long now = Time.currentMonotonicTimeMillis(); 405 while(!_ready && !_completed) 406 { 407 try 408 { 409 wait(timeout * 1000); 410 if(Time.currentMonotonicTimeMillis() - now > timeout * 1000) 411 { 412 throw new Test.Common.ProcessFailedException("timed out waiting for the process to be ready"); 413 } 414 } 415 catch(java.lang.InterruptedException ex) 416 { 417 } 418 } 419 420 if(_completed && _status != 0) 421 { 422 throw new Test.Common.ProcessFailedException(_out.toString()); 423 } 424 } 425 waitSuccess(int timeout)426 synchronized private int waitSuccess(int timeout) 427 throws Test.Common.ProcessFailedException 428 { 429 long now = Time.currentMonotonicTimeMillis(); 430 while(!_completed) 431 { 432 try 433 { 434 wait(timeout * 1000); 435 if(Time.currentMonotonicTimeMillis() - now > timeout * 1000) 436 { 437 throw new Test.Common.ProcessFailedException("timed out waiting for the process to be ready"); 438 } 439 } 440 catch(java.lang.InterruptedException ex) 441 { 442 } 443 } 444 return _status; 445 } 446 447 private TestSuiteBundle _bundle; 448 private String[] _args; 449 private String _exe; 450 private test.TestHelper _helper; 451 private boolean _ready = false; 452 private boolean _completed = false; 453 private int _status = 0; 454 private final StringBuffer _out = new StringBuffer(); 455 } 456 457 class ProcessControllerI implements Test.Common.ProcessController 458 { start(final String testsuite, final String exe, String[] args, com.zeroc.Ice.Current current)459 public Test.Common.ProcessPrx start(final String testsuite, final String exe, String[] args, 460 com.zeroc.Ice.Current current) 461 throws Test.Common.ProcessFailedException 462 { 463 println("starting " + testsuite + " " + exe + "... "); 464 String className = "test." + testsuite.replace("/", ".") + "." + 465 exe.substring(0, 1).toUpperCase(Locale.ROOT) + exe.substring(1); 466 try 467 { 468 TestSuiteBundle bundle = new TestSuiteBundle(className, getClassLoader()); 469 ControllerHelperI mainHelper = new ControllerHelperI(bundle, args, exe); 470 mainHelper.start(); 471 return Test.Common.ProcessPrx.uncheckedCast(current.adapter.addWithUUID(new ProcessI(mainHelper))); 472 } 473 catch(ClassNotFoundException ex) 474 { 475 throw new Test.Common.ProcessFailedException( 476 "testsuite `" + testsuite + "' exe ` " + exe + "' start failed:\n" + ex.toString()); 477 } 478 } 479 getHost(String protocol, boolean ipv6, com.zeroc.Ice.Current current)480 public String getHost(String protocol, boolean ipv6, com.zeroc.Ice.Current current) 481 { 482 if(isEmulator()) 483 { 484 return "127.0.0.1"; 485 } 486 else 487 { 488 synchronized(ControllerApp.this) 489 { 490 return ipv6 ? _ipv6Address : _ipv4Address; 491 } 492 } 493 } 494 } 495 496 class ProcessI implements Test.Common.Process 497 { ProcessI(ControllerHelperI controllerHelper)498 public ProcessI(ControllerHelperI controllerHelper) 499 { 500 _controllerHelper = controllerHelper; 501 } 502 waitReady(int timeout, com.zeroc.Ice.Current current)503 public void waitReady(int timeout, com.zeroc.Ice.Current current) 504 throws Test.Common.ProcessFailedException 505 { 506 _controllerHelper.waitReady(timeout); 507 } 508 waitSuccess(int timeout, com.zeroc.Ice.Current current)509 public int waitSuccess(int timeout, com.zeroc.Ice.Current current) 510 throws Test.Common.ProcessFailedException 511 { 512 return _controllerHelper.waitSuccess(timeout); 513 } 514 terminate(com.zeroc.Ice.Current current)515 public String terminate(com.zeroc.Ice.Current current) 516 { 517 _controllerHelper.shutdown(); 518 current.adapter.remove(current.id); 519 while(true) 520 { 521 try 522 { 523 _controllerHelper.join(); 524 break; 525 } 526 catch(InterruptedException ex) 527 { 528 } 529 } 530 return _controllerHelper.getOutput(); 531 } 532 533 private ControllerHelperI _controllerHelper; 534 } 535 } 536