1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.jk.apr;
19
20 import java.io.FileOutputStream;
21 import java.io.IOException;
22 import java.io.PrintStream;
23 import java.util.Hashtable;
24 import org.apache.jk.core.JkHandler;
25 import org.apache.jk.core.MsgContext;
26 import org.apache.jk.core.JkChannel;
27
28 /** Implements the interface with the APR library. This is for internal-use
29 * only. The goal is to use 'natural' mappings for user code - for example
30 * java.net.Socket for unix-domain sockets, etc.
31 *
32 */
33 public class AprImpl extends JkHandler { // This will be o.a.t.util.handler.TcHandler - lifecycle and config
34 static AprImpl aprSingleton=null;
35
36 String baseDir;
37 String aprHome;
38 String soExt="so";
39
40 static boolean ok=true;
41 boolean initialized=false;
42 // Handlers for native callbacks
43 Hashtable jkHandlers=new Hashtable();
44
45 // Name of the so used in inprocess mode
46 String jniModeSo="inprocess";
47 // name of the so used by java. If not set we'll loadLibrary("jkjni" ),
48 // if set we load( nativeSo )
49 String nativeSo;
50
51 public AprImpl() {
52 aprSingleton=this;
53 }
54
55 // -------------------- Properties --------------------
56
57 /** Native libraries are located based on base dir.
58 * XXX Add platform, version, etc
59 */
60 public void setBaseDir(String s) {
61 baseDir=s;
62 }
63
64 public void setSoExt(String s ) {
65 soExt=s;
66 }
67
68 // XXX maybe install the jni lib in apr-home ?
69 public void setAprHome( String s ) {
70 aprHome=s;
71 }
72
73 /** Add a Handler for jni callbacks.
74 */
75 public void addJkHandler(String type, JkHandler cb) {
76 jkHandlers.put( type, cb );
77 }
78
79 /** Name of the so used in inprocess mode
80 */
81 public void setJniModeSo(String jniModeSo ) {
82 this.jniModeSo=jniModeSo;
83 }
84
85 /** name of the so used by java. If not set we'll loadLibrary("jkjni" ),
86 if set we load( nativeSo )
87 */
88 public void setNativeSo( String nativeSo ) {
89 this.nativeSo=nativeSo;
90 }
91
92 /** Sets the System.out stream */
93
94 public static void setOut( String filename ) {
95 try{
96 if( filename !=null ){
97 System.setOut( new PrintStream(new FileOutputStream(filename )));
98 }
99 }catch (Throwable th){
100 }
101 }
102 /** Sets the System.err stream */
103
104 public static void setErr( String filename ) {
105 try{
106 if( filename !=null ){
107 System.setErr( new PrintStream(new FileOutputStream(filename )));
108 }
109 }catch (Throwable th){
110 }
111 }
112
113 // -------------------- Apr generic utils --------------------
114 /** Initialize APR
115 */
116 public native int initialize();
117
118 public native int terminate();
119
120 /* -------------------- Access to the jk_env_t -------------------- */
121
122 /* The jk_env_t provide temporary storage ( pool ), logging, common services
123 */
124
125 /* Return a jk_env_t, used to keep the execution context ( temp pool, etc )
126 */
127 public native long getJkEnv();
128
129 /** Clean the temp pool, put back the env in the pool
130 */
131 public native void releaseJkEnv(long xEnv);
132
133 /* -------------------- Interface to the jk_bean object -------------------- */
134 /* Each jk component is 'wrapped' as a bean, with a specified lifecycle
135 *
136 */
137
138 /** Get a native component
139 * @return 0 if the component is not found.
140 */
141 public native long getJkHandler(long xEnv, String compName );
142
143 public native long createJkHandler(long xEnv, String compName );
144
145 public native int jkSetAttribute( long xEnv, long componentP, String name, String val );
146
147 public native String jkGetAttribute( long xEnv, long componentP, String name );
148
149 public native int jkInit( long xEnv, long componentP );
150
151 public native int jkDestroy( long xEnv, long componentP );
152
153 /** Send the packet to the C side. On return it contains the response
154 * or indication there is no response. Asymetrical because we can't
155 * do things like continuations.
156 */
157 public static native int jkInvoke(long xEnv, long componentP, long endpointP,
158 int code, byte data[], int off, int len, int raw);
159
160 /** Recycle an endpoint after use.
161 */
162 public native void jkRecycle(long xEnv, long endpointP);
163
164 // -------------------- Called from C --------------------
165 // XXX Check security, add guard or other protection
166 // It's better to do it the other way - on init 'push' AprImpl into
167 // the native library, and have native code call instance methods.
168
169 public static Object createJavaContext(String type, long cContext) {
170 // XXX will be an instance method, fields accessible directly
171 AprImpl apr=aprSingleton;
172 JkChannel jkH=(JkChannel)apr.jkHandlers.get( type );
173 if( jkH==null ) return null;
174
175 MsgContext ep=jkH.createMsgContext();
176
177 ep.setSource( jkH );
178
179 ep.setJniContext( cContext );
180 return ep;
181 }
182
183 /** Return a buffer associated with the ctx.
184 */
185 public static byte[] getBuffer( Object ctx, int id ) {
186 return ((MsgContext)ctx).getBuffer( id );
187 }
188
189 public static int jniInvoke( long jContext, Object ctx ) {
190 try {
191 MsgContext ep=(MsgContext)ctx;
192 ep.setJniEnv( jContext );
193 ep.setType( 0 );
194 return ((MsgContext)ctx).execute();
195 } catch( Throwable ex ) {
196 ex.printStackTrace();
197 return -1;
198 }
199 }
200
201 // -------------------- Initialization --------------------
202
203 public void init() throws IOException {
204 try {
205 initialized=true;
206 loadNative();
207
208 initialize();
209 jkSetAttribute(0, 0, "channel:jni", "starting");
210
211 log.info("JK: Initialized apr" );
212
213 } catch( Throwable t ) {
214 throw new IOException( t.toString() );
215 }
216 ok=true;
217 }
218
219 public boolean isLoaded() {
220 if( ! initialized ) {
221 try {
222 init();
223 } catch( Throwable t ) {
224 log.info("Apr not loaded: " + t);
225 }
226 }
227 return ok;
228 }
229
230 static boolean jniMode=false;
231
232
233 public static void jniMode() {
234 jniMode=true;
235 }
236
237 /** This method of loading the libs doesn't require setting
238 * LD_LIBRARY_PATH. Assuming a 'right' binary distribution,
239 * or a correct build all files will be in their right place.
240 *
241 * The burden is on our code to deal with platform specific
242 * extensions and to keep the paths consistent - not easy, but
243 * worth it if it avoids one extra step for the user.
244 *
245 * Of course, this can change to System.load() and putting the
246 * libs in LD_LIBRARY_PATH.
247 */
248 public void loadNative() throws Throwable {
249 if( aprHome==null )
250 aprHome=baseDir;
251
252 // XXX Update for windows
253 if( jniMode ) {
254 /* In JNI mode we use mod_jk for the native functions.
255 This seems the cleanest solution that works with multiple
256 VMs.
257 */
258 if (jniModeSo.equals("inprocess")) {
259 ok=true;
260 return;
261 }
262 try {
263 log.info("Loading " + jniModeSo);
264 if( jniModeSo!= null ) System.load( jniModeSo );
265 } catch( Throwable ex ) {
266 // ignore
267 //ex.printStackTrace();
268 return;
269 }
270 ok=true;
271 return;
272 }
273
274 /*
275 jkjni _must_ be linked with apr and crypt -
276 this seem the only ( decent ) way to support JDK1.4 and
277 JDK1.3 at the same time
278 try {
279 System.loadLibrary( "crypt" );
280 } catch( Throwable ex ) {
281 // ignore
282 ex.printStackTrace();
283 }
284 try {
285 System.loadLibrary( "apr" );
286 } catch( Throwable ex ) {
287 System.out.println("can't load apr, that's fine");
288 ex.printStackTrace();
289 }
290 */
291 try {
292 if( nativeSo == null ) {
293 // This will load libjkjni.so or jkjni.dll in LD_LIBRARY_PATH
294 log.debug("Loading jkjni from " + System.getProperty("java.library.path"));
295 System.loadLibrary( "jkjni" );
296 } else {
297 System.load( nativeSo );
298 }
299 } catch( Throwable ex ) {
300 ok=false;
301 //ex.printStackTrace();
302 throw ex;
303 }
304 }
305
306 public void loadNative(String libPath) {
307 try {
308 System.load( libPath );
309 } catch( Throwable ex ) {
310 ok=false;
311 if( log.isDebugEnabled() )
312 log.debug( "Error loading native library ", ex);
313 }
314 }
315 private static org.apache.juli.logging.Log log=
316 org.apache.juli.logging.LogFactory.getLog( AprImpl.class );
317 }