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