From 13a03ca68509b584b6017603bf2448feb95a9d6d Mon Sep 17 00:00:00 2001 From: Christian Morgner Date: Tue, 30 Apr 2024 22:33:02 +0200 Subject: [PATCH] Correctly restore state (parameters) after user-defined method call, adds test. --- .../org/structr/core/api/AbstractMethod.java | 3 ++ .../core/script/polyglot/StructrBinding.java | 44 ++++++++---------- .../test/core/script/ScriptingTest.java | 46 +++++++++++++++++++ 3 files changed, 68 insertions(+), 25 deletions(-) diff --git a/structr-base/src/main/java/org/structr/core/api/AbstractMethod.java b/structr-base/src/main/java/org/structr/core/api/AbstractMethod.java index 0df9b4fa98..749861bb43 100644 --- a/structr-base/src/main/java/org/structr/core/api/AbstractMethod.java +++ b/structr-base/src/main/java/org/structr/core/api/AbstractMethod.java @@ -98,6 +98,7 @@ public ProxyExecutable getProxyExecutable(final ActionContext actionContext, fin final StructrBinding binding = bindings.asProxyObject(); final GraphObject previousEntity = binding.getEntity(); final ActionContext previousContext = binding.getActionContext(); + final Map tmp = securityContext.getContextStore().getTemporaryParameters(); try { @@ -116,8 +117,10 @@ public ProxyExecutable getProxyExecutable(final ActionContext actionContext, fin } finally { + // restore state before this method call binding.setEntity(previousEntity); binding.setActionContext(previousContext); + securityContext.getContextStore().setTemporaryParameters(tmp); } } diff --git a/structr-base/src/main/java/org/structr/core/script/polyglot/StructrBinding.java b/structr-base/src/main/java/org/structr/core/script/polyglot/StructrBinding.java index a1dff38f36..6c6bc897dc 100644 --- a/structr-base/src/main/java/org/structr/core/script/polyglot/StructrBinding.java +++ b/structr-base/src/main/java/org/structr/core/script/polyglot/StructrBinding.java @@ -26,6 +26,7 @@ import org.structr.common.error.FrameworkException; import org.structr.core.GraphObject; import org.structr.core.Services; +import org.structr.core.app.StructrApp; import org.structr.core.function.Functions; import org.structr.core.script.polyglot.function.*; import org.structr.core.script.polyglot.wrappers.*; @@ -81,7 +82,7 @@ public Object getMember(String name) { return wrap(actionContext, entity); case "me": - return wrap(actionContext,actionContext.getSecurityContext().getUser(false)); + return wrap(actionContext, actionContext.getSecurityContext().getUser(false)); case "predicate": return new PredicateBinding(actionContext, entity); @@ -133,14 +134,7 @@ public Object getMember(String name) { default: - // look for user-defined function with the given name - final AbstractMethod method = Methods.resolveMethod(null, name); - if (method != null) { - - return method.getProxyExecutable(actionContext, null); - } - - // look for built-in function with the given name + // look for built-in function with the given name first (because it' fast) Function func = Functions.get(CaseHelper.toUnderscore(name, false)); if (func != null) { @@ -149,7 +143,7 @@ public Object getMember(String name) { // check if a named constant exists if (actionContext.getConstant(name) != null) { - return wrap(actionContext,actionContext.getConstant(name)); + return wrap(actionContext, actionContext.getConstant(name)); } // check request store @@ -157,31 +151,31 @@ public Object getMember(String name) { return wrap(actionContext, actionContext.getRequestStore().get(name)); } - // StructrScript result (what is this?) - final EvaluationHints hints = new EvaluationHints(); - Object structrScriptResult = null; - - try { + // static type? + final Class nodeType = StructrApp.getConfiguration().getNodeEntityClass(name); + if (nodeType != null) { - structrScriptResult = PolyglotWrapper.wrap(actionContext, actionContext.evaluate(entity, name, null, null, 0, hints, 1, 1)); + return new StaticTypeWrapper(actionContext, nodeType); + } - } catch (FrameworkException ex) { + // look for user-defined function with the given name + final AbstractMethod method = Methods.resolveMethod(null, name); + if (method != null) { - logger.error("Unexpected exception while trying to apply get function shortcut on script binding object.", ex); + return method.getProxyExecutable(actionContext, null); } - if (structrScriptResult != null) { + try { - if (structrScriptResult instanceof Class clazz) { + return PolyglotWrapper.wrap(actionContext, actionContext.evaluate(entity, name, null, null, 0, new EvaluationHints(), 1, 1)); - return new StaticTypeWrapper(actionContext, clazz); - } + } catch (FrameworkException ex) { - return structrScriptResult; + logger.error("Unexpected exception while trying to apply get function shortcut on script binding object.", ex); } - - return null; } + + return null; } @Override diff --git a/structr-core/src/test/java/org/structr/test/core/script/ScriptingTest.java b/structr-core/src/test/java/org/structr/test/core/script/ScriptingTest.java index 2922bbb5ee..c4d1c7e628 100644 --- a/structr-core/src/test/java/org/structr/test/core/script/ScriptingTest.java +++ b/structr-core/src/test/java/org/structr/test/core/script/ScriptingTest.java @@ -6342,6 +6342,52 @@ public void testThisInMethodCalls() { } } + @Test + public void testThatMethodParametersStillExistAfterMethodCalls() { + + // setup + try (final Tx tx = app.tx()) { + + final JsonSchema schema = StructrSchema.createFromDatabase(app); + final JsonType type = schema.addType("Test"); + + type.addMethod("method1", "{ $.log($.methodParameters); $.userMethod(); return $.methodParameters; }"); + + StructrSchema.extendDatabaseSchema(app, schema); + + app.create(SchemaMethod.class, + new NodeAttribute<>(AbstractNode.name, "userMethod"), + new NodeAttribute<>(SchemaMethod.source, "{ $.log('test'); }") + ); + + tx.success(); + + } catch (FrameworkException t) { + + t.printStackTrace(); + fail("Unexpected exception."); + } + + final Class testClass = StructrApp.getConfiguration().getNodeEntityClass("Test"); + + try (final Tx tx = app.tx()) { + + final NodeInterface node = app.create(testClass, "Test"); + + final Map value = (Map)Scripting.evaluate(new ActionContext(securityContext), node, "${{ return $.this.method1({ key1: 'value1', key2: 123 }); }}", "test"); + assertEquals("value1", value.get("key1")); + assertEquals(123, value.get("key2")); + + System.out.println(value); + + tx.success(); + + } catch (FrameworkException ex) { + ex.printStackTrace(); + fail("Unexpected exception"); + } + } + // ----- private methods ---- private void createTestType(final JsonSchema schema, final String name, final String createSource, final String saveSource) {