PageRenderTime 26ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/core/src/main/java/org/torquebox/core/util/RuntimeHelper.java

https://gitlab.com/meetly/torquebox
Java | 278 lines | 191 code | 34 blank | 53 comment | 11 complexity | c470bc3c3b53be936c989d743b62f9f2 MD5 | raw file
  1. /*
  2. * Copyright 2008-2013 Red Hat, Inc, and individual contributors.
  3. *
  4. * This is free software; you can redistribute it and/or modify it
  5. * under the terms of the GNU Lesser General Public License as
  6. * published by the Free Software Foundation; either version 2.1 of
  7. * the License, or (at your option) any later version.
  8. *
  9. * This software is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this software; if not, write to the Free
  16. * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  17. * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  18. */
  19. package org.torquebox.core.util;
  20. import java.io.File;
  21. import java.lang.ref.WeakReference;
  22. import java.util.Map;
  23. import java.util.Map.Entry;
  24. import java.util.WeakHashMap;
  25. import java.util.concurrent.Callable;
  26. import org.jboss.logging.Logger;
  27. import org.jruby.Ruby;
  28. import org.jruby.RubyHash;
  29. import org.jruby.RubyModule;
  30. import org.jruby.RubyThread;
  31. import org.jruby.javasupport.JavaEmbedUtils;
  32. import org.jruby.runtime.builtin.IRubyObject;
  33. import org.jruby.util.JRubyClassLoader;
  34. /**
  35. * Ruby reflection helper utilities.
  36. *
  37. * @author Bob McWhirter <bmcwhirt@redhat.com>
  38. */
  39. public class RuntimeHelper {
  40. /**
  41. * Set a property on a Ruby object, if possible.
  42. *
  43. * <p>
  44. * If the target responds to {@code name=}, the property will be set.
  45. * Otherwise, not.
  46. * </p>
  47. *
  48. * @param ruby
  49. * The Ruby interpreter.
  50. * @param target
  51. * The target object.
  52. * @param name
  53. * The basic name of the property.
  54. * @param value
  55. * The value to attempt to set.
  56. * @return {@code true} if successful, otherwise {@code false}
  57. */
  58. public static boolean setIfPossible(final Ruby ruby, final Object target, final String name, final Object value) {
  59. return withinContext( ruby, new Callable<Boolean>() {
  60. public Boolean call() throws Exception {
  61. boolean success = false;
  62. if (defined( ruby, target, name + "=" )) {
  63. JavaEmbedUtils.invokeMethod( ruby, target, name + "=", new Object[] { value }, void.class );
  64. success = true;
  65. }
  66. return success;
  67. }
  68. } );
  69. }
  70. public static Object getIfPossible(final Ruby ruby, final Object target, final String name) {
  71. return withinContext( ruby, new Callable<Object>() {
  72. public Object call() throws Exception {
  73. Object result = null;
  74. if (defined( ruby, target, name )) {
  75. result = JavaEmbedUtils.invokeMethod( ruby, target, name, new Object[] {}, Object.class );
  76. }
  77. return result;
  78. }
  79. } );
  80. }
  81. public static Object call(final Ruby ruby, final Object target, final String name, final Object[] parameters) {
  82. return withinContext( ruby, new Callable<Object>() {
  83. public Object call() throws Exception {
  84. return JavaEmbedUtils.invokeMethod( ruby, target, name, parameters, Object.class );
  85. }
  86. } );
  87. }
  88. public static Object callIfPossible(final Ruby ruby, final Object target, final String name, final Object[] parameters) {
  89. return withinContext( ruby, new Callable<Object>() {
  90. public Object call() throws Exception {
  91. Object result = null;
  92. if (defined( ruby, target, name )) {
  93. result = JavaEmbedUtils.invokeMethod( ruby, target, name, parameters, Object.class );
  94. }
  95. return result;
  96. }
  97. } );
  98. }
  99. public static boolean defined(final Ruby ruby, final Object target, final String name) {
  100. return withinContext( ruby, new Callable<Boolean>() {
  101. public Boolean call() throws Exception {
  102. return (Boolean) JavaEmbedUtils.invokeMethod( ruby, target, "respond_to?", new Object[] { name }, Boolean.class );
  103. }
  104. } );
  105. }
  106. public static Object invokeClassMethod(Ruby ruby, String className, String name, Object[] parameters) {
  107. RubyModule module = ruby.getClassFromPath( className );
  108. return call( ruby, module, name, parameters );
  109. }
  110. public static void require(Ruby ruby, String requirement) {
  111. try {
  112. evalScriptlet( ruby, "require %q(" + requirement + ")" );
  113. } catch (Throwable t) {
  114. log.errorf( t, "Unable to require file: %s", requirement );
  115. }
  116. }
  117. /**
  118. * Looks in application ROOT/config and application ROOT for configurationFile
  119. * and requires it if possible.
  120. */
  121. public static void requireTorqueBoxInit(Ruby ruby) {
  122. RuntimeHelper.requireIfAvailable( ruby, "config" + File.separator + "torquebox_init", false );
  123. RuntimeHelper.requireIfAvailable( ruby, "torquebox_init", false );
  124. }
  125. public static boolean requireIfAvailable(Ruby ruby, String requirement) {
  126. return requireIfAvailable( ruby, requirement, true );
  127. }
  128. /**
  129. * Calls "require 'requirement'" in the Ruby provided.
  130. * @returns boolean If successful, returns true, otherwise false.
  131. */
  132. public static boolean requireIfAvailable(Ruby ruby, String requirement, boolean logErrors) {
  133. boolean success = false;
  134. try {
  135. StringBuilder script = new StringBuilder();
  136. script.append("require %q(");
  137. script.append(requirement);
  138. script.append(")\n");
  139. evalScriptlet( ruby, script.toString(), false );
  140. success = true;
  141. } catch (Throwable t) {
  142. success = false;
  143. if (logErrors) {
  144. log.debugf( t, "Error encountered. Unable to require file: %s", requirement );
  145. }
  146. }
  147. return success;
  148. }
  149. public static void requireUnlessDefined(Ruby ruby, String requirement, String constant) {
  150. try {
  151. evalScriptlet( ruby, "require %q(" + requirement + ") unless defined?(" + constant + ")" );
  152. } catch (Throwable t) {
  153. log.errorf( t, "Unable to require file: %s", requirement );
  154. }
  155. }
  156. // ------------------------------------------------------------------------
  157. public static IRubyObject evalScriptlet(final Ruby ruby, final String script) {
  158. return evalScriptlet( ruby, script, true );
  159. }
  160. public static IRubyObject evalScriptlet(final Ruby ruby, final String script, final boolean logErrors) {
  161. return withinContext( ruby, new Callable<IRubyObject>() {
  162. public IRubyObject call() throws Exception {
  163. try {
  164. return ruby.evalScriptlet( script );
  165. } catch (Exception e) {
  166. if (logErrors)
  167. log.errorf( e, "Error during evaluation: %s", script );
  168. throw e;
  169. }
  170. }
  171. } );
  172. }
  173. public static IRubyObject executeScript(final Ruby ruby, final String script, final String location) {
  174. return withinContext( ruby, new Callable<IRubyObject>() {
  175. public IRubyObject call() throws Exception {
  176. try {
  177. return ruby.executeScript( script, location );
  178. } catch (Exception e) {
  179. log.errorf( e, "Error during execution: %s", script );
  180. throw e;
  181. }
  182. }
  183. } );
  184. }
  185. // ------------------------------------------------------------------------
  186. public static IRubyObject instantiate(Ruby ruby, String className) {
  187. return instantiate( ruby, className, new Object[] {} );
  188. }
  189. public static IRubyObject instantiate(final Ruby ruby, final String className, final Object[] parameters) {
  190. return withinContext( ruby, new Callable<IRubyObject>() {
  191. public IRubyObject call() throws Exception {
  192. IRubyObject result = null;
  193. RubyModule rubyClass = ruby.getClassFromPath( className );
  194. if (rubyClass != null) {
  195. try {
  196. result = (IRubyObject) JavaEmbedUtils.invokeMethod( ruby, rubyClass, "new", parameters, IRubyObject.class );
  197. } catch (Exception e) {
  198. log.errorf( e, "Unable to instantiate: %s", className );
  199. throw e;
  200. }
  201. }
  202. return result;
  203. }
  204. } );
  205. }
  206. // ------------------------------------------------------------------------
  207. public static RubyThread currentThread(Ruby ruby) {
  208. return (RubyThread) invokeClassMethod( ruby, "Thread", "current", EMPTY_OBJECT_ARRAY );
  209. }
  210. @SuppressWarnings("rawtypes")
  211. public static RubyHash convertJavaMapToRubyHash(Ruby runtime, Map map) {
  212. RubyHash rubyHash = RubyHash.newHash( runtime );
  213. for (Object object : map.entrySet()) {
  214. Entry entry = (Entry) object;
  215. rubyHash.put( entry.getKey(), entry.getValue() );
  216. }
  217. return rubyHash;
  218. }
  219. // ------------------------------------------------------------------------
  220. protected static <R> R withinContext(Ruby ruby, Callable<R> block) {
  221. WeakReference<ClassLoader> weakRef = jrubyClassLoaders.get(ruby);
  222. ClassLoader jrubyClassLoader = weakRef == null ? null : weakRef.get();
  223. if (jrubyClassLoader == null) {
  224. synchronized(jrubyClassLoaders) {
  225. jrubyClassLoader = ruby.getJRubyClassLoader();
  226. jrubyClassLoaders.put(ruby, new WeakReference<ClassLoader>(jrubyClassLoader));
  227. }
  228. }
  229. ClassLoader originalCl = Thread.currentThread().getContextClassLoader();
  230. try {
  231. Thread.currentThread().setContextClassLoader(jrubyClassLoader);
  232. return block.call();
  233. } catch (RuntimeException e) {
  234. throw e;
  235. } catch (Exception e) {
  236. throw new RuntimeException(e);
  237. } finally {
  238. Thread.currentThread().setContextClassLoader(originalCl);
  239. }
  240. }
  241. private static final WeakHashMap<Ruby, WeakReference<ClassLoader>> jrubyClassLoaders = new WeakHashMap<Ruby, WeakReference<ClassLoader>>();
  242. private static final Logger log = Logger.getLogger( "org.torquebox.core.runtime" );
  243. private static final Object[] EMPTY_OBJECT_ARRAY = new Object[] {};
  244. }