fix #2561 add scripnt engine

This commit is contained in:
Shinsuke Sugaya 2021-04-20 05:56:12 +09:00
parent 9c82b32e96
commit 999097a7b0
18 changed files with 236 additions and 64 deletions

13
pom.xml
View file

@ -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>

View file

@ -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";
}

View file

@ -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() {

View file

@ -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) {

View file

@ -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);
}
}

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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();
}

View file

@ -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);
}
}

View file

@ -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();
}

View file

@ -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);
}

View file

@ -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.");
}
}

View file

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

View file

@ -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);
}
}

View file

@ -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"/>

View file

@ -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>

View file

@ -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() {

View file

@ -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");