Skip to content

Commit

Permalink
fix #53: Allow to use jruby-rack in embedded environments
Browse files Browse the repository at this point in the history
Signed-off-by: David Calavera <david.calavera@gmail.com>
  • Loading branch information
nicobrevin authored and calavera committed Sep 14, 2011
1 parent ec660bb commit 9d2899c
Show file tree
Hide file tree
Showing 28 changed files with 814 additions and 367 deletions.
52 changes: 52 additions & 0 deletions src/main/java/org/jruby/rack/AbstractFilter.java
@@ -0,0 +1,52 @@
package org.jruby.rack;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.jruby.rack.servlet.ServletRackEnvironment;
import org.jruby.rack.servlet.ServletRackResponseEnvironment;

public abstract class AbstractFilter implements Filter {

public final void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {

HttpServletRequest httpReq = (HttpServletRequest) req;
HttpServletResponse httpResp = (HttpServletResponse) resp;

RackEnvironment env = new ServletRackEnvironment(httpReq, httpResp, getContext());
RackResponseEnvironment respEnv = new ServletRackResponseEnvironment(httpResp);

if (isDoDispatch(httpReq, httpResp, chain, env, respEnv)) {
getDispatcher().process(env, respEnv);
}

}

/**
* Some filters may want to by-pass the rack application. By default, all
* requests are given to the {@link RackDispatcher}, but you can extend
* this method and return false if you want to signal that you don't want
* the {@link RackDispatcher} to see the request.
* @return true if the dispatcher should handle the request, false if it
* shouldn't.
* @throws IOException
* @throws ServletException
*/
protected boolean isDoDispatch(HttpServletRequest req, HttpServletResponse resp,
FilterChain chain, RackEnvironment env, RackResponseEnvironment respEnv) throws IOException, ServletException {
return true;
}

protected abstract RackContext getContext();
protected abstract RackDispatcher getDispatcher();

}
54 changes: 54 additions & 0 deletions src/main/java/org/jruby/rack/AbstractRackDispatcher.java
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2010-2011 Engine Yard, Inc.
* Copyright (c) 2007-2009 Sun Microsystems, Inc.
* This source code is available under the MIT license.
* See the file LICENSE.txt for details.
*/

package org.jruby.rack;

import java.io.IOException;

/**
*
* @author nicksieger
*/
public abstract class AbstractRackDispatcher implements RackDispatcher {
private RackContext context;

public AbstractRackDispatcher(RackContext rackContext) {
this.context = rackContext;
}

public void process(RackEnvironment request, RackResponseEnvironment response)
throws IOException {

RackApplication app = null;
try {
app = getApplication(this.context);
app.call(request).respond(response);
} catch (Exception re) {
handleException(re, request, response);
} finally {
this.afterProcess(app);
}
}

private void handleException(Exception re, RackEnvironment request,
RackResponseEnvironment response)
throws IOException {
if (response.isCommitted()) {
context.log("Error: Couldn't handle error: response committed", re);
return;
}
response.reset();
context.log("Application Error", re);

afterException(request, re, response);
}

abstract protected void afterProcess(RackApplication app) throws IOException;
abstract protected RackApplication getApplication(RackContext context) throws RackInitializationException;
protected abstract void afterException(RackEnvironment request, Exception re,
RackResponseEnvironment response) throws IOException;
}
53 changes: 53 additions & 0 deletions src/main/java/org/jruby/rack/AbstractServlet.java
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2010-2011 Engine Yard, Inc.
* Copyright (c) 2007-2009 Sun Microsystems, Inc.
* This source code is available under the MIT license.
* See the file LICENSE.txt for details.
*/

package org.jruby.rack;

import org.jruby.rack.servlet.ServletRackEnvironment;
import org.jruby.rack.servlet.ServletRackResponseEnvironment;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
*
* @author nicksieger
*/
public abstract class AbstractServlet extends HttpServlet {

/** Default ctor, used by servlet container */
public AbstractServlet() {
}

@Override
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
getDispatcher().process(new ServletRackEnvironment((HttpServletRequest) request, (HttpServletResponse) response, getContext()),
new ServletRackResponseEnvironment(response));
}

@Override
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException {
service((HttpServletRequest) request, (HttpServletResponse) response);
}

@Override
public void destroy() {
super.destroy();
getDispatcher().destroy();
}

