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 else 853 { 854 String modulePath = getModulePath(); 855 856 if ( ! path.startsWith( modulePath ) ) 857 { 858 return false; 859 } 860 else 861 { 862 return path.indexOf( '/', modulePath.length() + 1 ) == -1; 863 } 864 } 865 } 866 867 private boolean isOnNestingStack() 868 { 869 return _isOnNestingStack; 870 } 871 872 876 public void valueUnbound( HttpSessionBindingEvent event ) 877 { 878 if ( ! _isOnNestingStack ) 882 { 883 destroy( event.getSession() ); 884 } 885 } 886 887 void setIsOnNestingStack( boolean isOnNestingStack ) 888 { 889 _isOnNestingStack = isOnNestingStack; 890 } 891 892 ActionForward forwardTo( ActionForward fwd, ActionMapping mapping, HttpServletRequest request, 893 HttpServletResponse response, String actionName, ModuleConfig altModuleConfig, 894 ActionForm form, ServletContext servletContext ) 895 { 896 ActionForward superFwd = super.forwardTo( fwd, mapping, request, response, actionName, 897 altModuleConfig, form, servletContext ); 898 899 if ( superFwd != null && InternalUtils.isNestable( getModuleConfig() ) ) 906 { 907 boolean selfNesting = false; 908 909 if ( superFwd.getContextRelative() ) 910 { 911 if ( superFwd.getPath().equals( getURI() ) ) 912 { 913 selfNesting = true; 914 } 915 } 916 else 917 { 918 if ( superFwd.getPath().equals( getStrutsLocalURI() ) ) 919 { 920 selfNesting = true; 921 } 922 } 923 924 if ( selfNesting ) 925 { 926 if ( _log.isDebugEnabled() ) 927 { 928 _log.debug( "Self-nesting page flow " + getURI() ); 929 } 930 931 try 932 { 933 RequestContext rc = new RequestContext( request, response ); 935 FlowControllerFactory.get( getServletContext() ).createPageFlow( rc, getClass() ); 936 } 937 catch ( IllegalAccessException e ) 938 { 939 assert false : e; 941 _log.error( e ); 942 } 943 catch ( InstantiationException e ) 944 { 945 _log.error( "Could not create PageFlowController instance of type " + getClass().getName(), e ); 946 } 947 } 948 } 949 950 return superFwd; 951 } 952 953 private String getStrutsLocalURI() 954 { 955 String className = getClass().getName(); 956 int lastDot = className.lastIndexOf( '.' ); 957 InternalStringBuilder ret = new InternalStringBuilder( "/" ); 958 return ret.append( className.substring( lastDot + 1 ) ).append( JPF_EXTENSION ).toString(); 959 } 960 961 private CachedPageFlowInfo getCachedInfo() 962 { 963 ClassLevelCache cache = ClassLevelCache.getCache( getClass() ); 964 CachedPageFlowInfo info = ( CachedPageFlowInfo ) cache.getCacheObject( CACHED_INFO_KEY ); 965 966 if ( info == null ) 967 { 968 info = new CachedPageFlowInfo( getClass(), getServletContext() ); 969 cache.setCacheObject( CACHED_INFO_KEY, info ); 970 } 971 972 return info; 973 } 974 975 final void beforePage() 976 { 977 if ( ! isPreviousPageInfoDisabled() ) 982 { 983 HttpServletRequest request = getRequest(); 984 String relativeUri = InternalUtils.getDecodedServletPath( request ); 985 986 String path = getCurrentForwardPath(); 987 if ( path == null || ! path.equals( relativeUri ) ) 988 { 989 ActionForward actionForward = new ActionForward( relativeUri ); 990 actionForward.setContextRelative( true ); 991 actionForward.setRedirect( false ); 992 savePreviousPageInfo( actionForward, null, null, request, getServletContext(), false ); 993 } 994 } 995 } 996 997 1000 public ActionForward exitNesting( HttpServletRequest request, HttpServletResponse response, ActionMapping mapping, 1001 ActionForm form ) 1002 { 1003 if ( _returnActionViewRenderer != null ) 1004 { 1005 PageFlowRequestWrapper.get( request ).setViewRenderer( _returnActionViewRenderer ); 1006 } 1007 1008 PerRequestState prevState = setPerRequestState( new PerRequestState( request, response, mapping ) ); 1009 1010 try 1011 { 1012 onExitNesting(); 1013 } 1014 catch ( Throwable th ) 1015 { 1016 try 1017 { 1018 return handleException( th, mapping, form, request, response ); 1019 } 1020 catch ( Exception e ) 1021 { 1022 _log.error( "Exception thrown while handling exception.", e ); 1023 } 1024 } 1025 finally 1026 { 1027 setPerRequestState( prevState ); 1028 } 1029 1030 return null; 1031 } 1032 1033 1038 protected void onExitNesting() 1039 throws Exception 1040 { 1041 } 1042} 1043 | Popular Tags |