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.common;
018:
019: import java.io.IOException;
020:
021: import org.apache.jk.core.JkHandler;
022: import org.apache.jk.core.Msg;
023: import org.apache.jk.core.MsgContext;
024: import org.apache.jk.core.JkChannel;
025:
026: import org.apache.coyote.Request;
027:
028: /** Pass messages using jni
029: *
030: * @author Costin Manolache
031: */
032: public class ChannelJni extends JniHandler implements JkChannel {
033: int receivedNote = 1;
034:
035: public ChannelJni() {
036: // we use static for now, it's easier on the C side.
037: // Easy to change after we get everything working
038: }
039:
040: public void init() throws IOException {
041: super .initNative("channel.jni:jni");
042:
043: if (apr == null)
044: return;
045:
046: // We'll be called from C. This deals with that.
047: apr.addJkHandler("channelJni", this );
048: log.info("JK2: listening on channel.jni:jni");
049:
050: if (next == null) {
051: if (nextName != null)
052: setNext(wEnv.getHandler(nextName));
053: if (next == null)
054: next = wEnv.getHandler("dispatch");
055: if (next == null)
056: next = wEnv.getHandler("request");
057: if (log.isDebugEnabled())
058: log.debug("Setting default next "
059: + next.getClass().getName());
060: }
061: }
062:
063: /** Receives does nothing - send will put the response
064: * in the same buffer
065: */
066: public int receive(Msg msg, MsgContext ep) throws IOException {
067: Msg sentResponse = (Msg) ep.getNote(receivedNote);
068: ep.setNote(receivedNote, null);
069:
070: if (sentResponse == null) {
071: if (log.isDebugEnabled())
072: log
073: .debug("No send() prior to receive(), no data buffer");
074: // No sent() was done prior to receive.
075: msg.reset();
076: return 0;
077: }
078:
079: sentResponse.processHeader();
080:
081: if (log.isTraceEnabled())
082: sentResponse.dump("received response ");
083:
084: if (msg != sentResponse) {
085: log
086: .error("Error, in JNI mode the msg used for receive() must be identical with the one used for send()");
087: }
088:
089: return 0;
090: }
091:
092: /** Send the packet. XXX This will modify msg !!!
093: * We could use 2 packets, or sendAndReceive().
094: *
095: */
096: public int send(Msg msg, MsgContext ep) throws IOException {
097: ep.setNote(receivedNote, null);
098: if (log.isDebugEnabled())
099: log.debug("ChannelJni.send: " + msg);
100:
101: int rc = super .nativeDispatch(msg, ep, JK_HANDLE_JNI_DISPATCH,
102: 0);
103:
104: // nativeDispatch will put the response in the same buffer.
105: // Next receive() will just get it from there. Very tricky to do
106: // things in one thread instead of 2.
107: ep.setNote(receivedNote, msg);
108:
109: return rc;
110: }
111:
112: public int flush(Msg msg, MsgContext ep) throws IOException {
113: ep.setNote(receivedNote, null);
114: return OK;
115: }
116:
117: public boolean isSameAddress(MsgContext ep) {
118: return true;
119: }
120:
121: public void registerRequest(Request req, MsgContext ep, int count) {
122: // Not supported.
123: }
124:
125: public String getChannelName() {
126: return getName();
127: }
128:
129: /** Receive a packet from the C side. This is called from the C
130: * code using invocation, but only for the first packet - to avoid
131: * recursivity and thread problems.
132: *
133: * This may look strange, but seems the best solution for the
134: * problem ( the problem is that we don't have 'continuation' ).
135: *
136: * sendPacket will move the thread execution on the C side, and
137: * return when another packet is available. For packets that
138: * are one way it'll return after it is processed too ( having
139: * 2 threads is far more expensive ).
140: *
141: * Again, the goal is to be efficient and behave like all other
142: * Channels ( so the rest of the code can be shared ). Playing with
143: * java objects on C is extremely difficult to optimize and do
144: * right ( IMHO ), so we'll try to keep it simple - byte[] passing,
145: * the conversion done in java ( after we know the encoding and
146: * if anyone asks for it - same lazy behavior as in 3.3 ).
147: */
148: public int invoke(Msg msg, MsgContext ep) throws IOException {
149: if (apr == null)
150: return -1;
151:
152: long xEnv = ep.getJniEnv();
153: long cEndpointP = ep.getJniContext();
154:
155: int type = ep.getType();
156: if (log.isDebugEnabled())
157: log.debug("ChannelJni.invoke: " + ep + " " + type);
158:
159: switch (type) {
160: case JkHandler.HANDLE_RECEIVE_PACKET:
161: return receive(msg, ep);
162: case JkHandler.HANDLE_SEND_PACKET:
163: return send(msg, ep);
164: case JkHandler.HANDLE_FLUSH:
165: return flush(msg, ep);
166: }
167:
168: // Reset receivedNote. It'll be visible only after a SEND and before a receive.
169: ep.setNote(receivedNote, null);
170:
171: // Default is FORWARD - called from C
172: try {
173: // first, we need to get an endpoint. It should be
174: // per/thread - and probably stored by the C side.
175: if (log.isDebugEnabled())
176: log.debug("Received request " + xEnv);
177:
178: // The endpoint will store the message pt.
179: msg.processHeader();
180:
181: if (log.isTraceEnabled())
182: msg.dump("Incoming msg ");
183:
184: int status = next.invoke(msg, ep);
185:
186: if (log.isDebugEnabled())
187: log.debug("after processCallbacks " + status);
188:
189: return status;
190: } catch (Exception ex) {
191: ex.printStackTrace();
192: }
193: return 0;
194: }
195:
196: private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
197: .getLog(ChannelJni.class);
198:
199: }
|