| 1 18 package org.apache.beehive.netui.pageflow.internal; 19 20 import org.apache.beehive.netui.util.internal.InternalStringBuilder; 21 22 import org.apache.beehive.netui.pageflow.*; 23 import org.apache.beehive.netui.pageflow.config.PageFlowActionMapping; 24 import org.apache.beehive.netui.pageflow.config.PageFlowControllerConfig; 25 import org.apache.beehive.netui.pageflow.config.PageFlowActionFormBean; 26 import org.apache.beehive.netui.pageflow.handler.Handlers; 27 import org.apache.beehive.netui.pageflow.handler.ReloadableClassHandler; 28 import org.apache.beehive.netui.pageflow.scoping.ScopedServletUtils; 29 import org.apache.beehive.netui.util.Bundle; 30 import org.apache.beehive.netui.util.internal.ServletUtils; 31 import org.apache.beehive.netui.util.config.ConfigUtil; 32 import org.apache.beehive.netui.util.config.bean.PageflowConfig; 33 import org.apache.beehive.netui.util.logging.Logger; 34 import org.apache.struts.Globals; 35 import org.apache.struts.util.MessageResources; 36 import org.apache.struts.action.*; 37 import org.apache.struts.config.ActionConfig; 38 import org.apache.struts.config.ControllerConfig; 39 import org.apache.struts.config.FormBeanConfig; 40 import org.apache.struts.config.ModuleConfig; 41 import org.apache.struts.config.MessageResourcesConfig; 42 import org.apache.struts.upload.MultipartRequestWrapper; 43 44 import javax.servlet.ServletContext ; 45 import javax.servlet.ServletException ; 46 import javax.servlet.ServletRequest ; 47 import javax.servlet.ServletResponse ; 48 import javax.servlet.jsp.JspContext ; 49 import javax.servlet.jsp.PageContext ; 50 import javax.servlet.http.HttpServletRequest ; 51 import javax.servlet.http.HttpServletResponse ; 52 import javax.servlet.http.HttpSession ; 53 import java.io.IOException ; 54 import java.lang.reflect.Method ; 55 import java.util.HashMap ; 56 import java.util.Iterator ; 57 import java.util.LinkedHashMap ; 58 import java.util.Map ; 59 import java.util.Locale ; 60 61 62 63 public class InternalUtils 64 implements PageFlowConstants, InternalConstants 65 { 66 private static final Logger _log = Logger.getInstance( InternalUtils.class ); 67 68 private static final String BEA_XMLOBJECT_CLASSNAME = "com.bea.xml.XmlObject"; 69 private static final String APACHE_XMLOBJECT_CLASSNAME = "org.apache.xmlbeans.XmlObject"; 70 private static final Class BEA_XMLOBJECT_CLASS = loadClassNonFatal( BEA_XMLOBJECT_CLASSNAME ); 71 private static final Class APACHE_XMLOBJECT_CLASS = loadClassNonFatal( APACHE_XMLOBJECT_CLASSNAME ); 72 private static final String LONGLIVED_PAGEFLOWS_ATTR_PREFIX = ATTR_PREFIX + "longLivedPageFlow:"; 73 private static final String ACTIONOUTPUT_MAP_ATTR = ATTR_PREFIX + "actionOutputs"; 74 private static final String BINDING_UPDATE_ERRORS_ATTR = ATTR_PREFIX + "bindingUpdateErrors"; 75 private static final String SHARED_FLOW_CLASSNAME_ATTR = ATTR_PREFIX + "sharedFlowClass"; 76 private static final String SERVLET_CONTEXT_ATTR = ATTR_PREFIX + "servletContext"; 77 private static final String AVOID_DIRECT_RESPONSE_OUTPUT_ATTR = ATTR_PREFIX + "_avoidDirectResponseOutput"; 78 private static final String FORWARDED_FORMBEAN_ATTR = ATTR_PREFIX + "forwardedForm"; 79 private static final String FORWARDING_MODULE_ATTR = ATTR_PREFIX + "forwardingModule"; 80 private static final String IGNORE_INCLUDE_SERVLET_PATH_ATTR = ATTR_PREFIX + "ignoreIncludeServletPath"; 81 82 83 86 public static void sendDevTimeError( String messageKey, Throwable cause, int productionTimeErrorCode, 87 ServletRequest request, ServletResponse response, 88 ServletContext servletContext, Object [] messageArgs ) 89 throws IOException  90 { 91 sendDevTimeError( messageKey, messageArgs, cause, productionTimeErrorCode, request, response, servletContext ); 92 } 93 94 98 public static void sendDevTimeError( String messageKey, Object [] messageArgs, Throwable cause, 99 int productionTimeErrorCode, ServletRequest request, 100 ServletResponse response, ServletContext servletContext ) 101 throws IOException  102 { 103 boolean prodMode = AdapterManager.getServletContainerAdapter( servletContext ).isInProductionMode(); 104 boolean avoidDirectResponseOutput = avoidDirectResponseOutput( request ); 105 106 if ( prodMode && ! avoidDirectResponseOutput && response instanceof HttpServletResponse ) 107 { 108 if ( _log.isErrorEnabled() ) 109 { 110 _log.error( "Error (message key " + messageKey + ") occurred. Response error was set to " 111 + productionTimeErrorCode, cause ); 112 } 113 114 ( ( HttpServletResponse ) response ).sendError( productionTimeErrorCode ); 115 } 116 else 117 { 118 sendError( messageKey, messageArgs, request, response, cause, prodMode || avoidDirectResponseOutput ); 119 } 120 } 121 122 125 public static void sendError( String messageKey, Throwable cause, ServletRequest request, 126 HttpServletResponse response, Object [] messageArgs ) 127 throws IOException  128 { 129 boolean avoidDirectResponseOutput = request != null ? avoidDirectResponseOutput( request ) : false; 132 sendError( messageKey, messageArgs, request, response, cause, avoidDirectResponseOutput ); 133 } 134 135 138 public static void sendError( String messageKey, Object [] messageArgs, ServletRequest request, 139 ServletResponse response, Throwable cause, boolean avoidDirectResponseOutput ) 140 throws IOException  141 { 142 assert messageArgs.length == 0 || ! ( messageArgs[0] instanceof Object [] ) 143 : "Object[] passed to sendError; this is probably a mistaken use of varargs"; 144 145 if ( request != null && avoidDirectResponseOutput ) 147 { 148 String baseMessage = Bundle.getString( messageKey + "_Message", messageArgs ); 149 throw new ResponseOutputException( baseMessage, cause ); 150 } 151 152 String html = Bundle.getString( messageKey + "_Page", messageArgs ); 153 response.setContentType( "text/html;charset=UTF-8" ); 154 response.getWriter().println( html ); 155 ServletUtils.preventCache( response ); 156 } 157 158 161 public static Object unwrapFormBean( ActionForm form ) 163 { 164 if ( form == null ) return null; 165 166 if ( form instanceof AnyBeanActionForm ) 167 { 168 return ( ( AnyBeanActionForm ) form ).getBean(); 169 } 170 171 return form; 172 } 173 174 public static ActionForm wrapFormBean( Object formBean ) 175 { 176 if ( formBean == null ) return null; 177 178 if ( formBean instanceof FormData ) 183 { 184 return ( ActionForm ) formBean; 185 } 186 else 187 { 188 Class formClass = formBean.getClass(); 189 190 if ( BEA_XMLOBJECT_CLASS != null && BEA_XMLOBJECT_CLASS.isAssignableFrom( formClass ) ) 191 { 192 return new XmlBeanActionForm( formBean ); 193 } 194 else if ( APACHE_XMLOBJECT_CLASS != null && APACHE_XMLOBJECT_CLASS.isAssignableFrom( formClass ) ) 195 { 196 return new XmlBeanActionForm( formBean ); 197 } 198 199 return new AnyBeanActionForm( formBean ); 200 } 201 } 202 203 private static Class loadClassNonFatal( String className ) 204 { 205 try 206 { 207 return Class.forName( className ); 208 } 209 catch ( ClassNotFoundException e ) 210 { 211 213 if ( _log.isDebugEnabled() ) 214 { 215 _log.debug( "Could not load class " + className ); 216 } 217 } 218 219 return null; 220 } 221 222 230 public static Method lookupMethod( Class parentClass, String methodName, Class [] signature ) 231 { 232 try 233 { 234 return parentClass.getDeclaredMethod( methodName, signature ); 235 } 236 catch ( NoSuchMethodException e ) 237 { 238 Class superClass = parentClass.getSuperclass(); 239 return superClass != null ? lookupMethod( superClass, methodName, signature ) : null; 240 } 241 } 242 243 public static String getFlowControllerClassName( String modulePath, ServletRequest request, ServletContext context ) 244 { 245 ModuleConfig mc = ensureModuleConfig( modulePath, request, context ); 249 return mc != null ? getFlowControllerClassName( mc ) : null; 250 } 251 252 public static String getFlowControllerClassName( ModuleConfig mc ) 253 { 254 ControllerConfig cc = mc.getControllerConfig(); 255 return cc instanceof PageFlowControllerConfig ? ( ( PageFlowControllerConfig ) cc ).getControllerClass() : null; 256 } 257 258 261 public static boolean isLongLived( ModuleConfig moduleConfig ) 262 { 263 ControllerConfig cc = moduleConfig.getControllerConfig(); 264 265 if ( cc instanceof PageFlowControllerConfig ) 266 { 267 return ( ( PageFlowControllerConfig ) cc ).isLongLivedPageFlow(); 268 } 269 else 270 { 271 return false; 272 } 273 } 274 275 278 public static boolean isNestable( ModuleConfig moduleConfig ) 279 { 280 ControllerConfig cc = moduleConfig.getControllerConfig(); 281 return cc instanceof PageFlowControllerConfig && ( ( PageFlowControllerConfig ) cc ).isNestedPageFlow(); 282 } 283 284 public static String getLongLivedFlowAttr( String modulePath ) 285 { 286 return LONGLIVED_PAGEFLOWS_ATTR_PREFIX + modulePath; 287 } 288 289 public static void setCurrentPageFlow( PageFlowController jpf, HttpServletRequest request ) 290 { 291 setCurrentActionResolver( jpf, request ); 292 } 293 294 public static void removeCurrentPageFlow( HttpServletRequest request ) 295 { 296 HttpServletRequest unwrappedRequest = PageFlowUtils.unwrapMultipart( request ); 297 ScopedServletUtils.removeScopedSessionAttr( CURRENT_JPF_ATTR, unwrappedRequest ); 298 ScopedServletUtils.removeScopedSessionAttr( CURRENT_LONGLIVED_ATTR, unwrappedRequest ); 299 } 300 301 public static String getDecodedURI( HttpServletRequest request ) 302 { 303 return request.getContextPath() + getDecodedServletPath( request ); 304 } 305 306 public static String getDecodedServletPath( HttpServletRequest request ) 307 { 308 if ( ignoreIncludeServletPath( request ) ) return request.getServletPath(); 309 310 String servletIncludePath = ( String ) request.getAttribute( RequestProcessor.INCLUDE_SERVLET_PATH ); 311 return servletIncludePath != null ? servletIncludePath : request.getServletPath(); 312 } 313 314 public static void addActionOutputs( Map toAdd, ServletRequest request, boolean overwrite ) 315 { 316 if ( toAdd != null ) 317 { 318 Map map = getActionOutputMap( request, true ); 319 320 for ( Iterator i = toAdd.entrySet().iterator(); i.hasNext(); ) 321 { 322 Map.Entry entry = ( Map.Entry ) i.next(); 323 String name = ( String ) entry.getKey(); 324 boolean alreadyExists = map.containsKey( name ); 325 326 if ( overwrite || ! alreadyExists ) 327 { 328 if ( alreadyExists ) 329 { 330 if ( _log.isWarnEnabled() ) 331 { 332 _log.warn( "Overwriting action output \"" + name + "\"." ); 333 } 334 } 335 336 map.put( name, entry.getValue() ); 337 } 338 } 339 } 340 } 341 342 public static void addActionError( String propertyName, ActionMessage error, ServletRequest request ) 343 { 344 ActionErrors errors = ( ActionErrors ) request.getAttribute( Globals.ERROR_KEY ); 345 if ( errors == null ) request.setAttribute( Globals.ERROR_KEY, errors = new ActionErrors() ); 346 errors.add( propertyName, error ); 347 } 348 349 public static Object newReloadableInstance( String className, ServletContext servletContext ) 350 throws ClassNotFoundException , InstantiationException , IllegalAccessException  351 { 352 return getReloadableClass( className, servletContext ).newInstance(); 353 } 354 355 public static Class getReloadableClass( String className, ServletContext servletContext ) 356 throws ClassNotFoundException  357 { 358 ReloadableClassHandler handler = Handlers.get( servletContext ).getReloadableClassHandler(); 359 return handler.loadClass( className ); 360 } 361 362 public static Map getActionOutputMap( ServletRequest request, boolean createIfNotExist ) 363 { 364 Map map = ( Map ) request.getAttribute( ACTIONOUTPUT_MAP_ATTR ); 365 366 if ( map == null && createIfNotExist ) 367 { 368 map = new HashMap (); 369 request.setAttribute( ACTIONOUTPUT_MAP_ATTR, map ); 370 } 371 372 return map; 373 } 374 375 public static Map getPageInputMap( ServletRequest request ) 376 { 377 Map actionOutputsFromPageFlow = getActionOutputMap( request, false ); 378 if ( actionOutputsFromPageFlow != null ) return actionOutputsFromPageFlow; 379 FacesBackingBean fbb = getFacesBackingBean( request ); 380 return fbb != null ? fbb.getPageInputMap() : null; 381 } 382 383 386 public static ModuleConfig getModuleConfig( String modulePath, ServletContext context ) 387 { 388 return ( ModuleConfig ) context.getAttribute( Globals.MODULE_KEY + modulePath ); 389 } 390 391 395 public static ModuleConfig ensureModuleConfig( String modulePath, ServletRequest request, ServletContext context ) 396 { 397 try 398 { 399 ModuleConfig ret = getModuleConfig( modulePath, context ); 400 401 if ( ret != null ) 402 { 403 return ret; 404 } 405 else 406 { 407 ActionServlet as = getActionServlet( context ); 408 409 if ( as instanceof AutoRegisterActionServlet ) 410 { 411 return ( ( AutoRegisterActionServlet ) as ).ensureModuleRegistered( modulePath, request ); 412 } 413 } 414 } 415 catch ( IOException e ) 416 { 417 _log.error( "Error while registering Struts module " + modulePath, e ); 418 } 419 catch ( ServletException e ) 420 { 421 _log.error( "Error while registering Struts module " + modulePath, e ); 422 } 423 424 return null; 425 } 426 427 433 public static ActionServlet getActionServlet( ServletContext context ) 434 { 435 if ( context == null ) return null; 436 return ( ActionServlet ) context.getAttribute( Globals.ACTION_SERVLET_KEY ); 437 } 438 439 447 public static void addBindingUpdateError( ServletRequest request, String expression, String message, Throwable cause ) 448 { 449 Map errors = ( Map ) request.getAttribute( BINDING_UPDATE_ERRORS_ATTR ); 450 451 if ( errors == null ) 452 { 453 errors = new LinkedHashMap (); 454 request.setAttribute( BINDING_UPDATE_ERRORS_ATTR, errors ); 455 } 456 457 errors.put( expression, new BindingUpdateError( expression, message, cause ) ); 458 } 459 460 465 public static Map getBindingUpdateErrors( ServletRequest request ) 466 { 467 return ( Map ) request.getAttribute( BINDING_UPDATE_ERRORS_ATTR ); 468 } 469 470 public static void setCurrentModule( ModuleConfig mc, ServletRequest request ) 471 { 472 request.setAttribute( Globals.MODULE_KEY, mc ); 473 } 474 475 public static ActionForm createActionForm( ActionMapping mapping, ModuleConfig moduleConfig, 476 ActionServlet actionServlet, ServletContext servletContext ) 477 { 478 String formName = mapping.getName(); 479 if ( formName == null ) return null; 480 FormBeanConfig config = moduleConfig.findFormBeanConfig( formName ); 481 if ( config == null ) return null; 482 483 try 484 { 485 ActionForm bean; 486 487 if ( config.getDynamic() ) 488 { 489 if ( _log.isDebugEnabled() ) 490 { 491 _log.debug( "Creating new DynaActionForm instance of type " + config.getType() ); 492 } 493 494 DynaActionFormClass dynaClass = DynaActionFormClass.createDynaActionFormClass( config ); 495 bean = ( ActionForm ) dynaClass.newInstance(); 496 ( ( DynaActionForm ) bean ).initialize( mapping ); 497 } 498 else 499 { 500 if ( _log.isDebugEnabled() ) 501 { 502 _log.debug( "Creating new ActionForm instance of type " + config.getType() ); 503 } 504 505 bean = ( ActionForm ) newReloadableInstance( config.getType(), servletContext ); 506 } 507 508 bean.setServlet( actionServlet ); 509 return bean; 510 } 511 catch ( Exception e ) 512 { 513 if ( _log.isErrorEnabled() ) 514 { 515 _log.error( "Error creating action form of type " + config.getType(), e ); 516 } 517 518 return null; 519 } 520 } 521 522 526 public static void setFormInScope( String formName, ActionForm form, ActionMapping mapping, 527 HttpServletRequest request, boolean overwrite ) 528 { 529 if ( formName != null && form != null ) 530 { 531 if ( isSessionScope( mapping ) ) 532 { 533 HttpSession session = request.getSession(); 534 535 if ( overwrite || session.getAttribute( formName ) == null ) 536 { 537 session.setAttribute( formName, form ); 538 } 539 } 540 else 541 { 542 if ( overwrite || request.getAttribute( formName ) == null ) 543 { 544 request.setAttribute( formName, form ); 545 } 546 } 547 } 548 } 549 550 public static boolean isSessionScope( ActionMapping mapping ) 551 { 552 return ( mapping.getScope() == null || mapping.getScope().equals( "session" ) ); 553 } 554 555 public static ActionForm getFormBean( ActionMapping mapping, ServletRequest request ) 556 { 557 String formBeanName = mapping.getAttribute(); 558 559 if ( formBeanName != null ) 560 { 561 if ( isSessionScope( mapping ) ) 562 { 563 HttpSession session = getHttpSession( request, false ); 564 return session != null ? ( ActionForm ) session.getAttribute( formBeanName ) : null; 565 } 566 else 567 { 568 return ( ActionForm ) request.getAttribute( formBeanName ); 569 } 570 } 571 572 return null; 573 } 574 575 581 public static void setCurrentActionResolver( ActionResolver resolver, HttpServletRequest request ) 582 { 583 HttpServletRequest unwrappedRequest = PageFlowUtils.unwrapMultipart( request ); 584 585 if ( resolver == null ) 586 { 587 ScopedServletUtils.removeScopedSessionAttr( CURRENT_JPF_ATTR, unwrappedRequest ); 588 ScopedServletUtils.removeScopedSessionAttr( CURRENT_LONGLIVED_ATTR, unwrappedRequest ); 589 return; 590 } 591 592 if ( resolver.isPageFlow() && isLongLived( ( ( PageFlowController ) resolver ).getModuleConfig() ) ) 596 { 597 String longLivedAttrName = getLongLivedFlowAttr( resolver.getModulePath() ); 598 599 if ( ScopedServletUtils.getScopedSessionAttr( longLivedAttrName, request ) != resolver ) 602 { 603 ScopedServletUtils.setScopedSessionAttr( longLivedAttrName, resolver, unwrappedRequest ); 604 } 605 ScopedServletUtils.setScopedSessionAttr( CURRENT_LONGLIVED_ATTR, resolver.getModulePath(), unwrappedRequest ); 606 ScopedServletUtils.removeScopedSessionAttr( CURRENT_JPF_ATTR, unwrappedRequest ); 607 } 608 else 609 { 610 ScopedServletUtils.setScopedSessionAttr( CURRENT_JPF_ATTR, resolver, unwrappedRequest ); 611 ScopedServletUtils.removeScopedSessionAttr( CURRENT_LONGLIVED_ATTR, unwrappedRequest ); 612 } 613 } 614 615 public static String getSharedFlowClassName( HttpServletRequest request, ServletContext servletContext ) 616 { 617 return getSharedFlowClassNameForRelativeURI( getDecodedServletPath( request ), request, servletContext ); 618 } 619 620 public static String getSharedFlowClassNameForRelativeURI( String relativeURI, ServletRequest request, 621 ServletContext servletContext ) 622 { 623 String cachedInRequest = ( String ) request.getAttribute( SHARED_FLOW_CLASSNAME_ATTR ); 624 if ( cachedInRequest != null ) return cachedInRequest.length() > 0 ? cachedInRequest : null; 625 626 String parentDir = PageFlowUtils.getModulePathForRelativeURI( relativeURI ); 627 String className = null; 628 629 if ( parentDir.length() > 0 ) 630 { 631 assert parentDir.charAt( 0 ) == '/' : parentDir; 632 parentDir = SHARED_FLOW_MODULE_PREFIX + parentDir.substring( 1 ); 633 634 do 635 { 636 className = getFlowControllerClassName( parentDir, request, servletContext ); 637 if ( className!= null ) break; 638 int lastSlash = parentDir.lastIndexOf( '/' ); 639 parentDir = parentDir.substring( 0, lastSlash ); 640 } while ( parentDir.length() > 0 ); 641 } 642 643 if ( className == null ) 644 { 645 className = getFlowControllerClassName( SHARED_FLOW_ROOT_MODULE, request, servletContext ); 646 } 647 648 if ( className == null ) 649 { 650 className = getFlowControllerClassName( GLOBALAPP_MODULE_CONTEXT_PATH, request, servletContext ); 651 } 652 653 request.setAttribute( SHARED_FLOW_CLASSNAME_ATTR, className != null ? className : "" ); 654 return className; 655 } 656 657 public static boolean isSharedFlowModule( ModuleConfig mc ) 658 { 659 ControllerConfig cc = mc.getControllerConfig(); 660 return cc instanceof PageFlowControllerConfig && ( ( PageFlowControllerConfig ) cc ).isSharedFlow(); 661 } 662 663 664 public static FacesBackingBean getFacesBackingBean( ServletRequest request ) 665 { 666 if ( request instanceof HttpServletRequest ) 667 { 668 HttpServletRequest unwrappedRequest = PageFlowUtils.unwrapMultipart( ( HttpServletRequest  |