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

com.sun.grizzly.jruby.rack.RackApplicationChooser Maven / Gradle / Ivy

package com.sun.grizzly.jruby.rack;


import com.sun.grizzly.http.SelectorThread;
import com.sun.grizzly.jruby.RailsAdapter;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.logging.Logger;

/**
 * @author Jacob Kessler
 * Attempts to determine the RackApplicationFactory most suited to handle
 * the given application directory
 */
public class RackApplicationChooser {
    public static RackAdapter getFactory(String appPath, RailsAdapter adapter) {
        Logger theLog = adapter.getLogger();
        String appType = System.getProperty("jruby.applicationType");
        RackAdapter rack;
        if (appType != null) {
            rack = handleUserSpecifiedFramework(adapter, appPath, appType, theLog);
            if (rack != null) {
                return rack;
            } else {
                rack = handleUserSpecifiedStartupScript(appType, adapter, theLog);
                if (rack != null) {
                    return rack;
                }
            }
        }
        // User has not overridden the detection process
        if (appPath.endsWith(".rb")) {
            File appFile = new File(appPath);
            rack = detectSinatra(appFile, theLog, adapter);
            if (rack != null) {
                return rack;
            }
        }
        theLog.fine("Path is " + appPath + ", checking for Rails");
        rack = detectRails(appPath, theLog, adapter);
        if (rack != null) {
            return rack;
        }
        theLog.fine("Rails not found, checking for Merb");
        rack = detectMerb(appPath, theLog, adapter);
        if (rack != null) {
            return rack;
        }
        // Other frameworks go here
        theLog.fine("Merb not found, checking for Sinatra");
        rack = findSinatra(appPath, theLog, adapter);
        if (rack != null) {
            return rack;
        }
        // Check for a launch script
        theLog.info("Unable to find a supported framework! Checking for .ru files");
        String rackUp = findRackup(appPath);
        if (rackUp != null) {
            theLog.info("Discovered a .ru file, attempting to launch a framework from that.");
            rack = handleUserSpecifiedStartupScript (rackUp, adapter, theLog);
            if (rack != null) {
                return rack;
            }
        }
        // No framework found
        SelectorThread.logger().severe("Framework autodetection failed! Please set -Djruby.rackup_script to the path to a script that will start your framework");
        throw new IllegalStateException("No framework to start!");
    }

    private static String inhale (File f, Logger theLog) {
        String app = "";
        if (f.exists()) {
            try {
                BufferedReader in = new BufferedReader(new FileReader(f));
                String s;
                while ((s = in.readLine()) != null) {
                    // read the file
                    app = app + s + "\n";
                }
            } catch (IOException e) {
                theLog.severe("IO Exception determining framework for " + f.getAbsolutePath() + ": " + e);
            }
        } else {
            theLog.severe("Was told to read nonexistant file " + f.getAbsolutePath());
        }
        return app;
    }

    private static RackAdapter findSinatra (String appPath, Logger theLog, RailsAdapter adapter) {
        File appDir = new File(appPath);
        if (appDir.isDirectory()) {
            File[] files = appDir.listFiles();
            RackAdapter rack;
            for (File file : files) {
                if (file.getAbsolutePath().endsWith(".rb")) {
                    theLog.fine("Checking " + file.getName());
                    // Check for require. This is expensive and we don't want to.

                    rack = detectSinatra(file, theLog, adapter);
                    if (rack != null) {
                        theLog.fine("Found Sinatra in " + file.getAbsolutePath());
                        return rack;
                    }

                }
            }
        }
        return null;
    }
    private static String findRackup (String appPath) {
        File appDir = new File(appPath);
        if (appDir.isDirectory()) {
            File[] files = appDir.listFiles();
            for (File file : files) {
                if (file.getAbsolutePath().endsWith(".ru")) {
                    return file.getPath();
                }
            }
        }
        return null;
    }

