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