Package com.github.kevwil.aspen

Source Code of com.github.kevwil.aspen.JRubyRackProxy

package com.github.kevwil.aspen;

import com.github.kevwil.aspen.domain.*;
import com.github.kevwil.aspen.exception.InvalidAppException;
import com.github.kevwil.aspen.exception.ServiceException;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jruby.*;
import org.jruby.runtime.*;
import org.jruby.runtime.builtin.IRubyObject;

import java.nio.charset.Charset;

/**
* @author kevwil
* @since Jan 05, 2011
*/
public class JRubyRackProxy
implements RackProxy
{
    private final IRubyObject _app;
    private static final Object _lock = new Object();

    public JRubyRackProxy( final IRubyObject app )
    {
        _app = app;
    }

    public Ruby getRuntime()
    {
        synchronized( _lock )
        {
            return _app.getRuntime();
        }
    }
   
    @Override
    public Response process( final Request request )
    {
        synchronized( _lock )
        {
            if( ! _app.respondsTo( "call" ) )
            {
                throw new InvalidAppException();
            }

            RubyHash env = request.getEnv().toRuby();
            IRubyObject[] args = { env };

            IRubyObject callResult = _app.callMethod( request.getRuntime().getCurrentContext(),
                                                           "call",
                                                           args,
                                                           Block.NULL_BLOCK );
            if( callResult.isNil() )
            {
                Response err = new Response( request );
                err.setException( new ServiceException( "'nil' was returned from the app" ) );
                return err;
            }
            if( callResult.getType().toString().equals( "Rack::File" ) )
            {
                RubyObject.puts( callResult.inspect() );
                // TODO: return a file-based response
                Response err = new Response( request );
                err.setException( new ServiceException( "body is a Rack::File - need to handle it differently" ) );
                return err;
            }
            try
            {
                RubyArray result = (RubyArray)callResult;
                return createResponse( request, result );
            }
            catch( Exception e )
            {
                Response err = new Response( request );
                err.setException( e );
                return err;
            }
        }
    }

    Response createResponse( final Request request, final RubyArray result )
    {
        Response r = new Response( request );
        if( result.size() != 3 )
        {
            r.setException( new ServiceException( "bad rack response: " + result.inspect().toString() ) );
            return r;
        }
        IRubyObject body = request.getRuntime().getNil();
        try
        {
            IRubyObject result1 = result.entry( 0 );
            if( result.isNil() )
            {
                r.setException( new ServiceException( "bad rack response, null status code: " + result.inspect().toString() ) );
                return r;
            }
            int codeInt = RubyInteger.num2int( result1 );
            if( codeInt < 100 )
            {
                r.setException( new ServiceException( "bad rack response, status code integer less than 100" ) );
                return r;
            }
            r.setResponseCode( codeInt );

            RubyHash headers = result.entry( 1 ).convertToHash();
            r.addHeaders( headers );

            body = result.entry( 2 );

            writeBodyToResponse( body, r );
            return r;
        }
        finally
        {
            if( body.respondsTo( "close" ) )
            {
                RubyUtil.call( "close", body );
            }
        }
    }

    void writeBodyToResponse( final IRubyObject body, final Response response )
    {
        if( !body.respondsTo( "each" ) )
        {
            throw new ServiceException( "response body does not respond to :each" );
        }
        ChannelBuffer bodyBuffer = RubyUtil.bodyToBuffer( body );
        response.setBody( bodyBuffer.toString( Charset.forName( "UTF-8" ) ) );
    }
}
TOP

Related Classes of com.github.kevwil.aspen.JRubyRackProxy

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.