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