1 package org.apache.turbine.services.rundata;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.io.IOException;
23 import java.io.PrintWriter;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Locale;
28 import java.util.Map;
29
30 import javax.naming.Context;
31 import javax.servlet.ServletConfig;
32 import javax.servlet.ServletContext;
33 import javax.servlet.http.HttpServletRequest;
34 import javax.servlet.http.HttpServletResponse;
35 import javax.servlet.http.HttpSession;
36
37 import org.apache.commons.lang.StringUtils;
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40 import org.apache.ecs.Document;
41 import org.apache.ecs.Element;
42 import org.apache.ecs.StringElement;
43 import org.apache.fulcrum.mimetype.MimeTypeService;
44 import org.apache.fulcrum.parser.CookieParser;
45 import org.apache.fulcrum.parser.ParameterParser;
46 import org.apache.fulcrum.pool.Recyclable;
47 import org.apache.turbine.Turbine;
48 import org.apache.turbine.TurbineConstants;
49 import org.apache.turbine.om.security.User;
50 import org.apache.turbine.pipeline.DefaultPipelineData;
51 import org.apache.turbine.services.ServiceManager;
52 import org.apache.turbine.services.TurbineServices;
53 import org.apache.turbine.services.template.TurbineTemplate;
54 import org.apache.turbine.util.FormMessages;
55 import org.apache.turbine.util.ServerData;
56 import org.apache.turbine.util.SystemError;
57 import org.apache.turbine.util.security.AccessControlList;
58 import org.apache.turbine.util.template.TemplateInfo;
59
60 /**
61 * DefaultTurbineRunData is the default implementation of the
62 * TurbineRunData interface, which is distributed by the Turbine
63 * RunData service, if another implementation is not defined in
64 * the default or specified RunData configuration.
65 * TurbineRunData is an extension to RunData, which
66 * is an interface to run-rime information that is passed
67 * within Turbine. This provides the threading mechanism for the
68 * entire system because multiple requests can potentially come in
69 * at the same time. Thus, there is only one RunData implementation
70 * for each request that is being serviced.
71 *
72 * <p>DefaultTurbineRunData implements the Recyclable interface making
73 * it possible to pool its instances for recycling.
74 *
75 * @author <a href="mailto:ilkka.priha@simsoft.fi">Ilkka Priha</a>
76 * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
77 * @author <a href="mailto:bhoeneis@ee.ethz.ch">Bernie Hoeneisen</a>
78 * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
79 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
80 * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a>
81 * @version $Id: DefaultTurbineRunData.java 1066938 2011-02-03 20:14:53Z ludwig $
82 */
83 public class DefaultTurbineRunData
84 extends DefaultPipelineData
85 implements TurbineRunData, Recyclable
86 {
87 /**
88 * The disposed flag.
89 */
90 private boolean disposed;
91
92 /** The default locale. */
93 private static Locale defaultLocale = null;
94
95 /** The default charset. */
96 private static String defaultCharSet = null;
97
98 /** A reference to the GET/POST data parser. */
99 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 }