KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openejb > server > httpd > HttpResponseImpl


1 /**
2  * Redistribution and use of this software and associated documentation
3  * ("Software"), with or without modification, are permitted provided
4  * that the following conditions are met:
5  *
6  * 1. Redistributions of source code must retain copyright
7  * statements and notices. Redistributions must also contain a
8  * copy of this document.
9  *
10  * 2. Redistributions in binary form must reproduce the
11  * above copyright notice, this list of conditions and the
12  * following disclaimer in the documentation and/or other
13  * materials provided with the distribution.
14  *
15  * 3. The name "OpenEJB" must not be used to endorse or promote
16  * products derived from this Software without prior written
17  * permission of The OpenEJB Group. For written permission,
18  * please contact openejb@openejb.org.
19  *
20  * 4. Products derived from this Software may not be called "OpenEJB"
21  * nor may "OpenEJB" appear in their names without prior written
22  * permission of The OpenEJB Group. OpenEJB is a registered
23  * trademark of The OpenEJB Group.
24  *
25  * 5. Due credit should be given to the OpenEJB Project
26  * (http://openejb.org/).
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE OPENEJB GROUP AND CONTRIBUTORS
29  * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30  * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
32  * THE OPENEJB GROUP OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39  * OF THE POSSIBILITY OF SUCH DAMAGE.
40  *
41  * Copyright 2001 (C) The OpenEJB Group. All Rights Reserved.
42  *
43  * $Id: HttpResponseImpl.java,v 1.2 2005/02/03 00:07:58 dblevins Exp $
44  */

45 package org.openejb.server.httpd;
46
47 import java.io.ByteArrayOutputStream JavaDoc;
48 import java.io.DataOutput JavaDoc;
49 import java.io.DataOutputStream JavaDoc;
50 import java.io.IOException JavaDoc;
51 import java.io.InputStream JavaDoc;
52 import java.io.OutputStream JavaDoc;
53 import java.io.PrintWriter JavaDoc;
54 import java.net.URL JavaDoc;
55 import java.net.URLConnection JavaDoc;
56 import java.util.HashMap JavaDoc;
57 import java.util.Iterator JavaDoc;
58 import java.util.Map JavaDoc;
59 import java.util.Properties JavaDoc;
60 import java.util.StringTokenizer JavaDoc;
61
62 import org.openejb.util.JarUtils;
63
64 /** This class takes care of HTTP Responses. It sends data back to the browser.
65  */

