Forum: JRuby 100% AOT compiled jruby with spring

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
M Suresh (Guest)
on 2009-03-18 11:12
(Received via mailing list)
Hi,

I am trying to create a 100 % AOT jruby app integrated with
springframework.
I am using jruby-1.2.0.

For performance reasons our goal is to have the ruby app with all the
dependencies compiled into jar files with no access whatsoever to rb
files or jruby home.

Is this possible?

I tried it for a webapp to show the result of a simple query using
activerecord for the DB query. I compiled my spring controller in ruby
and the below ruby dependencies using jrubyc:

activerecord-2.3.2
activerecord-jdbc-adapter-0.9
activesupport-2.3.2
rubygems
lib/ruby/1.8

I am running into trouble when I use RubyGems to include
'activerecord-jdbc-adapter' which seems to be a problem in general with
AOT compilation of scripts using gems. The same example works fine if I
add a -Djruby.home=<ruby_home> to my tomcat startup script.
Otherwise I get the below error:

Could not find RubyGem activerecord-jdbc-adapter (>= 0)

Below are the detailed steps I followed. The spring configurations are
just integration details and the below can apply to a java app also:

File RubyTestController.rb (A Ruby Controller extending Spring's
Controller):

require 'java'

require 'rubygems'
gem 'activerecord-jdbc-adapter'
require 'jdbc_adapter'
require 'active_record'

class RubyTestController <
org.springframework.web.servlet.mvc.AbstractController
    def handleRequestInternal(request, response)
        op = response.getOutputStream();

    ActiveRecord::Base.establish_connection(
      :adapter => 'jdbc',
      :jndi => "java:comp/env/jdbc/ctb",
      :driver => "oracle.jdbc.driver.OracleDriver"
    );
    con = ActiveRecord::Base.connection();
    results = con.execute("select hotel_name from hotel_geography_vw
where hotel_id = 119526");
results.each do |row|
  column = row['hotel_name']
    op.println(column);
end
    ActiveRecord::Base.remove_connection();
    return nil;
    end
end

File RubyBeanFactory.java (Bean Factory creating above for Spring):


import javax.script.*;

public class RubyBeanFactory {
    public static Object createRubyBean(String className) throws
Exception {
      /**
       * Engine manager and engine will be instantiate only once at the
class level.  What I am doing below, is just for testing.
       */
      ScriptEngineManager m = new ScriptEngineManager();
      ScriptEngine rubyEngine = m.getEngineByName("jruby");

      Object data = null;
      /**
       * We can either call a ruby file, or give an ruby expression for
evaluation.
       */
      data = rubyEngine.eval("require '" + className + "'\n" + className
+ ".new()");
      return data;
    }
}

Deployment Steps:

1. Copy jruby.jar jruby-engine.jar tomcat's lib directory

2. Add spring and related jar's to console classpath:

export
CLASSPATH=/c/dev-depot/common/lib/commons-logging.jar:/c/installs/apache-tomcat-6.0.14/lib/servlet-api.jar:/c/installs/jruby-1.2.0/lib/jruby.jar:/c/dev-depot/common/lib/spring-webmvc.jar:/c/dev-depot/common/lib/spring-web.jar:/c/dev-depot/common/lib/spring-context.jar:/c/dev-depot/common/lib/spring-beans.jar:/c/dev-depot/common/lib/spring-core.jar:/c/installs/apache-tomcat-6.0.14/lib/jruby-engine.jar:.

3. Generate compiled_rbs.jar and copy to tomact's lib dir:

jrubyc RubyTestController.rb
javac RubyBeanFactory.java
jar cf compiled_rbs.jar RubyTestController.class RubyBeanFactory.class

4. Spring app-servlet.xml config (Also add a URL entry for ruby_test in
web.xml):

    <bean id="testController"
            class="RubyBeanFactory" factory-method="createRubyBean">
        <constructor-arg value="RubyTestController"/>
    </bean>

     <!-- URL mapping definitions -->
    <bean id="simpleUrlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="ruby_test">testController</prop>
            </props>
        </property>
    </bean>

5. Compile required ruby dependencies and add them to ruby_gems.jar:

cd jruby-1.2.0/lib/ruby/1.8
jrubyc .
jar cf ../ruby_gems.jar `find . -name '*.class'`

cd jruby-1.2.0/lib/ruby/site_ruby/1.8
jrubyc rubygems.rb rubygems
jar uf ../../ruby_gems.jar rubygems.class `find rubygems -name
'*.class'`

jruby -S gem install activerecord-jdbc-adapter
cd
jruby-1.2.0/lib/ruby/gems/1.8/gems/activerecord-jdbc-adapter-0.9.1/lib
jrubyc .
jar uf ../../../../../ruby_gems.jar `find . -name '*.class'`

jruby -S gem install activerecord

cd jruby-1.2.0/lib/ruby/gems/1.8/gems/activerecord-2.3.2/lib
jrubyc .
jar uf ../../../../../ruby_gems.jar `find . -name '*.class'`

cd jruby-1.2.0/lib/ruby/gems/1.8/gems/activesupport-2.3.2/lib
jrubyc .
jar uf ../../../../../ruby_gems.jar `find . -name '*.class'`

6. Copy ruby_gems.jar to tomcat lib directory and start tomcat.

I get the below error:

2009-03-18 14:31:39,348 ERROR
[org.springframework.web.servlet.DispatcherServlet] - <Context
initialization failed>
org.springframework.beans.factory.BeanCreationException: Error creating
bean with name 'testController' defined in ServletContext resource
[/WEB-INF/hotel-servlet.xml]: Instantiation of bean failed; nested
exception is
org.springframework.beans.factory.BeanDefinitionStoreException: Factory
method [public static java.lang.Object
RubyBeanFactory.createRubyBean(java.lang.String) throws
java.lang.Exception] threw exception; nested exception is
javax.script.ScriptException: org.jruby.exceptions.RaiseException: Could
not find RubyGem activerecord-jdbc-adapter (>= 0)

  at
org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:413)
  at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:833)
  at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:747)
  at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:412)
  at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:383)
  at java.security.AccessController.doPrivileged(Native Method)
  at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:353)
  at
