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