66 public class HttpResponseImpl implements HttpResponse {
67     
68     /** Response string */
69     private String JavaDoc responseString = "OK";
70
71     /** Code */
72     private int code = 200;
73     
74     /** Response headers */
75     private HashMap JavaDoc headers;
76     
77     /** Response body */
78     private byte[] body = new byte[0];
79     
80     /** the writer for the response */
81     private transient PrintWriter JavaDoc writer;
82     /** the raw body */
83     private transient ByteArrayOutputStream JavaDoc baos;
84     
85     /** the HTTP version */
86     public static final String JavaDoc HTTP_VERSION = "HTTP/1.1";
87     /** a line feed character */
88     public static final String JavaDoc CRLF = "\r\n";
89     /** a space character */
90     public static final String JavaDoc SP = " ";
91     /** a colon and space */
92     public static final String JavaDoc CSP = ": ";
93     /** the server to send data from */
94     public static String JavaDoc server;
95
96     private HttpRequestImpl request;
97     private URLConnection JavaDoc content;
98     
99     protected void setRequest(HttpRequestImpl request){
100         this.request = request;
101     }
102     
103     /** sets a header to be sent back to the browser
104      * @param name the name of the header
105      * @param value the value of the header
106      */

107     public void setHeader(String JavaDoc name, String JavaDoc value){
108         headers.put(name, value);
109     }
110
111     /** Gets a header based on the name passed in
112      * @param name The name of the header
113      * @return the value of the header
114      */

115     public String JavaDoc getHeader(String JavaDoc name){
116         return (String JavaDoc) headers.get(name);
117     }
118
119     /** Gets the PrintWriter to send data to the browser
120      * @return the PrintWriter to send data to the browser
121      */

122     public PrintWriter JavaDoc getPrintWriter(){
123         return writer;
124     }
125
126     /** gets the OutputStream to send data to the browser
127      * @return the OutputStream to send data to the browser
128      */

129     public OutputStream JavaDoc getOutputStream(){
130         return baos;
131     }
132
133     /** sets the HTTP response code to be sent to the browser. These codes are:
134      *
135      * OPTIONS = 0
136      * GET = 1
137      * HEAD = 2
138      * POST = 3
139      * PUT = 4
140      * DELETE = 5
141      * TRACE = 6
142      * CONNECT = 7
143      * UNSUPPORTED = 8
144      * @param code the code to be sent to the browser
145      */

146     public void setCode(int code){
147         this.code = code;
148     }
149
150     /** gets the HTTP response code
151      * @return the HTTP response code
152      */

153     public int getCode(){
154         return code;
155     }
156
157     /** sets the content type to be sent back to the browser
158      * @param type the type to be sent to the browser (i.e. "text/html")
159      */

160     public void setContentType(String JavaDoc type){
161         setHeader("Content-Type", type);
162     }
163
164     /** gets the content type that will be sent to the browser
165      * @return the content type (i.e. "text/html")
166      */

167     public String JavaDoc getContentType(){
168         return getHeader("Content-Type");
169     }
170
171     /** Sets the response string to be sent to the browser
172      * @param responseString the response string
173      */

174     public void setResponseString(String JavaDoc responseString){
175        this.responseString = responseString;
176     }
177
178     /** resets the data to be sent to the browser */
179     public void reset(){
180         initBody();
181     }
182
183     /** resets the data to be sent to the browser with the response code and response
184      * string
185      * @param code the code to be sent to the browser
186      * @param responseString the response string to be sent to the browser
187      */

188     public void reset(int code, String JavaDoc responseString){
189         setCode(code);
190         setResponseString(responseString);
191         initBody();
192     }
193
194     /*------------------------------------------------------------*/
195     /* Methods for writing out a response */
196     /*------------------------------------------------------------*/
197     /** creates a new instance of HttpResponseImpl with default values */
198     protected HttpResponseImpl(){
199         this(200, "OK", "text/html");
200     }
201
202     /** Creates a new HttpResponseImpl with user provided parameters
203      * @param code the HTTP Response code, see <a HREF="http://www.ietf.org/rfc/rfc2616.txt">http://www.ietf.org/rfc/rfc2616.txt</a>
204      * for these codes
205      * @param responseString the response string to be sent back
206      * @param contentType the content type to be sent back
207      */

208     protected HttpResponseImpl(int code, String JavaDoc responseString, String JavaDoc contentType){
209         this.responseString = responseString;
210         this.headers = new HashMap JavaDoc();
211         this.code = code;
212         
213         // Default headers
214
setHeader("Server", getServerName());
215         setHeader("Connection","close");
216         setHeader("Content-Type",contentType);
217         
218         // create the body.
219
initBody();
220     }
221
222     /** Takes care of sending the response line, headers and body
223      *
224      * HTTP/1.1 200 OK
225      * Server: Netscape-Enterprise/3.6 SP3
226      * Date: Thu, 07 Jun 2001 17:30:42 GMT
227      * Content-Type: text/html
228      * Connection: close
229      * @param output the output to send the response to
230      * @throws java.io.IOException if an exception is thrown
231      */

232     protected void writeMessage(OutputStream JavaDoc output) throws IOException JavaDoc{
233         DataOutput JavaDoc out = new DataOutputStream JavaDoc(output);
234         //DataOutput log = new DataOutputStream(System.out);
235
//System.out.println("\nRESPONSE");
236
closeMessage();
237 // writeResponseLine(log);
238
// writeHeaders(log);
239
// writeBody(log);
240
writeResponseLine(out);
241         writeHeaders(out);
242         writeBody(out);
243     }
244
245      /** initalizes the body */
246     private void initBody(){
247         baos = new ByteArrayOutputStream JavaDoc();
248         writer = new PrintWriter JavaDoc( baos );
249     }
250
251     /** Creates a string version of the response similar to:
252      *
253      * HTTP/1.1 200 OK
254      * @return the string value of this HttpResponseImpl
255      */

256     public String JavaDoc toString(){
257         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(40);
258
259         buf.append(HTTP_VERSION);
260         buf.append(SP);
261         buf.append(code+"");
262         buf.append(SP);
263         buf.append(responseString);
264
265         return buf.toString();
266     }
267
268     /** closes the message sent to the browser
269      */

270     private void closeMessage() {
271         setContentLengthHeader();
272         setCookieHeader();
273     }
274
275
276     private void setContentLengthHeader() {
277         if (content == null){
278             writer.flush();
279             writer.close();
280             body = baos.toByteArray();
281             setHeader("Content-Length", body.length+"");
282         } else {
283             setHeader("Content-Length", content.getContentLength()+"");
284         }
285     }
286
287     private void setCookieHeader() {
288         if (request == null || request.getSession() == null) return;
289         
290         HttpSession session = request.getSession(false);
291
292         if (session == null) return;
293
294         StringBuffer JavaDoc cookie = new StringBuffer JavaDoc();
295         cookie.append(HttpRequestImpl.EJBSESSIONID);
296         cookie.append('=');
297         cookie.append(session.getId());
298         cookie.append("; Path=/");
299
300         headers.put(HttpRequest.HEADER_SET_COOKIE, cookie.toString());
301     }
302     
303     /** Writes a response line similar to this:
304      *
305      * HTTP/1.1 200 OK
306      *
307      * to the browser
308      * @param out the output stream to write the response line to
309      * @throws java.io.IOException if an exception is thrown
310      */

311     private void writeResponseLine(DataOutput JavaDoc out) throws IOException JavaDoc{
312         out.writeBytes(HTTP_VERSION);
313         out.writeBytes(SP);
314         out.writeBytes(code+"");
315         out.writeBytes(SP);
316         out.writeBytes(responseString);
317         out.writeBytes(CRLF);
318     }
319
320     /** writes the headers out to the browser
321      * @param out the output stream to be sent to the browser
322      * @throws java.io.IOException if an exception is thrown
323      */

324     private void writeHeaders(DataOutput JavaDoc out) throws IOException JavaDoc{
325         Iterator JavaDoc it = headers.entrySet().iterator();
326
327         while (it.hasNext()){
328             Map.Entry JavaDoc entry = (Map.Entry JavaDoc)it.next();
329             out.writeBytes(""+entry.getKey());
330             out.writeBytes(CSP);
331             out.writeBytes(""+entry.getValue());
332             out.writeBytes(CRLF);
333         }
334     }
335
336     /** writes the body out to the browser
337      * @param out the output stream that writes to the browser
338      * @throws java.io.IOException if an exception is thrown
339      */

340     private void writeBody(DataOutput JavaDoc out) throws IOException JavaDoc{
341         out.writeBytes(CRLF);
342         if (content == null){
343             out.write(body);
344         } else {
345             InputStream JavaDoc in = content.getInputStream();
346             byte buf[] = new byte[1024];
347             for(int i = 0; (i = in.read(buf)) != -1; out.write(buf, 0, i));
348         }
349     }
350
351     /** gets the name of the server being used
352      * @return the name of the server
353      */

354     public String JavaDoc getServerName(){
355         if (server == null) {
356             String JavaDoc version = "???";
357             String JavaDoc os = "(unknown os)";
358             
359             try {
360                 Properties JavaDoc versionInfo = new Properties JavaDoc();
361                 JarUtils.setHandlerSystemProperty();
362                 versionInfo.load( new URL JavaDoc( "resource:/openejb-version.properties" ).openConnection().getInputStream() );
363                 version = versionInfo.getProperty( "version" );
364                 os = System.getProperty("os.name")+"/"+System.getProperty("os.version")+" ("+System.getProperty("os.arch")+")";
365             } catch (IOException JavaDoc e) {
366             }
367             
368             server = "OpenEJB/" +version+ " "+os;
369         }
370         return server;
371     }
372     
373     
374     /** This could be improved at some day in the future
375      * to also include a stack trace of the exceptions
376      * @param message the error message to be sent
377      * @return the HttpResponseImpl that this error belongs to
378      */

379     protected static HttpResponseImpl createError(String JavaDoc message){
380         return createError(message, null);
381     }
382
383     /** creates an error with user defined variables
384      * @param message the message of the error
385      * @param t a Throwable to print a stack trace to
386      * @return the HttpResponseImpl that this error belongs to
387      */

388     protected static HttpResponseImpl createError(String JavaDoc message, Throwable JavaDoc t){
389         HttpResponseImpl res = new HttpResponseImpl(500, "Internal Server Error", "text/html");
390         PrintWriter JavaDoc body = res.getPrintWriter();
391
392         body.println("<html>");
393         body.println("<body>");
394         body.println("<h3>Internal Server Error</h3>");
395         body.println("<br><br>");
396         System.out.println("ERROR");
397         if (message != null) {
398             StringTokenizer JavaDoc msg = new StringTokenizer JavaDoc(message, "\n\r");
399
400             while (msg.hasMoreTokens()) {
401                 body.print( msg.nextToken() );
402                 body.println("<br>");
403             }
404         }
405
406         if (t != null) {
407             try{
408                 body.println("<br><br>");
409                 body.println("Stack Trace:<br>");
410                 ByteArrayOutputStream JavaDoc baos = new ByteArrayOutputStream JavaDoc();
411                 PrintWriter JavaDoc writer = new PrintWriter JavaDoc( baos );
412                 t.printStackTrace(writer);
413                 writer.flush();
414                 writer.close();
415                 message = new String JavaDoc(baos.toByteArray());
416                 StringTokenizer JavaDoc msg = new StringTokenizer JavaDoc(message, "\n\r");
417                 
418                 while (msg.hasMoreTokens()) {
419                     body.print( msg.nextToken() );
420                     body.println("<br>");
421                 }
422             } catch (Exception JavaDoc e){
423             }
424         }
425
426         body.println("</body>");
427         body.println("</html>");
428
429         return res;
430     }
431
432     /** Creates a forbidden response to be sent to the browser using IP authentication
433      * @param ip the ip that is forbidden
434      * @return the HttpResponseImpl that this error belongs to
435      */

436     protected static HttpResponseImpl createForbidden(String JavaDoc ip){
437         HttpResponseImpl res = new HttpResponseImpl(403, "Forbidden", "text/html");
438         PrintWriter JavaDoc body = res.getPrintWriter();
439
440         body.println("<html>");
441         body.println("<body>");
442         body.println("<h3>Forbidden</h3>");
443         body.println("<br><br>");
444         // Add more text here
445
// IP not allowed, etc.
446
body.println("IP address: " + ip + " is not registered on this server, please contact your system administrator.");
447         body.println("</body>");
448         body.println("</html>");
449
450         return res;
451     }
452
453     /** writes this object out to a file
454      * @param out the ObjectOutputStream to write to
455      * @throws java.io.IOException if an exception is thrown
456      */

457     private void writeObject(java.io.ObjectOutputStream JavaDoc out) throws IOException JavaDoc{
458         /** Response string */
459         out.writeObject( responseString );
460
461         /** Code */
462         out.writeInt( code );
463
464         /** Response headers */
465         out.writeObject( headers );
466
467         /** Response body */
468         writer.flush();
469         body = baos.toByteArray();
470         //System.out.println("[] body "+body.length );
471
out.writeObject( body );
472     }
473     
474     /** Reads in a serilized HttpResponseImpl object from a file
475      * @param in the input to read the object from
476      * @throws java.io.IOException if an exception is thrown
477      * @throws ClassNotFoundException if an exception is thrown
478      */

479     private void readObject(java.io.ObjectInputStream JavaDoc in) throws IOException JavaDoc, ClassNotFoundException JavaDoc{
480         /** Response string */
481         this.responseString = (String JavaDoc)in.readObject();
482
483         /** Code */
484         this.code = in.readInt();
485
486         /** Response headers */
487         this.headers = (HashMap JavaDoc) in.readObject();
488
489         /** Response body */
490         body = (byte[]) in.readObject();
491         //System.out.println("[] body "+body.length );
492
baos = new ByteArrayOutputStream JavaDoc();
493         baos.write( body );
494         writer = new PrintWriter JavaDoc( baos );
495
496     }
497     /**
498      * @param content The content to set.
499      */

500     public void setContent(URLConnection JavaDoc content) {
501         this.content = content;
502     }
503
504     public void setStatusCode(int code) {
505         this.setCode(code);
506     }
507
508     public int getStatusCode() {
509         return this.getCode();
510     }
511
512     public void setStatusMessage(String JavaDoc responseString) {
513         this.setResponseString(responseString);
514     }
515
516 }
Popular Tags