[java-support] branch maint-7 updated: IDP-1314 Scripted Function

Rod Widdowson rdw at steadingsoftware.com
Tue Jul 10 11:47:31 EDT 2018


This is an automated email from the git hooks/post-receive script.

rdw pushed a commit to branch maint-7
in repository java-support.

View the commit online:
http://git.shibboleth.net/view/?p=java-support.git;a=commit;h=0d69b320f7cbf7e3de63edc74e99b9336c10a915

The following commit(s) were added to refs/heads/maint-7 by this push:
       new  0d69b32   IDP-1314 Scripted Function
0d69b32 is described below

commit 0d69b320f7cbf7e3de63edc74e99b9336c10a915
Author: Rod Widdowson <rdw at steadingsoftware.com>
AuthorDate: Mon Jul 9 17:14:05 2018 +0100

    IDP-1314 Scripted Function
    
    https://issues.shibboleth.net/jira/browse/IDP-1314
    
    The actual code, plus a test for this and for ScriptedPredicate.
---
 .../java/support/logic/ScriptedFunction.java       | 185 +++++++++++++++++++++
 .../utilities/java/support/logic/ScriptedTest.java | 135 +++++++++++++++
 2 files changed, 320 insertions(+)

diff --git a/src/main/java/net/shibboleth/utilities/java/support/logic/ScriptedFunction.java b/src/main/java/net/shibboleth/utilities/java/support/logic/ScriptedFunction.java
new file mode 100644
index 0000000..7476e8b
--- /dev/null
+++ b/src/main/java/net/shibboleth/utilities/java/support/logic/ScriptedFunction.java
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.utilities.java.support.logic;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.script.ScriptContext;
+import javax.script.ScriptException;
+
+import net.shibboleth.utilities.java.support.annotation.ParameterName;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.resource.Resource;
+import net.shibboleth.utilities.java.support.scripting.AbstractScriptEvaluator;
+import net.shibboleth.utilities.java.support.scripting.EvaluableScript;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Function;
+
+/**
+ * A {@link Function} which calls out to a supplied script.
+ *
+ * @param <T> input type
+ * @param <U> output type
+ * @since 7.4.0
+ */
+public class ScriptedFunction<T, U> extends AbstractScriptEvaluator implements Function<T,U> {
+
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(ScriptedFunction.class);
+
+    /** Input Type.*/
+    @Nullable private Class<T> inputTypeClass;
+
+    /**
+     * Constructor.
+     *
+     * @param theScript the script we will evaluate.
+     * @param extraInfo debugging information.
+     */
+    protected ScriptedFunction(@Nonnull @NotEmpty @ParameterName(name="theScript") final EvaluableScript theScript,
+            @Nullable @NotEmpty @ParameterName(name="extraInfo") final String extraInfo) {
+        super(theScript);
+        setLogPrefix("Scripted Function from " + extraInfo + ":");
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param theScript the script we will evaluate.
+     */
+    protected ScriptedFunction(@Nonnull @NotEmpty @ParameterName(name="theScript") final EvaluableScript theScript) {
+        super(theScript);
+        setLogPrefix("Anonymous Function:");
+    }
+
+    /**
+     * Set the output type to be enforced.
+     *
+     * @param type output type
+     */
+    @Override public void setOutputType(@Nullable final Class type) {
+        super.setOutputType(type);
+    }
+
+    /**
+     * Get the input type to be enforced.
+     *
+     * @return input type
+     */
+    @Nullable public  Class getInputType() {
+        return inputTypeClass;
+    }
+
+    /**
+     * Set the input type to be enforced.
+     *
+     * @param type input type
+     */
+    public void setInputType(@Nullable final Class type) {
+        inputTypeClass = type;
+    }
+
+    /**
+     * Set value to return if an error occurs.
+     *
+     * @param value value to return
+     */
+    @Override public void setReturnOnError(@Nullable final Object value) {
+        super.setReturnOnError(value);
+    }
+
+    /** {@inheritDoc} */
+    public U apply(@Nullable final T input) {
+
+        if (null != getInputType() && null != input && !getInputType().isInstance(input)) {
+            log.error("{} Input of type {} was not of type {}", getLogPrefix(), input.getClass(),
+                    getInputType());
+            return (U) getReturnOnError();
+        }
+
+        return (U) evaluate(input);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void prepareContext(@Nonnull final ScriptContext scriptContext, @Nullable final Object... input) {
+        scriptContext.setAttribute("input", input[0], ScriptContext.ENGINE_SCOPE);
+    }
+
+    /**
+     * Factory to create {@link ScriptedFunction} from a {@link Resource}.
+     *
+     * @param resource the resource to look at
+     * @param engineName the language
+     * @return the function
+     * @throws ScriptException if the compile fails
+     * @throws IOException if the file doesn't exist.
+     */
+    static ScriptedFunction resourceScript(@Nonnull @NotEmpty final String engineName,
+            @Nonnull final Resource resource) throws ScriptException, IOException {
+        try (final InputStream is = resource.getInputStream()) {
+            final EvaluableScript script = new EvaluableScript(engineName, is);
+            return new ScriptedFunction(script, resource.getDescription());
+        }
+    }
+
+    /**
+     * Factory to create {@link ScriptedFunction} from a {@link Resource}.
+     *
+     * @param resource the resource to look at
+     * @return the function
+     * @throws ScriptException if the compile fails
+     * @throws IOException if the file doesn't exist.
+     */
+    static ScriptedFunction resourceScript(final Resource resource) throws ScriptException, IOException {
+        return resourceScript(DEFAULT_ENGINE, resource);
+    }
+
+    /**
+     * Factory to create {@link ScriptedFunction} from inline data.
+     *
+     * @param scriptSource the script, as a string
+     * @param engineName the language
+     * @return the function
+     * @throws ScriptException if the compile fails
+     */
+    static ScriptedFunction inlineScript(@Nonnull @NotEmpty final String engineName,
+            @Nonnull @NotEmpty final String scriptSource) throws ScriptException {
+        final EvaluableScript script = new EvaluableScript(engineName, scriptSource);
+        return new ScriptedFunction(script, "Inline");
+    }
+
+    /**
+     * Factory to create {@link ScriptedFunction} from inline data.
+     *
+     * @param scriptSource the script, as a string
+     * @return the function
+     * @throws ScriptException if the compile fails
+     */
+    static ScriptedFunction inlineScript(@Nonnull @NotEmpty final String scriptSource) throws ScriptException {
+        final EvaluableScript script = new EvaluableScript(DEFAULT_ENGINE, scriptSource);
+        return new ScriptedFunction(script, "Inline");
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/net/shibboleth/utilities/java/support/logic/ScriptedTest.java b/src/test/java/net/shibboleth/utilities/java/support/logic/ScriptedTest.java
new file mode 100644
index 0000000..2f30f6b
--- /dev/null
+++ b/src/test/java/net/shibboleth/utilities/java/support/logic/ScriptedTest.java
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.utilities.java.support.logic;
+
+import org.testng.Assert;
+
+import javax.script.ScriptException;
+
+import org.testng.annotations.Test;
+
+/**
+ * Tests for the {@link ScriptedFunction} and {@link ScriptedPredicate}.
+ */
+public class ScriptedTest {
+
+    static final private String returnSelf="input";
+    static final private String returnSelfString="input.toString()";
+    static final private String returnCustom="custom";
+
+    @Test public void testPredicate() throws ScriptException {
+
+        ScriptedPredicate test = ScriptedPredicate.inlineScript(returnSelf);
+
+        Assert.assertTrue(test.apply(Boolean.TRUE));
+        Assert.assertFalse(test.apply(Boolean.FALSE));
+        Assert.assertFalse(test.apply(new Integer(1)));
+        test.setReturnOnError(true);
+        Assert.assertTrue(test.apply(new Integer(1)));
+    }
+
+    @Test public void testPredicateCustom() throws ScriptException {
+
+        ScriptedPredicate test = ScriptedPredicate.inlineScript(returnCustom);
+
+        test.setCustomObject(Boolean.TRUE);
+        Assert.assertTrue(test.apply(Boolean.FALSE));
+        test.setCustomObject(Boolean.FALSE);
+        Assert.assertFalse(test.apply(Boolean.TRUE));
+        test.setCustomObject(new Integer(1));
+        Assert.assertFalse(test.apply("true"));
+        test.setReturnOnError(true);
+        Assert.assertTrue(test.apply("false"));
+    }
+
+    @Test public void testBadScriptPredicate() throws ScriptException {
+
+        final ScriptedPredicate test = ScriptedPredicate.inlineScript(returnSelfString);
+
+        test.setHideExceptions(true);
+        test.setReturnOnError(true);
+        Assert.assertTrue(test.apply(null));
+        test.setReturnOnError(false);
+        Assert.assertFalse(test.apply(null));
+
+        test.setHideExceptions(false);
+        try {
+            Assert.assertFalse(test.apply(null));
+            Assert.fail();
+        } catch (final RuntimeException e) {
+            Assert.assertEquals(e.getCause().getClass(), ScriptException.class);
+            // nothing
+        }
+    }
+
+    @Test public void testFunction() throws ScriptException {
+
+        ScriptedFunction test = ScriptedFunction.inlineScript(returnSelf);
+
+        Assert.assertEquals(test.apply(Boolean.FALSE), Boolean.FALSE);
+        Assert.assertEquals(test.apply(Boolean.TRUE), Boolean.TRUE);
+        Assert.assertEquals(test.apply(new Integer(1)), new Integer(1));
+        test.setOutputType(Boolean.class);
+        Assert.assertEquals(test.apply(Boolean.FALSE), Boolean.FALSE);
+        Assert.assertEquals(test.apply(Boolean.TRUE), Boolean.TRUE);
+        Assert.assertNotEquals(test.apply(new Integer(1)), new Integer(1));
+        test.setReturnOnError(Boolean.TRUE);
+        Assert.assertEquals(test.apply(new Integer(1)), Boolean.TRUE);
+
+        test.setReturnOnError(Boolean.TRUE);
+        test.setOutputType(Integer.class);
+        test.setInputType(Integer.class);
+        Assert.assertEquals(test.apply(Boolean.FALSE), Boolean.TRUE);
+    }
+
+    @Test public void testFunctionCustom() throws ScriptException {
+
+        ScriptedFunction test = ScriptedFunction.inlineScript(returnCustom);
+
+        test.setReturnOnError(new Integer(99));
+        test.setOutputType(Integer.class);
+        test.setInputType(Integer.class);
+        test.setCustomObject(12);
+        Assert.assertEquals(test.apply(false), 99);
+        Assert.assertEquals(test.apply(1), 12);
+        test.setCustomObject(false);
+        Assert.assertEquals(test.apply(false), 99);
+    }
+
+    @Test public void testBadScriptFunction() throws ScriptException {
+
+        ScriptedFunction test = ScriptedFunction.inlineScript(returnSelfString);
+        test.setOutputType(Boolean.class);
+        test.setInputType(Boolean.class);
+
+        test.setHideExceptions(true);
+        test.setReturnOnError(true);
+        Assert.assertEquals(test.apply(null), true);
+        test.setReturnOnError(false);
+        Assert.assertEquals(test.apply(null), false);
+
+        test.setHideExceptions(false);
+        try {
+            Assert.assertEquals(test.apply(null), true);
+            Assert.fail();
+        } catch (final RuntimeException e) {
+            Assert.assertEquals(e.getCause().getClass(), ScriptException.class);
+            // nothing
+        }
+    }
+}

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list