Author: henrib Date: Thu May 26 21:13:48 2016 New Revision: 1745646 URL: http://svn.apache.org/viewvc?rev=1745646&view=rev Log: JEXL-196: break out of method resolution loop when already failed to resolve through context method
Modified: commons/proper/jexl/trunk/RELEASE-NOTES.txt commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java commons/proper/jexl/trunk/src/site/xdoc/changes.xml commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ScriptCallableTest.java Modified: commons/proper/jexl/trunk/RELEASE-NOTES.txt URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/RELEASE-NOTES.txt?rev=1745646&r1=1745645&r2=1745646&view=diff ============================================================================== --- commons/proper/jexl/trunk/RELEASE-NOTES.txt (original) +++ commons/proper/jexl/trunk/RELEASE-NOTES.txt Thu May 26 21:13:48 2016 @@ -28,6 +28,7 @@ Version 3.0.1 is a micro release to fix Bugs Fixed in 3.0.1: ==================== +* JEXL-196: Script execution hangs while calling method with one argument without parameter * JEXL-195: Support for AtomicBoolean in logical expressions * JEXL-193: InterruptedException is swallowed in function call in silent and non-strict mode * JEXL-192: Invalid return type when expected result is null Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java?rev=1745646&r1=1745645&r2=1745646&view=diff ============================================================================== --- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java (original) +++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java Thu May 26 21:13:48 2016 @@ -219,13 +219,7 @@ public class Interpreter extends ParserV } finally { if (functors != null && AUTOCLOSEABLE != null) { for (Object functor : functors.values()) { - if (functor != null && AUTOCLOSEABLE.isAssignableFrom(functor.getClass())) { - try { - jexl.invokeMethod(functor, "close", EMPTY_PARAMS); - } catch (Exception xclose) { - logger.warn(xclose.getMessage(), xclose.getCause()); - } - } + closeIfSupported(functor); } } functors = null; @@ -249,6 +243,26 @@ public class Interpreter extends ParserV } /** + * Attempt to call close() if supported. + * <p>This is used when dealing with auto-closeable (duck-like) objects + * @param closeable the object we'd like to close + */ + protected void closeIfSupported(Object closeable) { + if (closeable != null) { + if (AUTOCLOSEABLE == null || AUTOCLOSEABLE.isAssignableFrom(closeable.getClass())) { + JexlMethod mclose = uberspect.getMethod(closeable, "close", EMPTY_PARAMS); + if (mclose != null) { + try { + mclose.invoke(closeable, EMPTY_PARAMS); + } catch (Exception xignore) { + logger.warn(xignore); + } + } + } + } + } + + /** * Finds the node causing a NPE for diadic operators. * @param xrt the RuntimeException * @param node the parent node @@ -810,9 +824,13 @@ public class Interpreter extends ParserV if (iterableValue != null && node.jjtGetNumChildren() >= 3) { /* third objectNode is the statement to execute */ JexlNode statement = node.jjtGetChild(2); - // get an iterator for the collection/array etc via the - // introspector. - Iterator<?> itemsIterator = uberspect.getIterator(iterableValue); + // get an iterator for the collection/array etc via the introspector. + Object forEach = null; + try { + forEach = null;//operators.tryForeachOverload(node, iterableValue); + Iterator<?> itemsIterator = forEach instanceof Iterator + ? (Iterator<?>) forEach + : uberspect.getIterator(iterableValue); if (itemsIterator != null) { while (itemsIterator.hasNext()) { if (isCancelled()) { @@ -835,7 +853,11 @@ public class Interpreter extends ParserV } } } - } + } finally { + // closeable iterator handling + closeIfSupported(forEach); + } + } return result; } @@ -1708,7 +1730,11 @@ public class Interpreter extends ParserV // solve 'null' namespace if (target == context) { Object namespace = resolveNamespace(null, node); - if (namespace != null) { + if (namespace == context) { + // we can not solve it + break; + } + else if (namespace != null) { target = namespace; caller = null; continue; Modified: commons/proper/jexl/trunk/src/site/xdoc/changes.xml URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/site/xdoc/changes.xml?rev=1745646&r1=1745645&r2=1745646&view=diff ============================================================================== --- commons/proper/jexl/trunk/src/site/xdoc/changes.xml (original) +++ commons/proper/jexl/trunk/src/site/xdoc/changes.xml Thu May 26 21:13:48 2016 @@ -26,6 +26,9 @@ </properties> <body> <release version="3.0.1" date="unreleased"> + <action dev="henrib" type="fix" issue="JEXL-196" due-to="Dmitri Blinov"> + Script execution hangs while calling method with one argument without parameter + </action> <action dev="henrib" type="fix" issue="JEXL-195" due-to="Dmitri Blinov"> Support for AtomicBoolean in logical expressions </action> Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ScriptCallableTest.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ScriptCallableTest.java?rev=1745646&r1=1745645&r2=1745646&view=diff ============================================================================== --- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ScriptCallableTest.java (original) +++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ScriptCallableTest.java Thu May 26 21:13:48 2016 @@ -146,6 +146,10 @@ public class ScriptCallableTest extends throw xint; } } + + public int hangs(Object t) { + return 1; + } } @Test @@ -409,4 +413,21 @@ public class ScriptCallableTest extends exec.shutdown(); } } + + @Test + public void testHangs() throws Exception { + JexlScript e = JEXL.createScript("hangs()"); + Callable<Object> c = e.callable(new TestContext()); + + ExecutorService executor = Executors.newFixedThreadPool(1); + try { + Future<?> future = executor.submit(c); + Object t = future.get(1, TimeUnit.SECONDS); + Assert.fail("hangs should not be solved"); + } catch(ExecutionException xexec) { + Assert.assertTrue(xexec.getCause() instanceof JexlException.Method); + } finally { + executor.shutdown(); + } + } }