com.liferay.portal.scripting.ruby.RubyExecutor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of portal-impl Show documentation
Show all versions of portal-impl Show documentation
Contains implementation for the portal services.
/**
* Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.scripting.ruby;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.scripting.BaseScriptingExecutor;
import com.liferay.portal.kernel.scripting.ExecutionException;
import com.liferay.portal.kernel.scripting.ScriptingException;
import com.liferay.portal.kernel.util.AggregateClassLoader;
import com.liferay.portal.kernel.util.ArrayUtil;
import com.liferay.portal.kernel.util.FileUtil;
import com.liferay.portal.kernel.util.NamedThreadFactory;
import com.liferay.portal.kernel.util.ReflectionUtil;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.SystemProperties;
import com.liferay.portal.util.ClassLoaderUtil;
import com.liferay.portal.util.PropsValues;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ThreadFactory;
import jodd.io.ZipUtil;
import org.jruby.Ruby;
import org.jruby.RubyInstanceConfig;
import org.jruby.RubyInstanceConfig.CompileMode;
import org.jruby.embed.LocalContextScope;
import org.jruby.embed.ScriptingContainer;
import org.jruby.embed.internal.LocalContextProvider;
import org.jruby.exceptions.RaiseException;
/**
* @author Alberto Montero
* @author Raymond Augé
*/
public class RubyExecutor extends BaseScriptingExecutor {
public static final String LANGUAGE = "ruby";
public RubyExecutor() {
try {
initRubyGems();
}
catch (Exception e) {
_log.error(e, e);
}
_scriptingContainer = new ScriptingContainer(
LocalContextScope.THREADSAFE);
LocalContextProvider localContextProvider =
_scriptingContainer.getProvider();
RubyInstanceConfig rubyInstanceConfig =
localContextProvider.getRubyInstanceConfig();
if (PropsValues.SCRIPTING_JRUBY_COMPILE_MODE.equals(
_COMPILE_MODE_FORCE)) {
rubyInstanceConfig.setCompileMode(CompileMode.FORCE);
}
else if (PropsValues.SCRIPTING_JRUBY_COMPILE_MODE.equals(
_COMPILE_MODE_JIT)) {
rubyInstanceConfig.setCompileMode(CompileMode.JIT);
}
rubyInstanceConfig.setJitThreshold(
PropsValues.SCRIPTING_JRUBY_COMPILE_THRESHOLD);
rubyInstanceConfig.setLoader(ClassLoaderUtil.getPortalClassLoader());
_basePath = PropsValues.LIFERAY_LIB_PORTAL_DIR;
_loadPaths = new ArrayList(
PropsValues.SCRIPTING_JRUBY_LOAD_PATHS.length);
for (String gemLibPath : PropsValues.SCRIPTING_JRUBY_LOAD_PATHS) {
_loadPaths.add(gemLibPath);
}
rubyInstanceConfig.setLoadPaths(_loadPaths);
_scriptingContainer.setCurrentDirectory(_basePath);
}
@Override
public Map eval(
Set allowedClasses, Map inputObjects,
Set outputNames, File scriptFile,
ClassLoader... classLoaders)
throws ScriptingException {
return eval(
allowedClasses, inputObjects, outputNames, scriptFile, null,
classLoaders);
}
@Override
public Map eval(
Set allowedClasses, Map inputObjects,
Set outputNames, String script, ClassLoader... classLoaders)
throws ScriptingException {
return eval(
allowedClasses, inputObjects, outputNames, null, script,
classLoaders);
}
@Override
public String getLanguage() {
return LANGUAGE;
}
public void setExecuteInSeparateThread(boolean executeInSeparateThread) {
_executeInSeparateThread = executeInSeparateThread;
}
protected Map doEval(
Set allowedClasses, Map inputObjects,
Set outputNames, File scriptFile, String script,
ClassLoader... classLoaders)
throws ScriptingException {
if (allowedClasses != null) {
throw new ExecutionException(
"Constrained execution not supported for Ruby");
}
try {
LocalContextProvider localContextProvider =
_scriptingContainer.getProvider();
RubyInstanceConfig rubyInstanceConfig =
localContextProvider.getRubyInstanceConfig();
rubyInstanceConfig.setCurrentDirectory(_basePath);
if (ArrayUtil.isNotEmpty(classLoaders)) {
ClassLoader aggregateClassLoader =
AggregateClassLoader.getAggregateClassLoader(
ClassLoaderUtil.getPortalClassLoader(), classLoaders);
rubyInstanceConfig.setLoader(aggregateClassLoader);
}
rubyInstanceConfig.setLoadPaths(_loadPaths);
for (Map.Entry entry : inputObjects.entrySet()) {
String inputName = entry.getKey();
Object inputObject = entry.getValue();
if (!inputName.startsWith(StringPool.DOLLAR)) {
inputName = StringPool.DOLLAR + inputName;
}
_scriptingContainer.put(inputName, inputObject);
}
if (scriptFile != null) {
_scriptingContainer.runScriptlet(
new FileInputStream(scriptFile), scriptFile.toString());
}
else {
_scriptingContainer.runScriptlet(script);
}
if (outputNames == null) {
return null;
}
Map outputObjects = new HashMap();
for (String outputName : outputNames) {
outputObjects.put(
outputName, _scriptingContainer.get(outputName));
}
return outputObjects;
}
catch (RaiseException re) {
throw new ScriptingException(
re.getException().message.asJavaString() + "\n\n", re);
}
catch (FileNotFoundException fnfe) {
throw new ScriptingException(fnfe);
}
finally {
try {
_globalRuntimeField.set(null, null);
}
catch (Exception e) {
_log.error(e, e);
}
}
}
protected Map eval(
Set allowedClasses, Map inputObjects,
Set outputNames, File scriptFile, String script,
ClassLoader... classLoaders)
throws ScriptingException {
if (!_executeInSeparateThread) {
return doEval(
allowedClasses, inputObjects, outputNames, scriptFile, script,
classLoaders);
}
EvalCallable evalCallable = new EvalCallable(
allowedClasses, inputObjects, outputNames, scriptFile, script,
classLoaders);
FutureTask