protected abstract RackDispatcher getDispatcher();
protected abstract RackContext getContext();
}
4 changes: 4 additions & 0 deletions src/main/java/org/jruby/rack/DefaultRackApplication.java
Expand Up @@ -29,6 +29,10 @@ public class DefaultRackApplication implements RackApplication {
public DefaultRackApplication() {
}

public DefaultRackApplication(IRubyObject application) {
this.application = application;
}

public RackResponse call(final RackEnvironment env) {
Ruby runtime = getRuntime();
try {
Expand Down
Expand Up @@ -11,6 +11,7 @@
import org.jruby.RubyInstanceConfig;
import org.jruby.exceptions.RaiseException;
import org.jruby.javasupport.JavaUtil;
import org.jruby.rack.servlet.ServletRackContext;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;

Expand All @@ -30,12 +31,12 @@
*/
public class DefaultRackApplicationFactory implements RackApplicationFactory {
private String rackupScript, rackupLocation;
private RackContext rackContext;
private ServletRackContext rackContext;
private RubyInstanceConfig defaultConfig;
private RackApplication errorApplication;

public void init(RackContext rackContext) {
this.rackContext = rackContext;
this.rackContext = (ServletRackContext) rackContext;
this.rackupScript = findRackupScript();
this.defaultConfig = createDefaultConfig();
rackContext.log(defaultConfig.getVersionString());
Expand Down
93 changes: 42 additions & 51 deletions src/main/java/org/jruby/rack/DefaultRackDispatcher.java
@@ -1,63 +1,54 @@
/*
* Copyright (c) 2010-2011 Engine Yard, Inc.
* Copyright (c) 2007-2009 Sun Microsystems, Inc.
* This source code is available under the MIT license.
* See the file LICENSE.txt for details.
*/

package org.jruby.rack;

import java.io.IOException;

import org.jruby.rack.servlet.ServletRackContext;

/**
* Dispatcher suited for use in a servlet container
* @author nick
*
* @author nicksieger
*/
public class DefaultRackDispatcher implements RackDispatcher {
private RackContext context;

public DefaultRackDispatcher(RackContext rackContext) {
this.context = rackContext;
public class DefaultRackDispatcher extends AbstractRackDispatcher {

private final ServletRackContext servletRackContext;

public DefaultRackDispatcher(RackContext rackContext) {
super(rackContext);
this.servletRackContext = (ServletRackContext) rackContext;
}

@Override
protected RackApplication getApplication(RackContext context) throws RackInitializationException {
return getRackFactory().getApplication();
}

@Override
protected void afterException(RackEnvironment request, Exception re,
RackResponseEnvironment response) throws IOException {
try {
RackApplication errorApp = getRackFactory().getErrorApplication();
request.setAttribute(RackEnvironment.EXCEPTION, re);
errorApp.call(request).respond(response);
} catch (Exception e) {
servletRackContext.log("Error: Couldn't handle error", e);
response.sendError(500);
}
}

public void process(RackEnvironment request, RackResponseEnvironment response)
throws IOException {
final RackApplicationFactory rackFactory = context.getRackFactory();
RackApplication app = null;
try {
app = rackFactory.getApplication();
app.call(request).respond(response);
} catch (Exception re) {
handleException(re, rackFactory, request, response);
} finally {
if (app != null) {
rackFactory.finishedWithApplication(app);
}
}
}

private void handleException(Exception re, RackApplicationFactory rackFactory,
RackEnvironment request, RackResponseEnvironment response)
throws IOException {
if (response.isCommitted()) {
context.log("Error: Couldn't handle error: response committed", re);
return;
}
response.reset();
context.log("Application Error", re);

try {
RackApplication errorApp = rackFactory.getErrorApplication();
request.setAttribute(RackEnvironment.EXCEPTION, re);
errorApp.call(request).respond(response);
} catch (Exception e) {
context.log("Error: Couldn't handle error", e);
response.sendError(500);
}
}
public void destroy() {
final RackApplicationFactory rackFactory = servletRackContext.getRackFactory();
rackFactory.destroy();
}

protected RackApplicationFactory getRackFactory() {
return servletRackContext.getRackFactory();
}

@Override
protected void afterProcess(RackApplication app) {
getRackFactory().finishedWithApplication(app);
}

public void destroy() {
final RackApplicationFactory rackFactory = context.getRackFactory();
rackFactory.destroy();
}
}

0 comments on commit 9d2899c

Please sign in to comment.