1 18 package org.apache.beehive.netui.pageflow; 19 20 import org.apache.beehive.netui.core.urls.MutableURI; 21 import org.apache.beehive.netui.pageflow.config.PageFlowActionMapping; 22 import org.apache.beehive.netui.pageflow.handler.ActionForwardHandler; 23 import org.apache.beehive.netui.pageflow.handler.ExceptionsHandler; 24 import org.apache.beehive.netui.pageflow.handler.FlowControllerHandlerContext; 25 import org.apache.beehive.netui.pageflow.handler.Handlers; 26 import org.apache.beehive.netui.pageflow.handler.LoginHandler; 27 import org.apache.beehive.netui.pageflow.internal.AdapterManager; 28 import org.apache.beehive.netui.pageflow.internal.InternalConstants; 29 import org.apache.beehive.netui.pageflow.internal.InternalExpressionUtils; 30 import org.apache.beehive.netui.pageflow.internal.InternalUtils; 31 import org.apache.beehive.netui.pageflow.scoping.ScopedRequest; 32 import org.apache.beehive.netui.util.internal.FileUtils; 33 import org.apache.beehive.netui.util.internal.InternalStringBuilder; 34 import org.apache.beehive.netui.util.internal.cache.ClassLevelCache; 35 import org.apache.beehive.netui.util.logging.Logger; 36 import org.apache.struts.Globals; 37 import org.apache.struts.action.ActionForm; 38 import org.apache.struts.action.ActionForward; 39 import org.apache.struts.action.ActionMapping; 40 import org.apache.struts.action.ActionMessage; 41 import org.apache.struts.action.ActionMessages; 42 import org.apache.struts.action.ActionServlet; 43 import org.apache.struts.action.RequestProcessor; 44 import org.apache.struts.config.ActionConfig; 45 import org.apache.struts.config.ControllerConfig; 46 import org.apache.struts.config.ModuleConfig; 47 import org.apache.struts.util.MessageResources; 48 import org.apache.struts.util.RequestUtils; 49 import org.apache.struts.util.TokenProcessor; 50 51 import javax.security.auth.login.LoginException ; 52 import javax.servlet.ServletContext ; 53 import javax.servlet.ServletException ; 54 import javax.servlet.http.HttpServletRequest ; 55 import javax.servlet.http.HttpServletResponse ; 56 import javax.servlet.http.HttpSession ; 57 import javax.sql.DataSource ; 58 import java.io.IOException ; 59 import java.lang.reflect.Field ; 60 import java.lang.reflect.InvocationTargetException ; 61 import java.lang.reflect.Method ; 62 import java.net.URISyntaxException ; 63 import java.util.ArrayList ; 64 import java.util.Iterator ; 65 import java.util.Locale ; 66 import java.util.Map ; 67 68 69 70 73 public abstract class FlowController extends PageFlowManagedObject 74 implements PageFlowConstants, ActionResolver 75 { 76 private static final Logger _log = Logger.getInstance( FlowController.class ); 77 78 private static final String ONCREATE_EXCEPTION_FORWARD = InternalConstants.ATTR_PREFIX + "onCreateException"; 79 private static final String CACHEID_ACTION_METHODS = InternalConstants.ATTR_PREFIX + "actionMethods"; 80 private static final int DEFAULT_MAX_CONCURRENT_REQUEST_COUNT = 4; 81 private static final String MAX_CONCURRENT_REQUESTS_PARAM = "pageflow-max-concurrent-requests"; 82 private static final int EXCEEDED_MAX_CONCURRENT_REQUESTS_ERRORCODE = 503; 83 private static final Locale DEFAULT_LOCALE = Locale.getDefault(); 84 private static final ActionForward NULL_ACTION_FORWARD = new ActionForward(); 85 private static final TokenProcessor TOKEN_PROCESSOR = TokenProcessor.getInstance(); 86 87 92 protected static Locale defaultLocale = DEFAULT_LOCALE; 93 94 95 102 protected transient ActionServlet servlet = null; 103 104 105 static class PerRequestState 106 { 107 private HttpServletRequest _request; 108 private HttpServletResponse _response; 109 private ActionMapping _actionMapping; 110 111 public PerRequestState( HttpServletRequest request, HttpServletResponse response, ActionMapping actionMapping ) 112 { 113 _request = request; 114 _response = response; 115 _actionMapping = actionMapping; 116 } 117 118 public HttpServletRequest getRequest() 119 { 120 return _request; 121 } 122 123 public HttpServletResponse getResponse() 124 { 125 return _response; 126 } 127 128 public ActionMapping getActionMapping() 129 { 130 return _actionMapping; 131 } 132 } 133 134 137 private transient PerRequestState _perRequestState; 138 139 142 private transient ModuleConfig _moduleConfig = null; 143 144 147 private transient int _requestCount = 0; 148 149 152 private static int _maxConcurrentRequestCount = -1; 153 154 155 158 protected FlowController() 159 { 160 } 161 162 165 public void reinitialize( HttpServletRequest request, HttpServletResponse response, ServletContext servletContext ) 166 { 167 super.reinitialize( request, response, servletContext ); 172 initModuleConfig( servletContext, request ); 173 servlet = getServlet(); 174 } 175 176 184 public void login( String username, String password ) 185 throws LoginException 186 { 187 LoginHandler lh = Handlers.get( getServletContext() ).getLoginHandler(); 188 lh.login( getHandlerContext(), username, password ); 189 } 190 191 200 public void logout( boolean invalidateSessions ) 201 { 202 LoginHandler lh = Handlers.get( getServletContext() ).getLoginHandler(); 203 lh.logout( getHandlerContext(), invalidateSessions ); 204 } 205 206 213 protected void sendError( String errText, HttpServletResponse response ) 214 throws IOException 215 { 216 sendError( errText, null, response ); 217 } 218 219 225 protected void sendError( String errText, HttpServletRequest request, HttpServletResponse response ) 226 throws IOException 227 { 228 InternalUtils.sendError( "PageFlow_Custom_Error", null, request, response, 229 new Object []{ getDisplayName(), errText } ); 230 } 231 232 243 public synchronized ActionForward handleException( Throwable ex, ActionMapping mapping, 244 ActionForm form, HttpServletRequest request, 245 HttpServletResponse response ) 246 throws IOException , ServletException 247 { 248 PerRequestState prevState = setPerRequestState( new PerRequestState( request, response, mapping ) ); 249 250 try 251 { 252 ExceptionsHandler eh = Handlers.get( getServletContext() ).getExceptionsHandler(); 253 FlowControllerHandlerContext context = getHandlerContext(); 254 255 Throwable unwrapped = eh.unwrapException( context, ex ); 257 eh.exposeException( context, unwrapped, mapping ); 258 return eh.handleException( context, unwrapped, mapping, form ); 259 } 260 finally 261 { 262 setPerRequestState( prevState ); 263 } 264 } 265 266 276 277 protected String getCurrentActionName() 278 { 279 return InternalUtils.getActionName( getActionMapping() ); 280 } 281 282 292 public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest request, 293 HttpServletResponse response ) 294 throws Exception 295 { 296 if ( incrementRequestCount( request, response, getServletContext() ) ) 301 { 302 try 303 { 304 synchronized ( this ) 305 { 306 return internalExecute( mapping, form, request, response ); 307 } 308 } 309 finally 310 { 311 decrementRequestCount( request ); 312 } 313 } 314 else 315 { 316 return null; } 318 } 319 320 323 protected ActionForward internalExecute( ActionMapping mapping, ActionForm form, HttpServletRequest request, 324 HttpServletResponse response ) 325 throws Exception 326 { 327 ServletContainerAdapter sca = AdapterManager.getServletContainerAdapter( getServletContext() ); 328 PageFlowEventReporter eventReporter = sca.getEventReporter(); 329 eventReporter.actionRaised( this, mapping, form, request, response ); 330 long startTime = System.currentTimeMillis(); 331 332 ActionForward onCreateFwd = ( ActionForward ) request.getAttribute( ONCREATE_EXCEPTION_FORWARD ); 336 337 if ( onCreateFwd != null ) 338 { 339 return onCreateFwd == NULL_ACTION_FORWARD ? null : onCreateFwd; 340 } 341 342 343 PageFlowUtils.setActionURI( request ); 344 345 boolean gotPastBeforeAction = false; 350 ServletContext servletContext = getServletContext(); 351 PerRequestState prevState = setPerRequestState( new PerRequestState( request, response, mapping ) ); 352 353 try 354 { 355 beforeAction(); 359 gotPastBeforeAction = true; 360 361 PageFlowActionMapping pfActionMapping = 362 mapping instanceof PageFlowActionMapping ? ( PageFlowActionMapping ) mapping : null; 363 Object unwrappedForm = InternalUtils.unwrapFormBean( form ); 364 365 if ( unwrappedForm != null && pfActionMapping != null ) 370 { 371 if ( pfActionMapping.isOverloaded() ) 372 { 373 String mappingPath = pfActionMapping.getPath(); 374 375 for ( Class i = unwrappedForm.getClass(); i != null; i = i.getSuperclass() ) 379 { 380 String formQualifiedActionPath = getFormQualifiedActionPath( i, mappingPath ); 381 ActionConfig cf = pfActionMapping.getModuleConfig().findActionConfig( formQualifiedActionPath ); 382 383 if ( cf != null ) 384 { 385 assert cf instanceof PageFlowActionMapping : cf.getClass().getName(); 386 387 if ( _log.isDebugEnabled() ) 388 { 389 _log.debug( "Found form-specific mapping " + cf.getPath() + 390 " -- choosing this one over current mapping " + mappingPath ); 391 } 392 393 pfActionMapping = ( PageFlowActionMapping ) cf; 394 mapping = pfActionMapping; 395 break; 396 } 397 } 398 } 399 } 400 401 String actionName = InternalUtils.getActionName( mapping ); 402 403 LoginHandler loginHandler = Handlers.get( getServletContext() ).getLoginHandler(); 407 408 if ( pfActionMapping != null && pfActionMapping.isLoginRequired() 409 && loginHandler.getUserPrincipal( getHandlerContext() ) == null ) 410 { 411 NotLoggedInException ex = createNotLoggedInException( actionName, request ); 412 return handleException( ex, mapping, form, request, response ); 413 } 414 415 ActionForward retVal; 419 if ( pfActionMapping != null && pfActionMapping.isSimpleAction() ) 420 { 421 retVal = handleSimpleAction( pfActionMapping, form, request, servletContext ); 422 } 423 else 424 { 425 retVal = getActionMethodForward( actionName, unwrappedForm, request, response, mapping ); 426 } 427 428 ActionForward ret = forwardTo( retVal, mapping, request, response, actionName, null, form, servletContext ); 429 long timeTaken = System.currentTimeMillis() - startTime; 430 eventReporter.actionSuccess( this, mapping, form, request, response, ret, timeTaken ); 431 return ret; 432 } 433 catch ( Exception e ) 434 { 435 return handleException( e, mapping, form, request, response ); 443 } 444 finally 445 { 446 try 447 { 448 ActionForward overrideReturn = null; 449 450 if ( gotPastBeforeAction ) 451 { 452 try 456 { 457 afterAction(); 458 } 459 catch ( Throwable th ) 460 { 461 overrideReturn = handleException( th, mapping, form, request, response ); 462 } 463 } 464 465 savePreviousActionInfo( form, request, mapping, getServletContext() ); 469 470 if ( overrideReturn != null ) 471 { 472 return overrideReturn; 473 } 474 } 475 finally 476 { 477 setPerRequestState( prevState ); 478 } 479 } 480 } 481 482 ActionForward forwardTo( ActionForward fwd, ActionMapping mapping, HttpServletRequest request, 483 HttpServletResponse response, String actionName, ModuleConfig altModuleConfig, 484 ActionForm form, ServletContext servletContext ) 485 { 486 ActionForwardHandler handler = Handlers.get( servletContext ).getActionForwardHandler(); 490 FlowControllerHandlerContext context = new FlowControllerHandlerContext( request, response, this ); 491 return handler.doForward( context, fwd, mapping, actionName, altModuleConfig, form ); 492 } 493 494 NotLoggedInException createNotLoggedInException( String actionName, HttpServletRequest request ) 495 { 496 if ( InternalUtils.sessionExpired( request ) ) 497 { 498 return new LoginExpiredException( actionName, this ); 499 } 500 else 501 { 502 return new NotLoggedInException( actionName, this ); 503 } 504 } 505 506 509 public synchronized void create( HttpServletRequest request, HttpServletResponse response, 510 ServletContext servletContext ) 511 { 512 PerRequestState prevState = setPerRequestState( new PerRequestState( request, response, null ) ); 513 514 try 515 { 516 try 517 { 518 super.create( request, response, servletContext ); 519 } 520 catch ( Throwable th ) 521 { 522 try 523 { 524 _log.info( "Handling exception in onCreate(), FlowController " + this, th ); 525 ActionForward fwd = handleException( th, null, null, request, response ); 526 if ( fwd == null ) fwd = NULL_ACTION_FORWARD; 527 request.setAttribute( ONCREATE_EXCEPTION_FORWARD, fwd ); 528 } 529 catch ( Exception e ) 530 { 531 _log.error( "Exception thrown while handling exception in onCreate(): " + e.getMessage(), th ); 532 } 533 } 534 } 535 finally 536 { 537 setPerRequestState( prevState ); 538 } 539 540 PageFlowEventReporter er = AdapterManager.getServletContainerAdapter( servletContext ).getEventReporter(); 541 er.flowControllerCreated( this, request, response ); 542 } 543 544 548 void destroy( HttpSession session ) 549 { 550 onDestroy(); super.destroy( session ); 552 553 ServletContext servletContext = getServletContext(); 558 if ( servletContext == null && session != null ) servletContext = session.getServletContext(); 559 560 if ( servletContext != null ) 561 { 562 PageFlowEventReporter er = AdapterManager.getServletContainerAdapter( servletContext ).getEventReporter(); 563 er.flowControllerDestroyed( this ); 564 } 565 } 566 567 572 public abstract String getModulePath(); 573 574 581 protected synchronized void beforeAction() 582 throws Exception 583 { 584 } 585 586 593 protected synchronized void afterAction() 594 throws Exception 595 { 596 } 597 598 602 protected void onCreate() 603 throws Exception 604 { 605 } 606 607 620 protected void onDestroy() 621 { 622 } 623 624 634 protected void onDestroy( HttpSession session ) 635 { 636 } 637 638 642 public abstract PreviousPageInfo getPreviousPageInfoLegacy( PageFlowController curJpf, HttpServletRequest request ); 643 644 652 protected Method getActionMethod( String methodName, Class argType ) 653 { 654 String cacheKey = argType != null ? methodName + '/' + argType.getName() : methodName; 655 Class thisClass = getClass(); 656 ClassLevelCache cache = ClassLevelCache.getCache( thisClass ); 657 Method actionMethod = ( Method ) cache.get( CACHEID_ACTION_METHODS, cacheKey ); 658 659 if ( actionMethod != null ) 660 { 661 return actionMethod; 662 } 663 else 664 { 665 if ( argType == null ) 669 { 670 actionMethod = InternalUtils.lookupMethod( thisClass, methodName, null ); 674 } 675 else 676 { 677 while ( argType != null ) 682 { 683 actionMethod = InternalUtils.lookupMethod( thisClass, methodName, new Class []{ argType } ); 684 685 if ( actionMethod != null ) 686 { 687 break; 688 } 689 690 argType = argType.getSuperclass(); 691 } 692 } 693 694 if ( actionMethod != null && actionMethod.getReturnType().equals( Forward.class ) ) 695 { 696 actionMethod.setAccessible( true ); 697 cache.put( CACHEID_ACTION_METHODS, cacheKey, actionMethod ); 698 return actionMethod; 699 } 700 } 701 702 return null; 703 } 704 705 private Class getFormClass( Object form, ActionMapping mapping, HttpServletRequest request ) 706 throws ClassNotFoundException 707 { 708 if ( mapping instanceof PageFlowActionMapping ) 709 { 710 String formClassName = ( ( PageFlowActionMapping ) mapping ).getFormClass(); 711 712 if ( formClassName != null ) 713 { 714 return InternalUtils.getReloadableClass( formClassName, getServletContext() ); 715 } 716 } 717 718 return form != null ? form.getClass() : null; 719 } 720 721 734 ActionForward getActionMethodForward( String actionName, Object inputForm, 735 HttpServletRequest request, HttpServletResponse response, 736 ActionMapping mapping ) 737 throws Exception 738 { 739 Class formClass = getFormClass( inputForm, mapping, request ); 743 Method actionMethod = getActionMethod( actionName, formClass ); 744 745 if ( actionMethod != null ) 749 { 750 return invokeActionMethod( actionMethod, inputForm, request, mapping ); 751 } 752 753 if ( _log.isWarnEnabled() ) 754 { 755 InternalStringBuilder msg = new InternalStringBuilder( "Could not find matching action method for action=" ); 756 msg.append( actionName ).append( ", form=" ); 757 msg.append( inputForm != null ? inputForm.getClass().getName() :"[none]" ); 758 _log.warn( msg.toString() ); 759 } 760 761 PageFlowException ex = new NoMatchingActionMethodException( actionName, inputForm, this ); 762 InternalUtils.throwPageFlowException( ex, request ); 763 return null; 764 } 765 766 private static String getFormQualifiedActionPath( Class formClass, String actionPath ) 767 { 768 InternalStringBuilder ret = new InternalStringBuilder( actionPath ); 769 ret.append( '_' ); 770 ret.append( formClass.getName().replace( '.', '_' ).replace( '$', '_' ) ); 771 return ret.toString(); 772 } 773 774 782 protected ActionForward invokeActionMethod( Method method, Object arg ) 783 throws Exception 784 { 785 return invokeActionMethod( method, arg, getRequest(), getActionMapping() ); 786 } 787 788 797 ActionForward invokeActionMethod( Method method, Object arg, HttpServletRequest request, ActionMapping mapping ) 798 throws Exception 799 { 800 Class [] paramTypes = method.getParameterTypes(); 801 802 try 803 { 804 if ( paramTypes.length > 0 && paramTypes[0].isInstance( arg ) ) 805 { 806 if ( _log.isDebugEnabled() ) 807 { 808 _log.debug( "Invoking action method " + method.getName() + '(' + paramTypes[0].getName() + ')' ); 809 } 810 811 return ( ActionForward ) method.invoke( this, new Object []{ arg } ); 812 } 813 else if ( paramTypes.length == 0 ) 814 { 815 if ( _log.isDebugEnabled() ) 816 { 817 _log.debug( "Invoking action method " + method.getName() + "()" ); 818 } 819 820 return ( ActionForward ) method.invoke( this, null ); 821 } 822 } 823 finally 824 { 825 boolean readonly = false; 826 827 if ( mapping instanceof PageFlowActionMapping ) 828 { 829 PageFlowActionMapping pfam = ( PageFlowActionMapping ) mapping; 830 readonly = pfam.isReadonly(); 831 } 832 833 if ( ! readonly ) 834 { 835 ensureFailover( getRequest() ); 836 } 837 } 838 839 if ( _log.isWarnEnabled() ) 840 { 841 _log.warn( "Could not find action method " + method.getName() + " with appropriate signature." ); 842 } 843 844 return null; 845 } 846 847 857 protected final HttpServletRequest getRequest() 858 { 859 if ( _perRequestState == null ) 860 { 861 throw new IllegalStateException ( "getRequest was called outside of a valid context." ); 862 } 863 864 return _perRequestState.getRequest(); 865 } 866 867 877 protected final HttpServletResponse getResponse() 878 { 879 if ( _perRequestState == null ) 880 { 881 throw new IllegalStateException ( "getResponse was called outside of a valid context." ); 882 } 883 884 return _perRequestState.getResponse(); 885 } 886 887 899 protected final ActionMapping getMapping() 900 { 901 return getActionMapping(); 902 } 903 904 915 protected final ActionMapping getActionMapping() 916 { 917 if ( _perRequestState == null ) 918 { 919 throw new IllegalStateException ( "getActionMapping was called outside of a valid context." ); 920 } 921 922 return _perRequestState.getActionMapping(); 923 } 924 925 935 protected final HttpSession getSession() 936 { 937 if ( _perRequestState == null ) 938 { 939 throw new IllegalStateException ( "getSession was called outside of a valid context." ); 940 } 941 942 return _perRequestState.getRequest().getSession( true ); 943 } 944 945 PerRequestState setPerRequestState( PerRequestState state ) 946 { 947 if ( state != null ) 948 { 949 assert state.getRequest() != null; 950 assert state.getResponse() != null; 951 } 952 953 PerRequestState prevState = _perRequestState; 954 _perRequestState = state; 955 return prevState; 956 } 957 958 961 public final ModuleConfig getModuleConfig() 962 { 963 assert _moduleConfig != null : "no cached ModuleConfig for " + getClass().getName(); 964 return _moduleConfig; 965 } 966 967 private void initModuleConfig( ServletContext servletContext, HttpServletRequest request ) 968 { 969 if ( _moduleConfig == null ) 970 { 971 _moduleConfig = InternalUtils.getModuleConfig( getModulePath(), servletContext ); 972 973 if ( _moduleConfig == null ) 974 { 975 ActionServlet actionServlet = InternalUtils.getActionServlet( servletContext ); 980 if ( actionServlet instanceof AutoRegisterActionServlet ) 981 { 982 try 983 { 984 AutoRegisterActionServlet servlet = ( AutoRegisterActionServlet ) actionServlet; 985 _moduleConfig = servlet.ensureModuleRegistered( getModulePath(), request ); 986 } 987 catch ( Exception e ) 988 { 989 _log.error( "Error while registering module " + getModulePath(), e ); 990 } 991 } 992 } 993 994 assert _moduleConfig != null : getModulePath() + "; " + getClass().getName(); 995 } 996 } 997 998 1004 public ModuleConfig getModuleConfig( ServletContext servletContext, HttpServletRequest request ) 1005 { 1006 initModuleConfig( servletContext, request ); 1007 return _moduleConfig; 1008 } 1009 1010 1018 public static ActionResult lookup( String actionName, ServletContext context, HttpServletRequest request, 1019 HttpServletResponse response ) 1020 throws Exception 1021 { 1022 return PageFlowUtils.strutsLookup( context, request, response, actionName, null ); 1023 } 1024 1025 1032 public static ActionResult lookup( String actionName, ServletContext context, HttpServletRequest request, 1033 HttpServletResponse response, String actionServletClassName ) 1034 throws Exception 1035 { 1036 return PageFlowUtils.strutsLookup( context, request, response, actionName, null ); 1037 } 1038 1039 1048 public String resolveAction( String actionName, Object form, HttpServletRequest request, 1049 HttpServletResponse response ) 1050 throws Exception 1051 { 1052 ActionMapping mapping = ( ActionMapping ) getModuleConfig().findActionConfig( '/' + actionName ); 1053 1054 if ( mapping == null ) 1055 { 1056 InternalUtils.throwPageFlowException( new ActionNotFoundException( actionName, this, form ), request ); 1057 } 1058 1059 ActionForward fwd = getActionMethodForward( actionName, form, request, response, mapping ); 1060 1061 if ( fwd instanceof Forward ) 1062 { 1063 ( ( Forward ) fwd ).initialize( mapping, this, request ); 1064 } 1065 1066 String path = fwd.getPath(); 1067 if ( fwd.getContextRelative() || FileUtils.isAbsoluteURI( path ) ) 1068 { 1069 return path; 1070 } 1071 else 1072 { 1073 return getModulePath() + path; 1074 } 1075 } 1076 1077 1087 public String resolveAction( String actionName, Object form ) 1088 throws Exception 1089 { 1090 return resolveAction( actionName, form, getRequest(), getResponse() ); 1091 } 1092 1093 1098 public String [] getActions() 1099 { 1100 ActionConfig[] actionConfigs = getModuleConfig().findActionConfigs(); 1101 ArrayList actionNames = new ArrayList (); 1102 1103 for ( int i = 0; i < actionConfigs.length; i++ ) 1104 { 1105 ActionConfig ac = actionConfigs[i]; 1106 actionNames.add( ac.getPath().substring( 1 ) ); } 1108 1109 return ( String [] ) actionNames.toArray( new String [0] ); 1110 } 1111 1112 1119 public boolean isAction( String name ) 1120 { 1121 return getModuleConfig().findActionConfig( '/' + name ) != null; 1122 } 1123 1124 1129 public boolean isPageFlow() 1130 { 1131 return false; 1132 } 1133 1134 1142 protected ActionServlet getServlet() 1143 { 1144 return InternalUtils.getActionServlet( getServletContext() ); 1145 } 1146 1147 1151 public final synchronized void refresh( HttpServletRequest request, HttpServletResponse response ) 1152 { 1153 PerRequestState prevState = setPerRequestState( new PerRequestState( request, response, null ) ); 1154 1155 try 1156 { 1157 onRefresh(); 1158 } 1159 finally 1160 { 1161 setPerRequestState( prevState ); 1162 } 1163 } 1164 1165 1170 protected void onRefresh() 1171 { 1172 } 1173 1174 1177 protected void remove() 1178 { 1179 removeFromSession( getRequest() ); 1180 } 1181 1182 1185 void savePreviousActionInfo( ActionForm form, HttpServletRequest request, ActionMapping mapping, 1186 ServletContext servletContext ) 1187 { 1188 } 1189 1190 1194 public void savePreviousPageInfo( ActionForward forward, ActionForm form, ActionMapping mapping, 1195 HttpServletRequest request, ServletContext servletContext, 1196 boolean isSpecialForward ) 1197 { 1198 } 1199 1200 1219 protected boolean alwaysTrackPreviousAction() 1220 { 1221 return false; 1222 } 1223 1224 1248 protected boolean alwaysTrackPreviousPage() 1249 { 1250 return false; 1251 } 1252 1253 1258 boolean incrementRequestCount( HttpServletRequest request, HttpServletResponse response, 1259 ServletContext servletContext ) 1260 throws IOException 1261 { 1262 if ( _maxConcurrentRequestCount == -1 ) 1266 { 1267 _maxConcurrentRequestCount = DEFAULT_MAX_CONCURRENT_REQUEST_COUNT; 1268 String countStr = servletContext.getInitParameter( MAX_CONCURRENT_REQUESTS_PARAM ); 1269 1270 if ( countStr != null ) 1271 { 1272 try 1273 { 1274 _maxConcurrentRequestCount = Integer.parseInt( countStr ); 1275 } 1276 catch ( NumberFormatException e ) 1277 { 1278 _log.error( "Invalid value for servlet context parameter" + MAX_CONCURRENT_REQUESTS_PARAM 1279 + ": " + countStr, e ); 1280 } 1281 1282 if ( _maxConcurrentRequestCount < 1 ) 1283 { 1284 _maxConcurrentRequestCount = DEFAULT_MAX_CONCURRENT_REQUEST_COUNT; 1285 _log.error( "Invalid value for servlet context parameter" + MAX_CONCURRENT_REQUESTS_PARAM 1286 + ": " + countStr ); 1287 } 1288 } 1289 } 1290 1291 if ( _requestCount >= _maxConcurrentRequestCount ) 1296 { 1297 if ( _log.isDebugEnabled() ) 1298 { 1299 _log.debug( "Too many requests to FlowController " + getDisplayName() + " (" 1300 + ( _requestCount + 1 ) + '>' + _maxConcurrentRequestCount + "); returning error code " 1301 + EXCEEDED_MAX_CONCURRENT_REQUESTS_ERRORCODE ); 1302 } 1303 1304 response.sendError( EXCEEDED_MAX_CONCURRENT_REQUESTS_ERRORCODE ); 1305 return false; 1306 } 1307 1308 ++_requestCount; 1312 return true; 1313 } 1314 1315 void decrementRequestCount( HttpServletRequest request ) 1316 { 1317 assert _requestCount > 0 : request.getRequestURI(); 1318 --_requestCount; 1319 } 1320 1321 1334 public synchronized ActionForward invokeExceptionHandler( 1335 Method method, Throwable ex, String message, Object formBean, ActionForm wrappedFormBean, 1336 ActionMapping actionMapping, HttpServletRequest request, HttpServletResponse response, boolean readonly ) 1337 throws IOException , ServletException 1338 { 1339 PerRequestState prevState = setPerRequestState( new PerRequestState( request, response, actionMapping ) ); 1340 1341 try 1342 { 1343 if ( _log.isDebugEnabled() ) 1344 { 1345 _log.debug( "Invoking exception handler method " + method.getName() + '(' 1346 + method.getParameterTypes()[0].getName() + ", ...)" ); 1347 } 1348 1349 try 1350 { 1351 ActionForward retVal = null; 1352 String actionName = InternalUtils.getActionName( actionMapping ); 1353 1354 if ( actionName == null && ex instanceof PageFlowException ) 1355 { 1356 actionName = ( ( PageFlowException ) ex ).getActionName(); 1357 } 1358 1359 try 1360 { 1361 Object [] args = new Object []{ ex, actionName, message, formBean }; 1362 retVal = ( ActionForward ) method.invoke( this, args ); 1363 } 1364 finally 1365 { 1366 if ( ! readonly ) 1367 { 1368 ensureFailover( request ); 1369 } 1370 } 1371 1372 ActionForwardHandler handler = Handlers.get( getServletContext() ).getActionForwardHandler(); 1373 return handler.doForward( getHandlerContext(), retVal, actionMapping, actionName, getModuleConfig(), 1374 wrappedFormBean ); 1375 } 1376 catch ( InvocationTargetException e ) 1377 { 1378 Throwable target = e.getTargetException(); 1379 1380 if ( target instanceof Exception ) 1381 { 1382 throw ( Exception ) target; 1383 } 1384 else 1385 { 1386 throw e; 1387 } 1388 } 1389 } 1390 catch ( Throwable e ) 1391 { 1392 _log.error( "Exception while handling exception " + ex.getClass().getName() 1393 + ". The original exception will be thrown.", e ); 1394 1395 ExceptionsHandler eh = Handlers.get( getServletContext() ).getExceptionsHandler(); 1396 FlowControllerHandlerContext context = new FlowControllerHandlerContext( request, response, this ); 1397 Throwable unwrapped = eh.unwrapException( context, e ); 1398 1399 if ( ! eh.eatUnhandledException( context, unwrapped ) ) 1400 { 1401 if ( ex instanceof ServletException ) throw ( ServletException ) ex; 1402 if ( ex instanceof IOException ) throw ( IOException ) ex; 1403 throw new ServletException ( ex ); 1404 } 1405 1406 return null; 1407 } 1408 finally 1409 { 1410 setPerRequestState( prevState ); 1411 } 1412 } 1413 1414 1421 protected void addActionError( String propertyName, String messageKey, Object [] messageArgs ) 1422 { 1423 InternalUtils.addActionError( propertyName, new ActionMessage( messageKey, messageArgs ), getRequest() ); 1424 } 1425 1426 1433 protected void addActionErrorExpression( String propertyName, String expression, Object [] messageArgs ) 1434 { 1435 PageFlowUtils.addActionErrorExpression( getRequest(), propertyName, expression, messageArgs ); 1436 } 1437 1438 1446 protected void addValidationError( String propertyName, String messageKey, Object [] messageArgs ) 1447 { 1448 PageFlowUtils.addValidationError( propertyName, messageKey, messageArgs, getRequest() ); 1449 } 1450 1451 1458 protected void addValidationError( String propertyName, String messageKey ) 1459 { 1460 PageFlowUtils.addValidationError( propertyName, messageKey, getRequest() ); 1461 } 1462 1463 private static ActionForward handleSimpleAction( PageFlowActionMapping mapping, 1464 ActionForm wrappedFormBean, 1465 HttpServletRequest request, 1466 ServletContext servletContext ) 1467 { 1468 1469 Map conditionalForwards = mapping.getConditionalForwardsMap(); 1470 1471 if ( ! conditionalForwards.isEmpty() ) 1472 { 1473 Object formBean = InternalUtils.unwrapFormBean( wrappedFormBean ); 1474 1475 for ( Iterator i = conditionalForwards.entrySet().iterator(); i.hasNext(); ) 1476 { 1477 Map.Entry entry = ( Map.Entry ) i.next(); 1478 String expression = ( String ) entry.getKey(); 1479 String forwardName = ( String ) entry.getValue(); 1480 1481 try 1482 { 1483 if ( InternalExpressionUtils.evaluateCondition( expression, formBean, request, servletContext ) ) 1484 { 1485 if ( _log.isTraceEnabled() ) 1486 { 1487 _log.trace( "Expression '" + expression + "' evaluated to true on simple action " 1488 + mapping.getPath() + "; using forward " + forwardName + '.' ); 1489 } 1490 1491 return new Forward( forwardName ); 1492 } 1493 } 1494 catch( Exception e ) { 1496 if( _log.isErrorEnabled() ) 1497 { 1498 _log.error( "Exception occurred evaluating navigation expression '" + expression 1499 + "'. Cause: " + e.getCause(), e); 1500 } 1501 } 1502 } 1503 } 1504 1505 1506 String defaultForwardName = mapping.getDefaultForward(); 1507 assert defaultForwardName != null : "defaultForwardName is null on Simple Action " + mapping.getPath(); 1508 1509 if ( _log.isTraceEnabled() ) 1510 { 1511 _log.trace( "No expression evaluated to true on simple action " + mapping.getPath() 1512 + "; using forward " + defaultForwardName + '.' ); 1513 } 1514 1515 return new Forward( defaultForwardName ); 1516 } 1517 1518 1523 protected static Locale getDefaultLocale() 1524 { 1525 return defaultLocale; 1526 } 1527 1528 1533 protected DataSource getDataSource( HttpServletRequest request ) 1534 { 1535 return getDataSource( request, Globals.DATA_SOURCE_KEY ); 1536 } 1537 1538 1546 protected DataSource getDataSource( HttpServletRequest request, String key ) 1547 { 1548 return ( DataSource ) getServletContext().getAttribute( key + getModuleConfig().getPrefix() ); 1550 } 1551 1552 1553 1560 protected Locale getLocale( HttpServletRequest request ) 1561 { 1562 1563 HttpSession session = request.getSession(); 1564 Locale locale = ( Locale ) session.getAttribute( Globals.LOCALE_KEY ); 1565 return locale != null ? locale : DEFAULT_LOCALE; 1566 } 1567 1568 1573 protected Locale getLocale() 1574 { 1575 return retrieveUserLocale( getRequest(), null ); 1576 } 1577 1578 public static Locale retrieveUserLocale( HttpServletRequest request, String locale ) 1579 { 1580 if ( locale == null ) locale = Globals.LOCALE_KEY; 1581 HttpSession session = request.getSession( false ); 1582 Locale userLocale = null; 1583 if ( session != null ) userLocale = ( Locale ) session.getAttribute( locale ); 1584 if ( userLocale == null ) userLocale = DEFAULT_LOCALE; 1585 return userLocale; 1586 } 1587 1588 1589 1596 protected MessageResources getResources() 1597 { 1598 return ( MessageResources ) getServletContext().getAttribute( Globals.MESSAGES_KEY ); 1599 } 1600 1601 1607 protected MessageResources getResources( HttpServletRequest request ) 1608 { 1609 return getMessageResources(); 1610 } 1611 1612 1613 1621 protected MessageResources getResources( HttpServletRequest request, String key ) 1622 { 1623 return getMessageResources( key ); 1624 } 1625 1626 1629 protected MessageResources getMessageResources() 1630 { 1631 return getMessageResources( Globals.MESSAGES_KEY ); 1632 } 1633 1634 1640 protected MessageResources getMessageResources( String key ) 1641 { 1642 return ( MessageResources ) getServletContext().getAttribute( key + getModuleConfig().getPrefix() ); 1643 } 1644 1645 1660 protected boolean isCancelled( HttpServletRequest request ) 1661 { 1662 1663 return request.getAttribute( Globals.CANCEL_KEY ) != null; 1664 1665 } 1666 1667 1673 protected String generateToken( HttpServletRequest request ) 1674 { 1675 return TOKEN_PROCESSOR.generateToken( request ); 1676 } 1677 1678 1685 protected String generateToken() 1686 { 1687 return TOKEN_PROCESSOR.generateToken( getRequest() ); 1688 } 1689 1690 1706 protected boolean isTokenValid( HttpServletRequest request ) 1707 { 1708 1709 return TOKEN_PROCESSOR.isTokenValid( request, false ); 1710 1711 } 1712 1713 1729 protected boolean isTokenValid() 1730 { 1731 1732 return TOKEN_PROCESSOR.isTokenValid( getRequest(), false ); 1733 1734 } 1735 1736 1752 protected boolean isTokenValid( HttpServletRequest request, boolean reset ) 1753 { 1754 return TOKEN_PROCESSOR.isTokenValid( request, reset ); 1755 } 1756 1757 1773 protected boolean isTokenValid( boolean reset ) 1774 { 1775 1776 return TOKEN_PROCESSOR.isTokenValid( getRequest(), reset ); 1777 } 1778 1779 1780 1788 protected void resetToken( HttpServletRequest request ) 1789 { 1790 TOKEN_PROCESSOR.resetToken( request ); 1791 } 1792 1793 1802 protected void resetToken() 1803 { 1804 TOKEN_PROCESSOR.resetToken( getRequest() ); 1805 } 1806 1807 1808 1814 protected void saveErrors( HttpServletRequest request, ActionMessages errors ) 1815 { 1816 saveActionErrors( errors ); 1817 } 1818 1819 1820 1830 protected void saveMessages( HttpServletRequest request, ActionMessages messages ) 1831 { 1832 1833 if ( messages == null || messages.isEmpty() ) 1835 { 1836 request.removeAttribute( Globals.MESSAGE_KEY ); 1837 return; 1838 } 1839 1840 request.setAttribute( Globals.MESSAGE_KEY, messages ); 1842 1843 } 1844 1845 1850 protected void saveActionErrors( ActionMessages errors ) 1851 { 1852 if ( errors == null || errors.isEmpty() ) 1854 { 1855 getRequest().removeAttribute( Globals.MESSAGE_KEY ); 1856 } 1857 else 1858 { 1859 getRequest().setAttribute( Globals.MESSAGE_KEY, errors ); 1860 } 1861 } 1862 1863 1864 1870 protected void saveToken( HttpServletRequest request ) 1871 { 1872 TOKEN_PROCESSOR.saveToken( request ); 1873 } 1874 1875 1876 1884 protected void setLocale( HttpServletRequest request, Locale locale ) 1885 { 1886 1887 HttpSession session = request.getSession(); 1888 if ( locale == null ) 1889 { 1890 locale = getDefaultLocale(); 1891 } 1892 session.setAttribute( Globals.LOCALE_KEY, locale ); 1893 1894 } 1895 1896 1902 protected void setLocale( Locale locale ) 1903 { 1904 if ( locale == null ) locale = getDefaultLocale(); 1905 getSession().setAttribute( Globals.LOCALE_KEY, locale ); 1906 } 1907 1908 1912 public ActionForm getFormBean( ActionMapping mapping ) 1913 { 1914 if ( mapping instanceof PageFlowActionMapping ) 1915 { 1916 PageFlowActionMapping pfam = ( PageFlowActionMapping ) mapping; 1917 String formMember = pfam.getFormMember(); 1918 1919 try 1920 { 1921 if ( formMember != null ) 1922 { 1923 Field field = getClass().getDeclaredField( formMember ); 1924 field.setAccessible( true ); 1925 return InternalUtils.wrapFormBean( field.get( this ) ); 1926 } 1927 } 1928 catch ( Exception e ) 1929 { 1930 _log.error( "Could not use member field " + formMember + " as the form bean.", e ); 1931 } 1932 } 1933 1934 return null; 1935 } 1936 1937 PageFlowRequestProcessor getRequestProcessor() 1938 { 1939 ModuleConfig mc = getModuleConfig(); 1940 String key = Globals.REQUEST_PROCESSOR_KEY + mc.getPrefix(); 1941 RequestProcessor rp = ( RequestProcessor ) getServletContext().getAttribute( key ); 1942 1943 if ( rp == null ) 1947 { 1948 try 1949 { 1950 ControllerConfig cc = mc.getControllerConfig(); 1951 rp = ( RequestProcessor ) RequestUtils.applicationInstance( cc.getProcessorClass() ); 1952 rp.init( InternalUtils.getActionServlet( getServletContext() ), mc ); 1953 } 1954 catch ( Exception e ) 1955 { 1956 _log.error( "Could not initialize request processor for module " + mc.getPrefix(), e ); 1957 } 1958 } 1959 1960 assert rp == null || rp instanceof PageFlowRequestProcessor : rp.getClass().getName(); 1961 return ( PageFlowRequestProcessor ) rp; 1962 } 1963 1964 1978 public MutableURI getActionURI( String actionName ) 1979 throws URISyntaxException 1980 { 1981 if ( _perRequestState == null ) 1982 { 1983 throw new IllegalStateException ( "getActionURI was called outside of a valid context." ); 1984 } 1985 ServletContext servletContext = getServletContext(); 1986 HttpServletRequest request = getRequest(); 1987 HttpServletResponse response = getResponse(); 1988 1989 return PageFlowUtils.getActionURI( servletContext, request, response, actionName ); 1990 } 1991 1992 2008 public String getRewrittenActionURI( String actionName, Map parameters, boolean asValidXml ) 2009 throws URISyntaxException 2010 { 2011 if ( _perRequestState == null ) 2012 { 2013 throw new IllegalStateException ( "getRewrittenActionURI was called outside of a valid context." ); 2014 } 2015 ServletContext servletContext = getServletContext(); 2016 HttpServletRequest request = getRequest(); 2017 HttpServletResponse response = getResponse(); 2018 2019 return PageFlowUtils.getRewrittenActionURI( servletContext, request, response, 2020 actionName, parameters, null, asValidXml ); 2021 } 2022 2023 FlowControllerHandlerContext getHandlerContext() 2024 { 2025 return new FlowControllerHandlerContext( getRequest(), getResponse(), this ); 2026 } 2027} 2028 | Popular Tags |