Clover coverage report - Code Coverage for tapestry release 3.1-alpha-1
Coverage timestamp: Mon Feb 21 2005 09:16:14 EST
file stats: LOC: 1,064   Methods: 43
NCLOC: 596   Classes: 2
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
RequestContext.java 60.7% 80% 83.7% 75.7%
coverage coverage
 1   
 // Copyright 2004, 2005 The Apache Software Foundation
 2   
 //
 3   
 // Licensed under the Apache License, Version 2.0 (the "License");
 4   
 // you may not use this file except in compliance with the License.
 5   
 // You may obtain a copy of the License at
 6   
 //
 7   
 //     http://www.apache.org/licenses/LICENSE-2.0
 8   
 //
 9   
 // Unless required by applicable law or agreed to in writing, software
 10   
 // distributed under the License is distributed on an "AS IS" BASIS,
 11   
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12   
 // See the License for the specific language governing permissions and
 13   
 // limitations under the License.
 14   
 
 15   
 package org.apache.tapestry.request;
 16   
 
 17   
 import java.io.IOException;
 18   
 import java.util.ArrayList;
 19   
 import java.util.Collections;
 20   
 import java.util.Date;
 21   
 import java.util.Enumeration;
 22   
 import java.util.HashMap;
 23   
 import java.util.List;
 24   
 import java.util.Map;
 25   
 import java.util.Properties;
 26   
 import java.util.StringTokenizer;
 27   
 
 28   
 import javax.servlet.ServletConfig;
 29   
 import javax.servlet.ServletContext;
 30   
 import javax.servlet.http.Cookie;
 31   
 import javax.servlet.http.HttpServlet;
 32   
 import javax.servlet.http.HttpServletRequest;
 33   
 import javax.servlet.http.HttpServletResponse;
 34   
 import javax.servlet.http.HttpSession;
 35   
 
 36   
 import org.apache.commons.logging.Log;
 37   
 import org.apache.commons.logging.LogFactory;
 38   
 import org.apache.tapestry.ApplicationServlet;
 39   
 import org.apache.tapestry.IMarkupWriter;
 40   
 import org.apache.tapestry.IRender;
 41   
 import org.apache.tapestry.IRequestCycle;
 42   
 import org.apache.tapestry.Tapestry;
 43   
 import org.apache.tapestry.multipart.DefaultMultipartDecoder;
 44   
 import org.apache.tapestry.multipart.IMultipartDecoder;
 45   
 import org.apache.tapestry.spec.IApplicationSpecification;
 46   
 
 47   
 /**
 48   
  * This class encapsulates all the relevant data for one request cycle of an
 49   
  * {@link ApplicationServlet}. This includes:
 50   
  * <ul>
 51   
  * <li>{@link HttpServletRequest}
 52   
  * <li>{@link HttpServletResponse}
 53   
  * <li>{@link HttpSession}
 54   
  * <li>{@link javax.servlet.http.HttpServlet}
 55   
  * </ul>
 56   
  * <p>
 57   
  * It also provides methods for:
 58   
  * <ul>
 59   
  * <li>Retrieving the request parameters (even if a file upload is involved)
 60   
  * <li>Getting, setting and removing request attributes
 61   
  * <li>Forwarding requests
 62   
  * <li>Redirecting requests
 63   
  * <li>Getting and setting Cookies
 64   
  * <li>Intepreting the request path info
 65   
  * <li>Writing an HTML description of the <code>RequestContext</code> (for debugging).
 66   
  * </ul>
 67   
  * <p>
 68   
  * If some cases, it is necesary to provide an implementation of {@link IRequestDecoder}(often, due
 69   
  * to a firewall). If the application specifification provides an extension named
 70   
  * <code>org.apache.tapestry.request-decoder</code> then it will be used, instead of a default
 71   
  * decoder.
 72   
  * <p>
 73   
  * This class is not a component, but does implement {@link IRender}. When asked to render (perhaps
 74   
  * as the delegate of a {@link org.apache.tapestry.components.Delegator}component} it simply
 75   
  * invokes {@link #write(IMarkupWriter)}to display all debugging output.
 76   
  * <p>
 77   
  * This class is derived from the original class <code>com.primix.servlet.RequestContext</code>,
 78   
  * part of the <b>ServletUtils </b> framework available from <a
 79   
  * href="http://www.gjt.org/servlets/JCVSlet/list/gjt/com/primix/servlet">The Giant Java Tree </a>.
 80   
  * 
 81   
  * @author Howard Lewis Ship
 82   
  */
 83   
 
 84   
 public class RequestContext implements IRender
 85   
 {
 86   
     /** @since 2.2 * */
 87   
 
 88   
     private static class DefaultRequestDecoder implements IRequestDecoder
 89   
     {
 90  185
         public DecodedRequest decodeRequest(HttpServletRequest request)
 91   
         {
 92  185
             DecodedRequest result = new DecodedRequest();
 93   
 
 94  185
             result.setRequestURI(request.getRequestURI());
 95  185
             result.setScheme(request.getScheme());
 96  185
             result.setServerName(request.getServerName());
 97  185
             result.setServerPort(request.getServerPort());
 98   
 
 99  185
             return result;
 100   
         }
 101   
     }
 102   
 
 103   
     private static final Log LOG = LogFactory.getLog(RequestContext.class);
 104   
 
 105   
     private HttpSession _session;
 106   
 
 107   
     private HttpServletRequest _request;
 108   
 
 109   
     private HttpServletResponse _response;
 110   
 
 111   
     private HttpServlet _servlet;
 112   
 
 113   
     private DecodedRequest _decodedRequest;
 114   
 
 115   
     private IMultipartDecoder _decoder;
 116   
 
 117   
     private boolean _decoded;
 118   
 
 119   
     private IApplicationSpecification _specification;
 120   
 
 121   
     /**
 122   
      * A mapping of the cookies available in the request.
 123   
      */
 124   
 
 125   
     private Map _cookieMap;
 126   
 
 127   
     /**
 128   
      * Used during {@link #write(IMarkupWriter)}.
 129   
      */
 130   
 
 131   
     private boolean _evenRow;
 132   
 
 133   
     /**
 134   
      * Creates a <code>RequestContext</code> from its components.
 135   
      */
 136   
 
 137  187
     public RequestContext(HttpServlet servlet, HttpServletRequest request,
 138   
             HttpServletResponse response, IApplicationSpecification specification)
 139   
             throws IOException
 140   
     {
 141  187
         _servlet = servlet;
 142  187
         _request = request;
 143  187
         _response = response;
 144  187
         _specification = specification;
 145   
 
 146   
         // All three parameters may be null if created from
 147   
         // AbstractEngine.cleanupEngine().
 148   
 
 149  187
         if (_request != null && DefaultMultipartDecoder.isMultipartRequest(request))
 150   
         {
 151  6
             IMultipartDecoder decoder = obtainMultipartDecoder(servlet, request);
 152  6
             setDecoder(decoder);
 153   
         }
 154   
     }
 155   
 
 156   
     /**
 157   
      * Invoked from the constructor to create a {@link DefaultMultipartDecoder}instance.
 158   
      * Applications with specific upload needs may need to override this to provide a subclass
 159   
      * instance instead. The caller will invoke {@link IMultipartDecoder#decode(HttpServletRequest)}
 160   
      * on the returned object.
 161   
      * <p>
 162   
      * This implementation checks for application extension
 163   
      * {@link Tapestry#MULTIPART_DECODER_EXTENSION_NAME}. If that is not defined, a shared instance
 164   
      * of {@link DefaultMultipartDecoder}is returned.
 165   
      * 
 166   
      * @see ApplicationServlet#createRequestContext(HttpServletRequest, HttpServletResponse)
 167   
      * @since 3.0
 168   
      */
 169   
 
 170  6
     protected IMultipartDecoder obtainMultipartDecoder(HttpServlet servlet,
 171   
             HttpServletRequest request) throws IOException
 172   
     {
 173  6
         if (_specification.checkExtension(Tapestry.MULTIPART_DECODER_EXTENSION_NAME))
 174  6
             return (IMultipartDecoder) _specification.getExtension(
 175   
                     Tapestry.MULTIPART_DECODER_EXTENSION_NAME,
 176   
                     IMultipartDecoder.class);
 177   
 
 178  0
         return DefaultMultipartDecoder.getSharedInstance();
 179   
     }
 180   
 
 181   
     /**
 182   
      * Adds a simple {@link Cookie}. To set a Cookie with attributes, use
 183   
      * {@link #addCookie(Cookie)}.
 184   
      */
 185   
 
 186  0
     public void addCookie(String name, String value)
 187   
     {
 188  0
         addCookie(new Cookie(name, value));
 189   
     }
 190   
 
 191   
     /**
 192   
      * Adds a {@link Cookie}to the response. Once added, the Cookie will also be available to
 193   
      * {@link #getCookie(String)}method.
 194   
      * <p>
 195   
      * Cookies should only be added <em>before</em> invoking
 196   
      * {@link HttpServletResponse#getWriter()}..
 197   
      */
 198   
 
 199  0
     public void addCookie(Cookie cookie)
 200   
     {
 201  0
         if (LOG.isDebugEnabled())
 202  0
             LOG.debug("Adding cookie " + cookie);
 203   
 
 204  0
         _response.addCookie(cookie);
 205   
 
 206  0
         if (_cookieMap == null)
 207  0
             readCookieMap();
 208   
 
 209  0
         _cookieMap.put(cookie.getName(), cookie);
 210   
     }
 211   
 
 212  18
     private void datePair(IMarkupWriter writer, String name, long value)
 213   
     {
 214  18
         pair(writer, name, new Date(value));
 215   
     }
 216   
 
 217   
     /** @since 2.2 * */
 218   
 
 219  704
     private DecodedRequest getDecodedRequest()
 220   
     {
 221  704
         if (_decodedRequest != null)
 222  519
             return _decodedRequest;
 223   
 
 224  185
         IRequestDecoder decoder = null;
 225   
 
 226  185
         if (!_specification.checkExtension(Tapestry.REQUEST_DECODER_EXTENSION_NAME))
 227  185
             decoder = new DefaultRequestDecoder();
 228   
         else
 229  0
             decoder = (IRequestDecoder) _specification.getExtension(
 230   
                     Tapestry.REQUEST_DECODER_EXTENSION_NAME,
 231   
                     IRequestDecoder.class);
 232   
 
 233  185
         _decodedRequest = decoder.decodeRequest(_request);
 234   
 
 235  185
         return _decodedRequest;
 236   
     }
 237   
 
 238   
     /**
 239   
      * Returns the actual scheme, possibly decoded from the request.
 240   
      * 
 241   
      * @see IRequestDecoder
 242   
      * @see javax.servlet.ServletRequest#getScheme()
 243   
      * @since 2.2
 244   
      */
 245   
 
 246  173
     public String getScheme()
 247   
     {
 248  173
         return getDecodedRequest().getScheme();
 249   
     }
 250   
 
 251   
     /**
 252   
      * Returns the actual server name, possibly decoded from the request.
 253   
      * 
 254   
      * @see IRequestDecoder
 255   
      * @see javax.servlet.ServletRequest#getServerName()
 256   
      * @since 2.2
 257   
      */
 258   
 
 259  173
     public String getServerName()
 260   
     {
 261  173
         return getDecodedRequest().getServerName();
 262   
     }
 263   
 
 264   
     /**
 265   
      * Returns the actual server port, possibly decoded from the request.
 266   
      * 
 267   
      * @see IRequestDecoder
 268   
      * @see javax.servlet.ServletRequest#getServerPort()
 269   
      * @since 2.2
 270   
      */
 271   
 
 272  173
     public int getServerPort()
 273   
     {
 274  173
         return getDecodedRequest().getServerPort();
 275   
     }
 276   
 
 277   
     /**
 278   
      * Returns the actual request URI, possibly decoded from the request.
 279   
      * 
 280   
      * @see IRequestDecoder
 281   
      * @see HttpServletRequest#getRequestURI()
 282   
      * @since 2.2
 283   
      */
 284   
 
 285  185
     public String getRequestURI()
 286   
     {
 287  185
         return getDecodedRequest().getRequestURI();
 288   
     }
 289   
 
 290   
     /**
 291   
      * Builds an absolute URL from the given URI, using the {@link HttpServletRequest}as the source
 292   
      * for scheme, server name and port.
 293   
      * 
 294   
      * @see #getAbsoluteURL(String, String, String, int)
 295   
      */
 296   
 
 297  172
     public String getAbsoluteURL(String URI)
 298   
     {
 299  172
         String scheme = getScheme();
 300  172
         String server = getServerName();
 301  172
         int port = getServerPort();
 302   
 
 303   
         // Keep things simple ... port 80 is accepted as the
 304   
         // standard port for http so it can be ommitted.
 305   
         // Some of the Tomcat code indicates that port 443 is the default
 306   
         // for https, and that needs to be researched.
 307   
 
 308  172
         if (scheme.equals("http") && port == 80)
 309  172
             port = 0;
 310   
 
 311  172
         return getAbsoluteURL(URI, scheme, server, port);
 312   
     }
 313   
 
 314   
     /**
 315   
      * Does some easy checks to turn a path (or URI) into an absolute URL. We assume
 316   
      * <ul>
 317   
      * <li>The presense of a colon means the path is complete already (any other colons in the URI
 318   
      * portion should have been converted to %3A).
 319   
      * <li>A leading pair of forward slashes means the path is simply missing the scheme.
 320   
      * <li>Otherwise, we assemble the scheme, server, port (if non-zero) and the URI as given.
 321   
      * </ul>
 322   
      */
 323   
 
 324  172
     public String getAbsoluteURL(String URI, String scheme, String server, int port)
 325   
     {
 326  172
         StringBuffer buffer = new StringBuffer();
 327   
 
 328   
         // Though, really, what does a leading colon with no scheme before it
 329   
         // mean?
 330   
 
 331  172
         if (URI.indexOf(':') >= 0)
 332  0
             return URI;
 333   
 
 334   
         // Should check the length here, first.
 335   
 
 336  172
         if (URI.substring(0, 1).equals("//"))
 337   
         {
 338  0
             buffer.append(scheme);
 339  0
             buffer.append(':');
 340  0
             buffer.append(URI);
 341  0
             return buffer.toString();
 342   
         }
 343   
 
 344  172
         buffer.append(scheme);
 345  172
         buffer.append("://");
 346  172
         buffer.append(server);
 347   
         
 348  172
         if (port > 0)
 349   
         {
 350  0
             buffer.append(':');
 351  0
             buffer.append(port);
 352   
         }
 353   
 
 354  172
         if (URI.charAt(0) != '/')
 355  0
             buffer.append('/');
 356   
 
 357  172
         buffer.append(URI);
 358   
 
 359  172
         return buffer.toString();
 360   
     }
 361   
 
 362   
     /**
 363   
      * Gets a named {@link Cookie}.
 364   
      * 
 365   
      * @param name
 366   
      *            The name of the Cookie.
 367   
      * @return The Cookie, or null if no Cookie with that name exists.
 368   
      */
 369   
 
 370  0
     public Cookie getCookie(String name)
 371   
     {
 372  0
         if (_cookieMap == null)
 373  0
             readCookieMap();
 374   
 
 375  0
         return (Cookie) _cookieMap.get(name);
 376   
     }
 377   
 
 378   
     /**
 379   
      * Reads the named {@link Cookie}and returns its value (if it exists), or null if it does not
 380   
      * exist.
 381   
      */
 382   
 
 383  0
     public String getCookieValue(String name)
 384   
     {
 385  0
         Cookie cookie;
 386   
 
 387  0
         cookie = getCookie(name);
 388   
 
 389  0
         if (cookie == null)
 390  0
             return null;
 391   
 
 392  0
         return cookie.getValue();
 393   
     }
 394   
 
 395   
     /**
 396   
      * Returns the named parameter from the {@link HttpServletRequest}.
 397   
      * <p>
 398   
      * Use {@link #getParameters(String)}for parameters that may include multiple values.
 399   
      * <p>
 400   
      * This is the preferred way to obtain parameter values (rather than obtaining the
 401   
      * {@link HttpServletRequest}itself). For form/multipart-data encoded requests, this method
 402   
      * will still work.
 403   
      */
 404   
 
 405  49
     public String getParameter(String name)
 406   
     {
 407  49
         IMultipartDecoder decoder = getDecoder();
 408  49
         if (decoder != null)
 409  0
             return decoder.getString(_request, name);
 410   
 
 411  49
         return _request.getParameter(name);
 412   
     }
 413   
 
 414   
     /**
 415   
      * Convienience method for getting a {@link HttpServletRequest}attribute.
 416   
      * 
 417   
      * @since 2.3
 418   
      */
 419   
 
 420  60
     public Object getAttribute(String name)
 421   
     {
 422  60
         return _request.getAttribute(name);
 423   
     }
 424   
 
 425   
     /**
 426   
      * For parameters that are, or are possibly, multi-valued, this method returns all the values as
 427   
      * an array of Strings.
 428   
      * 
 429   
      * @see #getParameter(String)
 430   
      */
 431   
 
 432  589
     public String[] getParameters(String name)
 433   
     {
 434  589
         IMultipartDecoder decoder = getDecoder();
 435  589
         if (decoder != null)
 436  30
             return decoder.getStrings(_request, name);
 437   
 
 438  559
         return _request.getParameterValues(name);
 439   
     }
 440   
 
 441  185
     public String[] getParameterNames()
 442   
     {
 443  185
         IMultipartDecoder decoder = getDecoder();
 444  185
         if (decoder != null)
 445  6
             return decoder.getStringParameterNames(_request);
 446   
 
 447  179
         Enumeration e = _request.getParameterNames();
 448  179
         List names = new ArrayList();
 449   
 
 450  179
         while (e.hasMoreElements())
 451  553
             names.add(e.nextElement());
 452   
 
 453  179
         int count = names.size();
 454   
 
 455  179
         String[] result = new String[count];
 456   
 
 457  179
         return (String[]) names.toArray(result);
 458   
     }
 459   
 
 460   
     /**
 461   
      * Returns the named {@link IUploadFile}, if it exists, or null if it doesn't. Uploads require
 462   
      * an encoding of <code>multipart/form-data</code> (this is specified in the form's enctype
 463   
      * attribute). If the encoding type is not so, or if no upload matches the name, then this
 464   
      * method returns null.
 465   
      */
 466   
 
 467  3
     public IUploadFile getUploadFile(String name)
 468   
     {
 469  3
         IMultipartDecoder decoder = getDecoder();
 470  3
         if (decoder == null)
 471  0
             return null;
 472   
 
 473  3
         return decoder.getUploadFile(_request, name);
 474   
     }
 475   
 
 476   
     /**
 477   
      * Invoked at the end of the request cycle to cleanup and temporary resources. This is chained
 478   
      * to the {@link DefaultMultipartDecoder}, if there is one.
 479   
      * 
 480   
      * @since 2.0.1
 481   
      */
 482   
 
 483  185
     public void cleanup()
 484   
     {
 485  185
         if (_decoder != null)
 486  6
             _decoder.cleanup(_request);
 487   
     }
 488   
 
 489   
     /**
 490   
      * Returns the request which initiated the current request cycle. Note that the methods
 491   
      * {@link #getParameter(String)}and {@link #getParameters(String)}should be used, rather than
 492   
      * obtaining parameters directly from the request (since the RequestContext handles the
 493   
      * differences between normal and multipart/form requests).
 494   
      */
 495   
 
 496  375
     public HttpServletRequest getRequest()
 497   
     {
 498  375
         return _request;
 499   
     }
 500   
 
 501  314
     public HttpServletResponse getResponse()
 502   
     {
 503  314
         return _response;
 504   
     }
 505   
 
 506  2339
     private String getRowClass()
 507   
     {
 508  2339
         String result;
 509   
 
 510  2339
         result = _evenRow ? "even" : "odd";
 511   
 
 512  2339
         _evenRow = !_evenRow;
 513   
 
 514  2339
         return result;
 515   
     }
 516   
 
 517  2
     public HttpServlet getServlet()
 518   
     {
 519  2
         return _servlet;
 520   
     }
 521   
 
 522   
     /**
 523   
      * Returns the {@link HttpSession}, if necessary, invoking
 524   
      * {@link HttpServletRequest#getSession(boolean)}. However, this method will <em>not</em>
 525   
      * create a session.
 526   
      */
 527   
 
 528  37
     public HttpSession getSession()
 529   
     {
 530  37
         if (_session == null)
 531  34
             _session = _request.getSession(false);
 532   
 
 533  37
         return _session;
 534   
     }
 535   
 
 536   
     /**
 537   
      * Like {@link #getSession()}, but forces the creation of the {@link HttpSession}, if
 538   
      * necessary.
 539   
      */
 540   
 
 541  0
     public HttpSession createSession()
 542   
     {
 543  0
         if (_session == null)
 544   
         {
 545  0
             if (LOG.isDebugEnabled())
 546  0
                 LOG.debug("Creating HttpSession");
 547   
 
 548  0
             _session = _request.getSession(true);
 549   
         }
 550   
 
 551  0
         return _session;
 552   
     }
 553   
 
 554  233
     private void header(IMarkupWriter writer, String valueName, String dataName)
 555   
     {
 556  233
         writer.begin("tr");
 557  233
         writer.attribute("class", "request-context-header");
 558   
 
 559  233
         writer.begin("th");
 560  233
         writer.print(valueName);
 561  233
         writer.end();
 562   
 
 563  233
         writer.begin("th");
 564  233
         writer.print(dataName);
 565  233
         writer.end("tr");
 566   
 
 567  233
         _evenRow = true;
 568   
     }
 569   
 
 570  145
     private void object(IMarkupWriter writer, String objectName)
 571   
     {
 572  145
         writer.begin("span");
 573  145
         writer.attribute("class", "request-context-object");
 574  145
         writer.print(objectName);
 575  145
         writer.end();
 576   
     }
 577   
 
 578  145
     private void pair(IMarkupWriter writer, String name, int value)
 579   
     {
 580  145
         pair(writer, name, Integer.toString(value));
 581   
     }
 582   
 
 583  144
     private void pair(IMarkupWriter writer, String name, Object value)
 584   
     {
 585  144
         if (value == null)
 586  34
             return;
 587   
 
 588  110
         pair(writer, name, value.toString());
 589   
     }
 590   
 
 591  2598
     private void pair(IMarkupWriter writer, String name, String value)
 592   
     {
 593  2598
         if (value == null)
 594  340
             return;
 595   
 
 596  2258
         if (value.length() == 0)
 597  102
             return;
 598   
 
 599  2156
         writer.begin("tr");
 600  2156
         writer.attribute("class", getRowClass());
 601   
 
 602  2156
         writer.begin("th");
 603  2156
         writer.print(name);
 604  2156
         writer.end();
 605   
 
 606  2156
         writer.begin("td");
 607  2156
         writer.print(value);
 608  2156
         writer.end("tr");
 609  2156
         writer.println();
 610   
     }
 611   
 
 612  9
     private void pair(IMarkupWriter writer, String name, boolean value)
 613   
     {
 614  9
         pair(writer, name, value ? "yes" : "no");
 615   
     }
 616   
 
 617  0
     private void readCookieMap()
 618   
     {
 619  0
         _cookieMap = new HashMap();
 620   
 
 621  0
         Cookie[] cookies = _request.getCookies();
 622   
 
 623  0
         if (cookies != null)
 624  0
             for (int i = 0; i < cookies.length; i++)
 625  0
                 _cookieMap.put(cookies[i].getName(), cookies[i]);
 626   
     }
 627   
 
 628  199
     private void section(IMarkupWriter writer, String sectionName)
 629   
     {
 630  199
         writer.begin("tr");
 631  199
         writer.attribute("class", "request-context-section");
 632  199
         writer.begin("th");
 633  199
         writer.attribute("colspan", 2);
 634   
 
 635  199
         writer.print(sectionName);
 636  199
         writer.end("tr");
 637   
     }
 638   
 
 639  213
     private List getSorted(Enumeration e)
 640   
     {
 641  213
         List result = new ArrayList();
 642   
 
 643   
         // JDK 1.4 includes a helper method in Collections for
 644   
         // this; but we want 1.2 compatibility for the
 645   
         // forseable future.
 646   
 
 647  213
         while (e.hasMoreElements())
 648  152
             result.add(e.nextElement());
 649   
 
 650  213
         Collections.sort(result);
 651   
 
 652  213
         return result;
 653   
     }
 654   
 
 655   
     /**
 656   
      * Writes the state of the context to the writer, typically for inclusion in a HTML page
 657   
      * returned to the user. This is useful when debugging. The Inspector uses this as well.
 658   
      */
 659   
 
 660  34
     public void write(IMarkupWriter writer)
 661   
     {
 662   
         // Create a box around all of this stuff ...
 663   
 
 664  34
         writer.begin("table");
 665  34
         writer.attribute("class", "request-context-border");
 666  34
         writer.begin("tr");
 667  34
         writer.begin("td");
 668   
 
 669   
         // Get the session, if it exists, and display it.
 670   
 
 671  34
         HttpSession session = getSession();
 672   
 
 673  34
         if (session != null)
 674   
         {
 675  9
             object(writer, "Session");
 676  9
             writer.begin("table");
 677  9
             writer.attribute("class", "request-context-object");
 678   
 
 679  9
             section(writer, "Properties");
 680  9
             header(writer, "Name", "Value");
 681   
 
 682  9
             pair(writer, "id", session.getId());
 683  9
             datePair(writer, "creationTime", session.getCreationTime());
 684  9
             datePair(writer, "lastAccessedTime", session.getLastAccessedTime());
 685  9
             pair(writer, "maxInactiveInterval", session.getMaxInactiveInterval());
 686  9
             pair(writer, "new", session.isNew());
 687   
 
 688  9
             List names = getSorted(session.getAttributeNames());
 689  9
             int count = names.size();
 690   
 
 691  9
             for (int i = 0; i < count; i++)
 692   
             {
 693  24
                 if (i == 0)
 694   
                 {
 695  9
                     section(writer, "Attributes");
 696  9
                     header(writer, "Name", "Value");
 697   
                 }
 698   
 
 699  24
                 String name = (String) names.get(i);
 700  24
                 pair(writer, name, session.getAttribute(name));
 701   
             }
 702   
 
 703  9
             writer.end(); // Session
 704   
 
 705   
         }
 706   
 
 707  34
         object(writer, "Request");
 708  34
         writer.begin("table");
 709  34
         writer.attribute("class", "request-context-object");
 710   
 
 711   
         // Parameters ...
 712   
 
 713  34
         List parameters = getSorted(_request.getParameterNames());
 714  34
         int count = parameters.size();
 715   
 
 716  34
         for (int i = 0; i < count; i++)
 717   
         {
 718   
 
 719  81
             if (i == 0)
 720   
             {
 721  33
                 section(writer, "Parameters");
 722  33
                 header(writer, "Name", "Value(s)");
 723   
             }
 724   
 
 725  81
             String name = (String) parameters.get(i);
 726  81
             String[] values = _request.getParameterValues(name);
 727   
 
 728  81
             writer.begin("tr");
 729  81
             writer.attribute("class", getRowClass());
 730  81
             writer.begin("th");
 731  81
             writer.print(name);
 732  81
             writer.end();
 733  81
             writer.begin("td");
 734   
 
 735  81
             if (values.length > 1)
 736  1
                 writer.begin("ul");
 737   
 
 738  81
             for (int j = 0; j < values.length; j++)
 739   
             {
 740  83
                 if (values.length > 1)
 741  3
                     writer.beginEmpty("li");
 742   
 
 743  83
                 writer.print(values[j]);
 744   
 
 745   
             }
 746   
 
 747  81
             writer.end("tr");
 748   
         }
 749   
 
 750  34
         section(writer, "Properties");
 751  34
         header(writer, "Name", "Value");
 752   
 
 753  34
         pair(writer, "authType", _request.getAuthType());
 754  34
         pair(writer, "characterEncoding", _request.getCharacterEncoding());
 755  34
         pair(writer, "contentLength", _request.getContentLength());
 756  34
         pair(writer, "contentType", _request.getContentType());
 757  34
         pair(writer, "method", _request.getMethod());
 758  34
         pair(writer, "pathInfo", _request.getPathInfo());
 759  34
         pair(writer, "pathTranslated", _request.getPathTranslated());
 760  34
         pair(writer, "protocol", _request.getProtocol());
 761  34
         pair(writer, "queryString", _request.getQueryString());
 762  34
         pair(writer, "remoteAddr", _request.getRemoteAddr());
 763  34
         pair(writer, "remoteHost", _request.getRemoteHost());
 764  34
         pair(writer, "remoteUser", _request.getRemoteUser());
 765   
 
 766  34
         String sessionId = _request.getRequestedSessionId();
 767   
 
 768  34
         if (sessionId != null)
 769   
         {
 770  0
             StringBuffer buffer = new StringBuffer(sessionId);
 771   
 
 772  0
             if (_request.isRequestedSessionIdFromCookie())
 773  0
                 buffer.append(" (from cookie)");
 774   
 
 775  0
             if (_request.isRequestedSessionIdFromURL())
 776  0
                 buffer.append(" (from URL)");
 777   
 
 778  0
             if (_request.isRequestedSessionIdValid())
 779  0
                 buffer.append(" (valid)");
 780   
 
 781  0
             pair(writer, "requestedSessionId", buffer.toString());
 782   
         }
 783   
 
 784  34
         pair(writer, "requestURI", _request.getRequestURI());
 785  34
         pair(writer, "scheme", _request.getScheme());
 786  34
         pair(writer, "serverName", _request.getServerName());
 787  34
         pair(writer, "serverPort", _request.getServerPort());
 788  34
         pair(writer, "contextPath", _request.getContextPath());
 789  34
         pair(writer, "servletPath", _request.getServletPath());
 790  34
         pair(writer, "userPrincipal", _request.getUserPrincipal());
 791   
 
 792   
         // Now deal with any headers
 793   
 
 794  34
         List headers = getSorted(_request.getHeaderNames());
 795  34
         count = headers.size();
 796   
 
 797  34
         for (int i = 0; i < count; i++)
 798   
         {
 799  0
             if (i == 0)
 800   
             {
 801  0
                 section(writer, "Headers");
 802  0
                 header(writer, "Name", "Value");
 803   
             }
 804   
 
 805  0
             String name = (String) headers.get(i);
 806  0
             String value = _request.getHeader(name);
 807   
 
 808  0
             pair(writer, name, value);
 809   
         }
 810   
 
 811   
         // Attributes
 812   
 
 813  34
         List attributes = getSorted(_request.getAttributeNames());
 814  34
         count = attributes.size();
 815   
 
 816  34
         for (int i = 0; i < count; i++)
 817   
         {
 818  34
             if (i == 0)
 819   
             {
 820  34
                 section(writer, "Attributes");
 821  34
                 header(writer, "Name", "Value");
 822   
             }
 823   
 
 824  34
             String name = (String) attributes.get(i);
 825   
 
 826  34
             pair(writer, name, _request.getAttribute(name));
 827   
         }
 828   
 
 829   
         // Cookies ...
 830   
 
 831  34
         Cookie[] cookies = _request.getCookies();
 832   
 
 833  34
         if (cookies != null)
 834   
         {
 835  34
             for (int i = 0; i < cookies.length; i++)
 836   
             {
 837   
 
 838  0
                 if (i == 0)
 839   
                 {
 840  0
                     section(writer, "Cookies");
 841  0
                     header(writer, "Name", "Value");
 842   
                 }
 843   
 
 844  0
                 Cookie cookie = cookies[i];
 845   
 
 846  0
                 pair(writer, cookie.getName(), cookie.getValue());
 847   
 
 848   
             } // Cookies loop
 849   
         }
 850   
 
 851  34
         writer.end(); // Request
 852   
 
 853  34
         object(writer, "Servlet");
 854  34
         writer.begin("table");
 855  34
         writer.attribute("class", "request-context-object");
 856   
 
 857  34
         section(writer, "Properties");
 858  34
         header(writer, "Name", "Value");
 859   
 
 860  34
         pair(writer, "servlet", _servlet);
 861  34
         pair(writer, "name", _servlet.getServletName());
 862  34
         pair(writer, "servletInfo", _servlet.getServletInfo());
 863   
 
 864  34
         ServletConfig config = _servlet.getServletConfig();
 865   
 
 866  34
         List names = getSorted(config.getInitParameterNames());
 867  34
         count = names.size();
 868   
 
 869  34
         for (int i = 0; i < count; i++)
 870   
         {
 871   
 
 872  13
             if (i == 0)
 873   
             {
 874  12
                 section(writer, "Init Parameters");
 875  12
                 header(writer, "Name", "Value");
 876   
             }
 877   
 
 878  13
             String name = (String) names.get(i);
 879   
             ;
 880  13
             pair(writer, name, config.getInitParameter(name));
 881   
 
 882   
         }
 883   
 
 884  34
         writer.end(); // Servlet
 885   
 
 886  34
         ServletContext context = config.getServletContext();
 887   
 
 888  34
         object(writer, "Servlet Context");
 889  34
         writer.begin("table");
 890  34
         writer.attribute("class", "request-context-object");
 891   
 
 892  34
         section(writer, "Properties");
 893  34
         header(writer, "Name", "Value");
 894   
 
 895  34
         pair(writer, "majorVersion", context.getMajorVersion());
 896  34
         pair(writer, "minorVersion", context.getMinorVersion());
 897  34
         pair(writer, "serverInfo", context.getServerInfo());
 898   
 
 899  34
         names = getSorted(context.getInitParameterNames());
 900  34
         count = names.size();
 901  34
         for (int i = 0; i < count; i++)
 902   
         {
 903  0
             if (i == 0)
 904   
             {
 905  0
                 section(writer, "Initial Parameters");
 906  0
                 header(writer, "Name", "Value");
 907   
             }
 908   
 
 909  0
             String name = (String) names.get(i);
 910  0
             pair(writer, name, context.getInitParameter(name));
 911   
         }
 912   
 
 913  34
         names = getSorted(context.getAttributeNames());
 914  34
         count = names.size();
 915  34
         for (int i = 0; i < count; i++)
 916   
         {
 917  0
             if (i == 0)
 918   
             {
 919  0
                 section(writer, "Attributes");
 920  0
                 header(writer, "Name", "Value");
 921   
             }
 922   
 
 923  0
             String name = (String) names.get(i);
 924  0
             pair(writer, name, context.getAttribute(name));
 925   
         }
 926   
 
 927  34
         writer.end(); // Servlet Context
 928   
 
 929  34
         writeSystemProperties(writer);
 930   
 
 931  34
         writer.end("table"); // The enclosing border
 932   
     }
 933   
 
 934  34
     private void writeSystemProperties(IMarkupWriter writer)
 935   
     {
 936  34
         Properties properties = null;
 937   
 
 938  34
         object(writer, "JVM System Properties");
 939   
 
 940  34
         try
 941   
         {
 942  34
             properties = System.getProperties();
 943   
         }
 944   
         catch (SecurityException se)
 945   
         {
 946  0
             writer.print("<p>");
 947  0
             writer.print(se.toString());
 948  0
             return;
 949   
         }
 950   
 
 951  34
         String pathSeparator = System.getProperty("path.separator", ";");
 952   
 
 953  34
         writer.begin("table");
 954  34
         writer.attribute("class", "request-context-object");
 955   
 
 956  34
         List names = new ArrayList(properties.keySet());
 957  34
         Collections.sort(names);
 958  34
         int count = names.size();
 959   
 
 960  34
         for (int i = 0; i < count; i++)
 961   
         {
 962   
 
 963  1768
             if (i == 0)
 964  34
                 header(writer, "Name", "Value");
 965   
 
 966  1768
             String name = (String) names.get(i);
 967   
 
 968  1768
             String property = properties.getProperty(name);
 969   
 
 970  1768
             if (property != null && property.indexOf(pathSeparator) > 0 && name.endsWith(".path"))
 971   
             {
 972  102
                 writer.begin("tr");
 973  102
                 writer.attribute("class", getRowClass());
 974   
 
 975  102
                 writer.begin("th");
 976  102
                 writer.print(name);
 977  102
                 writer.end();
 978   
 
 979  102
                 writer.begin("td");
 980  102
                 writer.begin("ul");
 981   
 
 982  102
                 StringTokenizer tokenizer = new StringTokenizer(property, pathSeparator);
 983   
 
 984  102
                 while (tokenizer.hasMoreTokens())
 985   
                 {
 986  1802
                     writer.beginEmpty("li");
 987  1802
                     writer.print(tokenizer.nextToken());
 988   
                 }
 989   
 
 990  102
                 writer.end("tr");
 991   
             }
 992   
             else
 993   
             {
 994  1666
                 pair(writer, name, property);
 995   
             }
 996   
         }
 997   
 
 998  34
         writer.end(); // System Properties
 999   
     }
 1000   
 
 1001   
     /**
 1002   
      * Invokes {@link #write(IMarkupWriter)}, which is used for debugging. Does nothing if the
 1003   
      * cycle is rewinding.
 1004   
      */
 1005   
 
 1006  34
     public void render(IMarkupWriter writer, IRequestCycle cycle)
 1007   
     {
 1008  34
         if (!cycle.isRewinding())
 1009  34
             write(writer);
 1010   
     }
 1011   
 
 1012   
     /**
 1013   
      * Returns the multipart decoder and lazily decodes the request parameters. This allows both for
 1014   
      * this operation to be performed only when really needed and for opening the request for
 1015   
      * reading much later, so that the Engine can have a chance to set the encoding that the request
 1016   
      * needs to use.
 1017   
      * 
 1018   
      * @return the multipart decoder or null if not needed for this request
 1019   
      * @since 3.0
 1020   
      */
 1021  826
     private IMultipartDecoder getDecoder()
 1022   
     {
 1023  826
         if (_decoder != null && !_decoded)
 1024   
         {
 1025  6
             _decoder.decode(_request);
 1026  6
             _decoded = true;
 1027   
         }
 1028   
 
 1029  826
         return _decoder;
 1030   
     }
 1031   
 
 1032   
     /**
 1033   
      * Sets the multipart decoder to be used for the request.
 1034   
      * 
 1035   
      * @param decoder
 1036   
      *            the multipart decoder
 1037   
      * @since 3.0
 1038   
      */
 1039  6
     public void setDecoder(IMultipartDecoder decoder)
 1040   
     {
 1041  6
         _decoder = decoder;
 1042  6
         _decoded = false;
 1043   
     }
 1044   
 
 1045   
     /**
 1046   
      * @since 3.1 --- but probably pretty temporary!
 1047   
      */
 1048  0
     public IApplicationSpecification getApplicationSpecification()
 1049   
     {
 1050  0
         return _specification;
 1051   
     }
 1052   
 
 1053   
     /**
 1054   
      * Returns the context path, which is the portion of the URL that identifies the web application
 1055   
      * context. This value may be blank (but not null) and does not end in a slash.
 1056   
      * 
 1057   
      * @since 3.1
 1058   
      */
 1059  172
     public String getContextPath()
 1060   
     {
 1061  172
         return _request.getContextPath();
 1062   
     }
 1063   
 
 1064   
 }