From 999097a7b0fab8059ba1bafedd343f132b3b256a Mon Sep 17 00:00:00 2001
From: Shinsuke Sugaya <shinsuke@apache.org>
Date: Tue, 20 Apr 2021 05:56:12 +0900
Subject: [PATCH] fix #2561 add scripnt engine

---
 pom.xml                                       | 13 +++--
 .../java/org/codelibs/fess/Constants.java     |  2 +
 .../crawler/transformer/FessTransformer.java  |  3 +-
 .../codelibs/fess/ds/AbstractDataStore.java   |  3 +-
 .../fess/exception/ScriptEngineException.java | 29 +++++++++++
 .../fess/helper/PathMappingHelper.java        |  4 +-
 .../codelibs/fess/helper/PluginHelper.java    |  8 ++-
 .../fess/indexer/DocBoostMatcher.java         |  9 ++--
 .../fess/job/impl/GroovyExecutor.java         |  5 +-
 .../fess/script/AbstractScriptEngine.java     | 27 ++++++++++
 .../codelibs/fess/script/ScriptEngine.java}   | 17 ++----
 .../fess/script/ScriptEngineFactory.java      | 52 +++++++++++++++++++
 .../org/codelibs/fess/util/ComponentUtil.java |  7 +++
 .../org/codelibs/fess/util/GroovyUtil.java    | 34 ++----------
 src/main/resources/fess.xml                   |  1 +
 src/main/resources/fess_se.xml                |  7 +++
 .../fess/ds/AbstractDataStoreTest.java        | 37 +++++++++++++
 .../fess/indexer/DocBoostMatcherTest.java     | 42 +++++++++++++++
 18 files changed, 236 insertions(+), 64 deletions(-)
 create mode 100644 src/main/java/org/codelibs/fess/exception/ScriptEngineException.java
 create mode 100644 src/main/java/org/codelibs/fess/script/AbstractScriptEngine.java
 rename src/{test/java/org/codelibs/fess/util/GroovyUtilTest.java => main/java/org/codelibs/fess/script/ScriptEngine.java} (53%)
 create mode 100644 src/main/java/org/codelibs/fess/script/ScriptEngineFactory.java
 create mode 100644 src/main/resources/fess_se.xml

diff --git a/pom.xml b/pom.xml
index 5beca9134..a9feb2d4e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1445,13 +1445,6 @@
 			<version>4.2.0</version>
 		</dependency>
 
-		<!-- groovy -->
-		<dependency>
-			<groupId>org.codehaus.groovy</groupId>
-			<artifactId>groovy</artifactId>
-			<version>${groovy.version}</version>
-		</dependency>
-
 		<!-- Tomcat -->
 		<dependency>
 			<groupId>org.dbflute.tomcat</groupId>
@@ -1532,5 +1525,11 @@
 				</exclusion>
 			</exclusions>
 		</dependency>
+		<dependency>
+			<groupId>org.codehaus.groovy</groupId>
+			<artifactId>groovy</artifactId>
+			<version>${groovy.version}</version>
+			<scope>test</scope>
+		</dependency>
 	</dependencies>
 </project>
diff --git a/src/main/java/org/codelibs/fess/Constants.java b/src/main/java/org/codelibs/fess/Constants.java
index d764393c8..9e17c864a 100644
--- a/src/main/java/org/codelibs/fess/Constants.java
+++ b/src/main/java/org/codelibs/fess/Constants.java
@@ -469,4 +469,6 @@ public class Constants extends CoreLibConstants {
     public static final String EXECUTE_TYPE_PYTHON = "python";
 
     public static final String EXECUTE_TYPE_SUGGEST = "suggest";
+
+    public static final String DEFAULT_SCRIPT = "groovy";
 }
diff --git a/src/main/java/org/codelibs/fess/crawler/transformer/FessTransformer.java b/src/main/java/org/codelibs/fess/crawler/transformer/FessTransformer.java
index 89e593318..5aa8e537a 100644
--- a/src/main/java/org/codelibs/fess/crawler/transformer/FessTransformer.java
+++ b/src/main/java/org/codelibs/fess/crawler/transformer/FessTransformer.java
@@ -33,7 +33,6 @@ import org.codelibs.fess.crawler.entity.UrlQueue;
 import org.codelibs.fess.crawler.util.CrawlingParameterUtil;
 import org.codelibs.fess.mylasta.direction.FessConfig;
 import org.codelibs.fess.util.ComponentUtil;
