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.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 1822093 2018-01-24 10:40:57Z 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      private static Locale defaultLocale = null;
    92
    93      /** The default charset. */
    94      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     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     private int statusCode = HttpServletResponse.SC_OK;
    131
    132     /** This is a List to hold critical system errors. */
    133     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     private final Map<String, Object> debugVariables = new HashMap<String, Object>();
    159
    160     /** Logging */
    161     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             T user = (T) session.getAttribute(User.SESSION_KEY);
    179             return user;
    180         }
    181         catch (ClassCastException e)
    182         {
    183             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             session.removeAttribute(User.SESSION_KEY);
    198         }
    199         catch (Exception e)
    200         {
    201             return false;
    202         }
    203         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         if (defaultLocale == null)
    218         {
    219             /* Get the default locale and cache it in a static variable. */
    220             String lang = Turbine.getConfiguration()
    221                 .getString(TurbineConstants.LOCALE_DEFAULT_LANGUAGE_KEY,
    222                     TurbineConstants.LOCALE_DEFAULT_LANGUAGE_DEFAULT);
    223
    224             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             defaultLocale =  new Locale(lang, country);
    231         }
    232         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         log.debug("getDefaultCharSet()");
    245
    246         if (defaultCharSet == null)
    247         {
    248             /* Get the default charset and cache it in a static variable. */
    249             defaultCharSet = Turbine.getConfiguration()
    250                 .getString(TurbineConstants.LOCALE_DEFAULT_CHARSET_KEY,
    251                     TurbineConstants.LOCALE_DEFAULT_CHARSET_DEFAULT);
    252             log.debug("defaultCharSet = " + defaultCharSet + " (From Properties)");
    253         }
    254
    255         String charset = defaultCharSet;
    256
    257         if (StringUtils.isEmpty(charset))
    258         {
    259             log.debug("charset is empty!");
    260             /* Default charset isn't specified, get the locale specific one. */
    261             Locale locale = getLocale();
    262             if (locale == null)
    263             {
    264                 locale = getDefaultLocale();
    265                 log.debug("Locale was null, is now " + locale + " (from getDefaultLocale())");
    266             }
    267
    268             log.debug("Locale is " + locale);
    269
    270             if (!locale.equals(Locale.US))
    271             {
    272                 log.debug("We don't have US Locale!");
    273                 ServiceManager serviceManager = TurbineServices.getInstance();
    274 				MimeTypeService mimeTypeService=null;
    275                 try {
    276 					mimeTypeService= (MimeTypeService)serviceManager.getService(MimeTypeService.ROLE);
    277                 }
    278                 catch (Exception e){
    279                     throw new RuntimeException(e);
    280                 }
    281                 charset = mimeTypeService.getCharSet(locale);
    282
    283                 log.debug("Charset now " + charset);
    284             }
    285         }
    286
    287         log.debug("Returning default Charset of " + charset);
    288         return charset;
    289     }
    290
    291     /**
    292      * Constructs a run data object.
    293      */
    294     public DefaultTurbineRunData()
    295     {
    296         super();
    297
    298         // a map to hold information to be added to pipelineData
    299         put(Turbine.class, new HashMap<Class<?>, Object>());
    300         recycle();
    301     }
    302
    303     /**
    304      * Recycles the object by removing its disposed flag.
    305      */
    306     @Override
    307     public void recycle()
    308     {
    309         disposed = false;
    310     }
    311
    312     /**
    313      * Disposes a run data object.
    314      */
    315     @Override
    316     public void dispose()
    317     {
    318         // empty pipelinedata map
    319         get(Turbine.class).clear();
    320
    321         action = null;
    322         layout = null;
    323         screen = null;
    324         templateEncoding = null;
    325         title = null;
    326         outSet = false;
    327         out = null;
    328         charSet = null;
    329         contentType = "text/html";
    330         redirectURI = null;
    331         statusCode = HttpServletResponse.SC_OK;
    332         errors.clear();
    333         jndiContexts = null;
    334         remoteAddr = null;
    335         remoteHost = null;
    336         userAgent = null;
    337         stackTrace = null;
    338         stackTraceException = null;
    339         debugVariables.clear();
    340     }
    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         ParameterParser parameters = getParameterParser();
    356         HttpServletRequest request = getRequest();
    357
    358         if ((parameters != null) &&
    359                 (parameters.getRequest() != request))
    360         {
    361             parameters.setRequest(request);
    362         }
    363
    364         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         CookieParser cookies = getCookieParser();
    377         HttpServletRequest request = getRequest();
    378
    379         if ((cookies != null) &&
    380                 (cookies.getRequest() != request))
    381         {
    382             cookies.setData(request, getResponse());
    383         }
    384
    385         return cookies;
    386     }
    387
    388     /**
    389      * Gets the servlet request.
    390      *
    391      * @return the request.
    392      */
    393     @Override
    394     public HttpServletRequest getRequest()
    395     {
    396         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         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         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         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         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         A acl = (A)get(Turbine.class, TurbineAccessControlList.class);
    453         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         get(Turbine.class).put(TurbineAccessControlList.class, acl);
    467     }
    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         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         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         this.action = action;
    503     }
    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         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             TemplateService templateService = (TemplateService)TurbineServices.getInstance().getService(TemplateService.SERVICE_NAME);
    529             layout = templateService.getDefaultLayoutName(this);
    530
    531             if (layout == null)
    532             {
    533                 layout = "DefaultLayout";
    534             }
    535         }
    536
    537         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         this.layout = layout;
    549     }
    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         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         getTemplateInfo().setLayoutTemplate(layout);
    576     }
    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         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         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         this.screen = screen;
    609     }
    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         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         getTemplateInfo().setScreenTemplate(screen);
    635     }
    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         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         templateEncoding = encoding;
    657     }
    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         TemplateInfo templateInfo = get(Turbine.class, TemplateInfo.class);
    668
    669         if (templateInfo == null)
    670         {
    671             templateInfo = new TemplateInfo(this);
    672             get(Turbine.class).put(TemplateInfo.class, templateInfo);
    673         }
    674
    675         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         StringBuilder message = get(Turbine.class, StringBuilder.class);
    687         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         StringBuilder message = get(Turbine.class, StringBuilder.class);
    700         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         get(Turbine.class).put(StringBuilder.class, new StringBuilder(msg));
    712     }
    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         StringBuilder message = get(Turbine.class, StringBuilder.class);
    724         if (message == null)
    725         {
    726             setMessage(msg);
    727         }
    728         else
    729         {
    730             message.append(msg);
    731         }
    732     }
    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         String message = getMessage();
    744         return message == null ? "" : message;
    745     }
    746
    747     /**
    748      * Unsets the message for the request.
    749      */
    750     @Override
    751     public void unsetMessage()
    752     {
    753         get(Turbine.class).remove(StringBuilder.class);
    754     }
    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         FormMessages messages = get(Turbine.class, FormMessages.class);
    766         if (messages == null)
    767         {
    768             messages = new FormMessages();
    769             setMessages(messages);
    770         }
    771
    772         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         get(Turbine.class).put(FormMessages.class, msgs);
    784     }
    785
    786     /**
    787      * Gets the title of the page.
    788      *
    789      * @return a string.
    790      */
    791     @Override
    792     public String getTitle()
    793     {
    794         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         this.title = title;
    806     }
    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         User user = getUserFromSession();
    817
    818         // TODO: Check if this side effect is reasonable
    819         get(Turbine.class).put(User.class, user);
    820
    821         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         T user = (T)get(Turbine.class, User.class);
    836         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         log.debug("user set: " + user.getName());
    848         get(Turbine.class).put(User.class, user);
    849     }
    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         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         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         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         if (this.out == null)
    900         {
    901             setOut(getResponse().getWriter());
    902         }
    903         outSet = true;
    904         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         outSet = true;
    917     }
    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         Locale locale = get(Turbine.class, Locale.class);
    932         if (locale == null)
    933         {
    934             locale = getDefaultLocale();
    935         }
    936         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         get(Turbine.class).put(Locale.class, locale);
    948
    949         // propagate the locale to the parsers
    950         ParameterParser parameters = get(Turbine.class, ParameterParser.class);
    951         CookieParser cookies = get(Turbine.class, CookieParser.class);
    952
    953         if (parameters != null)
    954         {
    955             parameters.setLocale(locale);
    956         }
    957
    958         if (cookies != null)
    959         {
    960             cookies.setLocale(locale);
    961         }
    962     }
    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         log.debug("getCharSet()");
    977
    978         if (StringUtils.isEmpty(charSet))
    979         {
    980             log.debug("Charset was null!");
    981             return getDefaultCharSet();
    982         }
    983         else
    984         {
    985             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         log.debug("setCharSet(" + charSet + ")");
    998         this.charSet = charSet;
    999     }
    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         if (StringUtils.isNotEmpty(contentType))
    1016         {
    1017             if (StringUtils.isEmpty(charSet))
    1018             {
    1019                 if (contentType.startsWith("text/"))
    1020                 {
    1021                     return contentType + "; charset=" + getDefaultCharSet();
    1022                 }
    1023
    1024                 return contentType;
    1025             }
    1026             else
    1027             {
    1028                 return contentType + "; charset=" + charSet;
    1029             }
    1030         }
    1031
    1032         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         this.contentType = contentType;
    1044     }
    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         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         this.redirectURI = ruri;
    1068     }
    1069
    1070     /**
    1071      * Gets the HTTP status code to return.
    1072      *
    1073      * @return the status.
    1074      */
    1075     @Override
    1076     public int getStatusCode()
    1077     {
    1078         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         this.statusCode = statusCode;
    1090     }
    1091
    1092     /**
    1093      * Gets an array of system errors.
    1094      *
    1095      * @return a SystemError[].
    1096      */
    1097     @Override
    1098     public SystemError[] getSystemErrors()
    1099     {
    1100         SystemError[] result = new SystemError[errors.size()];
    1101         errors.toArray(result);
    1102         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         this.errors.add(err);
    1114     }
    1115
    1116     /**
    1117      * Gets JNDI Contexts.
    1118      *
    1119      * @return a hashmap.
    1120      */
    1121     @Override
    1122     public Map<String, Context> getJNDIContexts()
    1123     {
    1124         if (jndiContexts == null)
    1125         {
    1126             jndiContexts = new HashMap<String, Context>();
    1127         }
    1128         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         this.jndiContexts = contexts;
    1140     }
    1141
    1142     /**
    1143      * Gets the cached server scheme.
    1144      *
    1145      * @return a string.
    1146      */
    1147     @Override
    1148     public String getServerScheme()
    1149     {
    1150         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         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         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         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         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         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         if (this.remoteAddr == null)
    1217         {
    1218             this.remoteAddr = this.getRequest().getRemoteAddr();
    1219         }
    1220
    1221         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         if (this.remoteHost == null)
    1233         {
    1234             this.remoteHost = this.getRequest().getRemoteHost();
    1235         }
    1236
    1237         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         if (StringUtils.isEmpty(userAgent))
    1251         {
    1252             userAgent = this.getRequest().getHeader("User-Agent");
    1253         }
    1254
    1255         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         User user = getUserFromSession();
    1266         get(Turbine.class).put(User.class, user);
    1267
    1268         if (user != null)
    1269         {
    1270             user.setLastAccessDate();
    1271             user.incrementAccessCounter();
    1272             user.incrementAccessCounterForSession();
    1273         }
    1274     }
    1275
    1276     /**
    1277      * Saves a user object into the session.
    1278      */
    1279     @Override
    1280     public void save()
    1281     {
    1282         getSession().setAttribute(User.SESSION_KEY, getUser());
    1283     }
    1284
    1285     /**
    1286      * Gets the stack trace if set.
    1287      *
    1288      * @return the stack trace.
    1289      */
    1290     @Override
    1291     public String getStackTrace()
    1292     {
    1293         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         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         stackTrace = trace;
    1317         stackTraceException = exp;
    1318     }
    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         this.debugVariables.put(name, value);
    1332     }
    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         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         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         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         this.out = out;
    1390     }
    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         getServerData().setServerScheme(serverScheme);
    1400     }
    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         getServerData().setServerName(serverName);
    1410     }
    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         getServerData().setServerPort(port);
    1420     }
    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         getServerData().setContextPath(contextPath);
    1430     }
    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         getServerData().setScriptName(scriptName);
    1440     }
    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         return disposed;
    1451     }
    1452
    1453 }