package org.stokesdrift.container.jruby; import io.undertow.servlet.Servlets; import io.undertow.servlet.api.DeploymentInfo; import io.undertow.servlet.api.FilterInfo; import io.undertow.servlet.api.ListenerInfo; import java.io.File; import java.io.FileInputStream; import java.util.logging.Level; import java.util.logging.Logger; import javax.inject.Named; import javax.servlet.DispatcherType; import org.jruby.rack.RackFilter; import org.jruby.rack.util.IOHelpers; import org.stokesdrift.config.ApplicationConfig; import org.stokesdrift.container.Application; /** * Sets up the configuration for a rack application * * Jruby-Rack configs: * <ul> * <li>rackup: Rackup script for configuring how the Rack application is * mounted. Required for Rack-based applications other than Rails. Can be * omitted if a config.ru is included in the application root.</li> * <li>public.root: Relative path to the location of your application's static * assets. Defaults to /.</li> * <li>gem.path: Relative path to the bundled gem repository. Defaults to * /WEB-INF/gems.</li> * <li>jruby.compat.version: Set to "1.8" or "1.9" to make JRuby run a specific * version of Ruby (same as the --1.8 / --1.9 command line flags).</li> * <li>jruby.min.runtimes: For non-threadsafe Rails applications using a runtime * pool, specify an integer minimum number of runtimes to hold in the pool.</li> * <li>jruby.max.runtimes: For non-threadsafe Rails applications, an integer * maximum number of runtimes to keep in the pool.</li> * <li>jruby.runtime.init.threads: How many threads to use for initializing * application runtimes when pooling is used (default is 4). It does not make * sense to set this value higher than</li> * </ul> * * @author driedtoast * */ @Named(value = "rack_application") public class RackApplication implements Application { private static final String RACK_FILTER = "RackFilter"; private ApplicationConfig config; private static final Logger logger = Logger.getLogger(RackApplication.class.getName()); private String gemPathDirectory; @Override public DeploymentInfo getDeploymentInfo() { FilterInfo filter = Servlets.filter(RACK_FILTER, RackFilter.class); // TODO extend listener and setup the jruby env based on reloaded gems // and jars // Override appfactory? ListenerInfo listenerInfo = Servlets.listener(ServletContextListener.class); DeploymentInfo di = new DeploymentInfo().addListener(listenerInfo).setContextPath(config.getRootUrlPath()).addFilter(filter) .addFilterUrlMapping(RACK_FILTER, "/*", DispatcherType.REQUEST).setDeploymentName(config.getName()) .setClassLoader(ClassLoader.getSystemClassLoader()); setupInitParams(di); return di; } protected void setupInitParams(DeploymentInfo deployInfo) { deployInfo.addInitParameter("jruby.runtime.init.threads", "1"); deployInfo.addInitParameter("rackup", getRackupString()); deployInfo.addInitParameter("jruby.rack.debug.load", "true"); deployInfo.addInitParameter("jruby.rack.layout_class", "RailsFilesystemLayout"); deployInfo.addInitParameter("jruby.rack.logging.name", "jul"); deployInfo.addInitParameter("app.root", config.getRootPath()); } protected String getRackupString() { try { File file = new File(config.getRootPath() + File.separator + config.getAppFile()); FileInputStream fis = new FileInputStream(file); String script = IOHelpers.inputStreamToString(fis); StringBuilder withHeader = new StringBuilder(); withHeader.append("$:.unshift('").append(config.getRootPath()).append("/app')\n"); withHeader.append(script); script = withHeader.toString(); return script; } catch (Exception e) { logger.log(Level.SEVERE, "rack script not found", e); return null; } } @Override public void initializeConfig(ApplicationConfig config) { this.config = config; } }