FileDocCategorySizeDatePackage
JniHandler.javaAPI DocApache Tomcat 6.0.149897Fri Jul 20 04:20:36 BST 2007org.apache.jk.common

JniHandler

public class JniHandler extends org.apache.jk.core.JkHandler
Base class for components using native code ( libjkjni.so ). It allows to access the jk_env and wrap ( 'box' ? ) a native jk component, and call it's methods. Note that get/setAttribute are expensive ( Strings, etc ), invoke() is were all optimizations are done. We do recycle all memory on both C and java sides ( the only exception is when we attempt pinning but the VM doesn't support it ). The low level optimizations from ByteBuffer, etc are used to reduce the overhead of passing strings.
author
Costin Manolache

Fields Summary
protected org.apache.jk.apr.AprImpl
apr
protected long
nativeJkHandlerP
protected String
jkHome
public static final int
JK_HANDLE_JNI_DISPATCH
public static final int
JK_HANDLE_SHM_DISPATCH
public static final int
MSG_NOTE
public static final int
MB_NOTE
private boolean
paused
private static org.apache.juli.logging.Log
log
Constructors Summary
public JniHandler()



      
    
Methods Summary
public voidappendString(org.apache.jk.core.Msg msg, java.lang.String s, org.apache.tomcat.util.buf.C2BConverter charsetDecoder)

        ByteChunk bc=charsetDecoder.getByteChunk();
        charsetDecoder.recycle();
        charsetDecoder.convert( s );
        charsetDecoder.flushBuffer();
        msg.appendByteChunk( bc );
    
public org.apache.jk.core.MsgContextcreateMsgContext()
Create a msg context to be used with the shm channel

        if( nativeJkHandlerP==0 || apr==null  )
            return null;

        synchronized(this) {
            try{ 
                while(paused) {
                    wait();
                }
            }catch(InterruptedException ie) {
                // Ignore, since it can't happen
            }
        }

        try {
            MsgContext msgCtx=new MsgContext();
            MsgAjp msg=new MsgAjp();

            msgCtx.setSource( (JkChannel)this );
            msgCtx.setWorkerEnv( wEnv );

            msgCtx.setNext( this );

            msgCtx.setMsg( MSG_NOTE, msg); // XXX Use noteId

            C2BConverter c2b=new C2BConverter(  "iso-8859-1" );
            msgCtx.setConverter( c2b );

            MessageBytes tmpMB= MessageBytes.newInstance();
            msgCtx.setNote( MB_NOTE, tmpMB );
            return msgCtx;
        } catch( Exception ex ) {
            log.error("Can't create endpoint", ex);
            return null;
        }
    
public voiddestroyJkComponent()

        if( apr==null ) return;

        if( nativeJkHandlerP == 0 ) {
            log.error( "Unitialized component " );
            return;
        }

        long xEnv=apr.getJkEnv();

        apr.jkDestroy( xEnv, nativeJkHandlerP );

        apr.releaseJkEnv( xEnv );
    
public java.lang.StringgetJkHome()

        return jkHome;
    
public voidinit()
You must call initNative() inside the component init()

        // static field init, temp
    
public voidinitJkComponent()

        if( apr==null ) return;

        if( nativeJkHandlerP == 0 ) {
            log.error( "Unitialized component " );
            return;
        }

        long xEnv=apr.getJkEnv();

        apr.jkInit( xEnv, nativeJkHandlerP );

        apr.releaseJkEnv( xEnv );
    
