Skip to content

Commit

Permalink
Correctly restore state (parameters) after user-defined method call, …
Browse files Browse the repository at this point in the history
…adds test.
  • Loading branch information
cmorgner committed Apr 30, 2024
1 parent d4f1e8a commit 13a03ca
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 25 deletions.
Expand Up @@ -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<String, Object> tmp = securityContext.getContextStore().getTemporaryParameters();

try {

Expand All @@ -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);

}
}
Expand Down
Expand Up @@ -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.*;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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<Object, Object> func = Functions.get(CaseHelper.toUnderscore(name, false));
if (func != null) {

Expand All @@ -149,39 +143,39 @@ 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
if (actionContext.getRequestStore().containsKey(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
Expand Down
Expand Up @@ -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<String, Object> 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) {

Expand Down

0 comments on commit 13a03ca

Please sign in to comment.