View Javadoc

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