protected voidinitNative(java.lang.String nativeComponentName)

        apr=(AprImpl)wEnv.getHandler("apr");
        if( apr==null ) {
            // In most cases we can just load it automatically.
            // that requires all libs to be installed in standard places
            // ( LD_LIBRARY_PATH, /usr/lib
            try {
                apr=new AprImpl();
                wEnv.addHandler("apr", apr);
                apr.init();
                if( oname != null ) {
                    ObjectName aprname=new ObjectName(oname.getDomain() +
                            ":type=JkHandler, name=apr");
                    Registry.getRegistry(null, null).registerComponent(apr, aprname, null);
                }
            } catch( Throwable t ) {
                log.debug("Can't load apr", t);
                apr=null;
            }
        }
        if( apr==null || ! apr.isLoaded() ) {
            if( log.isDebugEnabled() )
                log.debug("No apr, disabling jni proxy ");
            apr=null;
            return;
        }

        try {
            long xEnv=apr.getJkEnv();
            nativeJkHandlerP=apr.getJkHandler(xEnv, nativeComponentName );
            
            if( nativeJkHandlerP==0 ) {
                log.debug("Component not found, creating it " + nativeComponentName );
                nativeJkHandlerP=apr.createJkHandler(xEnv, nativeComponentName);
            }
            log.debug("Native proxy " + nativeJkHandlerP );
            apr.releaseJkEnv(xEnv);
        } catch( Throwable t ) {
            apr=null;
            log.info("Error calling apr ", t);
        }
   
public intinvoke(org.apache.jk.core.Msg msg, org.apache.jk.core.MsgContext ep)
Base implementation for invoke. Dispatch the action to the native code, where invoke() is called on the wrapped jk_bean.

        long xEnv=ep.getJniEnv();
        int type=ep.getType();

        int status=nativeDispatch(msg, ep, type, 0 );

        apr.jkRecycle(xEnv, ep.getJniContext());
        apr.releaseJkEnv( xEnv );
        return status;
    
protected intnativeDispatch(org.apache.jk.core.Msg msg, org.apache.jk.core.MsgContext ep, int code, int raw)
send and get the response in the same buffer. This calls the method on the wrapped jk_bean object.

        if( log.isDebugEnabled() )
            log.debug( "Sending packet " + code + " " + raw);

        if( raw == 0 ) {
            msg.end();

            if( log.isTraceEnabled() ) msg.dump("OUT:" );
        }

        // Create ( or reuse ) the jk_endpoint ( the native pair of
        // MsgContext )
        long xEnv=ep.getJniEnv();
        long nativeContext=ep.getJniContext();
        if( nativeContext==0 || xEnv==0 ) {
            setNativeEndpoint( ep );
            xEnv=ep.getJniEnv();
            nativeContext=ep.getJniContext();
        }

        if( xEnv==0 || nativeContext==0 || nativeJkHandlerP==0 ) {
            log.error("invokeNative: Null pointer ");
            return -1;
        }

        // Will process the message in the current thread.
        // No wait needed to receive the response, if any
        int status=AprImpl.jkInvoke( xEnv,
                                 nativeJkHandlerP,
                                 nativeContext,
                                 code, msg.getBuffer(), 0, msg.getLen(), raw );

        if( status != 0 && status != 2 ) {
            log.error( "nativeDispatch: error " + status, new Throwable() );
        }

        if( log.isDebugEnabled() ) log.debug( "Sending packet - done " + status);
        return status;
    
public voidpause()

        synchronized(this) {
            paused = true;
        }
    
protected voidrecycleNative(org.apache.jk.core.MsgContext ep)

        apr.jkRecycle(ep.getJniEnv(), ep.getJniContext());
    
public voidresume()

        synchronized(this) {
            paused = false;
            notifyAll();
        }
    
public voidsetJkHome(java.lang.String s)

        jkHome=s;
    
public voidsetNativeAttribute(java.lang.String name, java.lang.String val)

        if( apr==null ) return;

        if( nativeJkHandlerP == 0 ) {
            log.error( "Unitialized component " + name+ " " + val );
            return;
        }

        long xEnv=apr.getJkEnv();

        apr.jkSetAttribute( xEnv, nativeJkHandlerP, name, val );

        apr.releaseJkEnv( xEnv );
    
protected voidsetNativeEndpoint(org.apache.jk.core.MsgContext msgCtx)

        long xEnv=apr.getJkEnv();
        msgCtx.setJniEnv( xEnv );

        long epP=apr.createJkHandler(xEnv, "endpoint");
        log.debug("create ep " + epP );
        if( epP == 0 ) return;
        apr.jkInit( xEnv, epP );
        msgCtx.setJniContext( epP );