All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.grizzly.jruby.RubyAdapter Maven / Gradle / Ivy

package com.sun.grizzly.jruby;

import com.sun.grizzly.http.SelectorThread;
import com.sun.grizzly.pool.PoolAdapter;
import org.jruby.Ruby;
import org.jruby.RubyInstanceConfig;
import org.jruby.javasupport.JavaEmbedUtils;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.load.LoadService;
import org.jruby.util.ClassCache;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;


/**
 * An implementation of PoolAdapter to distribute JRuby runtimes.
 */
public class RubyAdapter implements PoolAdapter {

    // The root of Rail's directory structure, containing app, config, db, etc.
    private final String railsRoot;
    /**
     * JRUBY_LIB directory
     */
    private final String jrubyLib;

    public RubyAdapter(String railsRoot, String jrubyLib) {
        this.railsRoot = railsRoot;

        this.jrubyLib = jrubyLib;
    }

    /**
     * Creates a new Ruby runtime with Rails loaded into it
     * @return  the fully-initialized Ruby app with Rails running on it
     */
    public Ruby initializeObject() {
        ArrayList libs = new ArrayList();
        libs.add("META-INF/jruby.home/lib/ruby/site_ruby/1.8");
        ClassCache cache = new ClassCache(RubyAdapter.class.getClassLoader()); // All of these methods are JRuby helper methods
        RubyInstanceConfig config = new RubyInstanceConfig();
        File rdebugScript = configureRDebug(config);
        config.setLoader(RubyAdapter.class.getClassLoader());
        config.setClassCache(cache);
        org.jruby.Ruby runtime = JavaEmbedUtils.initialize(libs, config);
        return setupRails(runtime, rdebugScript);
    }

    /**
     * Asks Ruby to do whatever cleanup is required to shut down cleanly
     * @param dead the Ruby runtime to be shut down
     */
    public void dispose(Ruby dead) {
        dead.tearDown();
    }

    /**
     * Required method from PoolAdapter. Ruby runtimes can't be validated, so we always return true and rely on not doing stupid things like sharing Rails instances across applications
     * In general, validation should not be enabled for JRuby runtimes
     * @param toCheck the Ruby runtime to validate
     * @return true
     */
    public boolean validate(Ruby toCheck) {
        return true;
    }

    /**
     * Starts Rails on a JRuby runtime.
     * @param runtime The runtime to start Rails on
     * @param rdebugScript optional debugging script, null otherwise
     * @return the Ruby that was passed in, with Rails started on it
     */
    private Ruby setupRails(org.jruby.Ruby runtime, File rdebugScript) {
        LoadService loadService = runtime.getLoadService();

        if (rdebugScript != null) {
            // synchronize io is optional
            String iosynch = System.getProperty("glassfish.rdebug.iosynch");
            if (iosynch != null && iosynch.length() > 0 && new File(iosynch).exists()) {
                SelectorThread.logger().log(Level.FINEST,
                        "rdebug io synchronized by " + new File(iosynch).getAbsolutePath());
                loadService.require(iosynch);
            }

            try {
                // Run the ruby code in the rdebug script
                SelectorThread.logger().log(Level.FINEST, "Initializing rdebug...");
                runtime.runFromMain(
                        new java.io.BufferedInputStream(new FileInputStream(rdebugScript)),
                        rdebugScript.getAbsolutePath());
                SelectorThread.logger().log(Level.FINE, "rdebug started for " + railsRoot);
            } catch (Exception ex) {
                SelectorThread.logger().log(Level.SEVERE, ex.getLocalizedMessage(), ex);
            }
        } else {
            //set RAILS-ENV
            String railsEnv;
            if (System.getenv("RAILS_ENV") != null) {
                railsEnv = System.getenv("RAILS_ENV");
            } else {
                railsEnv = System.getProperty("rails-env") == null?System.getProperty("rails.env"):System.getProperty("rails-env");
                if(railsEnv == null){
                    railsEnv = (System.getProperty("jruby.rackEnv") == null) ? "development" : System.getProperty("jruby.rackEnv");
                }
            }
            runtime.evalScriptlet("ENV['RAILS_ENV'] = '" + railsEnv + "'");

            // load rails
            loadService.require(railsRoot + "/config/environment");
            loadService.require("dispatcher");
        }

        IRubyObject responder = (JavaEmbedUtils.newRuntimeAdapter()).eval(runtime, getDispatcherString());
        runtime.defineReadonlyVariable("$responder", responder);
        return runtime;
    }