    private static RackAdapter handleUserSpecifiedFramework(RailsAdapter adapter, String appPath, String appType, Logger theLog) {
        // User has told us what to look for, so we don't need to guess
        if (appType.equalsIgnoreCase("rails")) {
            RackApplicationFactory myFactory = new RailsApplicationFactory(adapter);
            if (System.getProperty("jruby.MTsafe") != null && System.getProperty("jruby.MTsafe").equalsIgnoreCase("true")) {
                theLog.info("User has specified rails in threadsafe mode, initializing multithreaded rails");
                return new MultiThreadedRackAdapter(myFactory, adapter);
            } else {
                theLog.info("User has specified rails in non-threadsafe mode, initializing pooled rails");
                return new SingleThreadedRackAdapter(myFactory, adapter);
            }
        } else if (appType.equalsIgnoreCase("merb")) {
            theLog.info("User has specified merb, initializing merb");
            RackApplicationFactory myFactory = new MerbApplicationFactory(adapter);
            return new MultiThreadedRackAdapter(myFactory, adapter);
        } else if (appType.equalsIgnoreCase("sinatra")) {
            theLog.info("User has specified Sinatra, locating Sinatra file and initializing");
            if (appPath.endsWith(".rb")) {
                RackApplicationFactory myFactory = new SinatraApplicationFactory(adapter, appPath);
                return new MultiThreadedRackAdapter(myFactory, adapter);
            } else {
                RackAdapter sinatra = findSinatra(appPath, theLog, adapter); // Well, maybe we need to guess a little
                if (sinatra != null) {
                    theLog.info("Found Sinatra in " + sinatra + ", launching");
                    return sinatra;
                } else {
                    theLog.severe("User specified a Sinatra application, but no sinatra application was found in the deployment directory. Falling back to autodetection");
                }
            }
        } else {
            theLog.severe("Unknown framework specified as appType, falling back to autodetection");
        }
        return null;
    }

    private static RackAdapter handleUserSpecifiedStartupScript (String rackUp, RailsAdapter adapter, Logger theLog) {
        // User has specified a file to run.
        RackApplicationFactory myFactory = new GenericApplicationFactory(rackUp, adapter);
        if (System.getProperty("jruby.MTsafe") != null && System.getProperty("jruby.MTsafe").equalsIgnoreCase("true")) {
            theLog.info("Running a user-provided rackup script in thread-safe mode");
            return new MultiThreadedRackAdapter(myFactory, adapter);
        } else {
            theLog.info("Running a user-provided rackup script in pooled mode");
            return new SingleThreadedRackAdapter(myFactory, adapter);
        }
    }

    private static RackAdapter detectSinatra(File appFile, Logger theLog, RailsAdapter adapter) {
        // Sinatra may not have a rake file. Check if we were given a .rb file
            theLog.fine("attempting to detect sinatra in " + appFile.getPath());
            String app = inhale(appFile, theLog);
            if (app.contains("require 'sinatra'")) {
                RackApplicationFactory myFactory = new SinatraApplicationFactory(adapter, appFile.getPath());
                theLog.info("Detected Sinatra application");
                // Sinatra is thread-safe
                return new MultiThreadedRackAdapter(myFactory, adapter);
            }
        return null;
    }

    private static RackAdapter detectRails(String appPath, Logger theLog, RailsAdapter adapter) {
        File boot = new File(appPath, "config/boot.rb");
        if (boot.exists()) {
            String bootFile = inhale(boot, theLog);
            if (bootFile.contains("RAILS_ROOT")) {
                RackApplicationFactory myFactory = new RailsApplicationFactory(adapter);
                theLog.info("Detected Rails application");
                // Check rails thread safety
                boolean multithreaded = false;
                String environment = "";
                if (System.getProperty("rails.env") == null || "development".compareTo(System.getProperty("rails.env")) == 0) {
                    // Grab the development environment file
                    environment = inhale(new File(appPath+"/config/environments/development.rb"), theLog);
                } else if ("production".compareTo(System.getProperty("rails.env")) == 0) {
                    // if we are in production mode
                    environment = inhale(new File(appPath+"/config/environments/production.rb"), theLog);
                } else if ("testing".compareTo(System.getProperty("rails.env")) == 0) {
                    environment = inhale(new File(appPath+"/config/environments/testing.rb"), theLog);
                }
                if (environment.matches("(?s)(?m).*^[^#]*config\\.threadsafe!.*")) { // If there is a non-commented line with config.threadsafe! in it
                    multithreaded = true;
                }
                if (multithreaded) {
                    theLog.info("config.threadsafe sighted! All hands prepare for multithread mode!");
                    return new MultiThreadedRackAdapter(myFactory, adapter);
                } else {
                    theLog.info("Rails not in thread-safe mode, starting in single-thread mode");
                    return new SingleThreadedRackAdapter(myFactory, adapter);
                }
            }
        }
        return null;
    }
    private static RackAdapter detectMerb(String appPath, Logger theLog, RailsAdapter adapter) {
        File init = new File (appPath, "config/init.rb");
        if (!(init.exists())) {
            // Init can also be at root/init.rb
            init = new File (appPath, "root/init.rb");
            if (!(init.exists())) {
                // Still no init file: Not a standard merb app
                return null;
            }
        }
        // Thus, init exists
        String initFile = inhale(init, theLog);
        if (initFile.contains("Merb::Config")) {
            RackApplicationFactory myFactory = new MerbApplicationFactory(adapter);
            theLog.info("Detected merb application");
            // Merb is thread-safe
            return new MultiThreadedRackAdapter(myFactory, adapter);
        }
        return null;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy