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