| 1 18 package org.apache.beehive.netui.pageflow; 19 20 import org.apache.beehive.netui.util.internal.InternalStringBuilder; 21 22 import javax.servlet.http.HttpServletRequest ; 23 import javax.servlet.http.HttpServletResponse ; 24 import javax.servlet.http.HttpSessionBindingEvent ; 25 import javax.servlet.ServletContext ; 26 import java.lang.reflect.Field ; 27 import java.util.Map ; 28 29 import org.apache.struts.action.ActionForm; 30 import org.apache.struts.action.ActionMapping; 31 import org.apache.struts.action.ActionForward; 32 import org.apache.struts.config.ModuleConfig; 33 import org.apache.struts.config.ControllerConfig; 34 import org.apache.beehive.netui.util.logging.Logger; 35 import org.apache.beehive.netui.util.internal.FileUtils; 36 import org.apache.beehive.netui.util.internal.DiscoveryUtils; 37 import org.apache.beehive.netui.util.internal.cache.ClassLevelCache; 38 import org.apache.beehive.netui.pageflow.config.PageFlowControllerConfig; 39 import org.apache.beehive.netui.pageflow.internal.CachedPageFlowInfo; 40 import org.apache.beehive.netui.pageflow.internal.InternalUtils; 41 import org.apache.beehive.netui.pageflow.internal.InternalConstants; 42 import org.apache.beehive.netui.pageflow.internal.AdapterManager; 43 import org.apache.beehive.netui.pageflow.internal.CachedSharedFlowRefInfo; 44 import org.apache.beehive.netui.pageflow.internal.ViewRenderer; 45 import org.apache.beehive.netui.pageflow.internal.PageFlowRequestWrapper; 46 import org.apache.beehive.netui.pageflow.scoping.ScopedServletUtils; 47 48 49 101 public abstract class PageFlowController 102 extends FlowController 103 implements InternalConstants 104 { 105 110 private PreviousPageInfo _previousPageInfo = null; 111 private PreviousPageInfo _currentPageInfo = null; 112 113 117 private PreviousActionInfo _previousActionInfo; 118 119 private boolean _isOnNestingStack = false; 120 private ViewRenderer _returnActionViewRenderer = null; 121 122 private static final String REMOVING_PAGEFLOW_ATTR = InternalConstants.ATTR_PREFIX + "removingPageFlow"; 123 private static final String SAVED_PREVIOUS_PAGE_INFO_ATTR = InternalConstants.ATTR_PREFIX + "savedPrevPageInfo"; 124 private static final String CACHED_INFO_KEY = "cachedInfo"; 125 private static final Logger _log = Logger.getInstance( PageFlowController.class ); 126 127 128 131 protected PageFlowController() 132 { 133 } 134 135 142 public String getModulePath() 143 { 144 return getCachedInfo().getModulePath(); 145 } 146 147 153 public String getURI() 154 { 155 return getCachedInfo().getURI(); 156 } 157 158 166 protected boolean isNestable() 167 { 168 return InternalUtils.isNestable( getModuleConfig() ); 169 } 170 171 176 protected boolean isLongLived() 177 { 178 return InternalUtils.isLongLived( getModuleConfig() ); 179 } 180 181 184 protected synchronized void removeFromSession( HttpServletRequest request ) 185 { 186 request.setAttribute( REMOVING_PAGEFLOW_ATTR, this ); 188 189 if ( isLongLived() ) 190 { 191 PageFlowUtils.removeLongLivedPageFlow( getModulePath(), request ); 192 } 193 else 194 { 195 InternalUtils.removeCurrentPageFlow( request ); 196 } 197 } 198 199 204 public boolean isPageFlow() 205 { 206 return true; 207 } 208 209 213 public void persistInSession( HttpServletRequest request, HttpServletResponse response ) 214 { 215 PageFlowController currentPageFlow = PageFlowUtils.getCurrentPageFlow( request ); 216 217 if ( currentPageFlow != null && ! currentPageFlow.isOnNestingStack() ) 218 { 219 synchronized ( currentPageFlow ) 224 { 225 InternalUtils.setCurrentPageFlow( this, request ); 226 } 227 } 228 else 229 { 230 InternalUtils.setCurrentPageFlow( this, request ); 231 } 232 } 233 234 242 public void ensureFailover( HttpServletRequest request ) 243 { 244 if ( request.getAttribute( REMOVING_PAGEFLOW_ATTR ) != this && request.getSession( false ) != null ) 250 { 251 HttpServletRequest unwrappedRequest = PageFlowUtils.unwrapMultipart( request ); 252 ServletContainerAdapter servletContainerAdapter = AdapterManager.getServletContainerAdapter( getServletContext() ); 253 254 if ( isLongLived() ) 258 { 259 String longLivedAttrName = InternalUtils.getLongLivedFlowAttr( getModulePath() ); 260 longLivedAttrName = ScopedServletUtils.getScopedSessionAttrName( longLivedAttrName, unwrappedRequest ); 261 String currentLongLivedAttrName = 262 ScopedServletUtils.getScopedSessionAttrName( CURRENT_LONGLIVED_ATTR, unwrappedRequest ); 263 servletContainerAdapter.ensureFailover( longLivedAttrName, this, unwrappedRequest ); 264 servletContainerAdapter.ensureFailover( currentLongLivedAttrName, getModulePath(), unwrappedRequest ); 265 } 266 else 267 { 268 String attrName = ScopedServletUtils.getScopedSessionAttrName( CURRENT_JPF_ATTR, unwrappedRequest ); 269 servletContainerAdapter.ensureFailover( attrName, this, unwrappedRequest ); 270 } 271 } 272 } 273 274 277 protected ActionForward internalExecute( ActionMapping mapping, ActionForm form, HttpServletRequest request, 278 HttpServletResponse response ) 279 throws Exception  280 { 281 initializeSharedFlowFields( request ); 282 return super.internalExecute( mapping, form, request, response ); 283 } 284 285 private void initializeSharedFlowFields( HttpServletRequest request ) 286 { 287 CachedSharedFlowRefInfo.SharedFlowFieldInfo[] sharedFlowMemberFields = 291 getCachedInfo().getSharedFlowMemberFields(); 292 293 if ( sharedFlowMemberFields != null ) 294 { 295 for ( int i = 0; i < sharedFlowMemberFields.length; i++ ) 296 { 297 CachedSharedFlowRefInfo.SharedFlowFieldInfo fi = sharedFlowMemberFields[i]; 298 Field field = fi.field; 299 300 if ( fieldIsUninitialized( field ) ) 301 { 302 Map sharedFlows = PageFlowUtils.getSharedFlows( request ); 303 String name = fi.sharedFlowName; 304 SharedFlowController sf = 305 name != null ? 306 ( SharedFlowController ) sharedFlows.get( name ) : 307 PageFlowUtils.getGlobalApp( request ); 308 309 if ( sf != null ) 310 { 311 initializeField( field, sf ); 312 } 313 else 314 { 315 _log.error( "Could not find shared flow with name \"" + fi.sharedFlowName 316 + "\" to initialize field " + field.getName() + " in " + getClass().getName() ); 317 } 318 } 319 } 320 } 321 } 322 323 327 public Map getSharedFlows() 328 { 329 return PageFlowUtils.getSharedFlows( getRequest() ); 330 } 331 332 344 public SharedFlowController getSharedFlow( String sharedFlowName ) 345 { 346 return ( SharedFlowController ) PageFlowUtils.getSharedFlows( getRequest() ).get( sharedFlowName ); 347 } 348 349 360 public void removeSharedFlow( String sharedFlowName ) 361 { 362 SharedFlowController sf = getSharedFlow( sharedFlowName ); 363 if ( sf != null ) sf.removeFromSession( getRequest() ); 364 } 365 366 370 public final synchronized void create( HttpServletRequest request, HttpServletResponse response, 371 ServletContext servletContext ) 372 { 373 reinitialize( request, response, servletContext ); 374 initializeSharedFlowFields( request ); 375 376 if ( isNestable() ) 377 { 378 String vrClassName = request.getParameter( InternalConstants.RETURN_ACTION_VIEW_RENDERER_PARAM ); 382 383 if ( vrClassName != null ) 384 { 385 ViewRenderer vr = 386 ( ViewRenderer ) DiscoveryUtils.newImplementorInstance( vrClassName, ViewRenderer.class ); 387 388 if ( vr != null ) 389 { 390 vr.init( request ); 391 _returnActionViewRenderer = vr; 392 } 393 } 394 } 395 396 super.create( request, response, servletContext ); 397 } 398 399 404 protected String getTaxonomy() 405 { 406 assert getRequest() != null : "this method can only be called during execute()"; 407 String contextPath = getRequest().getContextPath(); 408 assert contextPath.startsWith( "/" ) : contextPath; 409 return contextPath.substring( 1 ) + '.' + getClass().getName(); 410 } 411 412 441 protected ActionForm getPreviousForm() 442 { 443 checkPreviousActionInfoDisabled(); 444 return _previousActionInfo != null ? _previousActionInfo.getForm() : null; 445 } 446 447 474 protected Object getPreviousFormBean() 475 { 476 checkPreviousActionInfoDisabled(); 477 return _previousActionInfo != null ? InternalUtils.unwrapFormBean( _previousActionInfo.getForm() ) : null; 478 } 479 480 507 protected String getPreviousActionURI() 508 { 509 checkPreviousActionInfoDisabled(); 510 return _previousActionInfo != null ? _previousActionInfo.getActionURI() : null; 511 } 512 513 541 public String getCurrentForwardPath() 542 { 543 PreviousPageInfo curPageInfo = getCurrentPageInfo(); 544 String path = null; 545 546 if ( curPageInfo != null ) 547 { 548 ActionForward curForward = curPageInfo.getForward(); 549 if ( curForward != null ) 550 { 551 if ( curForward.getContextRelative() ) 552 { 553 path = curForward.getPath(); 554 } 555 else 556 { 557 path = getModulePath() + curForward.getPath(); 558 } 559 } 560 } 561 return path; 562 } 563 564 593 protected String getPreviousForwardPath() 594 { 595 PreviousPageInfo prevPageInfo = getPreviousPageInfo(); 596 597 if ( prevPageInfo != null ) 598 { 599 ActionForward prevForward = prevPageInfo.getForward(); 600 return prevForward != null ? prevForward.getPath() : null; 601 } 602 else 603 { 604 return null; 605 } 606 } 607 608 612 public final PreviousPageInfo getPreviousPageInfoLegacy( PageFlowController curJpf, HttpServletRequest request ) 613 { 614 if ( request.getAttribute( RETURNING_FROM_NESTING_ATTR ) != null ) 615 { 616 return getCurrentPageInfo(); 617 } 618 else 619 { 620 return getPreviousPageInfo(); 621 } 622 } 623 624 652 public final PreviousPageInfo getCurrentPageInfo() 653 { 654 checkPreviousPageInfoDisabled(); 655 656 if ( _currentPageInfo != null ) 657 { 658 _currentPageInfo.reinitialize( this ); 660 } 661 662 return _currentPageInfo; 663 } 664 665 687 public final PreviousPageInfo getPreviousPageInfo() 688 { 689 checkPreviousPageInfoDisabled(); 690 691 PreviousPageInfo ret = _previousPageInfo != null ? _previousPageInfo : _currentPageInfo; 692 693 if ( ret != null ) 694 { 695 ret.reinitialize( this ); } 697 698 return ret; 699 } 700 701 728 public final PreviousActionInfo getPreviousActionInfo() 729 { 730 checkPreviousActionInfoDisabled(); 731 return _previousActionInfo; 732 } 733 734 private void checkPreviousActionInfoDisabled() 735 { 736 if ( isPreviousActionInfoDisabled() ) 737 { 738 throw new IllegalStateException ( "Previous action information has been disabled in this page flow. Override alwaysTrackPreviousAction() to enable it." ); 739 } 740 } 741 742 private void checkPreviousPageInfoDisabled() 743 { 744 if ( isPreviousPageInfoDisabled() ) 745 { 746 throw new IllegalStateException ( "Previous page information has been disabled in this page flow. Override alwaysTrackPreviousPage() to enable it." ); 747 } 748 } 749 750 754 public String getDisplayName() 755 { 756 return getURI(); 757 } 758 759 public boolean isPreviousActionInfoDisabled() 760 { 761 if ( alwaysTrackPreviousAction() ) return false; 762 763 ModuleConfig mc = getModuleConfig(); 764 ControllerConfig cc = mc.getControllerConfig(); 765 return cc instanceof PageFlowControllerConfig && ( ( PageFlowControllerConfig ) cc ).isReturnToActionDisabled(); 766 } 767 768 public boolean isPreviousPageInfoDisabled() 769 { 770 if ( alwaysTrackPreviousPage() ) return false; 771 772 ModuleConfig mc = getModuleConfig(); 773 ControllerConfig cc = mc.getControllerConfig(); 774 return cc instanceof PageFlowControllerConfig && ( ( PageFlowControllerConfig ) cc ).isReturnToPageDisabled(); 775 } 776 777 780 void savePreviousActionInfo( ActionForm form, HttpServletRequest request, ActionMapping mapping, 781 ServletContext servletContext ) 782 { 783 if ( isPreviousActionInfoDisabled() ) return; 787 String actionURI = InternalUtils.getDecodedServletPath( request ); 788 _previousActionInfo = new PreviousActionInfo( form, actionURI, request.getQueryString() ); 789 } 790 791 795 public void savePreviousPageInfo( ActionForward forward, ActionForm form, ActionMapping mapping, 796 HttpServletRequest request, ServletContext servletContext, 797 boolean isSpecialForward ) 798 { 799 if ( forward != null ) 800 { 801 if ( request.getAttribute( SAVED_PREVIOUS_PAGE_INFO_ATTR ) != null || isPreviousPageInfoDisabled() ) return; 806 807 String path = forward.getPath(); 808 int queryPos = path.indexOf( '?' ); 809 if ( queryPos != -1 ) path = path.substring( 0, queryPos ); 810 811 if ( form != null && _currentPageInfo != null ) 817 { 818 ActionForm oldForm = _currentPageInfo.getForm(); 819 if ( oldForm == null || oldForm.getClass().equals( form.getClass() ) ) 820 { 821 _currentPageInfo.setForm( form ); 822 _currentPageInfo.setMapping( mapping ); 823 } 824 } 825 826 if ( ! FileUtils.osSensitiveEndsWith( path, ACTION_EXTENSION ) ) 830 { 831 if ( isLocalFile( forward ) ) { 836 _previousPageInfo = _currentPageInfo; 837 _currentPageInfo = new PreviousPageInfo( forward, form, mapping, request.getQueryString() ); 838 request.setAttribute( SAVED_PREVIOUS_PAGE_INFO_ATTR, Boolean.TRUE ); 839 } 840 } 841 } 842 } 843 844 private boolean isLocalFile( ActionForward forward ) 845 { 846 String path = forward.getPath(); 847 848 if ( ! forward.getContextRelative() ) 849 { 850 return path.indexOf( '/', 1 ) == -1; } 852
|