io.airlift.rack.RackServlet Maven / Gradle / Ivy
/*
* Copyright 2010 Proofpoint, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.airlift.rack;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.io.Resources;
import org.jruby.Ruby;
import org.jruby.RubyHash;
import org.jruby.RubyInstanceConfig;
import org.jruby.RubyObjectAdapter;
import org.jruby.javasupport.JavaEmbedUtils;
import org.jruby.runtime.builtin.IRubyObject;
import javax.inject.Inject;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import static org.jruby.javasupport.JavaEmbedUtils.javaToRuby;
public class RackServlet
implements Servlet
{
private final IRubyObject rackApplication;
private final Ruby runtime;
private final RubyObjectAdapter adapter = JavaEmbedUtils.newObjectAdapter();
//Servlet config to support the convention of getServletConfig/init
private ServletConfig servletConfig = null;
@Inject
public RackServlet(RackServletConfig config)
throws IOException
{
Preconditions.checkNotNull(config);
File rackScriptFile = new File(config.getRackConfigPath());
Preconditions.checkArgument(rackScriptFile.canRead(), "Could not find rack script specified by [" + config.getRackConfigPath()
+ "] and resolved to [" + rackScriptFile.getAbsolutePath() + "]");
runtime = JavaEmbedUtils.initialize(ImmutableList.of(rackScriptFile.getParentFile().getCanonicalPath()), createRuntimeConfig());
// don't inherit system settings for gems
RubyHash env = runtime.evalScriptlet("ENV").convertToHash();
env.remove("GEM_HOME");
env.remove("GEM_PATH");
InputStream stream = Resources.getResource("io/airlift/rack.rb").openStream();
try {
runtime.loadFile("rack.rb", stream, false);
}
finally {
stream.close();
}
IRubyObject builder = runtime.evalScriptlet("Airlift::RackServer::Builder.new");
rackApplication = adapter.callMethod(builder, "build", new IRubyObject[] {
javaToRuby(runtime, rackScriptFile.getCanonicalPath())
});
}
private RubyInstanceConfig createRuntimeConfig()
{
RubyInstanceConfig config = new RubyInstanceConfig();
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = ClassLoader.getSystemClassLoader();
}
config.setClassCache(JavaEmbedUtils.createClassCache(classLoader));
URL resource = RubyInstanceConfig.class.getResource("/META-INF/jruby.home");
if (resource != null && resource.getProtocol().equals("jar")) {
try { // http://weblogs.java.net/blog/2007/04/25/how-convert-javaneturl-javaiofile
config.setJRubyHome(resource.toURI().getSchemeSpecificPart());
}
catch (URISyntaxException e) {
config.setJRubyHome(resource.getPath());
}
}
return config;
}
@Override
public void init(ServletConfig servletConfig)
throws ServletException
{
this.servletConfig = servletConfig;
}
@Override
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException
{
Preconditions.checkNotNull(request);
Preconditions.checkNotNull(response);
Preconditions.checkArgument((request instanceof HttpServletRequest), "Expected a servlet request that implements HttpServletRequest, this servlet only supports Http(s)");
Preconditions.checkArgument((response instanceof HttpServletResponse), "Expected a servlet response that implements HttpServletResponse, this servlet only supports Http(s)");
adapter.callMethod(rackApplication, "call",
new IRubyObject[] {
javaToRuby(runtime, request),
javaToRuby(runtime, response)
});
}
@Override
public ServletConfig getServletConfig()
{
return servletConfig;
}
@Override
public String getServletInfo()
{
return "RackServlet, a servlet for running rack applications. Copyright 2010 Proofpoint, Inc.";
}
@Override
public void destroy()
{
}
}