2011/08/05 - Jakarta Cactus has been retired.

For more information, please explore the Attic.

View Javadoc

1   /* 
2    * ========================================================================
3    * 
4    * Licensed to the Apache Software Foundation (ASF) under one or more
5    * contributor license agreements.  See the NOTICE file distributed with
6    * this work for additional information regarding copyright ownership.
7    * The ASF licenses this file to You under the Apache License, Version 2.0
8    * (the "License"); you may not use this file except in compliance with
9    * the License.  You may obtain a copy of the License at
10   * 
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   * 
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * 
19   * ========================================================================
20   */
21  package org.apache.cactus.server;
22  
23  import java.io.BufferedReader;
24  import java.io.File;
25  import java.io.IOException;
26  
27  import java.lang.reflect.Constructor;
28  
29  import java.security.Principal;
30  
31  import java.util.Enumeration;
32  import java.util.Locale;
33  
34  import javax.servlet.RequestDispatcher;
35  import javax.servlet.ServletInputStream;
36  import javax.servlet.http.Cookie;
37  import javax.servlet.http.HttpServletRequest;
38  import javax.servlet.http.HttpSession;
39  
40  import org.apache.cactus.ServletURL;
41  import org.apache.cactus.util.ChainedRuntimeException;
42  
43  import org.apache.commons.logging.Log;
44  import org.apache.commons.logging.LogFactory;
45  
46  
47  /**
48   * Abstract wrapper around {@link HttpServletRequest}. This class provides
49   * a common implementation of the wrapper for the different Servlet APIs.
50   * This is an implementation that delegates all the call to the
51   * {@link HttpServletRequest} object passed in the constructor except for
52   * some overidden methods which are use to simulate a URL. This is to be able 
53   * to simulate any URL that would have been used to call the test method : if 
54   * this was not done, the URL that would be returned (by calling the
55   * {@link HttpServletRequest#getRequestURI()} method or others alike) would be 
56   * the URL of the Cactus redirector servlet and not a URL that the test case 
57   * want to simulate.
58   *
59   * @version $Id: AbstractHttpServletRequestWrapper.java 292559 2005-09-29 21:36:43Z kenney $
60   */
61  public abstract class AbstractHttpServletRequestWrapper
62      implements HttpServletRequest
63  {
64      /**
65       * The logger.
66       */
67      private static final Log LOGGER = 
68          LogFactory.getLog(AbstractHttpServletRequestWrapper.class);
69  
70      /**
71       * The real HTTP request.
72       */
73      protected HttpServletRequest request;
74  
75      /**
76       * The URL to simulate.
77       */
78      protected ServletURL url;
79  
80      /**
81       * Remote IP address to simulate (if any).
82       * @see #setRemoteIPAddress(String)
83       */
84      protected String remoteIPAddress;
85  
86      /**
87       * Remote Host name to simulate (if any).
88       * @see #setRemoteHostName(String)
89       */
90      protected String remoteHostName;
91  
92      /**
93       * Remote user to simulate (if any).
94       * @see #setRemoteUser(String)
95       */
96      protected String remoteUser;
97  
98      // New methods not in the interface --------------------------------------
99  
100     /**
101      * Construct an <code>HttpServletRequest</code> instance that delegates
102      * it's method calls to the request object passed as parameter and that
103      * uses the URL passed as parameter to simulate a URL from which the request
104      * would come from.
105      *
106      * @param theRequest the real HTTP request
107      * @param theURL     the URL to simulate or <code>null</code> if none
108      */
109     public AbstractHttpServletRequestWrapper(HttpServletRequest theRequest, 
110         ServletURL theURL)
111     {
112         this.request = theRequest;
113         this.url = theURL;
114     }
115     /**
116      * {@inheritDoc}
117      * @see HttpServletRequest#newInstance()
118      */
119     public static AbstractHttpServletRequestWrapper newInstance(
120         HttpServletRequest theOriginalRequest, ServletURL theURL)
121     {
122         try
123         {
124             Class clazz = Class.forName(
125                 "org.apache.cactus.server.HttpServletRequestWrapper");
126             Object[] args = new Object[] {theOriginalRequest, theURL};
127 
128             Constructor constructor = clazz.getConstructor(new Class[] {
129                 HttpServletRequest.class, ServletURL.class });
130 
131             return (AbstractHttpServletRequestWrapper) constructor.
132                newInstance(args);
133         }
134         catch (Throwable t)
135         {
136             throw new ChainedRuntimeException(
137                 "Failed to create HttpServletRequestWrapper", t);
138         }
139     }
140 
141 
142     /**
143      * @return the original request object
144      */
145     public HttpServletRequest getOriginalRequest()
146     {
147         return this.request;
148     }
149 
150     /**
151      * Simulates the remote IP address (ie the client IP address).
152      *
153      * @param theRemoteIPAddress the simulated IP address in string format.
154      *        Exemple : "127.0.0.1"
155      */
156     public void setRemoteIPAddress(String theRemoteIPAddress)
157     {
158         this.remoteIPAddress = theRemoteIPAddress;
159     }
160 
161     /**
162      * Simulates the remote host name(ie the client host name).
163      *
164      * @param theRemoteHostName the simulated host name in string format.
165      *        Exemple : "atlantis"
166      */
167     public void setRemoteHostName(String theRemoteHostName)
168     {
169         this.remoteHostName = theRemoteHostName;
170     }
171 
172     /**
173      * Sets the remote user name to simulate.
174      *
175      * @param theRemoteUser the simulated remote user name
176      */
177     public void setRemoteUser(String theRemoteUser)
178     {
179         this.remoteUser = theRemoteUser;
180     }
181 
182     // Modified methods ------------------------------------------------------
183 
184     /**
185      * @return the context path from the simulated URL or the real context path
186      *         if a simulation URL has not been defined. The real context path
187      *         will be returned if the context path defined in the simulated 
188      *         URL has a null value.
189      */
190     public String getContextPath()
191     {
192         String result = this.request.getContextPath();
193 
194         if ((this.url != null) && (this.url.getContextPath() != null))
195         {
196             result = this.url.getContextPath();
197             LOGGER.debug("Using simulated context : [" + result + "]");
198         }
199 
200         return result;
201     }
202 
203     /**
204      * @return the path info from the simulated URL or the real path info
205      *         if a simulation URL has not been defined.
206      */
207     public String getPathInfo()
208     {
209         String result;
210 
211         if (this.url != null)
212         {
213             result = this.url.getPathInfo();
214             LOGGER.debug("Using simulated PathInfo : [" + result + "]");
215         }
216         else
217         {
218             result = this.request.getPathInfo();
219         }
220 
221         return result;
222     }
223 
224     /**
225      * @return the server name from the simulated URL or the real server name
226      *         if a simulation URL has not been defined. If the server name
227      *         defined in the simulation URL is null, return the real server
228      *         name.
229      */
230     public String getServerName()
231     {
232         String result = this.request.getServerName();
233 
234         if ((this.url != null) && (this.url.getHost() != null))
235         {
236             result = this.url.getHost();
237             LOGGER.debug("Using simulated server name : [" + result + "]");
238         }
239 
240         return result;
241     }
242 
243     /**
244      * @return the server port number from the simulated URL or the real server
245      *         port number if a simulation URL has not been defined. If no
246      *         port is defined in the simulation URL, then port 80 is returned.
247      *         If the server name has been defined with a null value in
248      *         in the simulation URL, return the real server port. 
249      */
250     public int getServerPort()
251     {
252         int result = this.request.getServerPort();
253 
254         if ((this.url != null) && (this.url.getServerName() != null))
255         {
256             result = (this.url.getPort() == -1) ? 80 : this.url.getPort();
257             LOGGER.debug("Using simulated server port : [" + result + "]");
258         }
259 
260         return result;
261     }
262 
263     /**
264      * @return the URI from the simulated URL or the real URI
265      *         if a simulation URL has not been defined.
266      */
267     public String getRequestURI()
268     {
269         String result;
270 
271         if (this.url != null)
272         {
273             result = getContextPath()
274                 + ((getServletPath() == null) ? "" : getServletPath())
275                 + ((getPathInfo() == null) ? "" : getPathInfo());
276 
277             LOGGER.debug("Using simulated request URI : [" + result + "]");
278         }
279         else
280         {
281             result = this.request.getRequestURI();
282         }
283 
284         return result;
285     }
286 
287     /**
288      * @return the servlet path from the simulated URL or the real servlet path
289      *         if a simulation URL has not been defined. The real servlet path
290      *         will be returned if the servlet path defined in the simulated 
291      *         URL has a null value.
292      */
293     public String getServletPath()
294     {
295         String result = this.request.getServletPath();
296 
297         if ((this.url != null) && (this.url.getServletPath() != null))
298         {
299             result = this.url.getServletPath();
300             LOGGER.debug("Using simulated servlet path : [" + result + "]");
301         }
302 
303         return result;
304     }
305 
306     /**
307      * @return any extra path information after the servlet name but
308      *         before the query string, and translates it to a real path.
309      *         Takes into account the simulated URL (if any).
310      */
311     public String getPathTranslated()
312     {
313         String pathTranslated;
314 
315         if ((this.url != null) && (this.url.getPathInfo() != null))
316         {
317             String pathInfo = this.url.getPathInfo();
318             
319             // If getRealPath returns null then getPathTranslated should also
320             // return null (see section SRV.4.5 of the Servlet 2.3 spec).
321             if (this.request.getRealPath("/") == null)
322             {
323                 pathTranslated = null;
324             }
325             else
326             {
327                 // Compute the translated path using the root real path
328                 String newPathInfo = (pathInfo.startsWith("/")
329                     ? pathInfo.substring(1) : pathInfo);
330 
331                 if (this.request.getRealPath("/").endsWith("/"))
332                 {
333                     pathTranslated = this.request.getRealPath("/")
334                         + newPathInfo.replace('/', File.separatorChar);
335                 }
336                 else
337                 {
338                     pathTranslated = this.request.getRealPath("/")
339                         + File.separatorChar + newPathInfo.replace('/', 
340                         File.separatorChar);
341                 }
342             }
343         }
344         else
345         {
346             pathTranslated = this.request.getPathTranslated();
347         }
348 
349         return pathTranslated;
350     }
351 
352     /**
353      * @return the query string from the simulated URL or the real query
354      *         string if a simulation URL has not been defined.
355      */
356     public String getQueryString()
357     {
358         String result;
359 
360         if (this.url != null)
361         {
362             result = this.url.getQueryString();
363             LOGGER.debug("Using simulated query string : [" + result + "]");
364         }
365         else
366         {
367             result = this.request.getQueryString();
368         }
369 
370         return result;
371     }
372 
373     /**
374      * @param thePath the path to the resource
375      * @return a wrapped request dispatcher instead of the real one, so that
376      *         forward() and include() calls will use the wrapped dispatcher
377      *         passing it the *original* request [this is needed for some
378      *         servlet engine like Tomcat 3.x which do not support the new
379      *         mechanism introduced by Servlet 2.3 Filters].
380      * @see HttpServletRequest#getRequestDispatcher(String)
381      */
382     public RequestDispatcher getRequestDispatcher(String thePath)
383     {
384         // I hate it, but we have to write some logic here ! Ideally we
385         // shouldn't have to do this as it is supposed to be done by the servlet
386         // engine. However as we are simulating the request URL, we have to
387         // provide it ... This is where we can see the limitation of Cactus
388         // (it has to mock some parts of the servlet engine) !
389         if (thePath == null)
390         {
391             return null;
392         }
393 
394         RequestDispatcher dispatcher = null;
395         String fullPath;
396 
397         // The spec says that the path can be relative, in which case it will
398         // be relative to the request. So for relative paths, we need to take
399         // into account the simulated URL (ServletURL).
400         if (thePath.startsWith("/"))
401         {
402             fullPath = thePath;
403         }
404         else
405         {
406             String pI = getPathInfo();
407 
408             if (pI == null)
409             {
410                 fullPath = catPath(getServletPath(), thePath);
411             }
412             else
413             {
414                 fullPath = catPath(getServletPath() + pI, thePath);
415             }
416 
417             if (fullPath == null)
418             {
419                 return null;
420             }
421         }
422 
423         LOGGER.debug("Computed full path : [" + fullPath + "]");
424 
425         dispatcher = new RequestDispatcherWrapper(
426             this.request.getRequestDispatcher(fullPath));
427 
428         return dispatcher;
429     }
430 
431     /**
432      * Will concatenate 2 paths, normalising it. For example :
433      * ( /a/b/c + d = /a/b/d, /a/b/c + ../d = /a/d ). Code borrowed from
434      * Tomcat 3.2.2 !
435      *
436      * @param theLookupPath the first part of the path
437      * @param thePath the part to add to the lookup path
438      * @return the concatenated thePath or null if an error occurs
439      */
440     private String catPath(String theLookupPath, String thePath)
441     {
442         // Cut off the last slash and everything beyond
443         int index = theLookupPath.lastIndexOf("/");
444 
445         theLookupPath = theLookupPath.substring(0, index);
446 
447         // Deal with .. by chopping dirs off the lookup thePath
448         while (thePath.startsWith("../"))
449         {
450             if (theLookupPath.length() > 0)
451             {
452                 index = theLookupPath.lastIndexOf("/");
453                 theLookupPath = theLookupPath.substring(0, index);
454             }
455             else
456             {
457                 // More ..'s than dirs, return null
458                 return null;
459             }
460 
461             index = thePath.indexOf("../") + 3;
462             thePath = thePath.substring(index);
463         }
464 
465         return theLookupPath + "/" + thePath;
466     }
467 
468     /**
469      * @return the simulated remote IP address if any or the real one.
470      *
471      * @see HttpServletRequest#getRemoteAddr()
472      */
473     public String getRemoteAddr()
474     {
475         String remoteIPAddress;
476 
477         if (this.remoteIPAddress != null)
478         {
479             remoteIPAddress = this.remoteIPAddress;
480         }
481         else
482         {
483             remoteIPAddress = this.request.getRemoteAddr();
484         }
485 
486         return remoteIPAddress;
487     }
488 
489     /**
490      * @return the simulated remote host name if any or the real one.
491      *
492      * @see HttpServletRequest#getRemoteHost()
493      */
494     public String getRemoteHost()
495     {
496         String remoteHostName;
497 
498         if (this.remoteHostName != null)
499         {
500             remoteHostName = this.remoteHostName;
501         }
502         else
503         {
504             remoteHostName = this.request.getRemoteHost();
505         }
506 
507         return remoteHostName;
508     }
509 
510     /**
511      * @return the simulated remote user name if any or the real one.
512      *
513      * @see HttpServletRequest#getRemoteUser()
514      */
515     public String getRemoteUser()
516     {
517         String remoteUser;
518 
519         if (this.remoteUser != null)
520         {
521             remoteUser = this.remoteUser;
522         }
523         else
524         {
525             remoteUser = this.request.getRemoteUser();
526         }
527 
528         return remoteUser;
529     }
530 
531     // Not modified methods --------------------------------------------------
532 
533     /**
534      * {@inheritDoc}
535      * @see HttpServletRequest#isRequestedSessionIdFromURL()
536      */
537     public boolean isRequestedSessionIdFromURL()
538     {
539         return this.request.isRequestedSessionIdFromURL();
540     }
541 
542     /**
543      * {@inheritDoc} 
544      * @see HttpServletRequest#isRequestedSessionIdFromUrl()
545      */
546     public boolean isRequestedSessionIdFromUrl()
547     {
548         return this.request.isRequestedSessionIdFromURL();
549     }
550 
551     /**
552      * {@inheritDoc}
553      * @see HttpServletRequest#isUserInRole(String)
554      */
555     public boolean isUserInRole(String theRole)
556     {
557         return this.request.isUserInRole(theRole);
558     }
559 
560     /**
561      * {@inheritDoc}
562      * @see HttpServletRequest#isRequestedSessionIdValid()
563      */
564     public boolean isRequestedSessionIdValid()
565     {
566         return this.request.isRequestedSessionIdValid();
567     }
568 
569     /**
570      * {@inheritDoc}
571      * @see HttpServletRequest#isRequestedSessionIdFromCookie()
572      */
573     public boolean isRequestedSessionIdFromCookie()
574     {
575         return this.request.isRequestedSessionIdFromCookie();
576     }
577 
578     /**
579      * {@inheritDoc}
580      * @see HttpServletRequest#getLocales()
581      */
582     public Enumeration getLocales()
583     {
584         return this.request.getLocales();
585     }
586 
587     /**
588      * {@inheritDoc}
589      * @see HttpServletRequest#getHeader(String)
590      */
591     public String getHeader(String theName)
592     {
593         return this.request.getHeader(theName);
594     }
595 
596     /**
597      * {@inheritDoc}
598      * @see HttpServletRequest#getHeaders(String)
599      */
600     public Enumeration getHeaders(String theName)
601     {
602         return this.request.getHeaders(theName);
603     }
604 
605     /**
606      * {@inheritDoc}
607      * @see HttpServletRequest#getHeaderNames()
608      */
609     public Enumeration getHeaderNames()
610     {
611         return this.request.getHeaderNames();
612     }
613 
614     /**
615      * {@inheritDoc}
616      * @see HttpServletRequest#getScheme()
617      */
618     public String getScheme()
619     {
620         return this.request.getScheme();
621     }
622 
623     /**
624      * {@inheritDoc}
625      * @see HttpServletRequest#getAuthType()
626      */
627     public String getAuthType()
628     {
629         return this.request.getAuthType();
630     }
631 
632     /**
633      * {@inheritDoc}
634      * @see HttpServletRequest#getRealPath(String)
635      */
636     public String getRealPath(String thePath)
637     {
638         return this.request.getRealPath(thePath);
639     }
640 
641     /**
642      * {@inheritDoc}
643      * @see HttpServletRequest#getSession()
644      */
645     public HttpSession getSession()
646     {
647         return this.request.getSession();
648     }
649 
650     /**
651      * {@inheritDoc}
652      * @see HttpServletRequest#getSession(boolean)
653      */
654     public HttpSession getSession(boolean isCreate)
655     {
656         return this.request.getSession(isCreate);
657     }
658 
659     /**
660      * {@inheritDoc}
661      * @see HttpServletRequest#getReader()
662      */
663     public BufferedReader getReader() throws IOException
664     {
665         return this.request.getReader();
666     }
667 
668     /**
669      * {@inheritDoc}
670      * @see HttpServletRequest#getContentLength()
671      */
672     public int getContentLength()
673     {
674         return this.request.getContentLength();
675     }
676 
677     /**
678      * {@inheritDoc}
679      * @see HttpServletRequest#getParameterValues(String)
680      */
681     public String[] getParameterValues(String theName)
682     {
683         return this.request.getParameterValues(theName);
684     }
685 
686     /**
687      * {@inheritDoc}
688      * @see HttpServletRequest#getContentType()
689      */
690     public String getContentType()
691     {
692         return this.request.getContentType();
693     }
694 
695     /**
696      * {@inheritDoc}
697      * @see HttpServletRequest#getLocale()
698      */
699     public Locale getLocale()
700     {
701         return this.request.getLocale();
702     }
703 
704     /**
705      * {@inheritDoc}
706      * @see HttpServletRequest#removeAttribute(String)
707      */
708     public void removeAttribute(String theName)
709     {
710         this.request.removeAttribute(theName);
711     }
712 
713     /**
714      * {@inheritDoc}
715      * @see HttpServletRequest#getParameter(String)
716      */
717     public String getParameter(String theName)
718     {
719         return this.request.getParameter(theName);
720     }
721 
722     /**
723      * {@inheritDoc}
724      * @see HttpServletRequest#getInputStream()
725      */
726     public ServletInputStream getInputStream() throws IOException
727     {
728         return this.request.getInputStream();
729     }
730 
731     /**
732      * {@inheritDoc}
733      * @see HttpServletRequest#getUserPrincipal()
734      */
735     public Principal getUserPrincipal()
736     {
737         return this.request.getUserPrincipal();
738     }
739 
740     /**
741      * {@inheritDoc}
742      * @see HttpServletRequest#isSecure()
743      */
744     public boolean isSecure()
745     {
746         return this.request.isSecure();
747     }
748 
749     /**
750      * {@inheritDoc}
751      * @see HttpServletRequest#getCharacterEncoding()
752      */
753     public String getCharacterEncoding()
754     {
755         return this.request.getCharacterEncoding();
756     }
757 
758     /**
759      * {@inheritDoc}
760      * @see HttpServletRequest#getParameterNames()
761      */
762     public Enumeration getParameterNames()
763     {
764         return this.request.getParameterNames();
765     }
766 
767     /**
768      * {@inheritDoc}
769      * @see HttpServletRequest#getMethod()
770      */
771     public String getMethod()
772     {
773         return this.request.getMethod();
774     }
775 
776     /**
777      * {@inheritDoc}
778      * @see HttpServletRequest#setAttribute(String, Object)
779      */
780     public void setAttribute(String theName, Object theAttribute)
781     {
782         this.request.setAttribute(theName, theAttribute);
783     }
784 
785     /**
786      * {@inheritDoc}
787      * @see HttpServletRequest#getAttribute(String)
788      */
789     public Object getAttribute(String theName)
790     {
791         return this.request.getAttribute(theName);
792     }
793 
794     /**
795      * {@inheritDoc}
796      * @see HttpServletRequest#getIntHeader(String)
797      */
798     public int getIntHeader(String theName)
799     {
800         return this.request.getIntHeader(theName);
801     }
802 
803     /**
804      * {@inheritDoc}
805      * @see HttpServletRequest#getDateHeader(String)
806      */
807     public long getDateHeader(String theName)
808     {
809         return this.request.getDateHeader(theName);
810     }
811 
812     /**
813      * {@inheritDoc}
814      * @see HttpServletRequest#getAttributeNames()
815      */
816     public Enumeration getAttributeNames()
817     {
818         return this.request.getAttributeNames();
819     }
820 
821     /**
822      * {@inheritDoc}
823      * @see HttpServletRequest#getRequestedSessionId()
824      */
825     public String getRequestedSessionId()
826     {
827         return this.request.getRequestedSessionId();
828     }
829 
830     /**
831      * {@inheritDoc}
832      * @see HttpServletRequest#getCookies()
833      */
834     public Cookie[] getCookies()
835     {
836         return this.request.getCookies();
837     }
838 
839     /**
840      * {@inheritDoc}
841      * @see HttpServletRequest#getProtocol()
842      */
843     public String getProtocol()
844     {
845         return this.request.getProtocol();
846     }
847 }