    private File configureRDebug(RubyInstanceConfig config) {
        String rdebug = System.getProperty("glassfish.rdebug");
        File rdebugScript = null;
        if(rdebug != null && rdebug.length() > 0) {
            SelectorThread.logger().log(Level.FINER, "Enabling rdebug-ide for Grizzly/Rails.");
            rdebugScript = new File(rdebug);
            if(rdebugScript.exists()) {
                List args = new ArrayList();

                // version is optional
                String rdebugVersion = System.getProperty("glassfish.rdebug.version");
                if(rdebugVersion != null && rdebugVersion.length() > 0) {
                    args.add(rdebugVersion);
                }

                // port spec is required
                String debugPort = System.getProperty("glassfish.rdebug.port");
                if(debugPort != null && debugPort.length() > 0) {
                    args.add("-l");
                    args.add("-p");
                    args.add(debugPort);
                    if("true".equals(System.getProperty("glassfish.rdebug.verbose"))) {
                        args.add("-d");
                    }
                    args.add("--");

                    File script = null;
                    Writer writer = null;
                    try {
                        script = File.createTempFile("grizzly_jruby_debug_", ".rb");
                        script.deleteOnExit();
                        writer = new FileWriter(script);
                        writer.write(
                                "#!/usr/bin/env jruby\n" +
                                        "#\n" +
                                        "# Launch script for Grizzly/JRuby connector when debugging Rails apps\n" +
                                        "# on GlassFish V3.\n" +
                                        "#\n" +
                                        "require \"" + railsRoot.replace("\\", "/") + "/config/environment\"\n" +
                                        "require \"dispatcher\"\n"
                        );
                        writer.flush();
                        args.add(script.getAbsolutePath());
                        config.setArgv(args.toArray(new String [args.size()]));
                    } catch(IOException ex) {
                        SelectorThread.logger().log(Level.SEVERE,
                                "Error writing Rails launch script for rdebug.", ex);
                        rdebugScript = null;
                    } finally {
                        if(writer != null) {
                            try {
                                writer.close();
                            } catch(IOException ex) {
                                SelectorThread.logger().log(Level.SEVERE,
                                        "Exception closing " + script.getAbsolutePath(), ex);
                            }
                        }
                    }
                } else {
                    SelectorThread.logger().log(Level.SEVERE,
                            "glassfish.rdebug.port undefined.  Disabling rdebug.");
                    rdebugScript = null;
                }
            } else {
                SelectorThread.logger().log(Level.SEVERE,
                        "rdebug-ide script " + rdebugScript.getAbsolutePath() +
                                " does not exist.  Disabling rdebug");
                rdebugScript = null;
            }
        }

        return rdebugScript;
    }

    public String getJrubyLib() {
        return jrubyLib;
    }

    private String getDispatcherString() {
        String str;
        StringBuffer completeText = new StringBuffer();
        try {
            InputStream is = getClass().getResourceAsStream("/dispatch.rb");
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            str = br.readLine();
            while (str != null) {
                completeText.append(str);
                completeText.append("\n");
                str = br.readLine();
            }
        } catch (Exception e) {
            SelectorThread.logger().log(Level.WARNING, Messages.format(Messages.DISPATCH_STR_ERROR), e);
        }

        return completeText.toString();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy