Source Code Cross Referenced for HttpOutputStream.java in  » Net » SkunkDAV » HTTPClient » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Net » SkunkDAV » HTTPClient 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * @(#)HttpOutputStream.java				0.3-2 18/06/1999
003:         *
004:         *  This file is part of the HTTPClient package
005:         *  Copyright (C) 1996-1999  Ronald Tschalär
006:         *
007:         *  This library is free software; you can redistribute it and/or
008:         *  modify it under the terms of the GNU Lesser General Public
009:         *  License as published by the Free Software Foundation; either
010:         *  version 2 of the License, or (at your option) any later version.
011:         *
012:         *  This library is distributed in the hope that it will be useful,
013:         *  but WITHOUT ANY WARRANTY; without even the implied warranty of
014:         *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015:         *  Lesser General Public License for more details.
016:         *
017:         *  You should have received a copy of the GNU Lesser General Public
018:         *  License along with this library; if not, write to the Free
019:         *  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
020:         *  MA 02111-1307, USA
021:         *
022:         *  For questions, suggestions, bug-reports, enhancement-requests etc.
023:         *  I may be contacted at:
024:         *
025:         *  ronald@innovation.ch
026:         *
027:         */
028:
029:        package HTTPClient;
030:
031:        import java.io.OutputStream;
032:        import java.io.ByteArrayOutputStream;
033:        import java.io.IOException;
034:
035:        /**
036:         * This class provides an output stream for requests. The stream must first
037:         * be associated with a request before it may be used; this is done by
038:         * passing it to one of the request methods in HTTPConnection. Example:
039:         * <PRE>
040:         *    OutputStream out = new HttpOutputStream(12345);
041:         *    rsp = con.Post("/cgi-bin/my_cgi", out);
042:         *    out.write(...);
043:         *    out.close();
044:         *    if (rsp.getStatusCode() >= 300)
045:         *        ...
046:         * </PRE>
047:         *
048:         * <P>There are two constructors for this class, one taking a length parameter,
049:         * and one without any parameters. If the stream is created with a length
050:         * then the request will be sent with the corresponding Content-length header
051:         * and anything written to the stream will be written on the socket immediately.
052:         * This is the preferred way. If the stream is created without a length then
053:         * one of two things will happen: if, at the time of the request, the server
054:         * is known to understand HTTP/1.1 then each write() will send the data
055:         * immediately using the chunked encoding. If, however, either the server
056:         * version is unknown (because this is first request to that server) or the
057:         * server only understands HTTP/1.0 then all data will be written to a buffer
058:         * first, and only when the stream is closed will the request be sent.
059:         *
060:         * <P>Another reason that using the <var>HttpOutputStream(length)</var>
061:         * constructor is recommended over the <var>HttpOutputStream()</var> one is
062:         * that some HTTP/1.1 servers do not allow the chunked transfer encoding to
063:         * be used when POSTing to a cgi script. This is because the way the cgi API
064:         * is defined the cgi script expects a Content-length environment variable.
065:         * If the data is sent using the chunked transfer encoding however, then the
066:         * server would have to buffer all the data before invoking the cgi so that
067:         * this variable could be set correctly. Not all servers are willing to do
068:         * this.
069:         *
070:         * <P>If you cannot use the <var>HttpOutputStream(length)</var> constructor and
071:         * are having problems sending requests (usually a 411 response) then you can
072:         * try setting the system property <var>HTTPClient.dontChunkRequests</var> to
073:         * <var>true</var> (this needs to be done either on the command line or
074:         * somewhere in the code before the HTTPConnection is first accessed). This
075:         * will prevent the client from using the chunked encoding in this case and
076:         * will cause the HttpOutputStream to buffer all the data instead, sending it
077:         * only when close() is invoked.
078:         *
079:         * <P>The behaviour of a request sent with an output stream may differ from
080:         * that of a request sent with a data parameter. The reason for this is that
081:         * the various modules cannot resend a request which used an output stream.
082:         * Therefore such things as authorization and retrying of requests won't be
083:         * done by the HTTPClient for such requests.
084:         *
085:         * @version	0.3-2  18/06/1999
086:         * @author	Ronald Tschalär
087:         * @since	V0.3
088:         */
089:
090:        public class HttpOutputStream extends OutputStream implements 
091:                GlobalConstants {
092:            /** null trailers */
093:            private static final NVPair[] empty = new NVPair[0];
094:
095:            /** the length of the data to be sent */
096:            private int length;
097:
098:            /** the length of the data received so far */
099:            private int rcvd = 0;
100:
101:            /** the request this stream is associated with */
102:            private Request req = null;
103:
104:            /** the response from sendRequest if we stalled the request */
105:            private Response resp = null;
106:
107:            /** the socket output stream */
108:            private OutputStream os = null;
109:
110:            /** the buffer to be used if needed */
111:            private ByteArrayOutputStream bos = null;
112:
113:            /** the trailers to send if using chunked encoding. */
114:            private NVPair[] trailers = empty;
115:
116:            /** the timeout to pass to SendRequest() */
117:            private int con_to = 0;
118:
119:            /** just ignore all the data if told to do so */
120:            private boolean ignore = false;
121:
122:            // Constructors
123:
124:            /**
125:             * Creates an output stream of unspecified length. Note that it is
126:             * <strong>highly</strong> recommended that this constructor be avoided
127:             * where possible and <code>HttpOutputStream(int)</code> used instead.
128:             *
129:             * @see HttpOutputStream#HttpOutputStream(int)
130:             */
131:            public HttpOutputStream() {
132:                length = -1;
133:            }
134:
135:            /**
136:             * This creates an output stream which will take <var>length</var> bytes
137:             * of data.
138:             *
139:             * @param length the number of bytes which will be sent over this stream
140:             */
141:            public HttpOutputStream(int length) {
142:                if (length < 0)
143:                    throw new IllegalArgumentException(
144:                            "Length must be greater equal 0");
145:                this .length = length;
146:            }
147:
148:            // Methods
149:
150:            /**
151:             * Associates this stream with a request and the actual output stream.
152:             * No other methods in this class may be invoked until this method has
153:             * been invoked by the HTTPConnection.
154:             *
155:             * @param req    the request this stream is to be associated with
156:             * @param os     the underlying output stream to write our data to, or null
157:             *               if we should write to a ByteArrayOutputStream instead.
158:             * @param con_to connection timeout to use in sendRequest()
159:             */
160:            void goAhead(Request req, OutputStream os, int con_to) {
161:                this .req = req;
162:                this .os = os;
163:                this .con_to = con_to;
164:
165:                if (os == null)
166:                    bos = new ByteArrayOutputStream();
167:
168:                if (DebugConn) {
169:                    System.err.println("OutS:  Stream ready for writing");
170:                    if (bos != null)
171:                        System.err
172:                                .println("OutS:  Buffering all data before sending "
173:                                        + "request");
174:                }
175:            }
176:
177:            /**
178:             * Setup this stream to dump the data to the great bit-bucket in the sky.
179:             * This is needed for when a module handles the request directly.
180:             *
181:             * @param req the request this stream is to be associated with
182:             */
183:            void ignoreData(Request req) {
184:                this .req = req;
185:                ignore = true;
186:            }
187:
188:            /**
189:             * Return the response we got from sendRequest(). This waits until
190:             * the request has actually been sent.
191:             *
192:             * @return the response returned by sendRequest()
193:             */
194:            synchronized Response getResponse() {
195:                while (resp == null)
196:                    try {
197:                        wait();
198:                    } catch (InterruptedException ie) {
199:                    }
200:
201:                return resp;
202:            }
203:
204:            /**
205:             * Returns the number of bytes this stream is willing to accept, or -1
206:             * if it is unbounded.
207:             *
208:             * @return the number of bytes
209:             */
210:            public int getLength() {
211:                return length;
212:            }
213:
214:            /**
215:             * Gets the trailers which were set with <code>setTrailers()</code>.
216:             *
217:             * @return an array of header fields
218:             * @see #setTrailers(NVPair[])
219:             */
220:            public NVPair[] getTrailers() {
221:                return trailers;
222:            }
223:
224:            /**
225:             * Sets the trailers to be sent if the output is sent with the
226:             * chunked transfer encoding. These must be set before the output
227:             * stream is closed for them to be sent.
228:             *
229:             * <P>Any trailers set here <strong>should</strong> be mentioned
230:             * in a <var>Trailer</var> header in the request (see section 14.40
231:             * of draft-ietf-http-v11-spec-rev-06.txt).
232:             *
233:             * <P>This method (and its related <code>getTrailers()</code>)) are
234:             * in this class and not in <var>Request</var> because setting
235:             * trailers is something an application may want to do, not only
236:             * modules.
237:             *
238:             * @param trailers an array of header fields
239:             */
240:            public void setTrailers(NVPair[] trailers) {
241:                if (trailers != null)
242:                    this .trailers = trailers;
243:                else
244:                    this .trailers = empty;
245:            }
246:
247:            /**
248:             * Writes a single byte on the stream. It is subject to the same rules
249:             * as <code>write(byte[], int, int)</code>.
250:             *
251:             * @param b the byte to write
252:             * @exception IOException if any exception is thrown by the socket
253:             * @see #write(byte[], int, int)
254:             */
255:            public void write(int b) throws IOException, IllegalAccessError {
256:                byte[] tmp = { (byte) b };
257:                write(tmp, 0, 1);
258:            }
259:
260:            /**
261:             * Writes an array of bytes on the stream. This method may not be used
262:             * until this stream has been passed to one of the methods in
263:             * HTTPConnection (i.e. until it has been associated with a request).
264:             *
265:             * @param buf an array containing the data to write
266:             * @param off the offset of the data whithin the buffer
267:             * @param len the number bytes (starting at <var>off</var>) to write
268:             * @exception IOException if any exception is thrown by the socket, or
269:             *            if writing <var>len</var> bytes would cause more bytes to
270:             *            be written than this stream is willing to accept.
271:             * @exception IllegalAccessError if this stream has not been associated
272:             *            with a request yet
273:             */
274:            public synchronized void write(byte[] buf, int off, int len)
275:                    throws IOException, IllegalAccessError {
276:                if (req == null)
277:                    throw new IllegalAccessError(
278:                            "Stream not associated with a request");
279:
280:                if (ignore)
281:                    return;
282:
283:                if (length != -1 && rcvd + len > length) {
284:                    IOException ioe = new IOException(
285:                            "Tried to write too many bytes (" + (rcvd + len)
286:                                    + " > " + length + ")");
287:                    req.getConnection().closeDemux(ioe, false);
288:                    req.getConnection().outputFinished();
289:                    throw ioe;
290:                }
291:
292:                try {
293:                    if (bos != null)
294:                        bos.write(buf, off, len);
295:                    else if (length != -1)
296:                        os.write(buf, off, len);
297:                    else
298:                        os.write(Codecs.chunkedEncode(buf, off, len, null,
299:                                false));
300:                } catch (IOException ioe) {
301:                    req.getConnection().closeDemux(ioe, true);
302:                    req.getConnection().outputFinished();
303:                    throw ioe;
304:                }
305:
306:                rcvd += len;
307:            }
308:
309:            /**
310:             * Closes the stream and causes the data to be sent if it has not already
311:             * been done so. This method <strong>must</strong> be invoked when all
312:             * data has been written.
313:             *
314:             * @exception IOException if any exception is thrown by the underlying
315:             *            socket, or if too few bytes were written.
316:             * @exception IllegalAccessError if this stream has not been associated
317:             *            with a request yet.
318:             */
319:            public synchronized void close() throws IOException,
320:                    IllegalAccessError {
321:                if (req == null)
322:                    throw new IllegalAccessError(
323:                            "Stream not associated with a request");
324:
325:                if (ignore)
326:                    return;
327:
328:                if (bos != null) {
329:                    req.setData(bos.toByteArray());
330:                    req.setStream(null);
331:
332:                    if (trailers.length > 0) {
333:                        NVPair[] hdrs = req.getHeaders();
334:
335:                        // remove any Trailer header field
336:
337:                        int len = hdrs.length;
338:                        for (int idx = 0; idx < len; idx++) {
339:                            if (hdrs[idx].getName().equalsIgnoreCase("Trailer")) {
340:                                System.arraycopy(hdrs, idx + 1, hdrs, idx, len
341:                                        - idx - 1);
342:                                len--;
343:                            }
344:                        }
345:
346:                        // add the trailers to the headers
347:
348:                        hdrs = Util.resizeArray(hdrs, len + trailers.length);
349:                        System.arraycopy(trailers, 0, hdrs, len,
350:                                trailers.length);
351:
352:                        req.setHeaders(hdrs);
353:                    }
354:
355:                    if (DebugConn)
356:                        System.err.println("OutS:  Sending request");
357:
358:                    try {
359:                        resp = req.getConnection().sendRequest(req, con_to);
360:                    } catch (ModuleException me) {
361:                        throw new IOException(me.toString());
362:                    }
363:                    notify();
364:                } else {
365:                    if (rcvd < length) {
366:                        IOException ioe = new IOException(
367:                                "Premature close: only " + rcvd
368:                                        + " bytes written instead of the "
369:                                        + "expected " + length);
370:                        req.getConnection().closeDemux(ioe, false);
371:                        req.getConnection().outputFinished();
372:                        throw ioe;
373:                    }
374:
375:                    try {
376:                        if (length == -1) {
377:                            if (DebugConn && trailers.length > 0) {
378:                                System.err.println("OutS:  Sending trailers:");
379:                                for (int idx = 0; idx < trailers.length; idx++)
380:                                    System.err.println("       "
381:                                            + trailers[idx].getName() + ": "
382:                                            + trailers[idx].getValue());
383:                            }
384:
385:                            os.write(Codecs.chunkedEncode(null, 0, 0, trailers,
386:                                    true));
387:                        }
388:
389:                        os.flush();
390:
391:                        if (DebugConn)
392:                            System.err.println("OutS:  All data sent");
393:                    } catch (IOException ioe) {
394:                        req.getConnection().closeDemux(ioe, true);
395:                        throw ioe;
396:                    } finally {
397:                        req.getConnection().outputFinished();
398:                    }
399:                }
400:            }
401:
402:            /**
403:             * produces a string describing this stream.
404:             *
405:             * @return a string containing the name and the length
406:             */
407:            public String toString() {
408:                return getClass().getName() + "[length=" + length + "]";
409:            }
410:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.