Package com.commongroundpublishing.rubylet.jruby

Source Code of com.commongroundpublishing.rubylet.jruby.RubyFactory

package com.commongroundpublishing.rubylet.jruby;

import java.util.concurrent.atomic.AtomicInteger;

import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException;

import org.jruby.embed.ScriptingContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.commongroundpublishing.rubylet.Factory;
import com.commongroundpublishing.rubylet.config.IConfig;

import static com.commongroundpublishing.rubylet.Util.assertNotNull;

public final class RubyFactory implements Factory {
   
    private static final Logger logger = LoggerFactory.getLogger(RubyFactory.class);
   
    private RubyConfig config;
   
    private AtomicInteger refCount = new AtomicInteger(0);
   
    /**
     * The underlying ScriptingContainer (JRuby runtime)
     */
    private ScriptingContainer container;
   
    /**
     * RubyletHelper object for this container.
     */
    private Object helper;

    public void init(IConfig config) {
        this.config = new RubyConfig(config);
        initContainer();
    }

    public void destroy() {
        helper = null;
        logger.info("destroying JRuby runtime: {}", getContainer());
        getContainer().terminate();
        container = null;
    }
   
    private void initContainer() {
        container = makeContainer(getConfig());
        logger.info("new JRuby runtime: {}", container);
        container.runScriptlet("require 'rubylet_helper'");
        helper = container.runScriptlet("RubyletHelper.new");
        boot();
    }
   
    public RubyConfig getConfig() {
        return assertNotNull(this, config);
    }
   
    public Object getHelper() {
        return assertNotNull(this, helper);
    }
   
    public ScriptingContainer getContainer() {
        return assertNotNull(this, container);
    }
       
    public static ScriptingContainer makeContainer(RubyConfig config) {
        // Required global setting for when JRuby fakes up Kernel.system('ruby')
        // calls.
        // Since this is global, other JRuby servlets in this servlet container
        // are affected...
        //
        // TODO: move to a better location in the code?  remove?
        if (config.getJrubyHome() != null) {
            System.setProperty("jruby.home", config.getJrubyHome());
        }
       
        final ScriptingContainer container = new ScriptingContainer(config.getScope());
       
        container.setCompileMode(config.getCompileMode());
        if (config.getJrubyHome() != null) {
            container.setHomeDirectory(config.getJrubyHome());
        }
        container.setCompatVersion(config.getCompatVersion());
        container.setCurrentDirectory(config.getAppRoot());
        // don't propagate ENV to global JVM level
        container.getProvider().getRubyInstanceConfig().setUpdateNativeENVEnabled(false);
       
        logger.info("new ScriptingContainer scope={} compileMode={} jrubyHome={} compatVersion={}, pwd={}",
                    new Object[] {
                        config.getScope(),
                        config.getCompileMode(),
                        config.getJrubyHome(),
                        config.getCompatVersion(),
                        config.getAppRoot()
                     });
       
        return container;
    }

    public <T> T callHelper(String method, Object arg, Class<T> returnType) {
        return getContainer().callMethod(getHelper(), method, arg, returnType);
    }

    public <T> T callHelper(String method, Object[] args, Class<T> returnType) {
        return getContainer().callMethod(getHelper(), method, args, returnType);
    }

    public void boot() {
        callHelper("boot", getConfig(), Object.class);
    }
       
    public <T> T newInstance(String rubyClass, Class<T> returnType) {
        final T instance = callHelper("new_instance", rubyClass, returnType);
        logger.info("new {}: {}", returnType, instance);
        return instance;
    }
   
    /**
     * Make and initialize a new ruby Servlet within the ScriptingContainer.  The ruby
     * class and other options are taken from {@code servletConfig}.
     */
    public Servlet makeServlet(ServletConfig servletConfig) throws ServletException {
        final RubyConfig config = new RubyConfig(servletConfig);
        final Servlet servlet = newInstance(config.getServletClass(), Servlet.class);
        servlet.init(servletConfig);
        logger.info("initialized servlet: {}", servlet);
        return servlet;
    }
   
    public ServletContextListener makeListener(IConfig config) {
        return newInstance((new RubyConfig(config)).getListenerClass(),
                           ServletContextListener.class);
    }
   
    /**
     * No-op because this factory is not restartable.
     */
    public void checkRestart() {}
   
    public void reference(Object o) {
        refCount.incrementAndGet();
    }

    public void unreference(Object o) {
        if (refCount.decrementAndGet() <= 0) {
            destroy();
        }
    }

}
TOP

Related Classes of com.commongroundpublishing.rubylet.jruby.RubyFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.