package org.solrmarc.index.extractor.impl.script;
import bsh.BshMethod;
import bsh.EvalError;
import bsh.Interpreter;
import bsh.UtilEvalError;
import org.apache.log4j.Logger;
import org.solrmarc.index.SolrIndexer;
import org.solrmarc.index.extractor.AbstractValueExtractor;
import org.solrmarc.index.extractor.AbstractValueExtractorFactory;
import org.solrmarc.index.extractor.methodcall.MethodCallContext;
import org.solrmarc.index.extractor.methodcall.MethodCallMultiValueExtractor;
import org.solrmarc.index.extractor.methodcall.MethodCallSingleValueExtractor;
import org.solrmarc.index.indexer.ValueIndexerFactory;
import org.solrmarc.tools.PropertyUtils;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class ScriptValueExtractorFactory extends AbstractValueExtractorFactory
{
// TODO: Use dynamic paths
private final static Logger logger = Logger.getLogger(ScriptValueExtractorFactory.class);
// TODO: Use SolrIndexer instead of Object.
private final static Map<String, Interpreter> INTERPRETERS = new HashMap<>();
private static Map<String, BshMethod> methods = new HashMap<>();
private Interpreter getInterpreter(final String scriptFileName)
{
Interpreter bsh = INTERPRETERS.get(scriptFileName);
if (bsh != null)
{
return bsh;
}
logger.debug("Load bean shell script: " + scriptFileName);
bsh = new Interpreter();
bsh.setClassLoader(this.getClass().getClassLoader());
String paths[] = new String[ValueIndexerFactory.instance().getHomeDirs().length];
for (int i = 0 ; i < paths.length; i++)
{
paths[i] = (ValueIndexerFactory.instance().getHomeDirs())[i] + File.separator + "index_scripts";
}
String[] inputSource = new String[1];
InputStream script = PropertyUtils.getPropertyFileInputStream(paths, scriptFileName, false, inputSource);
try
{
bsh.setOut(System.out);
bsh.setErr(System.err);
bsh.eval(new InputStreamReader(script), bsh.getNameSpace(), inputSource[0]);
bsh.set("indexer", SolrIndexer.instance());
}
catch (EvalError e)
{
throw new IllegalArgumentException("Unable to evaluate script: " + scriptFileName, e);
}
try
{
script.close();
}
catch (IOException e)
{
}
INTERPRETERS.put(scriptFileName, bsh);
return bsh;
}
private BshMethod getBeanShellMethod(final Interpreter interpreter, final String methodName,
final Class<?>[] parameterTypes)
{
BshMethod method = methods.get(methodName + Arrays.toString(parameterTypes));
if (method != null)
{
return method;
}
try
{
method = interpreter.getNameSpace().getMethod(methodName, parameterTypes);
methods.put(methodName + Arrays.toString(parameterTypes), method);
return method;
}
catch (UtilEvalError e)
{
throw new IllegalStateException(e);
}
}
@Override
public boolean canHandle(final String solrFieldName, final String mappingConfiguration)
{
return mappingConfiguration.trim().startsWith("script");
}
private AbstractValueExtractor<?> createExtractor(final String solrFieldName, MethodCallContext context)
{
final String scriptFileName = context.getObjectName();
final Interpreter interpreter = getInterpreter(scriptFileName);
final BshMethod method = getBeanShellMethod(interpreter, context.getMethodName(), context.getParameterTypes());
if (method == null)
{
throw new IllegalStateException("Couldn't find bean shell method " + context.getMethodName()
+ Arrays.toString(context.getParameters()) + " in script file " + scriptFileName);
}
if (Collection.class.isAssignableFrom(method.getReturnType()))
{
return new MethodCallMultiValueExtractor(
new ScriptMultiValueMethodCall(interpreter, method, scriptFileName, context.getParameters().length), context.getParameters());
}
else
{
return new MethodCallSingleValueExtractor(
new ScriptSingleValueMethodCall(interpreter, method, scriptFileName, context.getParameters().length), context.getParameters());
}
}
@Override
public AbstractValueExtractor<?> createExtractor(String solrFieldName, String[] parts)
{
MethodCallContext context = MethodCallContext.parseContextFromExtractorParts(parts);
return(createExtractor(solrFieldName, context));
}
}