Added ConfigurationCustomizerCompiler

This CustomizerCompiler implementation makes it possible to set low-level 
configurations in the GremlinGroovyScriptEngine on the Groovy 
CompilerConfiguration which ultimately controls script compilation settings 
used by the classloader.


Project: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/commit/e32347c1
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/tree/e32347c1
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/diff/e32347c1

Branch: refs/heads/TINKERPOP-1278
Commit: e32347c13e6c4917ebc691aa70e8531cb6b36e1a
Parents: ddddc5f
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Thu Jun 2 16:39:51 2016 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Thu Jun 2 16:39:51 2016 -0400

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |  1 +
 .../src/reference/gremlin-applications.asciidoc |  5 +-
 .../gremlin/groovy/engine/ScriptEngines.java    | 28 ++++++-
 .../jsr223/GremlinGroovyScriptEngine.java       |  8 +-
 .../ConfigurationCustomizerProvider.java        | 83 ++++++++++++++++++++
 .../groovy/jsr223/BaseScriptForTesting.java     | 30 +++++++
 .../GremlinGroovyScriptEngineConfigTest.java    | 40 ++++++++++
 .../ConfigurationCustomizerProviderTest.java    | 78 ++++++++++++++++++
 .../gremlin/server/BaseScriptForTesting.java    | 30 +++++++
 .../server/GremlinServerIntegrateTest.java      | 50 +++++++++---
 10 files changed, 338 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/e32347c1/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 9590a90..6b53bb2 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -34,6 +34,7 @@ TinkerPop 3.2.1 (NOT OFFICIALLY RELEASED YET)
 * Added `EmptyMemory` for ease of use when no memory exists.
 * Updated `VertexComputing.generateProgram()` API to include `Memory`. 
(*breaking*)
 * `ImmutablePath.TailPath` is now serializable like `ImmutablePath`.
+* Added `ConfigurationCompilerProvider` which allows fine-grained control of 
some of the internal `GremlinGroovyScriptEngine` settings at the Groovy 
compilation level.
 * Intoduced the `application/vnd.gremlin-v1.0+gryo-lite` serialization type to 
Gremlin Server which users "reference" elements rather than "detached".
 * `GryoMapper` allows overrides of existing serializers on calls to 
`addCustom` on the builder.
 * Added a traversal style guide to the recipes cookbook.

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/e32347c1/docs/src/reference/gremlin-applications.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/reference/gremlin-applications.asciidoc 
b/docs/src/reference/gremlin-applications.asciidoc
index a8070ba..8c987fe 100644
--- a/docs/src/reference/gremlin-applications.asciidoc
+++ b/docs/src/reference/gremlin-applications.asciidoc
@@ -979,8 +979,8 @@ run Gremlin Server with Ganglia monitoring, download the 
`org.acplt:oncrpc` jar
 link:http://repo1.maven.org/maven2/org/acplt/oncrpc/1.0.7/[here] and copy it 
to the Gremlin Server `/lib` directory
 before starting the server.
 
-Security
-^^^^^^^^
+Security and Execution
+^^^^^^^^^^^^^^^^^^^^^^
 
 image:gremlin-server-secure.png[width=175,float=right] Gremlin Server provides 
for several features that aid in the
 security of the graphs that it exposes.  It has built in SSL support and a 
pluggable authentication framework using
@@ -1151,6 +1151,7 @@ There are a number of pre-packaged `CustomizerProvider` 
implementations:
 |=========================================================
 |Customizer |Description
 |`CompileStaticCustomizerProvider` |Applies `CompileStatic` annotations to 
incoming scripts thus removing dynamic dispatch. More information about static 
compilation can be found in the 
link:http://docs.groovy-lang.org/latest/html/documentation/#_static_compilation[Groovy
 Documentation].  It is possible to configure this `CustomizerProvider` by 
