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