KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > jk > common > JniHandler


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.jk.common;
18
19 import java.io.IOException JavaDoc;
20
21 import javax.management.ObjectName JavaDoc;
22
23 import org.apache.commons.modeler.Registry;
24 import org.apache.jk.apr.AprImpl;
25 import org.apache.jk.core.JkHandler;
26 import org.apache.jk.core.Msg;
27 import org.apache.jk.core.MsgContext;
28 import org.apache.jk.core.JkChannel;
29 import org.apache.tomcat.util.buf.ByteChunk;
30 import org.apache.tomcat.util.buf.C2BConverter;
31 import org.apache.tomcat.util.buf.MessageBytes;
32
33
34 /**
35  * Base class for components using native code ( libjkjni.so ).
36  * It allows to access the jk_env and wrap ( 'box' ? ) a native
37  * jk component, and call it's methods.
38  *
39  * Note that get/setAttribute are expensive ( Strings, etc ),
40  * invoke() is were all optimizations are done. We do recycle
41  * all memory on both C and java sides ( the only exception is
42  * when we attempt pinning but the VM doesn't support it ). The
43  * low level optimizations from ByteBuffer, etc are used to
44  * reduce the overhead of passing strings.
45  *
46  * @author Costin Manolache
47  */

48 public class JniHandler extends JkHandler {
49     protected AprImpl apr;
50
51     // The native side handler
52
protected long nativeJkHandlerP;
53
54     protected String JavaDoc jkHome;
55
56     // Dispatch table codes. Hardcoded for now, will change when we have more handlers.
57
public static final int JK_HANDLE_JNI_DISPATCH=0x15;
58     public static final int JK_HANDLE_SHM_DISPATCH=0x16;
59
60
61     public static final int MSG_NOTE=0;
62     public static final int C2B_NOTE=1;
63     public static final int MB_NOTE=2;
64     private boolean paused = false;
65
66
67     public JniHandler() {
68     }
69
70     /**
71      */

72     public void setJkHome( String JavaDoc s ) {
73         jkHome=s;
74     }
75
76     public String JavaDoc getJkHome() {
77         return jkHome;
78     }
79
80     /** You must call initNative() inside the component init()
81      */

82     public void init() throws IOException JavaDoc {
83         // static field init, temp
84
}
85
86     protected void initNative(String JavaDoc nativeComponentName) {
87         apr=(AprImpl)wEnv.getHandler("apr");
88         if( apr==null ) {
89             // In most cases we can just load it automatically.
90
// that requires all libs to be installed in standard places
91
// ( LD_LIBRARY_PATH, /usr/lib
92
try {
93                 apr=new AprImpl();
94                 wEnv.addHandler("apr", apr);
95                 apr.init();
96                 if( oname != null ) {
97                     ObjectName JavaDoc aprname=new ObjectName JavaDoc(oname.getDomain() +
98                             ":type=JkHandler, name=apr");
99                     Registry.getRegistry(null, null).registerComponent(apr, aprname, null);
100                 }
101             } catch( Throwable JavaDoc t ) {
102                 log.debug("Can't load apr", t);
103                 apr=null;
104             }
105         }
106         if( apr==null || ! apr.isLoaded() ) {
107             if( log.isDebugEnabled() )
108                 log.debug("No apr, disabling jni proxy ");
109             apr=null;
110             return;
111         }
112
113         try {
114             long xEnv=apr.getJkEnv();
115             nativeJkHandlerP=apr.getJkHandler(xEnv, nativeComponentName );
116             
117             if( nativeJkHandlerP==0 ) {
118                 log.debug("Component not found, creating it " + nativeComponentName );
119                 nativeJkHandlerP=apr.createJkHandler(xEnv, nativeComponentName);
120             }
121             log.debug("Native proxy " + nativeJkHandlerP );
122             apr.releaseJkEnv(xEnv);
123         } catch( Throwable JavaDoc t ) {
124             apr=null;
125             log.info("Error calling apr ", t);
126         }
127    }
128
129     public void appendString( Msg msg, String JavaDoc s, C2BConverter charsetDecoder)
130         throws IOException JavaDoc
131     {
132         ByteChunk bc=charsetDecoder.getByteChunk();
133         charsetDecoder.recycle();
134         charsetDecoder.convert( s );
135         charsetDecoder.flushBuffer();
136         msg.appendByteChunk( bc );
137     }
138
139     public void pause() throws Exception JavaDoc {
140         synchronized(this) {
141             paused = true;
142         }
143     }
144
145     public void resume() throws Exception JavaDoc {
146         synchronized(this) {
147             paused = false;
148             notifyAll();
149         }
150     }
151
152
153     /** Create a msg context to be used with the shm channel
154      */

155     public MsgContext createMsgContext() {
156         if( nativeJkHandlerP==0 || apr==null )
157             return null;
158
159         synchronized(this) {
160             try{
161                 while(paused) {
162                     wait();
163                 }
164             }catch(InterruptedException JavaDoc ie) {
165                 // Ignore, since it can't happen
166
}
167         }
168
169         try {
170             MsgContext msgCtx=new MsgContext();
171             MsgAjp msg=new MsgAjp();
172
173             msgCtx.setSource( (JkChannel)this );
174             msgCtx.setWorkerEnv( wEnv );
175
176             msgCtx.setNext( this );
177
178             msgCtx.setMsg( MSG_NOTE, msg); // XXX Use noteId
179

180             C2BConverter c2b=new C2BConverter( "iso-8859-1" );
181             msgCtx.setNote( C2B_NOTE, c2b );
182
183             MessageBytes tmpMB= MessageBytes.newInstance();
184             msgCtx.setNote( MB_NOTE, tmpMB );
185             return msgCtx;
186         } catch( Exception JavaDoc ex ) {
187             log.error("Can't create endpoint", ex);
188             return null;
189         }
190     }
191
192     public void setNativeAttribute(String JavaDoc name, String JavaDoc val) throws IOException JavaDoc {
193         if( apr==null ) return;
194
195         if( nativeJkHandlerP == 0 ) {
196             log.error( "Unitialized component " + name+ " " + val );
197             return;
198         }
199
200         long xEnv=apr.getJkEnv();
201
202         apr.jkSetAttribute( xEnv, nativeJkHandlerP, name, val );
203
204         apr.releaseJkEnv( xEnv );
205     }
206
207     public void initJkComponent() throws IOException JavaDoc {
208         if( apr==null ) return;
209
210         if( nativeJkHandlerP == 0 ) {
211             log.error( "Unitialized component " );
212             return;
213         }
214
215         long xEnv=apr.getJkEnv();
216
217         apr.jkInit( xEnv, nativeJkHandlerP );
218
219         apr.releaseJkEnv( xEnv );
220     }
221
222     public void destroyJkComponent() throws IOException JavaDoc {
223         if( apr==null ) return;
224
225         if( nativeJkHandlerP == 0 ) {
226             log.error( "Unitialized component " );
227             return;
228         }
229
230         long xEnv=apr.getJkEnv();
231
232         apr.jkDestroy( xEnv, nativeJkHandlerP );
233
234         apr.releaseJkEnv( xEnv );
235     }
236
237
238
239     protected void setNativeEndpoint(MsgContext msgCtx) {
240         long xEnv=apr.getJkEnv();
241         msgCtx.setJniEnv( xEnv );
242
243         long epP=apr.createJkHandler(xEnv, "endpoint");
244         log.debug("create ep " + epP );
245         if( epP == 0 ) return;
246         apr.jkInit( xEnv, epP );
247         msgCtx.setJniContext( epP );
248
249     }
250
251     protected void recycleNative(MsgContext ep) {
252         apr.jkRecycle(ep.getJniEnv(), ep.getJniContext());
253     }
254
255     /** send and get the response in the same buffer. This calls the
256     * method on the wrapped jk_bean object.
257      */

258     protected int nativeDispatch( Msg msg, MsgContext ep, int code, int raw )
259         throws IOException JavaDoc
260     {
261         if( log.isDebugEnabled() )
262             log.debug( "Sending packet " + code + " " + raw);
263
264         if( raw == 0 ) {
265             msg.end();
266
267             if( log.isTraceEnabled() ) msg.dump("OUT:" );
268         }
269
270         // Create ( or reuse ) the jk_endpoint ( the native pair of
271
// MsgContext )
272
long xEnv=ep.getJniEnv();
273         long nativeContext=ep.getJniContext();
274         if( nativeContext==0 || xEnv==0 ) {
275             setNativeEndpoint( ep );
276             xEnv=ep.getJniEnv();
277             nativeContext=ep.getJniContext();
278         }
279
280         if( xEnv==0 || nativeContext==0 || nativeJkHandlerP==0 ) {
281             log.error("invokeNative: Null pointer ");
282             return -1;
283         }
284
285         // Will process the message in the current thread.
286
// No wait needed to receive the response, if any
287
int status=AprImpl.jkInvoke( xEnv,
288                                  nativeJkHandlerP,
289                                  nativeContext,
290                                  code, msg.getBuffer(), 0, msg.getLen(), raw );
291
292         if( status != 0 && status != 2 ) {
293             log.error( "nativeDispatch: error " + status, new Throwable JavaDoc() );
294         }
295
296         if( log.isDebugEnabled() ) log.debug( "Sending packet - done " + status);
297         return status;
298     }
299
300     /** Base implementation for invoke. Dispatch the action to the native
301     * code, where invoke() is called on the wrapped jk_bean.
302     */

303     public int invoke(Msg msg, MsgContext ep )
304         throws IOException JavaDoc
305     {
306         long xEnv=ep.getJniEnv();
307         int type=ep.getType();
308
309         int status=nativeDispatch(msg, ep, type, 0 );
310
311         apr.jkRecycle(xEnv, ep.getJniContext());
312         apr.releaseJkEnv( xEnv );
313         return status;
314     }
315
316     private static org.apache.commons.logging.Log log=
317         org.apache.commons.logging.LogFactory.getLog( JniHandler.class );
318 }
319
Popular Tags