specifying a comma separated list of 
link:http://docs.groovy-lang.org/latest/html/documentation/#Typecheckingextensions-Workingwithextensions[type
 checking extensions] that can have the effect of securing calls to various 
methods.
+|`ConfigurationCustomizerProvider` |Allows configuration of the the Groovy 
`CompilerConfiguration` object by taking a `Map` of key/value pairs where the 
"key" is a property to set on the `CompilerConfiguration`.
 |`ThreadInterruptCustomizerProvider` |Injects checks for thread interruption, 
thus allowing the thread to potentially respect calls to `Thread.interrupt()`
 |`TimedInterruptCustomizerProvider` |Injects checks into loops to interrupt 
them if they exceed the configured timeout in milliseconds.
 |`TypeCheckedCustomizerProvider` |Similar to the above mentioned, 
`CompileStaticCustomizerProvider`, the `TypeCheckedCustomizerProvider` injects 
`TypeChecked` annotations to incoming scripts.  More information on the nature 
of this annotation can be found in the 
link:http://docs.groovy-lang.org/latest/html/documentation/#_the_code_typechecked_code_annotation[Groovy
 Documentation].  It too takes a comma separated list of 
link:http://docs.groovy-lang.org/latest/html/documentation/#Typecheckingextensions-Workingwithextensions[type
 checking extensions].

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/e32347c1/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/engine/ScriptEngines.java
----------------------------------------------------------------------
diff --git 
a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/engine/ScriptEngines.java
 
b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/engine/ScriptEngines.java
index 1113eb5..3d54bea 100644
--- 
a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/engine/ScriptEngines.java
+++ 
b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/engine/ScriptEngines.java
@@ -23,6 +23,7 @@ import 
org.apache.tinkerpop.gremlin.groovy.DefaultImportCustomizerProvider;
 import org.apache.tinkerpop.gremlin.groovy.jsr223.DependencyManager;
 import org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine;
 import 
org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngineFactory;
+import 
org.apache.tinkerpop.gremlin.groovy.jsr223.customizer.ConfigurationCustomizerProvider;
 import org.apache.tinkerpop.gremlin.groovy.plugin.GremlinPlugin;
 import org.apache.tinkerpop.gremlin.groovy.plugin.IllegalEnvironmentException;
 import org.slf4j.Logger;
@@ -382,8 +383,17 @@ public class ScriptEngines implements AutoCloseable {
 
                         final Class<?>[] argClasses = new 
Class<?>[args.length];
                         Stream.of(args).map(a -> 
a.getClass()).collect(Collectors.toList()).toArray(argClasses);
-                        final Constructor constructor = 
providerClass.getConstructor(argClasses);
-                        providers.add((CompilerCustomizerProvider) 
constructor.newInstance(args));
+
+                        final Optional<Constructor> constructor = 
Stream.of(providerClass.getConstructors())
+                                .filter(c -> c.getParameterCount() == 
argClasses.length &&
+                                             allMatch(c.getParameterTypes(), 
argClasses))
+                                .findFirst();
+
+                        if (constructor.isPresent()) 
providers.add((CompilerCustomizerProvider)
+                                constructor.get().newInstance(args));
+                        else
+                            throw new 
IllegalStateException(String.format("Could not configure %s with the supplied 
options %s",
+                                    
ConfigurationCustomizerProvider.class.getName(), Arrays.asList(args)));
                     } else {
                         providers.add((CompilerCustomizerProvider) 
providerClass.newInstance());
                     }
