001package org.apache.turbine.services.rundata; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.IOException; 023import java.io.PrintWriter; 024import java.util.ArrayList; 025import java.util.HashMap; 026import java.util.List; 027import java.util.Locale; 028import java.util.Map; 029 030import javax.naming.Context; 031import javax.servlet.ServletConfig; 032import javax.servlet.ServletContext; 033import javax.servlet.http.HttpServletRequest; 034import javax.servlet.http.HttpServletResponse; 035import javax.servlet.http.HttpSession; 036 037import org.apache.commons.lang.StringUtils; 038import org.apache.commons.logging.Log; 039import org.apache.commons.logging.LogFactory; 040import org.apache.fulcrum.mimetype.MimeTypeService; 041import org.apache.fulcrum.parser.CookieParser; 042import org.apache.fulcrum.parser.ParameterParser; 043import org.apache.fulcrum.pool.Recyclable; 044import org.apache.fulcrum.security.acl.AccessControlList; 045import org.apache.fulcrum.security.model.turbine.TurbineAccessControlList; 046import org.apache.turbine.Turbine; 047import org.apache.turbine.TurbineConstants; 048import org.apache.turbine.om.security.User; 049import org.apache.turbine.pipeline.DefaultPipelineData; 050import org.apache.turbine.services.ServiceManager; 051import org.apache.turbine.services.TurbineServices; 052import org.apache.turbine.services.template.TemplateService; 053import org.apache.turbine.util.FormMessages; 054import org.apache.turbine.util.ServerData; 055import org.apache.turbine.util.SystemError; 056import org.apache.turbine.util.template.TemplateInfo; 057 058/** 059 * DefaultTurbineRunData is the default implementation of the 060 * TurbineRunData interface, which is distributed by the Turbine 061 * RunData service, if another implementation is not defined in 062 * the default or specified RunData configuration. 063 * TurbineRunData is an extension to RunData, which 064 * is an interface to run-rime information that is passed 065 * within Turbine. This provides the threading mechanism for the 066 * entire system because multiple requests can potentially come in 067 * at the same time. Thus, there is only one RunData implementation 068 * for each request that is being serviced. 069 * 070 * <p>DefaultTurbineRunData implements the Recyclable interface making 071 * it possible to pool its instances for recycling. 072 * 073 * @author <a href="mailto:ilkka.priha@simsoft.fi">Ilkka Priha</a> 074 * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a> 075 * @author <a href="mailto:bhoeneis@ee.ethz.ch">Bernie Hoeneisen</a> 076 * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a> 077 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a> 078 * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a> 079 * @version $Id: DefaultTurbineRunData.java 1822093 2018-01-24 10:40:57Z gk $ 080 */ 081public class DefaultTurbineRunData 082 extends DefaultPipelineData 083 implements TurbineRunData, Recyclable 084{ 085 /** 086 * The disposed flag. 087 */ 088 private boolean disposed; 089 090 /** The default locale. */ 091 private static Locale defaultLocale = null; 092 093 /** The default charset. */ 094 private static String defaultCharSet = null; 095 096 /** Cached action name to execute for this request. */ 097 private String action; 098 099 /** 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}