001: /*
002: * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
003: *
004: * The Apache Software License, Version 1.1
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution, if
019: * any, must include the following acknowlegement:
020: * "This product includes software developed by the
021: * Caucho Technology (http://www.caucho.com/)."
022: * Alternately, this acknowlegement may appear in the software itself,
023: * if and wherever such third-party acknowlegements normally appear.
024: *
025: * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
026: * endorse or promote products derived from this software without prior
027: * written permission. For written permission, please contact
028: * info@caucho.com.
029: *
030: * 5. Products derived from this software may not be called "Resin"
031: * nor may "Resin" appear in their names without prior written
032: * permission of Caucho Technology.
033: *
034: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
035: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
036: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
037: * DISCLAIMED. IN NO EVENT SHALL CAUCHO TECHNOLOGY OR ITS CONTRIBUTORS
038: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
039: * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
040: * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
041: * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
042: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
043: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
044: * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
045: *
046: * @author Scott Ferguson
047: */
048:
049: package com.caucho.hessian.mux;
050:
051: import java.io.IOException;
052: import java.io.InputStream;
053:
054: /**
055: * Input stream to a specific channel.
056: */
057: public class MuxInputStream extends InputStream {
058: private MuxServer server;
059: protected InputStream is;
060: private int channel;
061:
062: private String url;
063:
064: private int chunkLength;
065:
066: /**
067: * Null argument constructor.
068: */
069: public MuxInputStream() {
070: }
071:
072: /**
073: * Initialize the multiplexor with input and output streams.
074: */
075: protected void init(MuxServer server, int channel)
076: throws IOException {
077: this .server = server;
078: this .channel = channel;
079:
080: this .url = null;
081:
082: chunkLength = 0;
083: }
084:
085: /**
086: * Gets the raw input stream. Clients will normally not call
087: * this.
088: */
089: protected InputStream getInputStream() throws IOException {
090: if (is == null && server != null)
091: is = server.readChannel(channel);
092:
093: return is;
094: }
095:
096: void setInputStream(InputStream is) {
097: this .is = is;
098: }
099:
100: /**
101: * Gets the channel of the connection.
102: */
103: public int getChannel() {
104: return channel;
105: }
106:
107: /**
108: * Returns the request's URL
109: */
110: public String getURL() {
111: return url;
112: }
113:
114: /**
115: * Writes a data byte to the output stream.
116: */
117: public int read() throws IOException {
118: if (chunkLength <= 0) {
119: readToData(false);
120:
121: if (chunkLength <= 0)
122: return -1;
123: }
124:
125: chunkLength--;
126: return is.read();
127: }
128:
129: /**
130: * Complete writing to the stream, closing the channel.
131: */
132: public void close() throws IOException {
133: skipToEnd();
134: }
135:
136: /**
137: * Skips data until the end of the channel.
138: */
139: private void skipToEnd() throws IOException {
140: InputStream is = getInputStream();
141:
142: if (is == null)
143: return;
144:
145: if (chunkLength > 0)
146: is.skip(chunkLength);
147:
148: for (int tag = is.read(); tag >= 0; tag = is.read()) {
149: switch (tag) {
150: case 'Y':
151: server.freeReadLock();
152: this .is = is = server.readChannel(channel);
153: if (is == null) {
154: this .server = null;
155: return;
156: }
157: break;
158:
159: case 'Q':
160: server.freeReadLock();
161: this .is = null;
162: this .server = null;
163: return;
164:
165: case -1:
166: server.freeReadLock();
167: this .is = null;
168: this .server = null;
169: return;
170:
171: default:
172: int length = (is.read() << 8) + is.read();
173: is.skip(length);
174: break;
175: }
176: }
177: }
178:
179: /**
180: * Reads tags, until getting data.
181: */
182: void readToData(boolean returnOnYield) throws IOException {
183: InputStream is = getInputStream();
184:
185: if (is == null)
186: return;
187:
188: for (int tag = is.read(); tag >= 0; tag = is.read()) {
189: switch (tag) {
190: case 'Y':
191: server.freeReadLock();
192: if (returnOnYield)
193: return;
194: server.readChannel(channel);
195: break;
196:
197: case 'Q':
198: server.freeReadLock();
199: this .is = null;
200: this .server = null;
201: return;
202:
203: case 'U':
204: this .url = readUTF();
205: break;
206:
207: case 'D':
208: chunkLength = (is.read() << 8) + is.read();
209: return;
210:
211: default:
212: readTag(tag);
213: break;
214: }
215: }
216: }
217:
218: /**
219: * Subclasses will extend this to read values.
220: */
221: protected void readTag(int tag) throws IOException {
222: int length = (is.read() << 8) + is.read();
223: is.skip(length);
224: }
225:
226: /**
227: * Reads a UTF-8 string.
228: *
229: * @return the utf-8 encoded string
230: */
231: protected String readUTF() throws IOException {
232: int len = (is.read() << 8) + is.read();
233:
234: StringBuffer sb = new StringBuffer();
235:
236: while (len > 0) {
237: int d1 = is.read();
238:
239: if (d1 < 0)
240: return sb.toString();
241: else if (d1 < 0x80) {
242: len--;
243: sb.append((char) d1);
244: } else if ((d1 & 0xe0) == 0xc0) {
245: len -= 2;
246: sb.append(((d1 & 0x1f) << 6) + (is.read() & 0x3f));
247: } else if ((d1 & 0xf0) == 0xe0) {
248: len -= 3;
249: sb.append(((d1 & 0x0f) << 12)
250: + ((is.read() & 0x3f) << 6)
251: + (is.read() & 0x3f));
252: } else
253: throw new IOException("utf-8 encoding error");
254: }
255:
256: return sb.toString();
257: }
258: }
|