-import org.codelibs.fess.util.GroovyUtil;
 
 public interface FessTransformer {
 
@@ -158,7 +157,7 @@ public interface FessTransformer {
             return StringUtil.EMPTY;
         }
 
-        return GroovyUtil.evaluate(template, paramMap);
+        return ComponentUtil.getScriptEngineFactory().getScriptEngine(Constants.DEFAULT_SCRIPT).evaluate(template, paramMap);
     }
 
     default int getMaxSiteLength() {
diff --git a/src/main/java/org/codelibs/fess/ds/AbstractDataStore.java b/src/main/java/org/codelibs/fess/ds/AbstractDataStore.java
index f3aa080b2..521103840 100644
--- a/src/main/java/org/codelibs/fess/ds/AbstractDataStore.java
+++ b/src/main/java/org/codelibs/fess/ds/AbstractDataStore.java
@@ -36,7 +36,6 @@ import org.codelibs.fess.helper.CrawlingInfoHelper;
 import org.codelibs.fess.helper.SystemHelper;
 import org.codelibs.fess.mylasta.direction.FessConfig;
 import org.codelibs.fess.util.ComponentUtil;
-import org.codelibs.fess.util.GroovyUtil;
 
 public abstract class AbstractDataStore implements DataStore {
 
@@ -130,7 +129,7 @@ public abstract class AbstractDataStore implements DataStore {
             return paramMap.get(template);
         }
 
-        return GroovyUtil.evaluate(template, paramMap);
+        return ComponentUtil.getScriptEngineFactory().getScriptEngine(Constants.DEFAULT_SCRIPT).evaluate(template, paramMap);
     }
 
     protected long getReadInterval(final Map<String, String> paramMap) {
diff --git a/src/main/java/org/codelibs/fess/exception/ScriptEngineException.java b/src/main/java/org/codelibs/fess/exception/ScriptEngineException.java
new file mode 100644
index 000000000..0807a6876
--- /dev/null
+++ b/src/main/java/org/codelibs/fess/exception/ScriptEngineException.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2012-2021 CodeLibs Project and the Others.
+ *
+ * Licensed 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.codelibs.fess.exception;
+
+public class ScriptEngineException extends FessSystemException {
+
+    private static final long serialVersionUID = 1L;
+
+    public ScriptEngineException(final String message) {
+        super(message);
+    }
+
+    public ScriptEngineException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/src/main/java/org/codelibs/fess/helper/PathMappingHelper.java b/src/main/java/org/codelibs/fess/helper/PathMappingHelper.java
index 08ae49569..55b204f36 100644
--- a/src/main/java/org/codelibs/fess/helper/PathMappingHelper.java
+++ b/src/main/java/org/codelibs/fess/helper/PathMappingHelper.java
@@ -32,7 +32,6 @@ import org.codelibs.fess.es.config.exbhv.PathMappingBhv;
 import org.codelibs.fess.es.config.exentity.PathMapping;
 import org.codelibs.fess.util.ComponentUtil;
 import org.codelibs.fess.util.DocumentUtil;
-import org.codelibs.fess.util.GroovyUtil;
 import org.lastaflute.di.core.exception.ComponentNotFoundException;
 import org.lastaflute.di.core.factory.SingletonLaContainerFactory;
 import org.lastaflute.web.util.LaRequestUtil;
@@ -164,7 +163,8 @@ public class PathMappingHelper {
             final Map<String, Object> paramMap = new HashMap<>();
             paramMap.put("url", u);
             paramMap.put("matcher", m);
-            final Object value = GroovyUtil.evaluate(template, paramMap);
+            final Object value =
+                    ComponentUtil.getScriptEngineFactory().getScriptEngine(Constants.DEFAULT_SCRIPT).evaluate(template, paramMap);
             if (value == null) {
                 return u;
             }
diff --git a/src/main/java/org/codelibs/fess/helper/PluginHelper.java b/src/main/java/org/codelibs/fess/helper/PluginHelper.java
index 04762a42d..34c3e7669 100644
--- a/src/main/java/org/codelibs/fess/helper/PluginHelper.java
+++ b/src/main/java/org/codelibs/fess/helper/PluginHelper.java
@@ -374,7 +374,7 @@ public class PluginHelper {
     }
 
     public enum ArtifactType {
-        DATA_STORE("fess-ds"), THEME("fess-theme"), INGEST("fess-ingest"), UNKNOWN("jar");
+        DATA_STORE("fess-ds"), THEME("fess-theme"), INGEST("fess-ingest"), SCRIPT("fess-script"), WEBAPP("fess-webapp"), UNKNOWN("jar");
 
         private final String id;
 
@@ -396,6 +396,12 @@ public class PluginHelper {
             if (name.startsWith(INGEST.getId())) {
                 return INGEST;
             }
+            if (name.startsWith(SCRIPT.getId())) {
+                return SCRIPT;
+            }
+            if (name.startsWith(WEBAPP.getId())) {
+                return WEBAPP;
+            }
             return UNKNOWN;
         }
     }
diff --git a/src/main/java/org/codelibs/fess/indexer/DocBoostMatcher.java b/src/main/java/org/codelibs/fess/indexer/DocBoostMatcher.java
index 68e132539..67b5135dc 100644
--- a/src/main/java/org/codelibs/fess/indexer/DocBoostMatcher.java
+++ b/src/main/java/org/codelibs/fess/indexer/DocBoostMatcher.java
@@ -17,8 +17,9 @@ package org.codelibs.fess.indexer;
 
 import java.util.Map;
 
+import org.codelibs.fess.Constants;
 import org.codelibs.fess.es.config.exentity.BoostDocumentRule;
-import org.codelibs.fess.util.GroovyUtil;
+import org.codelibs.fess.util.ComponentUtil;
 
 public class DocBoostMatcher {
 
@@ -41,7 +42,8 @@ public class DocBoostMatcher {
             return false;
         }
 
-        final Object value = GroovyUtil.evaluate(matchExpression, map);
+        final Object value =
+                ComponentUtil.getScriptEngineFactory().getScriptEngine(Constants.DEFAULT_SCRIPT).evaluate(matchExpression, map);
         if (value instanceof Boolean) {
             return ((Boolean) value);
         }
@@ -54,7 +56,8 @@ public class DocBoostMatcher {
             return 0.0f;
         }
 
-        final Object value = GroovyUtil.evaluate(boostExpression, map);
+        final Object value =
+                ComponentUtil.getScriptEngineFactory().getScriptEngine(Constants.DEFAULT_SCRIPT).evaluate(boostExpression, map);
         if (value instanceof Integer) {
             return ((Integer) value).floatValue();
         }
diff --git a/src/main/java/org/codelibs/fess/job/impl/GroovyExecutor.java b/src/main/java/org/codelibs/fess/job/impl/GroovyExecutor.java
index b7480a5e6..6ca8ed020 100644
--- a/src/main/java/org/codelibs/fess/job/impl/GroovyExecutor.java
+++ b/src/main/java/org/codelibs/fess/job/impl/GroovyExecutor.java
@@ -18,8 +18,9 @@ package org.codelibs.fess.job.impl;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.codelibs.fess.Constants;
 import org.codelibs.fess.job.JobExecutor;
-import org.codelibs.fess.util.GroovyUtil;
+import org.codelibs.fess.util.ComponentUtil;
 
 public class GroovyExecutor extends JobExecutor {
 
@@ -28,7 +29,7 @@ public class GroovyExecutor extends JobExecutor {
         final Map<String, Object> params = new HashMap<>();
         params.put("executor", this);
 
-        return GroovyUtil.evaluate(script, params);
+        return ComponentUtil.getScriptEngineFactory().getScriptEngine(Constants.DEFAULT_SCRIPT).evaluate(script, params);
     }
 
 }
diff --git a/src/main/java/org/codelibs/fess/script/AbstractScriptEngine.java b/src/main/java/org/codelibs/fess/script/AbstractScriptEngine.java
new file mode 100644
index 000000000..c263f4cdb
--- /dev/null
+++ b/src/main/java/org/codelibs/fess/script/AbstractScriptEngine.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2012-2021 CodeLibs Project and the Others.
+ *
+ * Licensed 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.codelibs.fess.script;
+
+import org.codelibs.fess.util.ComponentUtil;
+
+public abstract class AbstractScriptEngine implements ScriptEngine {
+
+    public void register() {
+        ComponentUtil.getScriptEngineFactory().add(getName(), this);
+    }
+
+    protected abstract String getName();
+}
diff --git a/src/test/java/org/codelibs/fess/util/GroovyUtilTest.java b/src/main/java/org/codelibs/fess/script/ScriptEngine.java
similarity index 53%
rename from src/test/java/org/codelibs/fess/util/GroovyUtilTest.java
rename to src/main/java/org/codelibs/fess/script/ScriptEngine.java
index c0a650759..ff8eaba72 100644
--- a/src/test/java/org/codelibs/fess/util/GroovyUtilTest.java
+++ b/src/main/java/org/codelibs/fess/script/ScriptEngine.java
@@ -13,21 +13,10 @@
  * either express or implied. See the License for the specific language
  * governing permissions and limitations under the License.
  */
-package org.codelibs.fess.util;
+package org.codelibs.fess.script;
 
-import java.util.HashMap;
 import java.util.Map;
 
-import org.codelibs.fess.unit.UnitFessTestCase;
-
-public class GroovyUtilTest extends UnitFessTestCase {
-    public void test_evaluate() {
-        final Map<String, Object> params = new HashMap<>();
-        assertNull(GroovyUtil.evaluate("", params));
-        assertEquals("", GroovyUtil.evaluate("return ''", params));
-        assertEquals(1, GroovyUtil.evaluate("return 1", params));
-
-        params.put("test", "123");
-        assertEquals("123", GroovyUtil.evaluate("return test", params));
-    }
+public interface ScriptEngine {
+    Object evaluate(final String template, final Map<String, Object> paramMap);
 }
diff --git a/src/main/java/org/codelibs/fess/script/ScriptEngineFactory.java b/src/main/java/org/codelibs/fess/script/ScriptEngineFactory.java
new file mode 100644
index 000000000..58e5c2176
--- /dev/null
+++ b/src/main/java/org/codelibs/fess/script/ScriptEngineFactory.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2012-2021 CodeLibs Project and the Others.
+ *
+ * Licensed 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.codelibs.fess.script;
+
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.codelibs.fess.exception.ScriptEngineException;
+
+public class ScriptEngineFactory {
+    private static final Logger logger = LogManager.getLogger(ScriptEngineFactory.class);
+
+    protected Map<String, ScriptEngine> scriptEngineMap = new LinkedHashMap<>();
+
+    public void add(final String name, final ScriptEngine scriptEngine) {
+        if (name == null || scriptEngine == null) {
+            throw new IllegalArgumentException("name or scriptEngine is null.");
+        }
+        if (logger.isDebugEnabled()) {
+            logger.debug("Loaded {}", name);
+        }
+        scriptEngineMap.put(name.toLowerCase(Locale.ROOT), scriptEngine);
+        scriptEngineMap.put(scriptEngine.getClass().getSimpleName().toLowerCase(Locale.ROOT), scriptEngine);
+    }
+
+    public ScriptEngine getScriptEngine(final String name) {
+        if (name == null) {
+            throw new ScriptEngineException("script name is null.");
+        }
+        final ScriptEngine scriptEngine = scriptEngineMap.get(name.toLowerCase(Locale.ROOT));
+        if (scriptEngine != null) {
+            return scriptEngine;
+        }
+        throw new ScriptEngineException(name + " is not found.");
+    }
+}
diff --git a/src/main/java/org/codelibs/fess/util/ComponentUtil.java b/src/main/java/org/codelibs/fess/util/ComponentUtil.java
index 838cff7b4..e1ec3a703 100644
--- a/src/main/java/org/codelibs/fess/util/ComponentUtil.java
+++ b/src/main/java/org/codelibs/fess/util/ComponentUtil.java
@@ -77,6 +77,7 @@ import org.codelibs.fess.job.JobExecutor;
 import org.codelibs.fess.ldap.LdapManager;
 import org.codelibs.fess.mylasta.direction.FessConfig;
 import org.codelibs.fess.mylasta.direction.FessProp;
+import org.codelibs.fess.script.ScriptEngineFactory;
 import org.codelibs.fess.sso.SsoManager;
 import org.codelibs.fess.thumbnail.ThumbnailManager;
 import org.lastaflute.core.message.MessageManager;
@@ -95,6 +96,8 @@ public final class ComponentUtil {
 
     private static Map<String, Object> componentMap = new HashMap<>();
 
+    private static final String SCRIPT_ENGINE_FACTORY = "scriptEngineFactory";
+
     private static final String INGEST_FACTORY = "ingestFactory";
 
     private static final String NOTIFICATION_HELPER = "notificationHelper";
@@ -481,6 +484,10 @@ public final class ComponentUtil {
         return getComponent(INGEST_FACTORY);
     }
 
+    public static ScriptEngineFactory getScriptEngineFactory() {
+        return getComponent(SCRIPT_ENGINE_FACTORY);
+    }
+
     public static <T> T getComponent(final Class<T> clazz) {
         try {
             return SingletonLaContainer.getComponent(clazz);
diff --git a/src/main/java/org/codelibs/fess/util/GroovyUtil.java b/src/main/java/org/codelibs/fess/util/GroovyUtil.java
index db8d4487f..d34d73d97 100644
--- a/src/main/java/org/codelibs/fess/util/GroovyUtil.java
+++ b/src/main/java/org/codelibs/fess/util/GroovyUtil.java
@@ -15,46 +15,18 @@
  */
 package org.codelibs.fess.util;
 
-import java.util.HashMap;
 import java.util.Map;
 
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.codelibs.fess.exception.JobProcessingException;
-import org.lastaflute.di.core.factory.SingletonLaContainerFactory;
-
-import groovy.lang.Binding;
-import groovy.lang.GroovyClassLoader;
-import groovy.lang.GroovyShell;
+import org.codelibs.fess.Constants;
 
+@Deprecated
 public final class GroovyUtil {
-    private static final Logger logger = LogManager.getLogger(GroovyUtil.class);
 
     private GroovyUtil() {
         // nothing
     }
 
     public static Object evaluate(final String template, final Map<String, Object> paramMap) {
-        final Map<String, Object> bindingMap = new HashMap<>(paramMap);
-        bindingMap.put("container", SingletonLaContainerFactory.getContainer());
-        final GroovyShell groovyShell = new GroovyShell(new Binding(bindingMap));
-        try {
-            return groovyShell.evaluate(template);
-        } catch (final JobProcessingException e) {
-            throw e;
-        } catch (final Exception e) {
-            logger.warn("Failed to evalue groovy script: {} => {}", template, paramMap, e);
-            return null;
-        } finally {
-            final GroovyClassLoader loader = groovyShell.getClassLoader();
-            //            StreamUtil.of(loader.getLoadedClasses()).forEach(c -> {
-            //                try {
-            //                    GroovySystem.getMetaClassRegistry().removeMetaClass(c);
-            //                } catch (Throwable t) {
-            //                    logger.warn("Failed to delete " + c, t);
-            //                }
-            //            });
-            loader.clearCache();
-        }
+        return ComponentUtil.getScriptEngineFactory().getScriptEngine(Constants.DEFAULT_SCRIPT).evaluate(template, paramMap);
     }
 }
diff --git a/src/main/resources/fess.xml b/src/main/resources/fess.xml
index b9be2e70d..e16e7507a 100644
--- a/src/main/resources/fess.xml
+++ b/src/main/resources/fess.xml
@@ -4,6 +4,7 @@
 <components>
 	<include path="fess_config.xml"/>
 	<include path="fess_ds.xml"/>
+	<include path="fess_se.xml"/>
 	<include path="esflute_config.xml"/>
 	<include path="esflute_user.xml"/>
 	<include path="esflute_log.xml"/>
diff --git a/src/main/resources/fess_se.xml b/src/main/resources/fess_se.xml
new file mode 100644
index 000000000..5e1786a2a
--- /dev/null
+++ b/src/main/resources/fess_se.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE components PUBLIC "-//DBFLUTE//DTD LastaDi 1.0//EN"
+	"http://dbflute.org/meta/lastadi10.dtd">
+<components>
+	<component name="scriptEngineFactory" class="org.codelibs.fess.script.ScriptEngineFactory">
+	</component>
+</components>
diff --git a/src/test/java/org/codelibs/fess/ds/AbstractDataStoreTest.java b/src/test/java/org/codelibs/fess/ds/AbstractDataStoreTest.java
index e73226a03..5ab388fb4 100644
--- a/src/test/java/org/codelibs/fess/ds/AbstractDataStoreTest.java
+++ b/src/test/java/org/codelibs/fess/ds/AbstractDataStoreTest.java
@@ -18,9 +18,19 @@ package org.codelibs.fess.ds;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.codelibs.fess.Constants;
 import org.codelibs.fess.ds.callback.IndexUpdateCallback;
 import org.codelibs.fess.es.config.exentity.DataConfig;
+import org.codelibs.fess.exception.JobProcessingException;
+import org.codelibs.fess.script.AbstractScriptEngine;
+import org.codelibs.fess.script.ScriptEngineFactory;
 import org.codelibs.fess.unit.UnitFessTestCase;
+import org.codelibs.fess.util.ComponentUtil;
+import org.lastaflute.di.core.factory.SingletonLaContainerFactory;
+
+import groovy.lang.Binding;
+import groovy.lang.GroovyClassLoader;
+import groovy.lang.GroovyShell;
 
 public class AbstractDataStoreTest extends UnitFessTestCase {
     public AbstractDataStore dataStore;
@@ -40,6 +50,33 @@ public class AbstractDataStoreTest extends UnitFessTestCase {
                 // TODO nothing
             }
         };
+
+        ScriptEngineFactory scriptEngineFactory = new ScriptEngineFactory();
+        ComponentUtil.register(scriptEngineFactory, "scriptEngineFactory");
+        new AbstractScriptEngine() {
+
+            @Override
+            public Object evaluate(String template, Map<String, Object> paramMap) {
+                final Map<String, Object> bindingMap = new HashMap<>(paramMap);
+                bindingMap.put("container", SingletonLaContainerFactory.getContainer());
+                final GroovyShell groovyShell = new GroovyShell(new Binding(bindingMap));
+                try {
+                    return groovyShell.evaluate(template);
+                } catch (final JobProcessingException e) {
+                    throw e;
+                } catch (final Exception e) {
+                    return null;
+                } finally {
+                    final GroovyClassLoader loader = groovyShell.getClassLoader();
+                    loader.clearCache();
+                }
+            }
+
+            @Override
+            protected String getName() {
+                return Constants.DEFAULT_SCRIPT;
+            }
+        }.register();
     }
 
     public void test_convertValue() {
diff --git a/src/test/java/org/codelibs/fess/indexer/DocBoostMatcherTest.java b/src/test/java/org/codelibs/fess/indexer/DocBoostMatcherTest.java
index f800010b2..7ccf20620 100644
--- a/src/test/java/org/codelibs/fess/indexer/DocBoostMatcherTest.java
+++ b/src/test/java/org/codelibs/fess/indexer/DocBoostMatcherTest.java
@@ -18,9 +18,51 @@ package org.codelibs.fess.indexer;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.codelibs.fess.Constants;
+import org.codelibs.fess.exception.JobProcessingException;
+import org.codelibs.fess.script.AbstractScriptEngine;
+import org.codelibs.fess.script.ScriptEngineFactory;
 import org.codelibs.fess.unit.UnitFessTestCase;
+import org.codelibs.fess.util.ComponentUtil;
+import org.lastaflute.di.core.factory.SingletonLaContainerFactory;
+
+import groovy.lang.Binding;
+import groovy.lang.GroovyClassLoader;
+import groovy.lang.GroovyShell;
 
 public class DocBoostMatcherTest extends UnitFessTestCase {
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        ScriptEngineFactory scriptEngineFactory = new ScriptEngineFactory();
+        ComponentUtil.register(scriptEngineFactory, "scriptEngineFactory");
+        new AbstractScriptEngine() {
+
+            @Override
+            public Object evaluate(String template, Map<String, Object> paramMap) {
+                final Map<String, Object> bindingMap = new HashMap<>(paramMap);
+                bindingMap.put("container", SingletonLaContainerFactory.getContainer());
+                final GroovyShell groovyShell = new GroovyShell(new Binding(bindingMap));
+                try {
+                    return groovyShell.evaluate(template);
+                } catch (final JobProcessingException e) {
+                    throw e;
+                } catch (final Exception e) {
+                    return null;
+                } finally {
+                    final GroovyClassLoader loader = groovyShell.getClassLoader();
+                    loader.clearCache();
+                }
+            }
+
+            @Override
+            protected String getName() {
+                return Constants.DEFAULT_SCRIPT;
+            }
+        }.register();
+    }
+
     public void test_integer() {
         final DocBoostMatcher docBoostMatcher = new DocBoostMatcher();
         docBoostMatcher.setBoostExpression("10");
-- 
GitLab