org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:245)
  at
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:169)
  at
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:242)
  at
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
  at
org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:400)
  at
org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:736)
  at
org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:369)
  at
org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:332)
  at
org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:266)
  at
org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:236)
  at
org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:126)
  at javax.servlet.GenericServlet.init(GenericServlet.java:212)
  at
org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1161)
  at
org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:981)
  at
org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4045)
  at
org.apache.catalina.core.StandardContext.start(StandardContext.java:4351)
  at
org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
  at
org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
  at
org.apache.catalina.core.StandardHost.addChild(StandardHost.java:525)
  at
org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:825)
  at
org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:714)
  at
org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:490)
  at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1138)
  at
org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:311)
  at
org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
  at
org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
  at org.apache.catalina.core.StandardHost.start(StandardHost.java:719)
  at
org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
  at
org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
  at
org.apache.catalina.core.StandardService.start(StandardService.java:516)
  at
org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
  at org.apache.catalina.startup.Catalina.start(Catalina.java:566)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
  at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
  at java.lang.reflect.Method.invoke(Method.java:597)
  at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288)
  at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)
Caused by:
org.springframework.beans.factory.BeanDefinitionStoreException: Factory
method [public static java.lang.Object
RubyBeanFactory.createRubyBean(java.lang.String) throws
java.lang.Exception] threw exception; nested exception is
javax.script.ScriptException: org.jruby.exceptions.RaiseException: Could
not find RubyGem activerecord-jdbc-adapter (>= 0)

  at
org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:127)
  at
org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:404)
  ... 44 more
Caused by: javax.script.ScriptException:
org.jruby.exceptions.RaiseException: Could not find RubyGem
activerecord-jdbc-adapter (>= 0)

  at
com.sun.script.jruby.JRubyScriptEngine.evalNode(JRubyScriptEngine.java:498)
  at
com.sun.script.jruby.JRubyScriptEngine.eval(JRubyScriptEngine.java:182)
  at
javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:247)
  at RubyBeanFactory.createRubyBean(RubyBeanFactory.java:15)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
  at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
  at java.lang.reflect.Method.invoke(Method.java:597)
  at
org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:115)
  ... 45 more
Caused by: org.jruby.exceptions.RaiseException: Could not find RubyGem
activerecord-jdbc-adapter (>= 0)

  at Kernel.raise(./rubygems.rb:636)
  at #<Class:01x1ceae51>.report_activate_error(./rubygems.rb:141)
  at #<Class:01x1ceae51>.activate(./rubygems.rb:49)
  at Kernel.gem(RubyTestController.rb:4)
  at Kernel.require(<unknown>:1)
  at (unknown).(unknown)(:1)

Tbanks,
Suresh


--
Be Yourself @ mail.com!
Choose From 200+ Email Addresses
Get a Free Account at www.mail.com


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email
Charles Oliver N. (Guest)
on 2009-03-21 20:21
(Received via mailing list)
I think there's a few others here who have precompiled all of Rails and
gotten applications to work, but it's a little tricky. Rails tends to
use a lot of filesystem APIs for loading things, so in some cases I
believe you have to patch around that.

Anyone else doing precompilation of Rails core for an application?

M Suresh wrote:
>
>
>
>     results = con.execute("select hotel_name from hotel_geography_vw where hotel_id = 
119526");
>
>
>
> jar cf compiled_rbs.jar RubyTestController.class RubyBeanFactory.class
>         <property name="mappings">
> jar cf ../ruby_gems.jar `find . -name '*.class'`
> jruby -S gem install activerecord
>
>   at java.security.AccessController.doPrivileged(Native Method)
>   at 
org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:236)
>   at org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:714)
>   at org.apache.catalina.startup.Catalina.start(Catalina.java:566)
>   ... 44 more
>   at 
org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:115)
> Tbanks,
> Suresh
>
>


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email
This topic is locked and can not be replied to.