/* AWE - Amanzi Wireless Explorer
* http://awe.amanzi.org
* (C) 2008-2009, AmanziTel AB
*
* This library is provided under the terms of the Eclipse Public License
* as described at http://www.eclipse.org/legal/epl-v10.html. Any use,
* reproduction or distribution of the library constitutes recipient's
* acceptance of this agreement.
*
* This library is distributed WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
package org.amanzi.awe.scripting;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.amanzi.awe.scripting.exceptions.ScriptingException;
import org.amanzi.awe.scripting.utils.ScriptUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.log4j.Logger;
import org.jruby.Ruby;
import org.jruby.RubyHash;
import org.jruby.RubyNumeric;
import org.jruby.RubyString;
import org.jruby.RubySymbol;
import org.jruby.java.proxies.JavaProxy;
import org.jruby.javasupport.JavaEmbedUtils;
import org.jruby.runtime.builtin.IRubyObject;
/**
* <p>
* wrap Ruby runtime
* </p>
*
* @author Vladislav_Kondratenko
* @since 1.0.0
*/
public class JRubyRuntimeWrapper {
private static final Logger LOGGER = Logger.getLogger(JRubyRuntimeWrapper.class);
private static final String NAME_SEPARATOR = ":";
private static final int MODULE_ELEMENT_INDEX = NumberUtils.INTEGER_ZERO;
private static final int SCRIPT_NAME_ELEMENT_INDEX = NumberUtils.INTEGER_ONE;
private final Ruby runtime;
private final File destination;
/**
* @param runtime
* @param destination
*/
protected JRubyRuntimeWrapper(final Ruby runtime, final File destination) {
this.runtime = runtime;
this.destination = destination;
}
/**
* execute string by script name
*
* @param scriptId
* @throws ScriptingException
* @throws FileNotFoundException
*/
public Object executeScriptByName(final String scriptId) throws FileNotFoundException, ScriptingException {
if (StringUtils.isEmpty(scriptId) && !scriptId.contains(NAME_SEPARATOR)) {
LOGGER.error(scriptId + " has incorrect format. Correct format is <MODULE>:<SCRIPT_NAME>");
}
String[] splittedName = scriptId.split(NAME_SEPARATOR);
String moduleName = splittedName[MODULE_ELEMENT_INDEX];
File destination = getModuleFolder(moduleName);
if (destination == null) {
LOGGER.error("Module " + moduleName + " doesn't exists in script folder");
throw new FileNotFoundException("Module " + moduleName + " doesn't exists in script folder "
+ this.destination.getAbsolutePath());
}
String scriptName = splittedName[SCRIPT_NAME_ELEMENT_INDEX];
String script = ScriptUtils.getInstance().getScript(scriptName, destination);
return executeScript(script);
}
/**
* execute string from file
*
* @param file
* @return
* @throws ScriptingException
*/
public Object executeScript(final File file) throws ScriptingException {
String script = ScriptUtils.getInstance().getScript(file);
return executeScript(script);
}
/**
* check inner folder for existence
*
* @param name
*/
private File getModuleFolder(final String name) {
File[] existedModules = destination.listFiles();
LOGGER.info("< Start searching " + name + " in destination " + destination.getAbsolutePath() + " children "
+ destination.list() + " >");
for (File module : existedModules) {
if (module.getName().equals(name)) {
return module;
}
}
return null;
}
/**
* execute script
*
* @param script
* @return
*/
public Object executeScript(final String script) throws ScriptingException {
try {
IRubyObject object = runtime.evalScriptlet(script);
return defineJavaObject(object);
} catch (Exception e) {
LOGGER.error("Can't execute script " + script + "because of", e);
throw new ScriptingException("Can't execute script " + script + "because of", e);
}
}
public Object executeScript(final File file, final Map<String, String> scriptReplacement) throws ScriptingException {
String script = ScriptUtils.getInstance().getScript(file);
for (Entry<String, String> entry : scriptReplacement.entrySet()) {
script = script.replace(entry.getKey(), entry.getValue());
}
return executeScript(script);
}
/**
* try to define ruby object as java object
*
* @param object
* @return
*/
private Object defineJavaObject(final IRubyObject object) {
Object unwrapped;
if (object instanceof JavaProxy) {
unwrapped = ((JavaProxy)object).unwrap();
} else if (object instanceof RubyNumeric) {
unwrapped = ((RubyNumeric)object).getDoubleValue();
} else if (object instanceof RubyHash) {
unwrapped = convertToHashMap((RubyHash)object);
} else if (object instanceof RubyString) {
unwrapped = object.asString().getValue();
} else {
unwrapped = object;
}
return unwrapped;
}
/**
* @param entrySet
* @return
*/
private Map<Object, Object> convertToHashMap(final RubyHash rubyMap) {
HashMap<Object, Object> map = new HashMap<Object, Object>();
for (Object key : rubyMap.keySet()) {
map.put(key, rubyMap.get(key));
}
return map;
}
public IRubyObject wrap(final Object javaObject) {
return JavaEmbedUtils.javaToRuby(runtime, javaObject);
}
public <K extends Object, V extends Object> Map<RubySymbol, V> toSymbolMap(final Map<K, V> originalMap) {
HashMap<RubySymbol, V> result = new HashMap<RubySymbol, V>();
for (Entry<K, V> entry : originalMap.entrySet()) {
RubySymbol symbol = RubySymbol.newSymbol(runtime, entry.getKey().toString());
result.put(symbol, entry.getValue());
}
return result;
}
}