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