View Javadoc

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