/* 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.FileFilter;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.amanzi.awe.scripting.exceptions.ScriptingException;
import org.amanzi.awe.scripting.utils.ScriptUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.log4j.Logger;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Plugin;
import org.jcodings.specific.UTF8Encoding;
import org.jruby.Ruby;
import org.jruby.RubyInstanceConfig;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
/**
* <p>
* activate JrubyScripting
* </p>
*
* @author Vladislav_Kondratenko
* @since 1.0.0
*/
public abstract class AbstractScriptingPlugin extends Plugin {
/*
* logger initialization
*/
private static final Logger LOGGER = Logger.getLogger(AbstractScriptingPlugin.class);
public static final String PLUGIN_ID = "org.amanzi.awe.scripting";
/*
* constants definition
*/
private static final String WORKSPACE_FOLDER = Platform.getInstanceLocation().getURL().getPath();
private static final String SCRIPTS_FOLDER = "awe-scripts";
private static final String RUBY_SCRIPT_FOLDER = "ruby";
private static final String COMMON_SCRIPTS_FOLDER = "common";
private static final String PATH_SEPARATOR = "/";
/**
* wrapper for runtime instance
*/
private JRubyRuntimeWrapper runtimeWrapper;
private final ScriptingManager manager = new ScriptingManager();
/**
* initialize runtime with required scripts from ruby/common folder
*
* @param runtime
* @throws ScriptingException
* @throws IOException
*/
protected void initDefaultScript(final Bundle bundle, final JRubyRuntimeWrapper runtime) throws ScriptingException, IOException {
URL workspaceName = bundle.getEntry(RUBY_SCRIPT_FOLDER + PATH_SEPARATOR + COMMON_SCRIPTS_FOLDER);
if (workspaceName == null) {
LOGGER.info("nothing to initialize in bundle " + bundle.getSymbolicName());
return;
}
URL scripts = FileLocator.toFileURL(workspaceName);
File scriptsFolder = new File(scripts.getPath());
for (File script : scriptsFolder.listFiles()) {
LOGGER.info("Initialize bundle " + bundle.getSymbolicName() + " with script " + script.getName());
if (script.isFile()) {
runtime.executeScript(script);
}
}
}
@Override
public void start(final BundleContext context) throws ScriptingException {
try {
super.start(context);
manager.initWorkspace();
initScriptManager(context);
} catch (Exception e) {
LOGGER.error("error when trying to initialize default ruby scripts", e);
throw new ScriptingException(e);
}
}
protected abstract String getPluginName();
/**
* get list of project folder content
*
* @param projectName
* @return project folder not exist, in other case return list of files
*/
public List<File> getScriptsForProject(final String projectName) {
File projectFolder = new File(AbstractScriptingPlugin.WORKSPACE_FOLDER + File.separator
+ AbstractScriptingPlugin.SCRIPTS_FOLDER + File.separator + projectName);
if (!projectFolder.exists()) {
LOGGER.info("project folder " + projectName + " doesn't exist");
return null;
}
return Arrays.asList(projectFolder.listFiles());
}
/**
* initialize script manager
*
* @param context
* @throws IOException
*/
public void initScriptManager(final BundleContext context) throws IOException {
try {
LOGGER.info("Start scripts processing. for plugin" + context.getBundle().getSymbolicName());
URL workspaceName = context.getBundle().getEntry(RUBY_SCRIPT_FOLDER);
LOGGER.info("Scripts folder founded in" + workspaceName.getPath());
URL workspaceLocator = FileLocator.toFileURL(workspaceName);
LOGGER.info("Start workspace initializing");
LOGGER.info("Start file copying");
manager.copySources(workspaceLocator);
} catch (IOException e) {
LOGGER.error("Error in wokspace preparator", e);
}
}
/**
* initialize runtime with default plugin workspace folder
*
* @throws ScriptingException
*/
public void initRuntime() throws ScriptingException {
initRuntime(manager.getScriptsFolder());
}
/**
* get all available scripts
*
* @return
*/
public Map<String, File> getAllScripts() {
return manager.getAllWorkspaceScripts(ScriptingManager.FILE_FILTER_TO_LOAD);
}
/**
* initialize ruby runtime
*
* @throws IOException
*/
public void initRuntime(final File scriptFolder) throws ScriptingException {
try {
Ruby runtime;
RubyInstanceConfig config = new RubyInstanceConfig() {
{
setJRubyHome(ScriptUtils.getInstance().getJRubyHome());
setObjectSpaceEnabled(true);
setLoader(getClassLoader());
setLoadPaths(ScriptUtils.getInstance().makeLoadPath(scriptFolder.getAbsolutePath(), getPluginName()));
}
};
runtime = Ruby.newInstance(config);
runtime.setDefaultExternalEncoding(UTF8Encoding.INSTANCE);
runtime.setDefaultInternalEncoding(UTF8Encoding.INSTANCE);
// TODO: LN: 09.08.2012, why manager.getScriptsFolder if we have this in scriptFolder
// variable?
runtimeWrapper = new JRubyRuntimeWrapper(runtime, manager.getScriptsFolder());
initRuntimeWithDefaultScripts();
} catch (Exception e) {
LOGGER.error("Error in runtime initialisation", e);
throw new ScriptingException(e);
}
}
/**
* @param runtime
* @throws ScriptingException
*/
private void initRuntimeWithDefaultScripts() throws ScriptingException {
try {
initDefaultScript(Platform.getBundle(PLUGIN_ID), runtimeWrapper);
initDefaultScript(getBundle(), runtimeWrapper);
} catch (Exception e) {
throw new ScriptingException("Unable to initialize runtime with default scripts", e);
}
}
/**
* @return Returns the runtimeWrapper.
* @throws ScriptingException
*/
public JRubyRuntimeWrapper getRuntimeWrapper() throws ScriptingException {
if (runtimeWrapper == null) {
initRuntime();
}
return runtimeWrapper;
}
/**
* return class loader for activator plugin
*
* @return
*/
private ClassLoader getClassLoader() {
return getClass().getClassLoader();
}
/**
* <p>
* Script management utils - purposed for control of script file and definition script
* directories
* </p>
*
* @author Vladislav_Kondratenko
* @since 1.0.0
*/
private static class ScriptingManager {
private static final String SCRIPT_NAME_FORMAT = "%s:%s";
private static final IOFileFilter FILE_FILTER_TO_LOAD = FileFilterUtils.suffixFileFilter(".t");
private static final FileFilter ALL_RUBY_FILES = FileFilterUtils.orFileFilter(FILE_FILTER_TO_LOAD,
FileFilterUtils.suffixFileFilter(".rb"));
private File scriptsFolder;
/**
* initialize scripts workspace;
*
* @param rubyScriptingFolder
* @return false if workspace is already exist, true- if newly created
* @throws IOException
*/
public void initWorkspace() throws IOException {
scriptsFolder = new File(WORKSPACE_FOLDER, SCRIPTS_FOLDER);
// IProjectTemplate template = new ProjectTemplate(path, type, name,
// isReplacingParameters, description, iconURL, id);
if (!scriptsFolder.exists()) {
FileUtils.forceMkdir(scriptsFolder);
}
}
public void copySources(final URL rubyScriptingFolder) throws IOException {
LOGGER.info("< start copy modules folder to" + scriptsFolder + " >");
File rubyFolder = new File(rubyScriptingFolder.getPath());
for (File module : rubyFolder.listFiles()) {
if (!module.isDirectory() || module.getName().equals(COMMON_SCRIPTS_FOLDER)) {
continue;
}
String scriptFolderName = module.getName();
File destination = new File(scriptsFolder.getAbsolutePath(), scriptFolderName);
FileUtils.forceMkdir(destination);
FileUtils.copyDirectory(module, destination, ALL_RUBY_FILES);
LOGGER.info("< modules" + module.getName() + " copyed to " + scriptsFolder.getName() + " >");
}
LOGGER.info("< All modules coppyed " + scriptsFolder.list() + " >");
}
/**
* @return Returns the scriptsFolder.
*/
public File getScriptsFolder() {
return scriptsFolder;
}
/**
* return all workspace file list
*
* @return
*/
public Map<String, File> getAllWorkspaceScripts(final FileFilter filter) {
File projectFolder = new File(WORKSPACE_FOLDER, SCRIPTS_FOLDER);
File[] modules = projectFolder.listFiles();
Map<String, File> fileList = new HashMap<String, File>();
for (File module : modules) {
File[] scripts = module.listFiles(filter);
if (scripts.length > NumberUtils.INTEGER_ZERO) {
for (File script : scripts) {
fileList.put(String.format(SCRIPT_NAME_FORMAT, module.getName(), script.getName()), script);
}
}
}
return fileList;
}
}
}