View Javadoc

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