@@ -400,6 +410,20 @@ public class ScriptEngines implements AutoCloseable {
     }
 
     /**
+     * Determine if the constructor argument types match the arg types that 
are going to be passed in to that
+     * constructor.
+     */
+    private static boolean allMatch(final Class<?>[] constructorArgTypes, 
final Class<?>[] argTypes) {
+        for (int ix = 0; ix < constructorArgTypes.length; ix++) {
+            if (!constructorArgTypes[ix].isAssignableFrom(argTypes[ix])) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
      * Takes the bindings from a request for eval and merges them with the 
{@code ENGINE_SCOPE} bindings.
      */
     private static Bindings mergeBindings(final Bindings bindings, final 
ScriptEngine engine) {

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/e32347c1/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
----------------------------------------------------------------------
diff --git 
a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
 
b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
index 23240cb..0069103 100644
--- 
a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
+++ 
b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
@@ -23,6 +23,7 @@ import 
org.apache.tinkerpop.gremlin.groovy.DefaultImportCustomizerProvider;
 import org.apache.tinkerpop.gremlin.groovy.EmptyImportCustomizerProvider;
 import org.apache.tinkerpop.gremlin.groovy.ImportCustomizerProvider;
 import org.apache.tinkerpop.gremlin.groovy.NoImportCustomizerProvider;
+import 
org.apache.tinkerpop.gremlin.groovy.jsr223.customizer.ConfigurationCustomizerProvider;
 import 
org.apache.tinkerpop.gremlin.groovy.jsr223.customizer.InterpreterModeCustomizerProvider;
 import org.apache.tinkerpop.gremlin.groovy.loaders.GremlinLoader;
 import org.apache.tinkerpop.gremlin.groovy.plugin.Artifact;
@@ -610,7 +611,12 @@ public class GremlinGroovyScriptEngine extends 
GroovyScriptEngineImpl implements
         final CompilerConfiguration conf = new CompilerConfiguration();
         conf.addCompilationCustomizers(this.importCustomizerProvider.create());
 
-        customizerProviders.forEach(p -> 
conf.addCompilationCustomizers(p.create()));
+        // ConfigurationCustomizerProvider is treated separately
+        customizerProviders.stream().filter(cp -> !(cp instanceof 
ConfigurationCustomizerProvider))
+                .forEach(p -> conf.addCompilationCustomizers(p.create()));
+
+        customizerProviders.stream().filter(cp -> cp instanceof 
ConfigurationCustomizerProvider).findFirst()
+                .ifPresent(cp -> ((ConfigurationCustomizerProvider) 
cp).applyCustomization(conf));
 
         this.loader = new GremlinGroovyClassLoader(getParentLoader(), conf);
     }

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/e32347c1/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/customizer/ConfigurationCustomizerProvider.java
----------------------------------------------------------------------
diff --git 
a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/customizer/ConfigurationCustomizerProvider.java
 
b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/customizer/ConfigurationCustomizerProvider.java
new file mode 100644
index 0000000..ba9855c
--- /dev/null
+++ 
b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/customizer/ConfigurationCustomizerProvider.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 org.apache.tinkerpop.gremlin.groovy.jsr223.customizer;
+
+import org.apache.tinkerpop.gremlin.groovy.CompilerCustomizerProvider;
+import org.apache.tinkerpop.gremlin.structure.util.ElementHelper;
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.control.customizers.CompilationCustomizer;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Allows configurations to be directly supplied to a groovy {@code 
CompilerConfiguration} when a
+ * {@link 
org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine} is 
initialized, providing fine-grained
+ * control over its internals.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class ConfigurationCustomizerProvider implements 
CompilerCustomizerProvider {
+
+    private final Map<String,Object> properties;
+
+    /**
+     * Creates a new instance using configuration values specified
+     */
+    public ConfigurationCustomizerProvider(final Object... keyValues) {
+        if (null == keyValues || keyValues.length == 0)
+            throw new 
IllegalArgumentException("ConfigurationCustomizerProvider must have key/values 
specified");
+
+        if (keyValues.length % 2 != 0)
+            throw new IllegalArgumentException("The keyValues must have an 
even number of values");
+
+        properties = ElementHelper.asMap(keyValues);
+    }
+
+    /**
+     * Creates a new instance using configuration values specified
+     */
+    public ConfigurationCustomizerProvider(final Map<String,Object> keyValues) 
{
+        properties = keyValues;
+    }
+
+    public CompilerConfiguration applyCustomization(final 
CompilerConfiguration compilerConfiguration) {
+        final Class<CompilerConfiguration> clazz = CompilerConfiguration.class;
+        final List<Method> methods = Arrays.asList(clazz.getMethods());
+        for (Map.Entry<String,Object> entry : properties.entrySet()) {
+            final Method method = methods.stream().filter(m -> 
m.getName().equals("set" + entry.getKey())).findFirst()
+                   .orElseThrow(() -> new IllegalStateException("Invalid 
setting [" + entry.getKey() + "] for CompilerConfiguration"));
+
+            try {
+                method.invoke(compilerConfiguration, entry.getValue());
+            } catch (Exception ex) {
+                throw new IllegalStateException(ex);
+            }
+        }
+
+        return compilerConfiguration;
+    }
+
+    @Override
+    public CompilationCustomizer create() {
+        throw new UnsupportedOperationException("This is a marker 
implementation that does not create a CompilationCustomizer instance");
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/e32347c1/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/BaseScriptForTesting.java
----------------------------------------------------------------------
diff --git 
a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/BaseScriptForTesting.java
 
b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/BaseScriptForTesting.java
new file mode 100644
index 0000000..98c8e8c
--- /dev/null
+++ 
b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/BaseScriptForTesting.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 org.apache.tinkerpop.gremlin.groovy.jsr223;
+
+import groovy.lang.Script;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public abstract class BaseScriptForTesting extends Script {
+    public String hello(final String name) {
+        return "hello, " + name;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/e32347c1/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineConfigTest.java
----------------------------------------------------------------------
diff --git 
a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineConfigTest.java
 
b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineConfigTest.java
new file mode 100644
index 0000000..d354ffa
--- /dev/null
+++ 
b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineConfigTest.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 org.apache.tinkerpop.gremlin.groovy.jsr223;
+
+import org.apache.tinkerpop.gremlin.groovy.DefaultImportCustomizerProvider;
+import 
org.apache.tinkerpop.gremlin.groovy.jsr223.customizer.ConfigurationCustomizerProvider;
+import org.junit.Test;
+
+import javax.script.ScriptEngine;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class GremlinGroovyScriptEngineConfigTest {
+    @Test
+    public void shouldAddBaseScriptClass() throws Exception {
+        final ScriptEngine engine = new GremlinGroovyScriptEngine(
+                new ConfigurationCustomizerProvider("ScriptBaseClass", 
BaseScriptForTesting.class.getName()), new DefaultImportCustomizerProvider());
+
+        assertEquals("hello, stephen", engine.eval("hello('stephen')"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/e32347c1/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/customizer/ConfigurationCustomizerProviderTest.java
----------------------------------------------------------------------
diff --git 
a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/customizer/ConfigurationCustomizerProviderTest.java
 
b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/customizer/ConfigurationCustomizerProviderTest.java
new file mode 100644
index 0000000..54b55b1
--- /dev/null
+++ 
b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/customizer/ConfigurationCustomizerProviderTest.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 org.apache.tinkerpop.gremlin.groovy.jsr223.customizer;
+
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.junit.Test;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class ConfigurationCustomizerProviderTest {
+    @Test(expected = IllegalArgumentException.class)
+    public void shouldThrowExceptionForNoSettings() {
+        new ConfigurationCustomizerProvider();
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void shouldThrowExceptionForInvalidSettings() {
+        new ConfigurationCustomizerProvider("only-one-arg");
+    }
+
+    @Test
+    public void shouldThrowExceptionForNotFoundSetting() {
+        final CompilerConfiguration configuration = new 
CompilerConfiguration();
+        try {
+            final ConfigurationCustomizerProvider provider = new 
ConfigurationCustomizerProvider(
+                    "Tolerance", 3,
+                    "NotRealSettingThatWouldEverOccur2", new java.util.Date());
+
+            provider.applyCustomization(configuration);
+        } catch (Exception ex) {
+            assertThat(ex, instanceOf(IllegalStateException.class));
+            assertEquals("Invalid setting [NotRealSettingThatWouldEverOccur2] 
for CompilerConfiguration", ex.getMessage());
+        }
+    }
+
+    @Test
+    public void shouldApplyConfigurationChanges() {
+        final CompilerConfiguration configuration = new 
CompilerConfiguration();
+
+        assertEquals(10, configuration.getTolerance());
+        assertNull(configuration.getScriptBaseClass());
+        assertEquals(false, configuration.getDebug());
+
+        final ConfigurationCustomizerProvider provider = new 
ConfigurationCustomizerProvider(
+                "Tolerance", 3,
+                "ScriptBaseClass", "Something",
+                "Debug", true);
+
+        provider.applyCustomization(configuration);
+
+        assertEquals(3, configuration.getTolerance());
+        assertEquals("Something", configuration.getScriptBaseClass());
+        assertEquals(true, configuration.getDebug());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/e32347c1/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/BaseScriptForTesting.java
----------------------------------------------------------------------
diff --git 
a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/BaseScriptForTesting.java
 
b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/BaseScriptForTesting.java
new file mode 100644
index 0000000..ae4c713
--- /dev/null
+++ 
b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/BaseScriptForTesting.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 org.apache.tinkerpop.gremlin.server;
+
+import groovy.lang.Script;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public abstract class BaseScriptForTesting extends Script {
+    public String hello(final String name) {
+        return "hello, " + name;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/e32347c1/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
----------------------------------------------------------------------
diff --git 
a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
 
b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
index 16cbdee..a2b415d 100644
--- 
a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
+++ 
b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
@@ -41,6 +41,7 @@ import 
org.apache.tinkerpop.gremlin.driver.simple.SimpleClient;
 import org.apache.tinkerpop.gremlin.driver.simple.WebSocketClient;
 import org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine;
 import 
org.apache.tinkerpop.gremlin.groovy.jsr223.customizer.CompileStaticCustomizerProvider;
+import 
org.apache.tinkerpop.gremlin.groovy.jsr223.customizer.ConfigurationCustomizerProvider;
 import 
org.apache.tinkerpop.gremlin.groovy.jsr223.customizer.InterpreterModeCustomizerProvider;
 import 
org.apache.tinkerpop.gremlin.groovy.jsr223.customizer.SimpleSandboxExtension;
 import 
org.apache.tinkerpop.gremlin.groovy.jsr223.customizer.TimedInterruptCustomizerProvider;
@@ -55,7 +56,6 @@ import org.junit.Before;
 import org.junit.Test;
 
 import java.nio.channels.ClosedChannelException;
-import java.security.cert.CertificateException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -72,12 +72,15 @@ import java.util.stream.IntStream;
 
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.core.IsInstanceOf.instanceOf;
 import static org.hamcrest.core.IsNot.not;
 import static org.hamcrest.core.StringEndsWith.endsWith;
 import static org.hamcrest.core.StringStartsWith.startsWith;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeThat;
+import static org.junit.Assert.assertEquals;
 
 /**
  * Integration tests for server-side settings and processing.
@@ -161,6 +164,9 @@ public class GremlinServerIntegrateTest extends 
AbstractGremlinServerIntegration
             case "shouldReceiveFailureTimeOutOnScriptEvalOfOutOfControlLoop":
                 settings.scriptEngines.get("gremlin-groovy").config = 
getScriptEngineConfForTimedInterrupt();
                 break;
+            case "shouldUseBaseScript":
+                settings.scriptEngines.get("gremlin-groovy").config = 
getScriptEngineConfForBaseScript();
+                break;
         }
 
         return settings;
@@ -206,6 +212,30 @@ public class GremlinServerIntegrateTest extends 
AbstractGremlinServerIntegration
         return scriptEngineConf;
     }
 
+    private static Map<String, Object> getScriptEngineConfForBaseScript() {
+        final Map<String,Object> scriptEngineConf = new HashMap<>();
+        final Map<String,Object> compilerCustomizerProviderConf = new 
HashMap<>();
+        final List<Object> keyValues = new ArrayList<>();
+
+        final Map<String,Object> properties = new HashMap<>();
+        properties.put("ScriptBaseClass", 
BaseScriptForTesting.class.getName());
+        keyValues.add(properties);
+
+        
compilerCustomizerProviderConf.put(ConfigurationCustomizerProvider.class.getName(),
 keyValues);
+        scriptEngineConf.put("compilerCustomizerProviders", 
compilerCustomizerProviderConf);
+        return scriptEngineConf;
+    }
+
+    @Test
+    public void shouldUseBaseScript() throws Exception {
+        final Cluster cluster = Cluster.open();
+        final Client client = cluster.connect(name.getMethodName());
+
+        assertEquals("hello, stephen", 
client.submit("hello('stephen')").all().get().get(0).getString());
+
+        cluster.close();
+    }
+
     @Test
     public void shouldUseInterpreterMode() throws Exception {
         final Cluster cluster = Cluster.open();
@@ -368,12 +398,12 @@ public class GremlinServerIntegrateTest extends 
AbstractGremlinServerIntegration
                 });
             });
 
-            assertTrue(latch.await(30000, TimeUnit.MILLISECONDS));
+            assertThat(latch.await(30000, TimeUnit.MILLISECONDS), is(true));
             assertEquals(0, latch.getCount());
-            assertFalse(faulty.get());
-            assertTrue(expected.get());
+            assertThat(faulty.get(), is(false));
+            assertThat(expected.get(), is(true));
 
-            assertTrue(recordingAppender.getMessages().stream().anyMatch(m -> 
m.contains("Pausing response writing as writeBufferHighWaterMark exceeded 
on")));
+            assertThat(recordingAppender.getMessages().stream().anyMatch(m -> 
m.contains("Pausing response writing as writeBufferHighWaterMark exceeded 
on")), is(true));
         } catch (Exception ex) {
             fail("Shouldn't have tossed an exception");
         } finally {
@@ -410,7 +440,7 @@ public class GremlinServerIntegrateTest extends 
AbstractGremlinServerIntegration
 
             if (!latch.await(3000, TimeUnit.MILLISECONDS))
                 fail("Request should have returned error, but instead timed 
out");
-            assertTrue(pass.get());
+            assertThat(pass.get(), is(true));
         }
     }
 
@@ -433,7 +463,7 @@ public class GremlinServerIntegrateTest extends 
AbstractGremlinServerIntegration
 
             if (!latch.await(3000, TimeUnit.MILLISECONDS))
                 fail("Request should have returned error, but instead timed 
out");
-            assertTrue(pass.get());
+            assertThat(pass.get(), is(true));
         }
     }
 
@@ -456,7 +486,7 @@ public class GremlinServerIntegrateTest extends 
AbstractGremlinServerIntegration
 
             if (!latch.await(3000, TimeUnit.MILLISECONDS))
                 fail("Request should have returned error, but instead timed 
out");
-            assertTrue(pass.get());
+            assertThat(pass.get(), is(true));
         }
     }
 
@@ -691,7 +721,7 @@ public class GremlinServerIntegrateTest extends 
AbstractGremlinServerIntegration
             client.submit("1+1").all().join();
             fail();
         } catch (RuntimeException re) {
-            assertTrue(re.getCause().getCause() instanceof 
ClosedChannelException);
+            assertThat(re.getCause().getCause() instanceof 
ClosedChannelException, is(true));
 
             //
             // should recover when the server comes back

Reply via email to