001 /* 002 * Copyright 1999,2004 The Apache Software Foundation. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 018 package org.apache.commons.messagelet.impl; 019 020 021 import java.io.BufferedReader; 022 import java.io.IOException; 023 import java.io.InputStream; 024 import java.io.InputStreamReader; 025 import java.io.UnsupportedEncodingException; 026 import java.util.ArrayList; 027 import java.util.Enumeration; 028 import java.util.HashMap; 029 import java.util.Locale; 030 import java.util.Map; 031 032 import javax.servlet.RequestDispatcher; 033 import javax.servlet.ServletContext; 034 import javax.servlet.ServletInputStream; 035 import javax.servlet.ServletRequest; 036 037 import org.apache.commons.collections.iterators.IteratorEnumeration; 038 import org.apache.commons.collections.iterators.SingletonIterator; 039 040 /** 041 * Based on the RequestBase code from Catalina. 042 * 043 * @author Craig R. McClanahan 044 * @author James Strachan 045 * @version $Revision: 155459 $ $Date: 2005-02-26 13:24:44 +0000 (Sat, 26 Feb 2005) $ 046 */ 047 048 public class ServletRequestImpl implements ServletRequest { 049 050 051 // ----------------------------------------------------- Instance Variables 052 053 054 /** 055 * The attributes associated with this Request, keyed by attribute name. 056 */ 057 protected HashMap attributes = new HashMap(); 058 059 060 /** 061 * The authorization credentials sent with this Request. 062 */ 063 protected String authorization = null; 064 065 066 /** 067 * The character encoding for this Request. 068 */ 069 protected String characterEncoding = null; 070 071 072 073 /** 074 * The content length associated with this request. 075 */ 076 protected int contentLength = -1; 077 078 079 /** 080 * The content type associated with this request. 081 */ 082 protected String contentType = null; 083 084 085 /** 086 * The default Locale if none are specified. 087 */ 088 protected static Locale defaultLocale = Locale.getDefault(); 089 090 091 /** 092 * The input stream associated with this Request. 093 */ 094 protected InputStream input = null; 095 096 097 /** 098 * The preferred Locales assocaited with this Request. 099 */ 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 }