package org.eclipse.eclipsemonkey.lang.ruby;
/**
* Copyright (c) 2007 Aptana, Inc.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html. If redistributing this code,
* this entire header must remain intact.
*/
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.InvalidRegistryObjectException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.eclipsemonkey.DOMDescriptor;
import org.eclipse.eclipsemonkey.EclipseMonkeyPlugin;
import org.eclipse.eclipsemonkey.IMonkeyScriptRunner;
import org.eclipse.eclipsemonkey.RunMonkeyException;
import org.eclipse.eclipsemonkey.ScriptMetadata;
import org.eclipse.eclipsemonkey.StoredScript;
import org.eclipse.eclipsemonkey.dom.IMonkeyDOMFactory;
import org.eclipse.eclipsemonkey.dom.Utilities;
import org.eclipse.eclipsemonkey.lang.ruby.doms.IRubyDOMFactory;
import org.eclipse.osgi.service.environment.Constants;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.jruby.Ruby;
import org.jruby.RubyInstanceConfig;
import org.jruby.exceptions.RaiseException;
import org.jruby.javasupport.Java;
import org.jruby.javasupport.JavaObject;
import org.jruby.javasupport.JavaUtil;
import org.jruby.runtime.GlobalVariable;
import org.jruby.runtime.builtin.IRubyObject;
import org.osgi.framework.Bundle;
/**
* @author Chris Williams
*/
public class RubyScriptRunner implements IMonkeyScriptRunner {
private static final String DOM_EXTENSION_POINT = "org.eclipse.eclipsemonkey.dom";
private static final String CLASS = "class";
private static final String VARIABLE_NAME = "variableName";
private static final String RUBY_DOM_EXTENSION_POINT = "org.eclipse.eclipsemonkey.lang.ruby.ruby_dom";
private static final String BASED_ON = "basedOn";
private IWorkbenchWindow window;
private IPath path;
private StoredScript storedScript;
private static Ruby fgRuby;
public RubyScriptRunner(IPath path, IWorkbenchWindow window) {
this.path = path;
if (window == null) {
this.window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
} else {
this.window = window;
}
}
public StoredScript getStoredScript() {
return storedScript;
}
public Object run(String entryName, Object[] functionArgs)
throws RunMonkeyException {
String fileName = this.path.toPortableString();
try {
Map scriptStore = EclipseMonkeyPlugin.getDefault().getScriptStore();
storedScript = (StoredScript) (scriptStore.get(fileName));
if (!storedScript.metadata.ensure_doms_are_loaded(window)) {
return null;
}
String script = Utilities.getFileContents(path);
Ruby ruby = getJRubyInstance();
defineStandardGlobalVariables(ruby);
List/*<ExtensionDOMLoader>*/ loaders = new ArrayList/*<ExtensionDOMLoader>*/();
loaders.add(new StandardDOMLoader(ruby, storedScript.metadata));
loaders.add(new ExtensionRubyDOMLoader(ruby, storedScript.metadata));
// for (ExtensionDOMLoader loader : loaders) {
// loader.run();
// }
for (Iterator iter = loaders.iterator(); iter.hasNext();) {
ExtensionDOMLoader loader = (ExtensionDOMLoader) iter.next();
loader.run();
}
ruby.setCurrentDirectory(path.toFile().getParent());
IRubyObject result = ruby.evalScriptlet(script);
return result;
} catch (CoreException e) {
error(e, fileName, "Core Exception");
} catch (IOException e) {
error(e, fileName, "IO error");
} catch (RaiseException e) {
error(e, fileName, e.getException().message.toString());
} catch (RuntimeException e) {
e.printStackTrace();
error(e, fileName, e.getLocalizedMessage());
}
return null;
}
private static Ruby getJRubyInstance() {
if (fgRuby == null) {
RubyInstanceConfig config = new RubyInstanceConfig();
PrintStream out = new PrintStream(RubyScriptConsole
.getConsoleStream());
config.setOutput(out);
fgRuby = Ruby.newInstance(config);
File jrubyHome = getIncludedJRuby();
if (jrubyHome != null)
fgRuby.setJRubyHome(jrubyHome.getAbsolutePath());
fgRuby.getLoadService().init(new ArrayList());
}
return fgRuby;
}
private static File getIncludedJRuby() {
try {
Bundle bundle = Platform.getBundle("org.jruby");
URL url = FileLocator.find(bundle, new Path(""), null);
url = FileLocator.toFileURL(url);
String fileName = url.getFile();
File file = new File(fileName);
if (!file.exists()) {
return null;
}
return file;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
private void defineStandardGlobalVariables(Ruby ruby) {
defineGlobal(ruby, "window", window);
}
private void defineGlobal(Ruby ruby, String name, Object value) {
IRubyObject object = JavaUtil.convertJavaToRuby(ruby, value);
if (object instanceof JavaObject) {
object = Java.wrap(ruby.getJavaSupport().getJavaUtilitiesModule(),
object);
}
ruby.defineVariable(new GlobalVariable(ruby, GlobalVariable
.variableName(name), object));
}
private void error(Exception x, String fileName, String string)
throws RunMonkeyException {
RunMonkeyException e = new RunMonkeyException(x.getClass().getName(),
fileName, null, string);
PrintStream cs = new PrintStream(RubyScriptConsole.getConsoleStream());
cs.println(string);
cs.println(x.getLocalizedMessage());
x.printStackTrace(cs);
throw e;
}
private abstract class ExtensionDOMLoader {
protected ScriptMetadata metadata;
protected Ruby ruby;
public ExtensionDOMLoader(Ruby ruby, ScriptMetadata metadata) {
this.ruby = ruby;
this.metadata = metadata;
}
public void run() throws IOException {
IExtension[] extensions = getExtensions(getExtensionPoint());
for (int i = 0; i < extensions.length; i++) {
IExtension extension = extensions[i];
IConfigurationElement[] configurations = extension.getConfigurationElements();
for (int j = 0; j < configurations.length; j++) {
IConfigurationElement element = configurations[j];
try {
IExtension declaring = element.getDeclaringExtension();
String declaring_plugin_id = declaring.getNamespaceIdentifier();
if (metadata.containsDOM_by_plugin(declaring_plugin_id)) {
checkExtensionPointSpecifics(element);
String variableName = element.getAttribute(VARIABLE_NAME);
Object object = element.createExecutableExtension(CLASS);
defineGlobal(ruby, variableName, getRootObject(object));
}
} catch (InvalidRegistryObjectException x) {
// ignore bad extensions
} catch (CoreException x) {
// ignore bad extensions
}
}
}
}
private IExtension[] getExtensions(String extensionPoint) {
IExtensionRegistry registry = Platform.getExtensionRegistry();
IExtensionPoint point = registry.getExtensionPoint(extensionPoint);
if (point != null)
return point.getExtensions();
return new IExtension[0];
}
protected abstract Object getRootObject(Object object);
protected abstract String getExtensionPoint();
protected abstract void checkExtensionPointSpecifics(IConfigurationElement element) throws IOException;
}
private class StandardDOMLoader extends ExtensionDOMLoader {
public StandardDOMLoader(Ruby ruby, ScriptMetadata metadata) {
super(ruby, metadata);
}
// @Override
protected String getExtensionPoint() {
return DOM_EXTENSION_POINT;
}
// @Override
protected void checkExtensionPointSpecifics(IConfigurationElement element) throws IOException {
return; // do nothing
}
protected Object getRootObject(Object object) {
IMonkeyDOMFactory factory = (IMonkeyDOMFactory) object;
return factory.getDOMroot();
}
}
private class ExtensionRubyDOMLoader extends ExtensionDOMLoader {
public ExtensionRubyDOMLoader(Ruby ruby, ScriptMetadata metadata) {
super(ruby, metadata);
}
protected void checkExtensionPointSpecifics(IConfigurationElement element) throws IOException {
String basedOnDOM = element.getAttribute(BASED_ON);
if (basedOnDOM != null
&& basedOnDOM.trim().length() > 0) {
Pattern p = Pattern.compile(
"\\s*(\\p{Graph}+)\\/((\\p{Alnum}|\\.)+)",
Pattern.DOTALL);
Matcher m = p.matcher(basedOnDOM);
while (m.find()) {
metadata.getDOMs().add(
new DOMDescriptor(m.group(1), m
.group(2)));
}
if (metadata.ensure_doms_are_loaded(window) == false) {
throw new IOException(
"Cannot load the required DOM extension:\n\n"
+ basedOnDOM + "\n");
}
}
}
protected Object getRootObject(Object object) {
IRubyDOMFactory factory = (IRubyDOMFactory) object;
return factory.getDOMroot(ruby);
}
// @Override
protected String getExtensionPoint() {
return RUBY_DOM_EXTENSION_POINT;
}
}
}