| 1 18 package org.apache.beehive.netui.pageflow; 19 20 import org.apache.beehive.netui.util.internal.InternalStringBuilder; 21 22 import org.apache.beehive.netui.core.urls.URLRewriterService; 23 import org.apache.beehive.netui.pageflow.config.PageFlowActionForward; 24 import org.apache.beehive.netui.pageflow.config.PageFlowActionMapping; 25 import org.apache.beehive.netui.pageflow.handler.ActionForwardHandler; 26 import org.apache.beehive.netui.pageflow.handler.FlowControllerHandlerContext; 27 import org.apache.beehive.netui.pageflow.handler.ForwardRedirectHandler; 28 import org.apache.beehive.netui.pageflow.handler.Handlers; 29 import org.apache.beehive.netui.pageflow.handler.LoginHandler; 30 import org.apache.beehive.netui.pageflow.handler.ReloadableClassHandler; 31 import org.apache.beehive.netui.pageflow.interceptor.InterceptorException; 32 import org.apache.beehive.netui.pageflow.interceptor.Interceptors; 33 import org.apache.beehive.netui.pageflow.interceptor.Interceptor; 34 import org.apache.beehive.netui.pageflow.interceptor.action.ActionInterceptorContext; 35 import org.apache.beehive.netui.pageflow.interceptor.action.InterceptorForward; 36 import org.apache.beehive.netui.pageflow.interceptor.action.internal.ActionInterceptors; 37 import org.apache.beehive.netui.pageflow.interceptor.request.RequestInterceptorContext; 38 import org.apache.beehive.netui.pageflow.internal.AdapterManager; 39 import org.apache.beehive.netui.pageflow.internal.DefaultURLRewriter; 40 import org.apache.beehive.netui.pageflow.internal.FlowControllerAction; 41 import org.apache.beehive.netui.pageflow.internal.InternalUtils; 42 import org.apache.beehive.netui.pageflow.internal.JavaControlUtils; 43 import org.apache.beehive.netui.pageflow.internal.LegacySettings; 44 import org.apache.beehive.netui.pageflow.internal.PageFlowRequestWrapper; 45 import org.apache.beehive.netui.pageflow.internal.InternalConstants; 46 import org.apache.beehive.netui.pageflow.scoping.ScopedRequest; 47 import org.apache.beehive.netui.pageflow.scoping.ScopedServletUtils; 48 import org.apache.beehive.netui.script.common.ImplicitObjectUtil; 49 import org.apache.beehive.netui.util.internal.DiscoveryUtils; 50 import org.apache.beehive.netui.util.internal.FileUtils; 51 import org.apache.beehive.netui.util.internal.ServletUtils; 52 import org.apache.beehive.netui.util.config.ConfigUtil; 53 import org.apache.beehive.netui.util.config.bean.PageflowConfig; 54 import org.apache.beehive.netui.util.logging.Logger; 55 import org.apache.struts.Globals; 56 import org.apache.struts.action.Action; 57 import org.apache.struts.action.ActionForm; 58 import org.apache.struts.action.ActionForward; 59 import org.apache.struts.action.ActionMapping; 60 import org.apache.struts.action.ActionServlet; 61 import org.apache.struts.action.DynaActionForm; 62 import org.apache.struts.action.DynaActionFormClass; 63 import org.apache.struts.config.ActionConfig; 64 import org.apache.struts.config.FormBeanConfig; 65 import org.apache.struts.config.ForwardConfig; 66 import org.apache.struts.config.ModuleConfig; 67 import org.apache.struts.tiles.TilesRequestProcessor; 68 import org.apache.struts.tiles.TilesUtil; 69 import org.apache.struts.tiles.TilesUtilImpl; 70 import org.apache.struts.tiles.TilesUtilStrutsImpl; 71 import org.apache.struts.upload.MultipartRequestHandler; 72 import org.apache.struts.upload.MultipartRequestWrapper; 73 import org.apache.struts.util.RequestUtils; 74 import org.apache.struts.util.TokenProcessor; 75 76 import javax.servlet.FilterChain ; 77 import javax.servlet.Servlet ; 78 import javax.servlet.ServletConfig ; 79 import javax.servlet.ServletContext ; 80 import javax.servlet.ServletException ; 81 import javax.servlet.ServletRequest ; 82 import javax.servlet.ServletResponse ; 83 import javax.servlet.http.HttpServletRequest ; 84 import javax.servlet.http.HttpServletResponse ; 85 import javax.servlet.http.HttpSession ; 86 import java.io.IOException ; 87 import java.io.InputStream ; 88 import java.io.Serializable ; 89 import java.lang.reflect.Field ; 90 import java.net.URI ; 91 import java.net.URISyntaxException ; 92 import java.util.ArrayList ; 93 import java.util.Collections ; 94 import java.util.Enumeration ; 95 import java.util.HashMap ; 96 import java.util.Iterator ; 97 import java.util.List ; 98 import java.util.Map ; 99 import java.util.Properties ; 100 import java.util.Set ; 101 import org.apache.beehive.netui.util.internal.concurrent.InternalConcurrentHashMap; 102 103 104 109 public class PageFlowRequestProcessor 110 extends TilesRequestProcessor 111 implements Serializable , InternalConstants, PageFlowConstants 112 { 113 private static int requestCount = 0; 114 115 private static final Logger _log = Logger.getInstance( PageFlowRequestProcessor.class ); 116 117 private static final String ACTION_OVERRIDE_PARAM_PREFIX = "actionOverride:"; 118 private static final int ACTION_OVERRIDE_PARAM_PREFIX_LEN = ACTION_OVERRIDE_PARAM_PREFIX.length(); 119 private static final String SCHEME_UNSECURE = "http"; 120 private static final String SCHEME_SECURE = "https"; 121 private static final String REDIRECT_REQUEST_ATTRS_PREFIX = InternalConstants.ATTR_PREFIX + "requestAttrs:"; 122 private static final String REDIRECT_REQUEST_ATTRS_PARAM = "forceRedirect"; 123 private static final String FLOW_CONTROLLER_ACTION_CLASSNAME = FlowControllerAction.class.getName(); 124 125 private Map _formBeanClasses = new HashMap (); 126 private Map _overloadedActions = new HashMap (); 127 private ServletContainerAdapter _servletContainerAdapter; 128 private Handlers _handlers; 129 private FlowControllerFactory _flowControllerFactory; 130 private LegacySettings _legacySettings; 131 private InternalConcurrentHashMap _pageServletClasses = new InternalConcurrentHashMap(); 132 private PageFlowPageFilter _pageServletFilter; 133 134 135 protected Action processActionCreate( HttpServletRequest request, HttpServletResponse response, 136 ActionMapping actionMapping ) 137 throws IOException  138 { 139 String className = actionMapping.getType(); 140 141 if ( className != null && className.equals( FLOW_CONTROLLER_ACTION_CLASSNAME ) ) 142 { 143 FlowController fc = PageFlowRequestWrapper.get( request ).getCurrentFlowController(); 144 assert fc != null : "no FlowController for request " + request.getRequestURI(); 145 assert fc.getClass().getName().equals( actionMapping.getParameter() ) 146 : "current page flow type " + fc.getClass().getName() + " does not match type specified in " 147 + FLOW_CONTROLLER_ACTION_CLASSNAME + ": " + actionMapping.getParameter(); 148 149 Action action = new FlowControllerAction( fc ); 150 action.setServlet( servlet ); 151 return action; 152 } 153 154 return super.processActionCreate( request, response, actionMapping ); 155 } 156 157 161 private ActionForm createActionForm( ActionMapping mapping, HttpServletRequest request ) 162 { 163 String name = mapping.getName(); 164 165 assert name != null : mapping.getPath(); 166 if ( name == null ) return null; 167 168 FormBeanConfig config = moduleConfig.findFormBeanConfig( name ); 169 ActionForm instance; 170 171 if ( config.getDynamic() ) 175 { 176 try 177 { 178 DynaActionFormClass dynaClass = DynaActionFormClass.createDynaActionFormClass( config ); 179 instance = ( ActionForm ) dynaClass.newInstance(); 180 ( ( DynaActionForm ) instance ).initialize( mapping ); 181 182 if ( _log.isDebugEnabled() ) 183 { 184 _log.debug( " Creating new DynaActionForm instance " + "of type '" + config.getType() + '\'' ); 185 } 186 } 187 catch ( Exception e ) 188 { 189 _log.error( servlet.getInternal().getMessage( "formBean", config.getType() ), e ); 190 return null; 191 } 192 } 193 else 194 { 195 try 196 { 197 instance = ( ActionForm ) InternalUtils.newReloadableInstance( config.getType(), getServletContext() ); 198 199 if ( _log.isDebugEnabled() ) 200 { 201 _log.debug( " Creating new ActionForm instance " + "of type '" + config.getType() + '\'' ); 202 } 203 } 204 catch ( Exception e ) 205 { 206 _log.error( servlet.getInternal().getMessage( "formBean", config.getType() ), e ); 207 return null; 208 } 209 } 210 211 instance.setServlet( servlet ); 212 return instance; 213 } 214 215 private Field getPageFlowScopedFormMember( ActionMapping mapping, HttpServletRequest request ) 216 { 217 if ( mapping instanceof PageFlowActionMapping ) 218 { 219 PageFlowActionMapping pfam = ( PageFlowActionMapping ) mapping; 220 String formMember = pfam.getFormMember(); 221 222 try 223 { 224 if ( formMember != null ) 225 { 226 FlowController fc = PageFlowRequestWrapper.get( request ).getCurrentFlowController(); 227 Field field = fc.getClass().getDeclaredField( formMember ); 228 field.setAccessible( true ); 229 return field; 230 } 231 } 232 catch ( Exception e ) 233 { 234 _log.error( "Could not use page flow member " + formMember + " as the form bean.", e ); 235 } 236 } 237 238 return null; 239 } 240 241 protected ActionForm processActionForm( HttpServletRequest request, HttpServletResponse response, 242 ActionMapping mapping ) 243 { 244 Field formMemberField = getPageFlowScopedFormMember( mapping, request ); 248 249 ActionForm previousForm = InternalUtils.getForwardedFormBean( request, false ); 257 258 if ( previousForm != null ) 259 { 260 if ( formMemberField != null ) 265 { 266 try 267 { 268 FlowController fc = PageFlowRequestWrapper.get( request ).getCurrentFlowController(); 269 assert fc != null : "no FlowController in request " + request.getRequestURI(); 270 formMemberField.set( fc, InternalUtils.unwrapFormBean( previousForm ) ); 271 } 272 catch ( IllegalAccessException e ) 273 { 274 _log.error( "Could not access page flow member " + formMemberField.getName() 275 + " as the form bean.", e ); 276 } 277 } 278 279 previousForm.setServlet( servlet ); 283 return previousForm; 284 } 285 286 String pageFlowScopedFormName = PageFlowRequestWrapper.get( request ).getPageFlowScopedFormName(); 291 if ( pageFlowScopedFormName != null ) 292 { 293 request.removeAttribute( pageFlowScopedFormName ); 294 PageFlowRequestWrapper.get( request ).setPageFlowScopedFormName( null ); 295 } 296 297 if ( formMemberField != null ) 301 { 302 try 303 { 304 FlowController fc = PageFlowRequestWrapper.get( request ).getCurrentFlowController(); 305 ActionForm form = InternalUtils.wrapFormBean( formMemberField.get( fc ) ); 306 307 if ( form == null ) { 309 form = createActionForm( mapping, request ); 310 form.reset( mapping, request ); 311 formMemberField.set( fc, InternalUtils.unwrapFormBean( form ) ); 312 } 313 314 String formAttrName = mapping.getAttribute(); 321 request.setAttribute( formAttrName, form ); 322 PageFlowRequestWrapper.get( request ).setPageFlowScopedFormName( formAttrName ); 323 return form; 324 } 325 catch ( IllegalAccessException e ) 326 { 327 _log.error( "Could not access page flow member " + formMemberField.getName() + " as the form bean.", e ); 328 } 329 } 330 331 ActionForm bean = super.processActionForm( request, response, mapping ); 332 if ( bean == null ) 333 { 334 bean = InternalUtils.createActionForm( mapping, moduleConfig, servlet, getServletContext() ); 335 } 336 337 return bean; 338 } 339 340 protected void processPopulate( HttpServletRequest request, HttpServletResponse response, ActionForm form, 341 ActionMapping mapping ) 342 throws ServletException  343 { 344 ActionForm previousForm = InternalUtils.getForwardedFormBean( request, true ); 348 349 if ( previousForm != null ) 350 { 351 return; 352 } 353 354 if ( _log.isDebugEnabled() ) 355 { 356 _log.debug( "Populating bean properties from this request" ); 357 } 358 359 if ( form != null ) 361 { 362 form.setServlet( servlet ); 363 form.reset( mapping, request ); 364 } 365 366 if ( mapping.getMultipartClass() != null ) 367 { 368 request.setAttribute( Globals.MULTIPART_KEY, mapping.getMultipartClass() ); 369 } 370 371 PageFlowRequestWrapper requestWrapper = PageFlowRequestWrapper.get( request ); 372 boolean alreadyCalledInRequest = requestWrapper.isProcessPopulateAlreadyCalled(); 373 if ( ! alreadyCalledInRequest ) requestWrapper.setProcessPopulateAlreadyCalled( true ); 374 375 if ( !alreadyCalledInRequest || form != null ) 381 { 382 ProcessPopulate.populate( request, response, form, alreadyCalledInRequest ); 383 } 384 } 385 386 397 protected boolean processActionOverride( HttpServletRequest request, HttpServletResponse response ) 398 throws IOException , ServletException  399 { 400 PageFlowRequestWrapper wrapper = PageFlowRequestWrapper.get( request ); 405 if ( ! wrapper.isForwardedByButton() ) 406 { 407 wrapper.setForwardedByButton( true ); 408 409 HttpServletRequest multipartAwareRequest = processMultipart( request ); 415 416 for ( Enumeration e = multipartAwareRequest.getParameterNames(); e.hasMoreElements(); ) 417 { 418 String paramName = ( String ) e.nextElement(); 419 420 if ( paramName.startsWith( ACTION_OVERRIDE_PARAM_PREFIX ) ) 421 { 422 String actionPath = paramName.substring( ACTION_OVERRIDE_PARAM_PREFIX_LEN ); 423 ServletContext servletContext = getServletContext(); 424 425 String qualifiedAction = InternalUtils.qualifyAction( servletContext,actionPath ); 426 actionPath = InternalUtils.createActionPath(request, qualifiedAction ); 427 428 if ( _log.isDebugEnabled() ) 429 { 430 _log.debug( "A request parameter overrode the action. Forwarding to: " + actionPath ); 431 } 432 433 doForward( actionPath, request, response ); 434 return true; 435 } 436 } 437 } 438 439 return false; 440 } 441 442 private void processInternal( HttpServletRequest request, HttpServletResponse response ) 443 throws IOException , ServletException  444 { 445 request = PageFlowRequestWrapper.wrapRequest( request ); 450 451 String uri = InternalUtils.getDecodedServletPath( request ); 452 ServletContext servletContext = getServletContext(); 453 454 if ( LegacySettings.get( servletContext ).shouldDoSecureForwards() 458 && PageFlowRequestWrapper.get( request ).isForwardedRequest() ) 459 { 460 if ( _servletContainerAdapter.doSecurityRedirect( uri, request, response ) ) 466 { 467 if ( _log.isDebugEnabled() ) 468 { 469 _log.debug( "checkSecurity() caused a redirect. Ending processing for this request " 470 + '(' + uri + ')' ); 471 } 472 473 return; 474 } 475 } 476 477 String hash = request.getParameter( REDIRECT_REQUEST_ATTRS_PARAM ); 482 if ( hash != null ) 483 { 484 HttpSession session = request.getSession( false ); 485 486 if ( session != null ) 487 { 488 String carryoverAttrName = makeRedirectedRequestAttrsKey( uri, hash ); 489 Map attrs = ( Map ) session.getAttribute( carryoverAttrName ); 490 session.removeAttribute( carryoverAttrName ); 491 492 if ( attrs != null ) 493 { 494 for ( Iterator i = attrs.entrySet().iterator(); i.hasNext(); ) 495 { 496 Map.Entry entry = ( Map.Entry ) i.next(); 497 498 String attrName = ( String ) entry.getKey(); 499 if ( request.getAttribute( attrName ) == null ) 500 { 501 request.setAttribute( attrName, entry.getValue() ); 502 } 503 } 504 } 505 } 506 } 507 508 if ( processActionOverride( request, response ) ) return; 513 514 if ( processPageFlowRequest( request, response, uri ) ) return; 518 519 String flowControllerClassName = InternalUtils.getFlowControllerClassName( moduleConfig ); 523 524 if ( flowControllerClassName == null && 525 ! ( moduleConfig instanceof AutoRegisterActionServlet.MissingRootModuleControllerConfig ) ) 526 { 527 _log.warn( "Struts module " + moduleConfig.getPrefix() + " is configured to use " + getClass().getName() 532 + " as the request processor, but the <controller> element does not contain a <set-property>" 533 + " for \"controllerClass\". Page Flow actions in this module may not be handled correctly." ); 534 } 535 536 if ( _log.isInfoEnabled() ) 540 { 541 _log.info( "Attempting to instantiate SharedFlowControllers for request " + request.getRequestURI() ); 542 } 543 544 FlowController currentFlowController = null; 545 546 try 547 { 548 RequestContext requestContext = new RequestContext( request, response ); 549 Map sharedFlows = 550 _flowControllerFactory.getSharedFlowsForRequest( requestContext ); 551 ImplicitObjectUtil.loadSharedFlow( request, sharedFlows ); 552 ImplicitObjectUtil.loadGlobalApp( request, PageFlowUtils.getGlobalApp( request ) ); 553 554 if ( flowControllerClassName != null ) 555 { 556 currentFlowController = getFlowController( requestContext, flowControllerClassName ); 557 PageFlowRequestWrapper.get( request ).setCurrentFlowController( currentFlowController ); 558 } 559 else 560 { 561 PageFlowRequestWrapper.get( request ).setCurrentFlowController( null ); 562 } 563 } 564 catch ( ClassNotFoundException e ) 565 { 566 _log.error( "Could not find FlowController class " + flowControllerClassName, e ); 567 throw new ServletException ( e ); 568 } 569 catch ( InstantiationException e ) 570 { 571 _log.error( "Could not instantiate FlowController of type " + flowControllerClassName, e ); 572 throw new ServletException ( e ); 573 } 574 catch ( IllegalAccessException e ) 575 { 576 _log.error( "Could not instantiate FlowController of type " + flowControllerClassName, e ); 577 throw new ServletException ( e ); 578 } 579 580 PageFlowController jpf = PageFlowUtils.getCurrentPageFlow( request ); 584 585 ImplicitObjectUtil.loadImplicitObjects( request, response, servletContext, jpf ); 589 590 try 591 { 592 super.process( request, response ); 593 } 594 catch ( ServletException servletEx ) 595 { 596 if ( ! handleException( servletEx, currentFlowController, request, response ) ) throw servletEx; 598 } 599 catch ( IOException ioe ) 600 { 601 if ( ! handleException( ioe, currentFlowController, request, response ) ) throw ioe; 603 } 604 catch ( Throwable th ) 605 { 606 if ( ! handleException( th, currentFlowController, request, response ) ) throw new ServletException ( th ); 608 } 609 } 610 611 private FlowController getFlowController( RequestContext requestContext, String fcClassName ) 612 throws ClassNotFoundException , InstantiationException , IllegalAccessException  613 { 614 Class fcClass = _flowControllerFactory.getFlowControllerClass( fcClassName ); 615 HttpServletRequest request = requestContext.getHttpRequest(); 616 HttpServletResponse response = requestContext.getHttpResponse(); 617 618 if ( PageFlowController.class.isAssignableFrom( fcClass ) ) 619 { 620 PageFlowController current = PageFlowUtils.getCurrentPageFlow( request ); 621 622 if ( current != null && current.getClass().equals( fcClass ) ) 623 { 624 if ( _log.isDebugEnabled() ) 625 { 626 _log.debug( "Using current page flow: " + current ); 627 } 628 629 current.reinitialize( request, response, getServletContext() ); 633 return current; 634 } 635 636 return _flowControllerFactory.createPageFlow( new RequestContext( request, response ), fcClass ); 637 } 638 else 639 { 640 assert SharedFlowController.class.isAssignableFrom( fcClass ) : fcClass.getName(); 641 642 SharedFlowController current = PageFlowUtils.getSharedFlow( fcClass.getName(), request ); 643 644 if ( current != null ) 645 { 646 current.reinitialize( request, response, getServletContext() ); 647 return current; 648 } 649 650 return _flowControllerFactory.createSharedFlow( new RequestContext( request, response ), fcClass ); 651 } 652 } 653 654 private boolean handleException( Throwable th, FlowController fc, HttpServletRequest request, 655 HttpServletResponse response ) 656 { 657 if ( fc != null ) 658 { 659 try 660 { 661 ActionMapping mapping = InternalUtils.getCurrentActionMapping( request ); 662 ActionForm form = InternalUtils.getCurrentActionForm( request ); 663 ActionForward fwd = fc.handleException( th, mapping, form, request, response ); 664 processForwardConfig( request, response, fwd ); 665 return true; 666 } 667 catch ( Throwable t ) 668 { 669 _log.error( "Exception while handling exception " + th.getClass().getName() 670 + ". The original exception will be thrown.", th ); 671 return false; 672 } 673 } 674 675 return false; 676 } 677 678 |