1 /*
2 * Copyright 1999,2004 The Apache Software Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17
18 package org.apache.commons.messagelet.impl;
19
20
21 import java.io.BufferedReader;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.InputStreamReader;
25 import java.io.UnsupportedEncodingException;
26 import java.util.ArrayList;
27 import java.util.Enumeration;
28 import java.util.HashMap;
29 import java.util.Locale;
30 import java.util.Map;
31
32 import javax.servlet.RequestDispatcher;
33 import javax.servlet.ServletContext;
34 import javax.servlet.ServletInputStream;
35 import javax.servlet.ServletRequest;
36
37 import org.apache.commons.collections.iterators.IteratorEnumeration;
38 import org.apache.commons.collections.iterators.SingletonIterator;
39
40 /**
41 * Based on the RequestBase code from Catalina.
42 *
43 * @author Craig R. McClanahan
44 * @author James Strachan
45 * @version $Revision: 155459 $ $Date: 2005-02-26 13:24:44 +0000 (Sat, 26 Feb 2005) $
46 */
47
48 public class ServletRequestImpl implements ServletRequest {
49
50
51 // ----------------------------------------------------- Instance Variables
52
53
54 /**
55 * The attributes associated with this Request, keyed by attribute name.
56 */
57 protected HashMap attributes = new HashMap();
58
59
60 /**
61 * The authorization credentials sent with this Request.
62 */
63 protected String authorization = null;
64
65
66 /**
67 * The character encoding for this Request.
68 */
69 protected String characterEncoding = null;
70
71
72
73 /**
74 * The content length associated with this request.
75 */
76 protected int contentLength = -1;
77
78
79 /**
80 * The content type associated with this request.
81 */
82 protected String contentType = null;
83
84
85 /**
86 * The default Locale if none are specified.
87 */
88 protected static Locale defaultLocale = Locale.getDefault();
89
90
91 /**
92 * The input stream associated with this Request.
93 */
94 protected InputStream input = null;
95
96
97 /**
98 * The preferred Locales assocaited with this Request.
99 */
100 protected ArrayList locales = new ArrayList();
101
102
103
104 /**
105 * The protocol name and version associated with this Request.
106 */
107 protected String protocol = null;
108
109
110 /**
111 * The reader that has been returned by <code>getReader</code>, if any.
112 */
113 protected BufferedReader reader = null;
114
115
116 /**
117 * The remote address associated with this request.
118 */
119 protected String remoteAddr = null;
120
121
122 /**
123 * The fully qualified name of the remote host.
124 */
125 protected String remoteHost = null;
126
127
128
129 /**
130 * The scheme associated with this Request.
131 */
132 protected String scheme = null;
133
134
135 /**
136 * Was this request received on a secure connection?
137 */
138 protected boolean secure = false;
139
140
141 /**
142 * The server name associated with this Request.
143 */
144 protected String serverName = null;
145
146
147 /**
148 * The server port associated with this Request.
149 */
150 protected int serverPort = -1;
151
152
153 /**
154 * The ServletInputStream that has been returned by
155 * <code>getInputStream()</code>, if any.
156 */
157 protected ServletInputStream stream = null;
158
159
160 /**
161 * The ServletContext which is used to dispatch further requests
162 */
163 protected ServletContext servletContext;
164
165
166
167 public ServletRequestImpl(ServletContext servletContext) {
168 this.servletContext = servletContext;
169 }
170
171 // ------------------------------------------------------------- Properties
172
173
174
175 /**
176 * Return the input stream associated with this Request.
177 */
178 public InputStream getStream() {
179
180 return (this.input);
181
182 }
183
184
185 /**
186 * Set the input stream associated with this Request.
187 *
188 * @param input The new input stream
189 */
190 public void setStream(InputStream input) {
191
192 this.input = input;
193
194 }
195
196
197
198 // --------------------------------------------------------- Public Methods
199
200
201 /**
202 * Add a Locale to the set of preferred Locales for this Request. The
203 * first added Locale will be the first one returned by getLocales().
204 *
205 * @param locale The new preferred Locale
206 */
207 public void addLocale(Locale locale) {
208
209 synchronized (locales) {
210 locales.add(locale);
211 }
212
213 }
214
215
216 /**
217 * Create and return a ServletInputStream to read the content
218 * associated with this Request. The default implementation creates an
219 * instance of RequestStream associated with this request, but this can
220 * be overridden if necessary.
221 *
222 * @exception IOException if an input/output error occurs
223 */
224 public ServletInputStream createInputStream() throws IOException {
225
226 //return (new RequestStream(this));
227 return null;
228
229 }
230
231
232 /**
233 * Perform whatever actions are required to flush and close the input
234 * stream or reader, in a single operation.
235 *
236 * @exception IOException if an input/output error occurs
237 */
238 public void finishRequest() throws IOException {
239
240 // If a Reader has been acquired, close it
241 if (reader != null) {
242 try {
243 reader.close();
244 } catch (IOException e) {
245 ;
246 }
247 }
248
249 // If a ServletInputStream has been acquired, close it
250 if (stream != null) {
251 try {
252 stream.close();
253 } catch (IOException e) {
254 ;
255 }
256 }
257
258 // The underlying input stream (perhaps from a socket)
259 // is not our responsibility
260
261 }
262
263
264 /**
265 * Set the content length associated with this Request.
266 *
267 * @param length The new content length
268 */
269 public void setContentLength(int length) {
270
271 this.contentLength = length;
272
273 }
274
275
276 /**
277 * Set the content type (and optionally the character encoding)
278 * associated with this Request. For example,
279 * <code>text/html; charset=ISO-8859-4</code>.
280 *
281 * @param type The new content type
282 */
283 public void setContentType(String type) {
284
285 this.contentType = type;
286 if (type.indexOf(';') >= 0) {
287 //characterEncoding = RequestUtil.parseCharacterEncoding(type);
288 }
289
290 }
291
292
293
294 /**
295 * Set the protocol name and version associated with this Request.
296 *
297 * @param protocol Protocol name and version
298 */
299 public void setProtocol(String protocol) {
300
301 this.protocol = protocol;
302
303 }
304
305
306 /**
307 * Set the IP address of the remote client associated with this Request.
308 *
309 * @param remoteAddr The remote IP address
310 */
311 public void setRemoteAddr(String remoteAddr) {
312
313 this.remoteAddr = remoteAddr;
314
315 }
316
317
318 /**
319 * Set the fully qualified name of the remote client associated with this
320 * Request.
321 *
322 * @param remoteHost The remote host name
323 */
324 public void setRemoteHost(String remoteHost) {
325
326 this.remoteHost = remoteHost;
327
328 }
329
330
331 /**
332 * Set the name of the scheme associated with this request. Typical values
333 * are <code>http</code>, <code>https</code>, and <code>ftp</code>.
334 *
335 * @param scheme The scheme
336 */
337 public void setScheme(String scheme) {
338
339 this.scheme = scheme;
340
341 }
342
343
344 /**
345 * Set the value to be returned by <code>isSecure()</code>
346 * for this Request.
347 *
348 * @param secure The new isSecure value
349 */
350 public void setSecure(boolean secure) {
351
352 this.secure = secure;
353
354 }
355
356
357 /**
358 * Set the name of the server (virtual host) to process this request.
359 *
360 * @param name The server name
361 */
362 public void setServerName(String name) {
363
364 this.serverName = name;
365
366 }
367
368
369 /**
370 * Set the port number of the server to process this request.
371 *
372 * @param port The server port
373 */
374 public void setServerPort(int port) {
375
376 this.serverPort = port;
377
378 }
379
380
381 // ------------------------------------------------- ServletRequest Methods
382
383
384 /**
385 * Return the specified request attribute if it exists; otherwise, return
386 * <code>null</code>.
387 *
388 * @param name Name of the request attribute to return
389 */
390 public Object getAttribute(String name) {
391
392 synchronized (attributes) {
393 return (attributes.get(name));
394 }
395
396 }
397
398
399 /**
400 * Return the names of all request attributes for this Request, or an
401 * empty <code>Enumeration</code> if there are none.
402 */
403 public Enumeration getAttributeNames() {
404
405 synchronized (attributes) {
406 return new IteratorEnumeration(attributes.keySet().iterator());
407 }
408
409 }
410
411
412 /**
413 * Return the character encoding for this Request.
414 */
415 public String getCharacterEncoding() {
416
417 if (characterEncoding== null) {
418 characterEncoding= "ISO-8859-1";
419 }
420 return (this.characterEncoding);
421 }
422
423
424 /**
425 * Return the content length for this Request.
426 */
427 public int getContentLength() {
428
429 return (this.contentLength);
430
431 }
432
433
434 /**
435 * Return the content type for this Request.
436 */
437 public String getContentType() {
438
439 return (contentType);
440
441 }
442
443
444 /**
445 * Return the servlet input stream for this Request. The default
446 * implementation returns a servlet input stream created by
447 * <code>createInputStream()</code>.
448 *
449 * @exception IllegalStateException if <code>getReader()</code> has
450 * already been called for this request
451 * @exception IOException if an input/output error occurs
452 */
453 public ServletInputStream getInputStream() throws IOException {
454
455 if (reader != null) {
456 throw new IllegalStateException( "getReader() has already been called" );
457 }
458
459 if (stream == null)
460 stream = createInputStream();
461 return (stream);
462
463 }
464
465
466 /**
467 * Return the preferred Locale that the client will accept content in,
468 * based on the value for the first <code>Accept-Language</code> header
469 * that was encountered. If the request did not specify a preferred
470 * language, the server's default Locale is returned.
471 */
472 public Locale getLocale() {
473
474 synchronized (locales) {
475 if (locales.size() > 0)
476 return ((Locale) locales.get(0));
477 else
478 return (defaultLocale);
479 }
480
481 }
482
483
484 /**
485 * Return the set of preferred Locales that the client will accept
486 * content in, based on the values for any <code>Accept-Language</code>
487 * headers that were encountered. If the request did not specify a
488 * preferred language, the server's default Locale is returned.
489 */
490 public Enumeration getLocales() {
491
492 synchronized (locales) {
493 if (locales.size() > 0) {
494 return new IteratorEnumeration( locales.iterator() );
495 }
496 }
497 return new IteratorEnumeration( new SingletonIterator( defaultLocale ) );
498
499 }
500
501
502 /**
503 * Return the value of the specified request parameter, if any; otherwise,
504 * return <code>null</code>. If there is more than one value defined,
505 * return only the first one.
506 *
507 * @param name Name of the desired request parameter
508 */
509 public String getParameter(String name) {
510 String values[] = (String[]) getParameterMap().get(name);
511 if (values != null)
512 return (values[0]);
513 else
514 return (null);
515
516 }
517
518
519 /**
520 * Return the defined values for the specified request parameter, if any;
521 * otherwise, return <code>null</code>.
522 *
523 * @param name Name of the desired request parameter
524 */
525 public String[] getParameterValues(String name) {
526 String values[] = (String[]) getParameterMap().get(name);
527 if (values != null)
528 return (values);
529 else
530 return (null);
531 }
532
533
534 /**
535 * Returns a <code>Map</code> of the parameters of this request.
536 * Request parameters are extra information sent with the request.
537 * For HTTP servlets, parameters are contained in the query string
538 * or posted form data.
539 *
540 * @return A <code>Map</code> containing parameter names as keys
541 * and parameter values as map values.
542 */
543 public Map getParameterMap() {
544 return new HashMap();
545 }
546
547
548 /**
549 * Return the names of all defined request parameters for this request.
550 */
551 public Enumeration getParameterNames() {
552 return new IteratorEnumeration(getParameterMap().keySet().iterator());
553 }
554
555
556 /**
557 * Return the protocol and version used to make this Request.
558 */
559 public String getProtocol() {
560
561 return (this.protocol);
562
563 }
564
565
566 /**
567 * Read the Reader wrapping the input stream for this Request. The
568 * default implementation wraps a <code>BufferedReader</code> around the
569 * servlet input stream returned by <code>createInputStream()</code>.
570 *
571 * @exception IllegalStateException if <code>getInputStream()</code>
572 * has already been called for this request
573 * @exception IOException if an input/output error occurs
574 */
575 public BufferedReader getReader() throws IOException {
576
577 if (stream != null) {
578 throw new IllegalStateException( "getInputStream() has already been called" );
579 }
580
581 if (reader == null) {
582 String encoding = getCharacterEncoding();
583 InputStreamReader isr =
584 new InputStreamReader(createInputStream(), encoding);
585 reader = new BufferedReader(isr);
586 }
587 return (reader);
588
589 }
590
591
592 /**
593 * Return the real path of the specified virtual path.
594 *
595 * @param path Path to be translated
596 *
597 * @deprecated As of version 2.1 of the Java Servlet API, use
598 * <code>ServletContext.getRealPath()</code>.
599 */
600 public String getRealPath(String path) {
601
602 if (servletContext == null)
603 return (null);
604 else {
605 try {
606 return (servletContext.getRealPath(path));
607 } catch (IllegalArgumentException e) {
608 return (null);
609 }
610 }
611
612 }
613
614
615 /**
616 * Return the remote IP address making this Request.
617 */
618 public String getRemoteAddr() {
619
620 return (this.remoteAddr);
621
622 }
623
624
625 /**
626 * Return the remote host name making this Request.
627 */
628 public String getRemoteHost() {
629
630 return (this.remoteHost);
631
632 }
633
634
635 /**
636 * Return a RequestDispatcher that wraps the resource at the specified
637 * path, which may be interpreted as relative to the current request path.
638 *
639 * @param path Path of the resource to be wrapped
640 */
641 public RequestDispatcher getRequestDispatcher(String path) {
642 return servletContext.getRequestDispatcher(path);
643 }
644
645
646 /**
647 * Return the scheme used to make this Request.
648 */
649 public String getScheme() {
650
651 return (this.scheme);
652
653 }
654
655
656 /**
657 * Return the server name responding to this Request.
658 */
659 public String getServerName() {
660
661 return (this.serverName);
662
663 }
664
665
666 /**
667 * Return the server port responding to this Request.
668 */
669 public int getServerPort() {
670
671 return (this.serverPort);
672
673 }
674
675
676 /**
677 * Was this request received on a secure connection?
678 */
679 public boolean isSecure() {
680
681 return (this.secure);
682
683 }
684
685
686 /**
687 * Remove the specified request attribute if it exists.
688 *
689 * @param name Name of the request attribute to remove
690 */
691 public void removeAttribute(String name) {
692
693 synchronized (attributes) {
694 attributes.remove(name);
695 }
696
697 }
698
699
700 /**
701 * Set the specified request attribute to the specified value.
702 *
703 * @param name Name of the request attribute to set
704 * @param value The associated value
705 */
706 public void setAttribute(String name, Object value) {
707
708 // Name cannot be null
709 if (name == null) {
710 throw new IllegalArgumentException( "Attribute name cannot be null" );
711 }
712
713 // Null value is the same as removeAttribute()
714 if (value == null) {
715 removeAttribute(name);
716 return;
717 }
718
719 synchronized (attributes) {
720 attributes.put(name, value);
721 }
722
723 }
724
725
726 /**
727 * Overrides the name of the character encoding used in the body of
728 * this request. This method must be called prior to reading request
729 * parameters or reading input using <code>getReader()</code>.
730 *
731 * @param enc The character encoding to be used
732 *
733 * @exception UnsupportedEncodingException if the specified encoding
734 * is not supported
735 *
736 * @since Servlet 2.3
737 */
738 public void setCharacterEncoding(String enc)
739 throws UnsupportedEncodingException {
740
741 // Ensure that the specified encoding is valid
742 byte buffer[] = new byte[1];
743 buffer[0] = (byte) 'a';
744 String dummy = new String(buffer, enc);
745
746 // Save the validated encoding
747 this.characterEncoding = enc;
748 }
749
750 /**
751 * Log a message to the current ServletContext
752 *
753 * @param message Message to be logged
754 */
755 protected void log(String message) {
756
757 servletContext.log(message);
758
759 }
760
761
762 /**
763 * Log a message to the current ServletContext
764 *
765 * @param message Message to be logged
766 * @param throwable Associated exception
767 */
768 protected void log(String message, Throwable throwable) {
769
770 servletContext.log(message, throwable);
771
772 }
773
774 }