/*
* Copyright (c) 2016 wetransform GmbH
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution. If not, see <http://www.gnu.org/licenses/>.
*
* Contributors:
* wetransform GmbH <http://www.wetransform.to>
*/
package eu.esdihumboldt.cst.functions.groovy.filter;
import java.util.Map;
import de.fhg.igd.slf4jplus.ALogger;
import de.fhg.igd.slf4jplus.ALoggerFactory;
import eu.esdihumboldt.cst.functions.groovy.GroovyConstants;
import eu.esdihumboldt.cst.functions.groovy.helper.HelperFunctions;
import eu.esdihumboldt.cst.functions.groovy.internal.SynchronizedContextProvider;
import eu.esdihumboldt.hale.common.core.HalePlatform;
import eu.esdihumboldt.hale.common.instance.model.ContextAwareFilter;
import eu.esdihumboldt.hale.common.instance.model.Instance;
import eu.esdihumboldt.util.groovy.sandbox.DefaultGroovyService;
import eu.esdihumboldt.util.groovy.sandbox.GroovyService;
import eu.esdihumboldt.util.groovy.sandbox.GroovyService.ResultProcessor;
import groovy.lang.Binding;
import groovy.lang.Script;
/**
* Filter based on a Groovy script.
*
* @author Simon Templer
*/
public class GroovyFilter implements ContextAwareFilter {
private static final ALogger log = ALoggerFactory.getLogger(GroovyFilter.class);
private final String script;
private final ThreadLocal<Script> localScript = new ThreadLocal<Script>();
private GroovyService groovyService;
/**
* Constructor.
*
* @param script the Groovy script text
*/
public GroovyFilter(String script) {
super();
this.script = script;
}
@Override
public boolean match(Instance instance) {
return match(instance, null);
}
/**
* Get a Groovy script instance and configure it with the given binding.
*
* @param service the Groovy service
* @param binding the script binding
* @return the Groovy script instance
*/
protected Script getScript(GroovyService service, Binding binding) {
/*
* The compiled script is stored in a ThreadLocal variable so it needs
* only to be created once per filter thread.
*/
Script groovyScript = localScript.get();
if (groovyScript == null) {
groovyScript = service.parseScript(script, null);
localScript.set(groovyScript);
}
groovyScript.setBinding(binding);
return groovyScript;
}
@Override
public boolean match(Instance instance, Map<Object, Object> context) {
GroovyService service = getGroovyService();
Binding binding = new Binding();
// helper functions
binding.setVariable(GroovyConstants.BINDING_HELPER_FUNCTIONS,
HelperFunctions.createDefault(null));
// instance
binding.setVariable("instance", instance);
// context
binding.setVariable("withContext", SynchronizedContextProvider.getContextClosure(context));
// log
binding.setVariable(GroovyConstants.BINDING_LOG, new LogWrapper(log));
Script script = getScript(service, binding);
try {
return service.evaluate(script, new ResultProcessor<Boolean>() {
@Override
public Boolean process(Script script, Object returnValue) throws Exception {
if (returnValue != null && returnValue.equals(true)) {
return true;
}
return false;
}
});
} catch (Exception e) {
throw new IllegalStateException("Error evaluating Groovy filter", e);
}
}
/**
* @return the Groovy service to use for building and evaluating the filter
* script.
*/
protected GroovyService getGroovyService() {
synchronized (this) {
if (groovyService != null) {
return groovyService;
}
GroovyService result = HalePlatform.getService(GroovyService.class);
// TODO where may the Groovy service come from?
// here there is no access to a dedicated service provider
// fall back to restrictive Groovy service
if (result == null) {
DefaultGroovyService def = new DefaultGroovyService();
def.setRestrictionActive(true);
result = def;
log.warn("No GroovyService found, using restricted execution for filter");
}
groovyService = result;
return result;
}
}
/**
* @return the script
*/
public String getScript() {
return script;
}
}