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