001: /*
002: * Copyright 1999-2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.jk.apr;
018:
019: import java.io.FileOutputStream;
020: import java.io.IOException;
021: import java.io.PrintStream;
022: import java.util.Hashtable;
023: import org.apache.jk.core.JkHandler;
024: import org.apache.jk.core.MsgContext;
025: import org.apache.jk.core.JkChannel;
026:
027: /** Implements the interface with the APR library. This is for internal-use
028: * only. The goal is to use 'natural' mappings for user code - for example
029: * java.net.Socket for unix-domain sockets, etc.
030: *
031: */
032: public class AprImpl extends JkHandler { // This will be o.a.t.util.handler.TcHandler - lifecycle and config
033: static AprImpl aprSingleton = null;
034:
035: String baseDir;
036: String aprHome;
037: String soExt = "so";
038:
039: static boolean ok = true;
040: boolean initialized = false;
041: // Handlers for native callbacks
042: Hashtable jkHandlers = new Hashtable();
043:
044: // Name of the so used in inprocess mode
045: String jniModeSo = "inprocess";
046: // name of the so used by java. If not set we'll loadLibrary("jkjni" ),
047: // if set we load( nativeSo )
048: String nativeSo;
049:
050: public AprImpl() {
051: aprSingleton = this ;
052: }
053:
054: // -------------------- Properties --------------------
055:
056: /** Native libraries are located based on base dir.
057: * XXX Add platform, version, etc
058: */
059: public void setBaseDir(String s) {
060: baseDir = s;
061: }
062:
063: public void setSoExt(String s) {
064: soExt = s;
065: }
066:
067: // XXX maybe install the jni lib in apr-home ?
068: public void setAprHome(String s) {
069: aprHome = s;
070: }
071:
072: /** Add a Handler for jni callbacks.
073: */
074: public void addJkHandler(String type, JkHandler cb) {
075: jkHandlers.put(type, cb);
076: }
077:
078: /** Name of the so used in inprocess mode
079: */
080: public void setJniModeSo(String jniModeSo) {
081: this .jniModeSo = jniModeSo;
082: }
083:
084: /** name of the so used by java. If not set we'll loadLibrary("jkjni" ),
085: if set we load( nativeSo )
086: */
087: public void setNativeSo(String nativeSo) {
088: this .nativeSo = nativeSo;
089: }
090:
091: /** Sets the System.out stream */
092:
093: public static void setOut(String filename) {
094: try {
095: if (filename != null) {
096: System.setOut(new PrintStream(new FileOutputStream(
097: filename)));
098: }
099: } catch (Throwable th) {
100: }
101: }
102:
103: /** Sets the System.err stream */
104:
105: public static void setErr(String filename) {
106: try {
107: if (filename != null) {
108: System.setErr(new PrintStream(new FileOutputStream(
109: filename)));
110: }
111: } catch (Throwable th) {
112: }
113: }
114:
115: // -------------------- Apr generic utils --------------------
116: /** Initialize APR
117: */
118: public native int initialize();
119:
120: public native int terminate();
121:
122: /* -------------------- Access to the jk_env_t -------------------- */
123:
124: /* The jk_env_t provide temporary storage ( pool ), logging, common services
125: */
126:
127: /* Return a jk_env_t, used to keep the execution context ( temp pool, etc )
128: */
129: public native long getJkEnv();
130:
131: /** Clean the temp pool, put back the env in the pool
132: */
133: public native void releaseJkEnv(long xEnv);
134:
135: /* -------------------- Interface to the jk_bean object -------------------- */
136: /* Each jk component is 'wrapped' as a bean, with a specified lifecycle
137: *
138: */
139:
140: /** Get a native component
141: * @return 0 if the component is not found.
142: */
143: public native long getJkHandler(long xEnv, String compName);
144:
145: public native long createJkHandler(long xEnv, String compName);
146:
147: public native int jkSetAttribute(long xEnv, long componentP,
148: String name, String val);
149:
150: public native String jkGetAttribute(long xEnv, long componentP,
151: String name);
152:
153: public native int jkInit(long xEnv, long componentP);
154:
155: public native int jkDestroy(long xEnv, long componentP);
156:
157: /** Send the packet to the C side. On return it contains the response
158: * or indication there is no response. Asymetrical because we can't
159: * do things like continuations.
160: */
161: public static native int jkInvoke(long xEnv, long componentP,
162: long endpointP, int code, byte data[], int off, int len,
163: int raw);
164:
165: /** Recycle an endpoint after use.
166: */
167: public native void jkRecycle(long xEnv, long endpointP);
168:
169: // -------------------- Called from C --------------------
170: // XXX Check security, add guard or other protection
171: // It's better to do it the other way - on init 'push' AprImpl into
172: // the native library, and have native code call instance methods.
173:
174: public static Object createJavaContext(String type, long cContext) {
175: // XXX will be an instance method, fields accessible directly
176: AprImpl apr = aprSingleton;
177: JkChannel jkH = (JkChannel) apr.jkHandlers.get(type);
178: if (jkH == null)
179: return null;
180:
181: MsgContext ep = jkH.createMsgContext();
182:
183: ep.setSource(jkH);
184:
185: ep.setJniContext(cContext);
186: return ep;
187: }
188:
189: /** Return a buffer associated with the ctx.
190: */
191: public static byte[] getBuffer(Object ctx, int id) {
192: return ((MsgContext) ctx).getBuffer(id);
193: }
194:
195: public static int jniInvoke(long jContext, Object ctx) {
196: try {
197: MsgContext ep = (MsgContext) ctx;
198: ep.setJniEnv(jContext);
199: ep.setType(0);
200: return ((MsgContext) ctx).execute();
201: } catch (Throwable ex) {
202: ex.printStackTrace();
203: return -1;
204: }
205: }
206:
207: // -------------------- Initialization --------------------
208:
209: public void init() throws IOException {
210: try {
211: initialized = true;
212: loadNative();
213:
214: initialize();
215: jkSetAttribute(0, 0, "channel:jni", "starting");
216:
217: log.info("JK2: Initialized apr");
218:
219: } catch (Throwable t) {
220: throw new IOException(t.toString());
221: }
222: ok = true;
223: }
224:
225: public boolean isLoaded() {
226: if (!initialized) {
227: try {
228: init();
229: } catch (Throwable t) {
230: log.info("Apr not loaded: " + t);
231: }
232: }
233: return ok;
234: }
235:
236: static boolean jniMode = false;
237:
238: public static void jniMode() {
239: jniMode = true;
240: }
241:
242: /** This method of loading the libs doesn't require setting
243: * LD_LIBRARY_PATH. Assuming a 'right' binary distribution,
244: * or a correct build all files will be in their right place.
245: *
246: * The burden is on our code to deal with platform specific
247: * extensions and to keep the paths consistent - not easy, but
248: * worth it if it avoids one extra step for the user.
249: *
250: * Of course, this can change to System.load() and putting the
251: * libs in LD_LIBRARY_PATH.
252: */
253: public void loadNative() throws Throwable {
254: if (aprHome == null)
255: aprHome = baseDir;
256:
257: // XXX Update for windows
258: if (jniMode) {
259: /* In JNI mode we use mod_jk for the native functions.
260: This seems the cleanest solution that works with multiple
261: VMs.
262: */
263: if (jniModeSo.equals("inprocess")) {
264: ok = true;
265: return;
266: }
267: try {
268: log.info("Loading " + jniModeSo);
269: if (jniModeSo != null)
270: System.load(jniModeSo);
271: } catch (Throwable ex) {
272: // ignore
273: //ex.printStackTrace();
274: return;
275: }
276: ok = true;
277: return;
278: }
279:
280: /*
281: jkjni _must_ be linked with apr and crypt -
282: this seem the only ( decent ) way to support JDK1.4 and
283: JDK1.3 at the same time
284: try {
285: System.loadLibrary( "crypt" );
286: } catch( Throwable ex ) {
287: // ignore
288: ex.printStackTrace();
289: }
290: try {
291: System.loadLibrary( "apr" );
292: } catch( Throwable ex ) {
293: System.out.println("can't load apr, that's fine");
294: ex.printStackTrace();
295: }
296: */
297: try {
298: if (nativeSo == null) {
299: // This will load libjkjni.so or jkjni.dll in LD_LIBRARY_PATH
300: log.debug("Loading jkjni from "
301: + System.getProperty("java.library.path"));
302: System.loadLibrary("jkjni");
303: } else {
304: System.load(nativeSo);
305: }
306: } catch (Throwable ex) {
307: ok = false;
308: //ex.printStackTrace();
309: throw ex;
310: }
311: }
312:
313: public void loadNative(String libPath) {
314: try {
315: System.load(libPath);
316: } catch (Throwable ex) {
317: ok = false;
318: if (log.isDebugEnabled())
319: log.debug("Error loading native library ", ex);
320: }
321: }
322:
323: private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
324: .getLog(AprImpl.class);
325: }
|