Coverage Report - org.apache.turbine.services.rundata.DefaultTurbineRunData
 
Classes in this File Line Coverage Branch Coverage Complexity
DefaultTurbineRunData
55%
142/255
43%
33/76
1,511
 
 1  
 package org.apache.turbine.services.rundata;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import java.io.IOException;
 23  
 import java.io.PrintWriter;
 24  
 import java.util.ArrayList;
 25  
 import java.util.HashMap;
 26  
 import java.util.List;
 27  
 import java.util.Locale;
 28  
 import java.util.Map;
 29  
 
 30  
 import javax.naming.Context;
 31  
 import javax.servlet.ServletConfig;
 32  
 import javax.servlet.ServletContext;
 33  
 import javax.servlet.http.HttpServletRequest;
 34  
 import javax.servlet.http.HttpServletResponse;
 35  
 import javax.servlet.http.HttpSession;
 36  
 
 37  
 import org.apache.commons.lang.StringUtils;
 38  
 import org.apache.commons.logging.Log;
 39  
 import org.apache.commons.logging.LogFactory;
 40  
 import org.apache.fulcrum.mimetype.MimeTypeService;
 41  
 import org.apache.fulcrum.parser.CookieParser;
 42  
 import org.apache.fulcrum.parser.ParameterParser;
 43  
 import org.apache.fulcrum.pool.Recyclable;
 44  
 import org.apache.fulcrum.security.acl.AccessControlList;
 45  
 import org.apache.fulcrum.security.model.turbine.TurbineAccessControlList;
 46  
 import org.apache.turbine.Turbine;
 47  
 import org.apache.turbine.TurbineConstants;
 48  
 import org.apache.turbine.om.security.User;
 49  
 import org.apache.turbine.pipeline.DefaultPipelineData;
 50  
 import org.apache.turbine.services.ServiceManager;
 51  
 import org.apache.turbine.services.TurbineServices;
 52  
 import org.apache.turbine.services.template.TemplateService;
 53  
 import org.apache.turbine.util.FormMessages;
 54  
 import org.apache.turbine.util.ServerData;
 55  
 import org.apache.turbine.util.SystemError;
 56  
 import org.apache.turbine.util.template.TemplateInfo;
 57  
 
 58  
 /**
 59  
  * DefaultTurbineRunData is the default implementation of the
 60  
  * TurbineRunData interface, which is distributed by the Turbine
 61  
  * RunData service, if another implementation is not defined in
 62  
  * the default or specified RunData configuration.
 63  
  * TurbineRunData is an extension to RunData, which
 64  
  * is an interface to run-rime information that is passed
 65  
  * within Turbine. This provides the threading mechanism for the
 66  
  * entire system because multiple requests can potentially come in
 67  
  * at the same time.  Thus, there is only one RunData implementation
 68  
  * for each request that is being serviced.
 69  
  *
 70  
  * <p>DefaultTurbineRunData implements the Recyclable interface making
 71  
  * it possible to pool its instances for recycling.
 72  
  *
 73  
  * @author <a href="mailto:ilkka.priha@simsoft.fi">Ilkka Priha</a>
 74  
  * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
 75  
  * @author <a href="mailto:bhoeneis@ee.ethz.ch">Bernie Hoeneisen</a>
 76  
  * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
 77  
  * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
 78  
  * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a>
 79  
  * @version $Id: DefaultTurbineRunData.java 1828977 2018-04-12 13:23:30Z gk $
 80  
  */
 81  
 public class DefaultTurbineRunData
 82  
         extends DefaultPipelineData
 83  
         implements TurbineRunData, Recyclable
 84  
 {
 85  
     /**
 86  
      * The disposed flag.
 87  
      */
 88  
     private boolean disposed;
 89  
 
 90  
     /** The default locale. */
 91  13
     private static Locale defaultLocale = null;
 92  
 
 93  
     /** The default charset. */
 94  13
     private static String defaultCharSet = null;
 95  
 
 96  
     /** Cached action name to execute for this request. */
 97  
     private String action;
 98  
 
 99  
     /** This is the layout that the page will use to render the screen. */
 100  
     private String layout;
 101  
 
 102  
     /** Cached screen name to execute for this request. */
 103  
     private String screen;
 104  
 
 105  
     /** The character encoding of template files. */
 106  
     private String templateEncoding;
 107  
 
 108  
     /** This is what will build the <title></title> of the document. */
 109  
     private String title;
 110  
 
 111  
     /** Determines if there is information in the outputstream or not. */
 112  
     private boolean outSet;
 113  
 
 114  
     /**
 115  
      * Cache the output stream because it can be used in many
 116  
      * different places.
 117  
      */
 118  
     private PrintWriter out;
 119  
 
 120  
     /** The HTTP charset. */
 121  
     private String charSet;
 122  
 
 123  
     /** The HTTP content type to return. */
 124  29
     private String contentType = "text/html";
 125  
 
 126  
     /** If this is set, also set the status code to 302. */
 127  
     private String redirectURI;
 128  
 
 129  
     /** The HTTP status code to return. */
 130  29
     private int statusCode = HttpServletResponse.SC_OK;
 131  
 
 132  
     /** This is a List to hold critical system errors. */
 133  29
     private final List<SystemError> errors = new ArrayList<SystemError>();
 134  
 
 135  
     /** JNDI Contexts. */
 136  
     private Map<String, Context> jndiContexts;
 137  
 
 138  
     /** @see #getRemoteAddr() */
 139  
     private String remoteAddr;
 140  
 
 141  
     /** @see #getRemoteHost() */
 142  
     private String remoteHost;
 143  
 
 144  
     /** @see #getUserAgent() */
 145  
     private String userAgent;
 146  
 
 147  
     /** A holder for stack trace. */
 148  
     private String stackTrace;
 149  
 
 150  
     /** A holder for stack trace exception. */
 151  
     private Throwable stackTraceException;
 152  
 
 153  
     /**
 154  
      * Put things here and they will be shown on the default Error
 155  
      * screen.  This is great for debugging variable values when an
 156  
      * exception is thrown.
 157  
      */
 158  29
     private final Map<String, Object> debugVariables = new HashMap<String, Object>();
 159  
 
 160  
     /** Logging */
 161  13
     private static Log log = LogFactory.getLog(DefaultTurbineRunData.class);
 162  
 
 163  
     /**
 164  
      * Attempts to get the User object from the session.  If it does
 165  
      * not exist, it returns null.
 166  
      *
 167  
      * @param session An HttpSession.
 168  
      *
 169  
      * @param <T> a type extending {@link User}
 170  
      *
 171  
      * @return A User.
 172  
      */
 173  
     public static <T extends User> T getUserFromSession(HttpSession session)
 174  
     {
 175  
         try
 176  
         {
 177  
             @SuppressWarnings("unchecked")
 178  4
             T user = (T) session.getAttribute(User.SESSION_KEY);
 179  4
             return user;
 180  
         }
 181  0
         catch (ClassCastException e)
 182  
         {
 183  0
             return null;
 184  
         }
 185  
     }
 186  
 
 187  
     /**
 188  
      * Allows one to invalidate the user in a session.
 189  
      *
 190  
      * @param session An HttpSession.
 191  
      * @return True if user was invalidated.
 192  
      */
 193  
     public static boolean removeUserFromSession(HttpSession session)
 194  
     {
 195  
         try
 196  
         {
 197  0
             session.removeAttribute(User.SESSION_KEY);
 198  
         }
 199  0
         catch (Exception e)
 200  
         {
 201  0
             return false;
 202  0
         }
 203  0
         return true;
 204  
     }
 205  
 
 206  
     /**
 207  
      * Gets the default locale defined by properties named
 208  
      * "locale.default.lang" and "locale.default.country".
 209  
      *
 210  
      * This changed from earlier Turbine versions that you can
 211  
      * rely on getDefaultLocale() to never return null.
 212  
      *
 213  
      * @return A Locale object.
 214  
      */
 215  
     protected static Locale getDefaultLocale()
 216  
     {
 217  1
         if (defaultLocale == null)
 218  
         {
 219  
             /* Get the default locale and cache it in a static variable. */
 220  1
             String lang = Turbine.getConfiguration()
 221  
                 .getString(TurbineConstants.LOCALE_DEFAULT_LANGUAGE_KEY,
 222  
                     TurbineConstants.LOCALE_DEFAULT_LANGUAGE_DEFAULT);
 223  
 
 224  1
             String country = Turbine.getConfiguration()
 225  
                 .getString(TurbineConstants.LOCALE_DEFAULT_COUNTRY_KEY,
 226  
                     TurbineConstants.LOCALE_DEFAULT_COUNTRY_DEFAULT);
 227  
 
 228  
 
 229  
             // We ensure that lang and country is never null
 230  1
             defaultLocale =  new Locale(lang, country);
 231  
         }
 232  1
         return defaultLocale;
 233  
     }
 234  
 
 235  
     /**
 236  
      * Gets the default charset defined by a property named
 237  
      * "locale.default.charset" or by the specified locale.
 238  
      * If the specified locale is null, the default locale is applied.
 239  
      *
 240  
      * @return the name of the default charset or null.
 241  
      */
 242  
     protected String getDefaultCharSet()
 243  
     {
 244  7
         log.debug("getDefaultCharSet()");
 245  
 
 246  7
         if (defaultCharSet == null)
 247  
         {
 248  
             /* Get the default charset and cache it in a static variable. */
 249  2
             defaultCharSet = Turbine.getConfiguration()
 250  
                 .getString(TurbineConstants.LOCALE_DEFAULT_CHARSET_KEY,
 251  
                     TurbineConstants.LOCALE_DEFAULT_CHARSET_DEFAULT);
 252  2
             log.debug("defaultCharSet = " + defaultCharSet + " (From Properties)");
 253  
         }
 254  
 
 255  7
         String charset = defaultCharSet;
 256  
 
 257  7
         if (StringUtils.isEmpty(charset)) // this might not occur actually, as a default is always set
 258  
         {
 259  1
             log.debug("charset is empty!");
 260  
             /* Default charset isn't specified, get the locale specific one. */
 261  1
             Locale locale = getLocale();
 262  1
             if (locale == null)
 263  
             {
 264  0
                 locale = getDefaultLocale();
 265  0
                 log.debug("Locale was null, is now " + locale + " (from getDefaultLocale())");
 266  
             }
 267  
 
 268  1
             log.debug("Locale is " + locale);
 269  
 
 270  1
             if (!locale.equals(Locale.US))
 271  
             {
 272  1
                 log.debug("We don't have US Locale!");
 273  1
                 ServiceManager serviceManager = TurbineServices.getInstance();
 274  1
                                 MimeTypeService mimeTypeService=null;
 275  
                 try {
 276  1
                                         mimeTypeService= (MimeTypeService)serviceManager.getService(MimeTypeService.ROLE);
 277  
                 }
 278  0
                 catch (Exception e){
 279  0
                     throw new RuntimeException(e);
 280  1
                 }
 281  1
                 charset = mimeTypeService.getCharSet(locale);
 282  
 
 283  1
                 log.debug("Charset now " + charset);
 284  
             }
 285  
         }
 286  
 
 287  7
         log.debug("Returning default Charset of " + charset);
 288  7
         return charset;
 289  
     }
 290  
 
 291  
     /**
 292  
      * Constructs a run data object.
 293  
      */
 294  
     public DefaultTurbineRunData()
 295  
     {
 296  29
         super();
 297  
 
 298  
         // a map to hold information to be added to pipelineData
 299  29
         put(Turbine.class, new HashMap<Class<?>, Object>());
 300  29
         recycle();
 301  29
     }
 302  
 
 303  
     /**
 304  
      * Recycles the object by removing its disposed flag.
 305  
      */
 306  
     @Override
 307  
     public void recycle()
 308  
     {
 309  29
         disposed = false;
 310  29
     }
 311  
 
 312  
     /**
 313  
      * Disposes a run data object.
 314  
      */
 315  
     @Override
 316  
     public void dispose()
 317  
     {
 318  
         // empty pipelinedata map
 319  1
         get(Turbine.class).clear();
 320  
 
 321  1
         action = null;
 322  1
         layout = null;
 323  1
         screen = null;
 324  1
         templateEncoding = null;
 325  1
         title = null;
 326  1
         outSet = false;
 327  1
         out = null;
 328  1
         charSet = null;
 329  1
         contentType = "text/html";
 330  1
         redirectURI = null;
 331  1
         statusCode = HttpServletResponse.SC_OK;
 332  1
         errors.clear();
 333  1
         jndiContexts = null;
 334  1
         remoteAddr = null;
 335  1
         remoteHost = null;
 336  1
         userAgent = null;
 337  1
         stackTrace = null;
 338  1
         stackTraceException = null;
 339  1
         debugVariables.clear();
 340  1
     }
 341  
 
 342  
     // ***************************************
 343  
     // Implementation of the RunData interface
 344  
     // ***************************************
 345  
 
 346  
     /**
 347  
      * Gets the parameters.
 348  
      *
 349  
      * @return a parameter parser.
 350  
      */
 351  
     @Override
 352  
     public ParameterParser getParameters()
 353  
     {
 354  
         // Parse the parameters first, if not yet done.
 355  37
         ParameterParser parameters = getParameterParser();
 356  37
         HttpServletRequest request = getRequest();
 357  
 
 358  37
         if ((parameters != null) &&
 359  
                 (parameters.getRequest() != request))
 360  
         {
 361  14
             parameters.setRequest(request);
 362  
         }
 363  
 
 364  37
         return parameters;
 365  
     }
 366  
 
 367  
     /**
 368  
      * Gets the cookies.
 369  
      *
 370  
      * @return a cookie parser.
 371  
      */
 372  
     @Override
 373  
     public CookieParser getCookies()
 374  
     {
 375  
         // Parse the cookies first, if not yet done.
 376  0
         CookieParser cookies = getCookieParser();
 377  0
         HttpServletRequest request = getRequest();
 378  
 
 379  0
         if ((cookies != null) &&
 380  
                 (cookies.getRequest() != request))
 381  
         {
 382  0
             cookies.setData(request, getResponse());
 383  
         }
 384  
 
 385  0
         return cookies;
 386  
     }
 387  
 
 388  
     /**
 389  
      * Gets the servlet request.
 390  
      *
 391  
      * @return the request.
 392  
      */
 393  
     @Override
 394  
     public HttpServletRequest getRequest()
 395  
     {
 396  95
         return get(Turbine.class, HttpServletRequest.class);
 397  
     }
 398  
 
 399  
     /**
 400  
      * Gets the servlet response.
 401  
      *
 402  
      * @return the response.
 403  
      */
 404  
     @Override
 405  
     public HttpServletResponse getResponse()
 406  
     {
 407  24
         return get(Turbine.class, HttpServletResponse.class);
 408  
     }
 409  
 
 410  
     /**
 411  
      * Gets the servlet session information.
 412  
      *
 413  
      * @return the session.
 414  
      */
 415  
     @Override
 416  
     public HttpSession getSession()
 417  
     {
 418  45
         return getRequest().getSession();
 419  
     }
 420  
 
 421  
     /**
 422  
      * Gets the servlet configuration used during servlet init.
 423  
      *
 424  
      * @return the configuration.
 425  
      */
 426  
     @Override
 427  
     public ServletConfig getServletConfig()
 428  
     {
 429  0
         return get(Turbine.class, ServletConfig.class);
 430  
     }
 431  
 
 432  
     /**
 433  
      * Gets the servlet context used during servlet init.
 434  
      *
 435  
      * @return the context.
 436  
      */
 437  
     @Override
 438  
     public ServletContext getServletContext()
 439  
     {
 440  0
         return get(Turbine.class, ServletContext.class);
 441  
     }
 442  
 
 443  
     /**
 444  
      * Gets the access control list.
 445  
      *
 446  
      * @return the access control list.
 447  
      */
 448  
     @Override
 449  
     public <A extends AccessControlList> A getACL()
 450  
     {
 451  
         @SuppressWarnings("unchecked")
 452  3
         A acl = (A)get(Turbine.class, TurbineAccessControlList.class);
 453  3
         return acl;
 454  
     }
 455  
 
 456  
     /**
 457  
      * Sets the access control list.
 458  
      * 
 459  
      * To delete ACL from session use key {@link TurbineConstants#ACL_SESSION_KEY}. Invalidate session, if session persist.
 460  
      *
 461  
      * @param acl an access control list.
 462  
      */
 463  
     @Override
 464  
     public void setACL(AccessControlList acl)
 465  
     {
 466  2
         get(Turbine.class).put(TurbineAccessControlList.class, acl);
 467  2
     }
 468  
 
 469  
     /**
 470  
      * Whether or not an action has been defined.
 471  
      *
 472  
      * @return true if an action has been defined.
 473  
      */
 474  
     @Override
 475  
     public boolean hasAction()
 476  
     {
 477  28
         return (StringUtils.isNotEmpty(this.action)
 478  
           && !this.action.equalsIgnoreCase("null"));
 479  
     }
 480  
 
 481  
     /**
 482  
      * Gets the action. It returns an empty string if null so
 483  
      * that it is easy to do conditionals on it based on the
 484  
      * equalsIgnoreCase() method.
 485  
      *
 486  
      * @return a string, "" if null.
 487  
      */
 488  
     @Override
 489  
     public String getAction()
 490  
     {
 491  19
         return (hasAction() ? this.action : "");
 492  
     }
 493  
 
 494  
     /**
 495  
      * Sets the action for the request.
 496  
      *
 497  
      * @param action a string.
 498  
      */
 499  
     @Override
 500  
     public void setAction(String action)
 501  
     {
 502  18
         this.action = action;
 503  18
     }
 504  
 
 505  
     /**
 506  
      * If the Layout has not been defined by the screen then set the
 507  
      * layout to be "DefaultLayout".  The screen object can also
 508  
      * override this method to provide intelligent determination of
 509  
      * the Layout to execute.  You can also define that logic here as
 510  
      * well if you want it to apply on a global scale.  For example,
 511  
      * if you wanted to allow someone to define layout "preferences"
 512  
      * where they could dynamically change the layout for the entire
 513  
      * site.
 514  
      *
 515  
      * @return a string.
 516  
      */
 517  
 
 518  
     @Override
 519  
     public String getLayout()
 520  
     {
 521  8
         if (this.layout == null)
 522  
         {
 523  
             /*
 524  
              * This will return something if the template
 525  
              * services are running. If we get nothing we
 526  
              * will fall back to the ECS layout.
 527  
              */
 528  3
             TemplateService templateService = (TemplateService)TurbineServices.getInstance().getService(TemplateService.SERVICE_NAME);
 529  3
             layout = templateService.getDefaultLayoutName(this);
 530  
 
 531  3
             if (layout == null)
 532  
             {
 533  0
                 layout = "DefaultLayout";
 534  
             }
 535  
         }
 536  
 
 537  8
         return this.layout;
 538  
     }
 539  
 
 540  
     /**
 541  
      * Set the layout for the request.
 542  
      *
 543  
      * @param layout a string.
 544  
      */
 545  
     @Override
 546  
     public void setLayout(String layout)
 547  
     {
 548  2
         this.layout = layout;
 549  2
     }
 550  
 
 551  
     /**
 552  
      * Convenience method for a template info that
 553  
      * returns the layout template being used.
 554  
      *
 555  
      * @return a string.
 556  
      */
 557  
     @Override
 558  
     public String getLayoutTemplate()
 559  
     {
 560  0
         return getTemplateInfo().getLayoutTemplate();
 561  
     }
 562  
 
 563  
     /**
 564  
      * Modifies the layout template for the screen. This convenience
 565  
      * method allows for a layout to be modified from within a
 566  
      * template. For example;
 567  
      *
 568  
      *    $data.setLayoutTemplate("NewLayout.vm")
 569  
      *
 570  
      * @param layout a layout template.
 571  
      */
 572  
     @Override
 573  
     public void setLayoutTemplate(String layout)
 574  
     {
 575  0
         getTemplateInfo().setLayoutTemplate(layout);
 576  0
     }
 577  
 
 578  
     /**
 579  
      * Whether or not a screen has been defined.
 580  
      *
 581  
      * @return true if a screen has been defined.
 582  
      */
 583  
     @Override
 584  
     public boolean hasScreen()
 585  
     {
 586  22
         return StringUtils.isNotEmpty(this.screen);
 587  
     }
 588  
 
 589  
     /**
 590  
      * Gets the screen to execute.
 591  
      *
 592  
      * @return a string.
 593  
      */
 594  
     @Override
 595  
     public String getScreen()
 596  
     {
 597  13
         return (hasScreen() ? this.screen : "");
 598  
     }
 599  
 
 600  
     /**
 601  
      * Sets the screen for the request.
 602  
      *
 603  
      * @param screen a string.
 604  
      */
 605  
     @Override
 606  
     public void setScreen(String screen)
 607  
     {
 608  8
         this.screen = screen;
 609  8
     }
 610  
 
 611  
     /**
 612  
      * Convenience method for a template info that
 613  
      * returns the name of the template being used.
 614  
      *
 615  
      * @return a string.
 616  
      */
 617  
     @Override
 618  
     public String getScreenTemplate()
 619  
     {
 620  0
         return getTemplateInfo().getScreenTemplate();
 621  
     }
 622  
 
 623  
     /**
 624  
      * Sets the screen template for the request. For
 625  
      * example;
 626  
      *
 627  
      *    $data.setScreenTemplate("NewScreen.vm")
 628  
      *
 629  
      * @param screen a screen template.
 630  
      */
 631  
     @Override
 632  
     public void setScreenTemplate(String screen)
 633  
     {
 634  2
         getTemplateInfo().setScreenTemplate(screen);
 635  2
     }
 636  
 
 637  
     /**
 638  
      * Gets the character encoding to use for reading template files.
 639  
      *
 640  
      * @return the template encoding or null if not specified.
 641  
      */
 642  
     @Override
 643  
     public String getTemplateEncoding()
 644  
     {
 645  4
         return templateEncoding;
 646  
     }
 647  
 
 648  
     /**
 649  
      * Sets the character encoding to use for reading template files.
 650  
      *
 651  
      * @param encoding the template encoding.
 652  
      */
 653  
     @Override
 654  
     public void setTemplateEncoding(String encoding)
 655  
     {
 656  0
         templateEncoding = encoding;
 657  0
     }
 658  
 
 659  
     /**
 660  
      * Gets the template info. Creates a new one if needed.
 661  
      *
 662  
      * @return a template info.
 663  
      */
 664  
     @Override
 665  
     public TemplateInfo getTemplateInfo()
 666  
     {
 667  65
         TemplateInfo templateInfo = get(Turbine.class, TemplateInfo.class);
 668  
 
 669  65
         if (templateInfo == null)
 670  
         {
 671  13
             templateInfo = new TemplateInfo(this);
 672  13
             get(Turbine.class).put(TemplateInfo.class, templateInfo);
 673  
         }
 674  
 
 675  65
         return templateInfo;
 676  
     }
 677  
 
 678  
     /**
 679  
      * Whether or not a message has been defined.
 680  
      *
 681  
      * @return true if a message has been defined.
 682  
      */
 683  
     @Override
 684  
     public boolean hasMessage()
 685  
     {
 686  0
         StringBuilder message = get(Turbine.class, StringBuilder.class);
 687  0
         return message != null && message.length() > 0;
 688  
     }
 689  
 
 690  
     /**
 691  
      * Gets the results of an action or another message
 692  
      * to be displayed as a string.
 693  
      *
 694  
      * @return a string.
 695  
      */
 696  
     @Override
 697  
     public String getMessage()
 698  
     {
 699  0
         StringBuilder message = get(Turbine.class, StringBuilder.class);
 700  0
         return message == null ? null : message.toString();
 701  
     }
 702  
 
 703  
     /**
 704  
      * Sets the message for the request as a string.
 705  
      *
 706  
      * @param msg a string.
 707  
      */
 708  
     @Override
 709  
     public void setMessage(String msg)
 710  
     {
 711  1
         get(Turbine.class).put(StringBuilder.class, new StringBuilder(msg));
 712  1
     }
 713  
 
 714  
     /**
 715  
      * Adds the string to message. If message has prior messages from
 716  
      * other actions or screens, this method can be used to chain them.
 717  
      *
 718  
      * @param msg a string.
 719  
      */
 720  
     @Override
 721  
     public void addMessage(String msg)
 722  
     {
 723  0
         StringBuilder message = get(Turbine.class, StringBuilder.class);
 724  0
         if (message == null)
 725  
         {
 726  0
             setMessage(msg);
 727  
         }
 728  
         else
 729  
         {
 730  0
             message.append(msg);
 731  
         }
 732  0
     }
 733  
 
 734  
     /**
 735  
      * Gets the results of an action or another message
 736  
      * to be displayed as a string (never null).
 737  
      *
 738  
      * @return a string element.
 739  
      */
 740  
     @Override
 741  
     public String getMessageAsHTML()
 742  
     {
 743  0
         String message = getMessage();
 744  0
         return message == null ? "" : message;
 745  
     }
 746  
 
 747  
     /**
 748  
      * Unsets the message for the request.
 749  
      */
 750  
     @Override
 751  
     public void unsetMessage()
 752  
     {
 753  0
         get(Turbine.class).remove(StringBuilder.class);
 754  0
     }
 755  
 
 756  
     /**
 757  
      * Gets a FormMessages object where all the messages to the
 758  
      * user should be stored.
 759  
      *
 760  
      * @return a FormMessages.
 761  
      */
 762  
     @Override
 763  
     public FormMessages getMessages()
 764  
     {
 765  0
         FormMessages messages = get(Turbine.class, FormMessages.class);
 766  0
         if (messages == null)
 767  
         {
 768  0
             messages = new FormMessages();
 769  0
             setMessages(messages);
 770  
         }
 771  
 
 772  0
         return messages;
 773  
     }
 774  
 
 775  
     /**
 776  
      * Sets the FormMessages object for the request.
 777  
      *
 778  
      * @param msgs A FormMessages.
 779  
      */
 780  
     @Override
 781  
     public void setMessages(FormMessages msgs)
 782  
     {
 783  0
         get(Turbine.class).put(FormMessages.class, msgs);
 784  0
     }
 785  
 
 786  
     /**
 787  
      * Gets the title of the page.
 788  
      *
 789  
      * @return a string.
 790  
      */
 791  
     @Override
 792  
     public String getTitle()
 793  
     {
 794  0
         return (this.title == null ? "" : this.title);
 795  
     }
 796  
 
 797  
     /**
 798  
      * Sets the title of the page.
 799  
      *
 800  
      * @param title a string.
 801  
      */
 802  
     @Override
 803  
     public void setTitle(String title)
 804  
     {
 805  0
         this.title = title;
 806  0
     }
 807  
 
 808  
     /**
 809  
      * Checks if a user exists in this session.
 810  
      *
 811  
      * @return true if a user exists in this session.
 812  
      */
 813  
     @Override
 814  
     public boolean userExists()
 815  
     {
 816  0
         User user = getUserFromSession();
 817  
 
 818  
         // TODO: Check if this side effect is reasonable
 819  0
         get(Turbine.class).put(User.class, user);
 820  
 
 821  0
         return (user != null);
 822  
     }
 823  
 
 824  
     /**
 825  
      * Gets the user.
 826  
      *
 827  
      * @param <T> a type extending {@link User}
 828  
      *
 829  
      * @return a user.
 830  
      */
 831  
     @Override
 832  
     public <T extends User> T getUser()
 833  
     {
 834  
         @SuppressWarnings("unchecked")
 835  28
         T user = (T)get(Turbine.class, User.class);
 836  28
         return user;
 837  
     }
 838  
 
 839  
     /**
 840  
      * Sets the user.
 841  
      *
 842  
      * @param user a user.
 843  
      */
 844  
     @Override
 845  
     public void setUser(User user)
 846  
     {
 847  7
         log.debug("user set: " + user.getName());
 848  7
         get(Turbine.class).put(User.class, user);
 849  7
     }
 850  
 
 851  
     /**
 852  
      * Attempts to get the user from the session. If it does
 853  
      * not exist, it returns null.
 854  
      *
 855  
      * @return a user.
 856  
      */
 857  
     @Override
 858  
     public <T extends User> T getUserFromSession()
 859  
     {
 860  4
         return getUserFromSession(getSession());
 861  
     }
 862  
 
 863  
     /**
 864  
      * Allows one to invalidate the user in the default session.
 865  
      *
 866  
      * @return true if user was invalidated.
 867  
      */
 868  
     @Override
 869  
     public boolean removeUserFromSession()
 870  
     {
 871  0
         return removeUserFromSession(getSession());
 872  
     }
 873  
 
 874  
     /**
 875  
      * Checks to see if out is set.
 876  
      *
 877  
      * @return true if out is set.
 878  
      * @deprecated no replacement planned, response writer will not be cached
 879  
      */
 880  
     @Override
 881  
     @Deprecated
 882  
     public boolean isOutSet()
 883  
     {
 884  0
         return outSet;
 885  
     }
 886  
 
 887  
     /**
 888  
      * Gets the print writer. First time calling this
 889  
      * will set the print writer via the response.
 890  
      *
 891  
      * @return a print writer.
 892  
      * @throws IOException on failure getting the PrintWriter
 893  
      */
 894  
     @Override
 895  
     public PrintWriter getOut()
 896  
             throws IOException
 897  
     {
 898  
         // Check to see if null first.
 899  0
         if (this.out == null)
 900  
         {
 901  0
             setOut(getResponse().getWriter());
 902  
         }
 903  0
         outSet = true;
 904  0
         return this.out;
 905  
     }
 906  
 
 907  
     /**
 908  
      * Declares that output will be direct to the response stream,
 909  
      * even though getOut() may never be called.  Useful for response
 910  
      * mechanisms that may call res.getWriter() themselves
 911  
      * (such as JSP.)
 912  
      */
 913  
     @Override
 914  
     public void declareDirectResponse()
 915  
     {
 916  0
         outSet = true;
 917  0
     }
 918  
 
 919  
     /**
 920  
      * Gets the locale. If it has not already been defined with
 921  
      * setLocale(), then  properties named "locale.default.lang"
 922  
      * and "locale.default.country" are checked from the Resource
 923  
      * Service and the corresponding locale is returned. If these
 924  
      * properties are undefined, JVM's default locale is returned.
 925  
      *
 926  
      * @return the locale.
 927  
      */
 928  
     @Override
 929  
     public Locale getLocale()
 930  
     {
 931  3
         Locale locale = get(Turbine.class, Locale.class);
 932  3
         if (locale == null)
 933  
         {
 934  1
             locale = getDefaultLocale();
 935  
         }
 936  3
         return locale;
 937  
     }
 938  
 
 939  
     /**
 940  
      * Sets the locale.
 941  
      *
 942  
      * @param locale the new locale.
 943  
      */
 944  
     @Override
 945  
     public void setLocale(Locale locale)
 946  
     {
 947  28
         get(Turbine.class).put(Locale.class, locale);
 948  
 
 949  
         // propagate the locale to the parsers
 950  28
         ParameterParser parameters = get(Turbine.class, ParameterParser.class);
 951  28
         CookieParser cookies = get(Turbine.class, CookieParser.class);
 952  
 
 953  28
         if (parameters != null)
 954  
         {
 955  28
             parameters.setLocale(locale);
 956  
         }
 957  
 
 958  28
         if (cookies != null)
 959  
         {
 960  28
             cookies.setLocale(locale);
 961  
         }
 962  28
     }
 963  
 
 964  
     /**
 965  
      * Gets the charset. If it has not already been defined with
 966  
      * setCharSet(), then a property named "locale.default.charset"
 967  
      * is checked from the Resource Service and returned. If this
 968  
      * property is undefined, the default charset of the locale
 969  
      * is returned. If the locale is undefined, null is returned.
 970  
      *
 971  
      * @return the name of the charset or null.
 972  
      */
 973  
     @Override
 974  
     public String getCharSet()
 975  
     {
 976  4
         log.debug("getCharSet()");
 977  
 
 978  4
         if (StringUtils.isEmpty(charSet))
 979  
         {
 980  4
             log.debug("Charset was null!");
 981  4
             return getDefaultCharSet();
 982  
         }
 983  
         else
 984  
         {
 985  0
             return charSet;
 986  
         }
 987  
     }
 988  
 
 989  
     /**
 990  
      * Sets the charset.
 991  
      *
 992  
      * @param charSet the name of the new charset.
 993  
      */
 994  
     @Override
 995  
     public void setCharSet(String charSet)
 996  
     {
 997  0
         log.debug("setCharSet(" + charSet + ")");
 998  0
         this.charSet = charSet;
 999  0
     }
 1000  
 
 1001  
     /**
 1002  
      * Gets the HTTP content type to return. If a charset
 1003  
      * has been specified, it is included in the content type.
 1004  
      * If the charset has not been specified and the main type
 1005  
      * of the content type is "text", the default charset is
 1006  
      * included. If the default charset is undefined, but the
 1007  
      * default locale is defined and it is not the US locale,
 1008  
      * a locale specific charset is included.
 1009  
      *
 1010  
      * @return the content type or an empty string.
 1011  
      */
 1012  
     @Override
 1013  
     public String getContentType()
 1014  
     {
 1015  2
         if (StringUtils.isNotEmpty(contentType))
 1016  
         {
 1017  2
             if (StringUtils.isEmpty(charSet))
 1018  
             {
 1019  2
                 if (contentType.startsWith("text/"))
 1020  
                 {
 1021  2
                     return contentType + "; charset=" + getDefaultCharSet();
 1022  
                 }
 1023  
 
 1024  0
                 return contentType;
 1025  
             }
 1026  
             else
 1027  
             {
 1028  0
                 return contentType + "; charset=" + charSet;
 1029  
             }
 1030  
         }
 1031  
 
 1032  0
         return "";
 1033  
     }
 1034  
 
 1035  
     /**
 1036  
      * Sets the HTTP content type to return.
 1037  
      *
 1038  
      * @param contentType a string.
 1039  
      */
 1040  
     @Override
 1041  
     public void setContentType(String contentType)
 1042  
     {
 1043  0
         this.contentType = contentType;
 1044  0
     }
 1045  
 
 1046  
     /**
 1047  
      * Gets the redirect URI. If this is set, also make sure to set
 1048  
      * the status code to 302.
 1049  
      *
 1050  
      * @return a string, "" if null.
 1051  
      */
 1052  
     @Override
 1053  
     public String getRedirectURI()
 1054  
     {
 1055  4
         return (this.redirectURI == null ? "" : redirectURI);
 1056  
     }
 1057  
 
 1058  
     /**
 1059  
      * Sets the redirect uri. If this is set, also make sure to set
 1060  
      * the status code to 302.
 1061  
      *
 1062  
      * @param ruri a string.
 1063  
      */
 1064  
     @Override
 1065  
     public void setRedirectURI(String ruri)
 1066  
     {
 1067  0
         this.redirectURI = ruri;
 1068  0
     }
 1069  
 
 1070  
     /**
 1071  
      * Gets the HTTP status code to return.
 1072  
      *
 1073  
      * @return the status.
 1074  
      */
 1075  
     @Override
 1076  
     public int getStatusCode()
 1077  
     {
 1078  0
         return statusCode;
 1079  
     }
 1080  
 
 1081  
     /**
 1082  
      * Sets the HTTP status code to return.
 1083  
      *
 1084  
      * @param statusCode the status.
 1085  
      */
 1086  
     @Override
 1087  
     public void setStatusCode(int statusCode)
 1088  
     {
 1089  0
         this.statusCode = statusCode;
 1090  0
     }
 1091  
 
 1092  
     /**
 1093  
      * Gets an array of system errors.
 1094  
      *
 1095  
      * @return a SystemError[].
 1096  
      */
 1097  
     @Override
 1098  
     public SystemError[] getSystemErrors()
 1099  
     {
 1100  0
         SystemError[] result = new SystemError[errors.size()];
 1101  0
         errors.toArray(result);
 1102  0
         return result;
 1103  
     }
 1104  
 
 1105  
     /**
 1106  
      * Adds a critical system error.
 1107  
      *
 1108  
      * @param err a system error.
 1109  
      */
 1110  
     @Override
 1111  
     public void setSystemError(SystemError err)
 1112  
     {
 1113  0
         this.errors.add(err);
 1114  0
     }
 1115  
 
 1116  
     /**
 1117  
      * Gets JNDI Contexts.
 1118  
      *
 1119  
      * @return a hashmap.
 1120  
      */
 1121  
     @Override
 1122  
     public Map<String, Context> getJNDIContexts()
 1123  
     {
 1124  0
         if (jndiContexts == null)
 1125  
         {
 1126  0
             jndiContexts = new HashMap<String, Context>();
 1127  
         }
 1128  0
         return jndiContexts;
 1129  
     }
 1130  
 
 1131  
     /**
 1132  
      * Sets JNDI Contexts.
 1133  
      *
 1134  
      * @param contexts a hashmap.
 1135  
      */
 1136  
     @Override
 1137  
     public void setJNDIContexts(Map<String, Context> contexts)
 1138  
     {
 1139  0
         this.jndiContexts = contexts;
 1140  0
     }
 1141  
 
 1142  
     /**
 1143  
      * Gets the cached server scheme.
 1144  
      *
 1145  
      * @return a string.
 1146  
      */
 1147  
     @Override
 1148  
     public String getServerScheme()
 1149  
     {
 1150  0
         return getServerData().getServerScheme();
 1151  
     }
 1152  
 
 1153  
     /**
 1154  
      * Gets the cached server name.
 1155  
      *
 1156  
      * @return a string.
 1157  
      */
 1158  
     @Override
 1159  
     public String getServerName()
 1160  
     {
 1161  0
         return getServerData().getServerName();
 1162  
     }
 1163  
 
 1164  
     /**
 1165  
      * Gets the cached server port.
 1166  
      *
 1167  
      * @return an int.
 1168  
      */
 1169  
     @Override
 1170  
     public int getServerPort()
 1171  
     {
 1172  0
         return getServerData().getServerPort();
 1173  
     }
 1174  
 
 1175  
     /**
 1176  
      * Gets the cached context path.
 1177  
      *
 1178  
      * @return a string.
 1179  
      */
 1180  
     @Override
 1181  
     public String getContextPath()
 1182  
     {
 1183  0
         return getServerData().getContextPath();
 1184  
     }
 1185  
 
 1186  
     /**
 1187  
      * Gets the cached script name.
 1188  
      *
 1189  
      * @return a string.
 1190  
      */
 1191  
     @Override
 1192  
     public String getScriptName()
 1193  
     {
 1194  0
         return getServerData().getScriptName();
 1195  
     }
 1196  
 
 1197  
     /**
 1198  
      * Gets the server data ofy the request.
 1199  
      *
 1200  
      * @return server data.
 1201  
      */
 1202  
     @Override
 1203  
     public ServerData getServerData()
 1204  
     {
 1205  18
         return get(Turbine.class, ServerData.class);
 1206  
     }
 1207  
 
 1208  
     /**
 1209  
      * Gets the IP address of the client that sent the request.
 1210  
      *
 1211  
      * @return a string.
 1212  
      */
 1213  
     @Override
 1214  
     public String getRemoteAddr()
 1215  
     {
 1216  0
         if (this.remoteAddr == null)
 1217  
         {
 1218  0
             this.remoteAddr = this.getRequest().getRemoteAddr();
 1219  
         }
 1220  
 
 1221  0
         return this.remoteAddr;
 1222  
     }
 1223  
 
 1224  
     /**
 1225  
      * Gets the qualified name of the client that sent the request.
 1226  
      *
 1227  
      * @return a string.
 1228  
      */
 1229  
     @Override
 1230  
     public String getRemoteHost()
 1231  
     {
 1232  0
         if (this.remoteHost == null)
 1233  
         {
 1234  0
             this.remoteHost = this.getRequest().getRemoteHost();
 1235  
         }
 1236  
 
 1237  0
         return this.remoteHost;
 1238  
     }
 1239  
 
 1240  
     /**
 1241  
      * Get the user agent for the request. The semantics here
 1242  
      * are muddled because RunData caches the value after the
 1243  
      * first invocation. This is different e.g. from getCharSet().
 1244  
      *
 1245  
      * @return a string.
 1246  
      */
 1247  
     @Override
 1248  
     public String getUserAgent()
 1249  
     {
 1250  0
         if (StringUtils.isEmpty(userAgent))
 1251  
         {
 1252  0
             userAgent = this.getRequest().getHeader("User-Agent");
 1253  
         }
 1254  
 
 1255  0
         return userAgent;
 1256  
     }
 1257  
 
 1258  
     /**
 1259  
      * Pulls a user object from the session and increments the access
 1260  
      * counter and sets the last access date for the object.
 1261  
      */
 1262  
     @Override
 1263  
     public void populate()
 1264  
     {
 1265  3
         User user = getUserFromSession();
 1266  3
         get(Turbine.class).put(User.class, user);
 1267  
 
 1268  3
         if (user != null)
 1269  
         {
 1270  1
             user.setLastAccessDate();
 1271  1
             user.incrementAccessCounter();
 1272  1
             user.incrementAccessCounterForSession();
 1273  
         }
 1274  3
     }
 1275  
 
 1276  
     /**
 1277  
      * Saves a user object into the session.
 1278  
      */
 1279  
     @Override
 1280  
     public void save()
 1281  
     {
 1282  4
         getSession().setAttribute(User.SESSION_KEY, getUser());
 1283  4
     }
 1284  
 
 1285  
     /**
 1286  
      * Gets the stack trace if set.
 1287  
      *
 1288  
      * @return the stack trace.
 1289  
      */
 1290  
     @Override
 1291  
     public String getStackTrace()
 1292  
     {
 1293  2
         return stackTrace;
 1294  
     }
 1295  
 
 1296  
     /**
 1297  
      * Gets the stack trace exception if set.
 1298  
      *
 1299  
      * @return the stack exception.
 1300  
      */
 1301  
     @Override
 1302  
     public Throwable getStackTraceException()
 1303  
     {
 1304  1
         return stackTraceException;
 1305  
     }
 1306  
 
 1307  
     /**
 1308  
      * Sets the stack trace.
 1309  
      *
 1310  
      * @param trace the stack trace.
 1311  
      * @param exp the exception.
 1312  
      */
 1313  
     @Override
 1314  
     public void setStackTrace(String trace, Throwable exp)
 1315  
     {
 1316  1
         stackTrace = trace;
 1317  1
         stackTraceException = exp;
 1318  1
     }
 1319  
 
 1320  
     /**
 1321  
      * Sets a name/value pair in an internal Map that is accessible from the
 1322  
      * Error screen.  This is a good way to get debugging information
 1323  
      * when an exception is thrown.
 1324  
      *
 1325  
      * @param name name of the variable
 1326  
      * @param value value of the variable.
 1327  
      */
 1328  
     @Override
 1329  
     public void setDebugVariable(String name, Object value)
 1330  
     {
 1331  0
         this.debugVariables.put(name, value);
 1332  0
     }
 1333  
 
 1334  
     /**
 1335  
      * Gets a Map of debug variables.
 1336  
      *
 1337  
      * @return a Map of debug variables.
 1338  
      */
 1339  
     @Override
 1340  
     public Map<String, Object> getDebugVariables()
 1341  
     {
 1342  0
         return this.debugVariables;
 1343  
     }
 1344  
 
 1345  
     // **********************************************
 1346  
     // Implementation of the TurbineRunData interface
 1347  
     // **********************************************
 1348  
 
 1349  
     /**
 1350  
      * Gets the parameter parser without parsing the parameters.
 1351  
      *
 1352  
      * @return the parameter parser.
 1353  
      * TODO Does this method make sense? Pulling the parameter out of
 1354  
      *       the run data object before setting a request (which happens
 1355  
      *       only in getParameters() leads to the Parameter parser having
 1356  
      *       no object and thus the default or even an undefined encoding
 1357  
      *       instead of the actual request character encoding).
 1358  
      */
 1359  
     @Override
 1360  
     public ParameterParser getParameterParser()
 1361  
     {
 1362  38
         return get(Turbine.class, ParameterParser.class);
 1363  
     }
 1364  
 
 1365  
     /**
 1366  
      * Gets the cookie parser without parsing the cookies.
 1367  
      *
 1368  
      * @return the cookie parser.
 1369  
      */
 1370  
     @Override
 1371  
     public CookieParser getCookieParser()
 1372  
     {
 1373  1
         return get(Turbine.class, CookieParser.class);
 1374  
     }
 1375  
 
 1376  
     // ********************
 1377  
     // Miscellanous setters
 1378  
     // ********************
 1379  
 
 1380  
     /**
 1381  
      * Sets the print writer.
 1382  
      *
 1383  
      * @param out a print writer.
 1384  
      * @deprecated no replacement planned, response writer will not be cached
 1385  
      */
 1386  
     @Deprecated
 1387  
     protected void setOut(PrintWriter out)
 1388  
     {
 1389  0
         this.out = out;
 1390  0
     }
 1391  
 
 1392  
     /**
 1393  
      * Sets the cached server scheme that is stored in the server data.
 1394  
      *
 1395  
      * @param serverScheme a string.
 1396  
      */
 1397  
     protected void setServerScheme(String serverScheme)
 1398  
     {
 1399  0
         getServerData().setServerScheme(serverScheme);
 1400  0
     }
 1401  
 
 1402  
     /**
 1403  
      * Sets the cached server same that is stored in the server data.
 1404  
      *
 1405  
      * @param serverName a string.
 1406  
      */
 1407  
     protected void setServerName(String serverName)
 1408  
     {
 1409  0
         getServerData().setServerName(serverName);
 1410  0
     }
 1411  
 
 1412  
     /**
 1413  
      * Sets the cached server port that is stored in the server data.
 1414  
      *
 1415  
      * @param port an int.
 1416  
      */
 1417  
     protected void setServerPort(int port)
 1418  
     {
 1419  0
         getServerData().setServerPort(port);
 1420  0
     }
 1421  
 
 1422  
     /**
 1423  
      * Sets the cached context path that is stored in the server data.
 1424  
      *
 1425  
      * @param contextPath a string.
 1426  
      */
 1427  
     protected void setContextPath(String contextPath)
 1428  
     {
 1429  0
         getServerData().setContextPath(contextPath);
 1430  0
     }
 1431  
 
 1432  
     /**
 1433  
      * Sets the cached script name that is stored in the server data.
 1434  
      *
 1435  
      * @param scriptName a string.
 1436  
      */
 1437  
     protected void setScriptName(String scriptName)
 1438  
     {
 1439  0
         getServerData().setScriptName(scriptName);
 1440  0
     }
 1441  
 
 1442  
     /**
 1443  
      * Checks whether the object is disposed.
 1444  
      *
 1445  
      * @return true, if the object is disposed.
 1446  
      */
 1447  
     @Override
 1448  
     public boolean isDisposed()
 1449  
     {
 1450  0
         return disposed;
 1451  
     }
 1452  
 
 1453  
 }