Source:
<code>public void test_Call_Method_In_JDK_Sandbox_Thread_Safety() throws Exception { final OgnlContext context = (OgnlContext) Ognl.createDefaultContext(null); final GenericService service = new GenericServiceImpl(); MethodBodyExecutionSandbox.enable(null, null, null); try { <START> final int NUM_THREADS = 1000; <END> final int MAX_WAIT_MS = 3000; ExecutorService exec = Executors.newFixedThreadPool(NUM_THREADS); final CountDownLatch allThreadsWaitOnThis = new CountDownLatch(1); final AtomicInteger numThreadsFailedTest = new AtomicInteger(0); for (int i = 0; i < NUM_THREADS; ++i) { exec.submit(new Runnable() { public void run() { try { allThreadsWaitOnThis.await(); } catch (InterruptedException ignored) { } try { Thread.sleep((long) (Math.random() * MAX_WAIT_MS)); } catch (InterruptedException ignored) { } Object[] args = OgnlRuntime.getObjectArrayPool().create(1); args[0] = Math.random() * MAX_WAIT_MS; try { OgnlRuntime.callMethod(context, service, "exec", args); numThreadsFailedTest.incrementAndGet(); } catch (Exception ex) { if (!(ex.getCause() instanceof SecurityException)) { numThreadsFailedTest.incrementAndGet(); } } } }); } allThreadsWaitOnThis.countDown(); Thread.sleep(MAX_WAIT_MS * 2); exec.shutdown(); exec.awaitTermination(MAX_WAIT_MS * 2, TimeUnit.MILLISECONDS); assertTrue(exec.isTerminated()); assertEquals(0, numThreadsFailedTest.get()); } finally { MethodBodyExecutionSandbox.disable(); } }</code><technical_language>**Note of interest**: appears this PR's OGNL sandbox reveal some kind of thread limitation shows JDK 7 (1.7.0_79 32-bit), 32-bit JVM threw failures in test due inability create native threads, happen sandbox. test complete dropping NUM_THREADS 350 (approximately) 32-bit JVM sandbox enabled. Switching a 64-bit JVM (1.7.0_79 64-bit) native thread failures disappear running sandbox. simply a factor of processing speed differences in 32/64-bit JVM implementations ..</technical_language>

Target:
public void test_Call_Method_In_JDK_Sandbox_Thread_Safety() throws Exception { final OgnlContext context = (OgnlContext) Ognl.createDefaultContext(null); final GenericService service = new GenericServiceImpl(); boolean temporaryEnabled = false; try { System.setProperty("ognl.security.manager", ""); temporaryEnabled = true; } catch (Exception ignore) { } try { final int NUM_THREADS = 100; final int MAX_WAIT_MS = 300; ExecutorService exec = Executors.newFixedThreadPool(NUM_THREADS); final CountDownLatch allThreadsWaitOnThis = new CountDownLatch(1); final AtomicInteger numThreadsFailedTest = new AtomicInteger(0); for (int i = 0; i < NUM_THREADS; ++i) { exec.submit(new Runnable() { public void run() { try { allThreadsWaitOnThis.await(); } catch (InterruptedException ignored) { } try { Thread.sleep((long) (Math.random() * MAX_WAIT_MS)); } catch (InterruptedException ignored) { } Object[] args = OgnlRuntime.getObjectArrayPool().create(1); args[0] = Math.random() * MAX_WAIT_MS; try { OgnlRuntime.callMethod(context, service, "exec", args); numThreadsFailedTest.incrementAndGet(); } catch (Exception ex) { if (!((ex.getCause() instanceof InvocationTargetException && ((InvocationTargetException)ex.getCause()).getTargetException().getMessage().contains("execute")) || (ex.getCause() instanceof SecurityException && ex.getCause().getMessage().contains("createClassLoader")))) { numThreadsFailedTest.incrementAndGet(); } } } }); } allThreadsWaitOnThis.countDown(); Thread.sleep(MAX_WAIT_MS * 3); exec.shutdown(); exec.awaitTermination(MAX_WAIT_MS * 3, TimeUnit.MILLISECONDS); assertTrue(exec.isTerminated()); assertEquals(0, numThreadsFailedTest.get()); } finally { if (temporaryEnabled) { System.clearProperty("ognl.security.manager"); } } }