1 18 19 package org.apache.beehive.netui.tools.testrecorder.server; 20 21 import javax.servlet.Filter ; 22 import javax.servlet.FilterChain ; 23 import javax.servlet.FilterConfig ; 24 import javax.servlet.ServletRequest ; 25 import javax.servlet.ServletResponse ; 26 import javax.servlet.ServletException ; 27 import javax.servlet.http.HttpServletRequest ; 28 import javax.servlet.http.HttpServletResponse ; 29 import javax.servlet.http.Cookie ; 30 31 import java.io.IOException ; 32 import java.io.Writer ; 33 import java.io.OutputStreamWriter ; 34 import java.text.MessageFormat ; 35 36 import org.apache.beehive.netui.tools.testrecorder.shared.Constants; 37 import org.apache.beehive.netui.tools.testrecorder.shared.Logger; 38 import org.apache.beehive.netui.tools.testrecorder.shared.xmlbeans.XMLHelper; 39 import org.apache.beehive.netui.tools.testrecorder.shared.config.TestDefinitions; 40 import org.apache.beehive.netui.tools.testrecorder.shared.config.WebappConfig; 41 import org.apache.beehive.netui.tools.testrecorder.server.state.State; 42 import org.apache.beehive.netui.tools.testrecorder.server.state.SessionFailedException; 43 import org.apache.beehive.netui.tools.testrecorder.server.state.PlaybackSession; 44 import org.apache.beehive.netui.tools.testrecorder.server.serverAdapter.ServerAdapter; 45 import org.apache.beehive.netui.tools.testrecorder.server.serverAdapter.ServerAdapterUtils; 46 47 48 public class TestRecorderFilter implements Filter { 49 50 private static final Logger log = Logger.getInstance( TestRecorderFilter.class ); 51 private static final String ADMIN_LINK = 52 "<div id=\"netuiTestRecorder\" style=\"background-color:yellow;color: blue;margin:5;padding:10;border: 1pt solid;\">\n" + 53 "<hr>\n" + 54 "<span style=\"font-weight:bold\">Test Recorder:</span> \n" + 55 "<a HREF=\"{0}\">\n" + 56 "<span style=\"color:{1};font-weight:bold;\">{2}</span> Recording</a>\n" + 57 "<a HREF=\"{3}\">Admin</a>\n" + 58 "</div>"; 59 68 private static final MessageFormat link = new MessageFormat ( ADMIN_LINK ); 69 private static TestRecorderFilter instance = null; 71 boolean initFlag = false; 72 private static String contextPath; 74 private static Object [] startLink; 76 private static Object [] stopLink; 77 78 private TestDefinitions testDefinitions; 79 private WebappConfig webapp; 80 private FilterConfig filterConfig = null; 81 private State state; 82 83 84 public TestRecorderFilter() { 85 } 86 87 public void doFilter( ServletRequest request, ServletResponse response, 88 FilterChain chain ) throws IOException , ServletException { 89 if ( initFlag == false ) { 90 filterInit( request ); 91 } 92 String reqURI = ( (HttpServletRequest ) request ).getRequestURI(); 93 if ( log.isDebugEnabled() ) { 94 log.debug( "\n\t\t**********************************************\n" ); 95 } 96 if ( !getState().isTestMode() || !shouldHandleRequest( reqURI ) || isControlRequest( reqURI ) ) { 97 if ( log.isDebugEnabled() ) { 99 log.debug( "ignoring request, reqURI( " + reqURI + " ), testMode( " + 100 getState().isTestMode() + " )" ); 101 } 102 chain.doFilter( request, response ); 103 return; 104 } 105 if ( log.isInfoEnabled() ) { 106 log.info( "reqURI( " + reqURI + " )" ); 107 } 108 if ( log.isDebugEnabled() ) { 109 log.debug( "state( " + getState() + " )" ); 110 } 113 ServerAdapter serverAdapter = ServerAdapterUtils.getServerAdapter(); 114 FilterData data = serverAdapter.genFilterDataInstance( request, response, state ); 115 try { 116 data.init(); 117 } 118 catch ( SessionFailedException e ) { 119 data.addSessionException( e ); 120 } 121 if ( data.isSkipFilter() == true ) { 122 if ( log.isDebugEnabled() ) { 124 log.debug( "skiping filter" ); 125 } 126 chain.doFilter( data.getRequest(), data.getResponse() ); 127 return; 128 } 129 try { 130 preFilter( data, chain ); 132 } 133 catch ( SessionFailedException e ) { 134 data.addSessionException( e ); 135 log.error( "Pre filter work failed", e ); 136 } 137 if ( log.isDebugEnabled() ) { 139 log.debug( "calling doFilter()" ); 140 } 141 try { 144 chain.doFilter( data.getRequest(), data.getNewResponse() ); 145 } 146 catch ( Exception ex ) { 147 data.addTestException( ex ); 148 if ( log.isDebugEnabled() ) { 149 log.debug( "caught filter chain exception( " + ex + " )", ex ); 150 } 151 } 152 finally { 153 postFilter( data ); 154 if ( log.isDebugEnabled() && data.isNewRequest() ) { 155 log.debug( "\nreturning, state( " + state + " )" ); 156 } 157 else if ( log.isDebugEnabled() ) { 158 log.debug( "data.isNewRequest()( " + data.isNewRequest() + " )" ); 159 } 160 } 161 return; 162 } 163 164 protected void postFilter( FilterData data ) throws IOException , ServletException { 165 if ( log.isDebugEnabled() ) { 166 log.debug( "postFilter START" ); 167 } 168 try { 169 if ( data.isPlayback() ) { 170 postFilterPlayback( data ); 171 } 172 else { 173 String body = null; 174 if ( data.isNewRequest() || data.isNewRecording() ) { 175 try { 177 if ( data.getTestExceptionCount() > 0 ) { 178 ( (HttpServletResponse ) data.getNewResponse() ).setStatus( 500 ); 179 } 180 data.setRespData( false ); 181 body = data.getRespData().getBody(); 182 } 183 catch ( Exception e ) { 184 data.addSessionException( e ); 185 body = "Failed getting output string from wrapper, exception( " + 186 e.getMessage() + " )"; 187 log.error( body, e ); 188 body = "<br/><br/><b>" + body + "</b><br/><br/></html>"; 189 } 190 } 191 if ( data.isNewRecording() ) { 192 if ( log.isDebugEnabled() ) { 194 log.debug( "filter data( " + data + " )" ); 195 } 196 postFilterRecord( data, body ); 197 } 198 else if ( data.isNewRequest() ) { 199 writeResponse( (ResponseWrapper) data.getNewResponse(), body, data, getState().isTestMode() ); 202 } 203 else { 204 if ( log.isDebugEnabled() ) { 206 log.debug( "forward or include, filter data( " + data + " )" ); 207 } 208 } 209 } 210 } 211 finally { 212 data.throwTestException(); 213 if ( log.isDebugEnabled() ) { 214 log.debug( "postFilter END" ); 215 } 216 } 217 } 218 219 protected void postFilterRecord( FilterData data, String body ) throws IOException , ServletException { 220 if ( log.isDebugEnabled() ) { 222 log.debug( "data.isNewRecording()( " + data.isNewRecording() + " )" ); 223 } 224 try { 226 writeResponse( (ResponseWrapper) data.getNewResponse(), body, data, true ); 227 } 228 finally { 229 int testNum = 0; 230 try { 231 if ( data.isTestException() ) { 232 if ( log.isDebugEnabled() ) { 233 log.debug( "skipping record end, isTestException(" + data.isTestException() + "), body( " + 234 body + " )"); 235 } 236 } 237 else { 238 String resp = data.getRespData().getBody(); 239 int pos = resp.indexOf("<![CDATA["); 241 if (pos != -1) { 242 resp = resp.replaceAll("\\Q<![CDATA[\\E","<![CDATA["); 243 resp = resp.replaceAll("\\Q]]>","]]>"); 244 data.getRespData().setBody(resp); 245 } 246 testNum = data.getRecordingSession().endTest( data.getReqData(), data.getRespData() ); 247 if ( log.isDebugEnabled() ) { 248 log.debug( "testNum( " + testNum + " )" ); 249 } 250 } 251 } 252 catch ( SessionFailedException e ) { 253 data.addSessionException( e ); 255 log.error( "Failed to end test(" + testNum + ") for session( " + 256 data.getRecordingSession().getSessionName() + " )" ); 257 } 258 data.clearRecording(); 259 } 260 } 261 262 protected void postFilterPlayback( FilterData data ) { 263 if ( log.isDebugEnabled() ) { 265 log.debug( "postFilterPlayback START" ); 266 } 267 if ( !data.isNewRequest() ) { 268 if ( log.isDebugEnabled() ) { 270 log.debug( "data.isNewRequest()( " + data.isNewRequest() + " )" ); 271 log.debug( "postFilterPlayback END" ); 272 } 273 return; 274 } 275 if ( log.isDebugEnabled() ) { 276 log.debug( "filter data( " + data + " )" ); 277 } 278 int testNum = -2; 280 try { 281 if ( data.getTestExceptionCount() > 0 ) { 282 ( (HttpServletResponse ) data.getNewResponse() ).setStatus( 500 ); 283 } 284 data.setRespData( true ); 285 if ( log.isDebugEnabled() ) { 286 log.debug( "response body( " + data.getRespData().getBody() + " )" ); 287 } 288 if ( data.isTestException() ) { 289 if ( log.isDebugEnabled() ) { 290 log.debug( "skipping playback end, isTestException(" + data.isTestException() + ")" ); 291 } 292 } 293 else { 294 testNum = data.getPlaybackSession().endTest( data ); 295 } 296 297 if ( log.isDebugEnabled() ) { 298 log.debug( "testNum( " + testNum + " )" ); 299 } 300 } 301 catch ( Exception ex ) { 303 data.addSessionException( ex ); 304 if ( log.isDebugEnabled() ) { 305 log.debug( "Failed ending playback, exception( " + ex.getMessage() + " )", ex ); 306 } 307 } 309 finally { 310 if ( testNum >= 0 ) { 311 setResponseOutcome( data.getResponse(), Constants.PASS ); 312 } 313 else { 314 log.error( "Failed ending test(" + testNum + ")" ); 315 setResponseOutcome( data.getResponse(), Constants.FAIL ); 316 } 317 writeResponse( (ResponseWrapper) data.getNewResponse(), data.getRespData().getBody(), data, false ); 319 } 320 if ( log.isDebugEnabled() ) { 321 log.debug( "postFilterPlayback END" ); 322 } 323 } 324 325 330 protected void preFilter( FilterData data, FilterChain chain ) throws SessionFailedException { 331 if ( log.isDebugEnabled() ) { 332 log.debug( "preFilter START" ); 333 } 334 if ( data.getTestId() != null ) { 335 if ( log.isDebugEnabled() ) { 337 log.debug( "filter data( " + data + " )" ); 338 } 339 if ( data.isNewRequest() ) { 340 PlaybackSession session = getState().getPlaybackSession( data.getTestId() ); 341 if ( session == null ) { 342 String msg = "ERROR: no playback session found for test id( " + data.getTestId() + " )"; 343 log.error( msg ); 344 throw new SessionFailedException( msg ); 345 } 346 data.setPlaybackSession( session ); 347 if ( data.isTestException() ) { 348 if ( log.isDebugEnabled() ) { 349 log.debug( "skipping playback start, isTestException(" + data.isTestException() + ")" ); 350 } 351 } 352 else { 353 boolean started = session.startTest(); 354 if ( !started ) { 356 throw new SessionFailedException( "Playback session failed to start, session( " + 357 session.getSessionName() + " )" ); 358 } 359 } 360 } 361 else { 362 } 364 if ( log.isDebugEnabled() ) { 365 log.debug( "filter data( " + data + " )" ); 366 } 367 } 368 else { 369 synchronized ( getState() ) { 373 if ( getState().isRecording() == true ) { 374 data.setRecordingSession( getState().getRecordingSession() ); 375 } 376 } 377 if ( data.isNewRecording() ) { 378 if ( log.isDebugEnabled() ) { 379 log.debug( "filter data.isNewRecording()( " + data.isNewRecording() + " )" ); 380 } 381 if ( data.isTestException() ) { 384 if ( log.isDebugEnabled() ) { 385 log.debug( "skipping record start, isTestException(" + data.isTestException() + ")" ); 386 } 387 } 388 else { 389 data.getRecordingSession().startTest(); 390 } 391 } 392 else { 393 if ( log.isDebugEnabled() ) { 394 log.debug( "forward, include or not recording filter data( " + data + " )" ); 395 } 396 } 397 } 398 if ( log.isDebugEnabled() ) { 399 log.debug( "preFilter END" ); 400 } 401 } 402 403 public void init( FilterConfig filterConfig ) throws ServletException { 404 this.filterConfig = filterConfig; 405 instance = this; 406 String webappName = filterConfig.getInitParameter( "webapp" ); 407 System.out.println( "initializing test recorder enabled webapp( " + webappName + " )" ); 408 if ( log.isInfoEnabled() ) { 409 log.info( "webapp name( " + webappName + " )" ); 410 } 411 testDefinitions = XMLHelper.getTestDefinitionsInstance( Thread.currentThread().getContextClassLoader() ); 412 webapp = testDefinitions.getWebapps().getWebapp( webappName ); 413 if ( webapp == null ) { 414 throw new ServletException ( 415 "ERROR: unable to find the webapp config for webapp name( " + webappName + " )" ); 416 } 417 if ( log.isInfoEnabled() ) { 418 log.debug( "webapp( " + webapp + " )" ); 419 } 420 state = new State(); 421 state.setTestMode( webapp.isTestMode() ); 422 } 423 424 public void destroy() { 425 if ( log.isInfoEnabled() ) { 426 log.info( "destroying test recorder filter for webapp( " + getWebapp().getName() + " )" ); 427 } 428 instance = null; 429 this.filterConfig = null; 430 } 431 432 public State getState() { 433 return state; 434 } 435 436 public static TestRecorderFilter instance() { 437 return instance; 438 } 439 440 protected FilterConfig getFilterConfig() { 441 return filterConfig; 442 } 443 444 public WebappConfig getWebapp() { 445 return webapp; 446 } 447 448 public TestDefinitions getTestDefinitions() { 449 return testDefinitions; 450 } 451 452 private void writeResponse( ResponseWrapper wrapper, String body, FilterData data, boolean addLink ) { 453 if ( log.isDebugEnabled() ) { 454 log.debug( "data.getReqURI()( " + data.getReqURI() + " )" ); 455 } 456 try { 457 ServletResponse response = wrapper.getResponse(); 458 Writer writer = getWriter( response ); 459 if ( addLink ) { 461 int index = body.lastIndexOf( Constants.BODY_END ); 462 if ( index == -1 ) { 463 index = body.lastIndexOf( Constants.BODY_END_CAPS ); 464 } 465 if ( index == -1 ) { 466 if ( log.isDebugEnabled() ) { 467 log.debug( "</body> was not found:\nbody(" + body + ")" ); 468 } 469 writer.write( body ); 471 } 472 else if ( data.isNewRequest() ) { 473 writer.write( body.substring( 0, index ) ); 474 Object [] objs = null; 476 if ( getState().isRecording() ) { 477 objs = stopLink; 478 } 479 else { 480 objs = startLink; 481 } 482 writer.write( Constants.NL + link.format( objs ) + Constants.NL ); 483 writer.write( body.substring( index ) ); 484 } 485 else { 486 writer.write( body ); 487 } 488 } 489 else { 490 writer.write( body ); 491 } 492 } 493 catch ( IOException e ) { 494 data.addTestException( e ); 495 if ( log.isWarnEnabled() ) { 496 log.warn( "Failed writing response, exception( " + e.getMessage() + " )" ); 497 } 498 } 499 } 500 501 private Writer getWriter( ServletResponse resp ) throws IOException { 502 Writer writer = null; 503 try { 504 writer = resp.getWriter(); 505 } 506 catch ( IllegalStateException e ) { 507 if ( log.isDebugEnabled() ) { 510 log.debug( "Creating a Writer for the response" ); 511 } 512 writer = new OutputStreamWriter ( resp.getOutputStream() ); 513 } 514 return writer; 515 } 516 517 private void filterInit( ServletRequest request ) { 518 contextPath = ( (HttpServletRequest ) request ).getContextPath(); 520 genStartStopLinks(); 521 initFlag = true; 522 } 523 524 protected static void genStartStopLinks() { 525 startLink = new Object [4]; 526 stopLink = new Object [4]; 527 528 startLink[0] = contextPath + "/testRecorder/startRecord.jsp?" + 529 Constants.FILTER_SKIP_PARAM + "=true"; 530 startLink[1] = Constants.GREEN; 531 startLink[2] = Constants.START; 532 startLink[3] = contextPath + "/testRecorder/index.jsp?" + 533 Constants.FILTER_SKIP_PARAM + "=true"; 534 535 stopLink[0] = contextPath + "/testRecorder?" + 536 Constants.MODE + "=" + Constants.RECORD + "&" + 537 Constants.CMD + "=" + Constants.STOP + "&" + 538 Constants.FILTER_SKIP_PARAM + "=true"; 539 stopLink[1] = Constants.RED; 540 stopLink[2] = Constants.STOP; 541 stopLink[3] = contextPath + "/testRecorder/index.jsp?" + 542 Constants.FILTER_SKIP_PARAM + "=true"; 543 } 544 545 private boolean shouldHandleRequest( String reqURI ) { 547 boolean rtnVal = false; 548 int slash = reqURI.lastIndexOf( "/" ); 550 int period = reqURI.lastIndexOf( "." ); 551 String suffix = null; 552 if ( slash > period ) { 553 suffix = Constants.EMPTY_STRING; 555 } 556 else { 557 suffix = reqURI.substring( period + 1 ); 558 } 559 rtnVal = getWebapp().handleSuffix( suffix ); 560 return rtnVal; 561 } 562 563 private boolean isControlRequest( String reqURI ) { 564 if ( reqURI.startsWith( getWebapp().getServletURI() ) ) { 565 return true; 566 } 567 return false; 568 } 569 570 static void setResponseOutcome( ServletResponse response, String value ) { 571 ( (HttpServletResponse ) response ).setHeader( Constants.OUTCOME_HEADER, value ); 572 } 573 574 protected static void reportCookies( Cookie [] cookies ) { 576 if ( cookies != null ) { 577 for ( int i = 0; i < cookies.length; i++ ) { 578 log.debug( "cookies[" + i + "]( " + cookies[i] + " )" ); 579 } 580 } 581 else { 582 log.debug( "cookies( " + cookies + " )" ); 583 } 584 } 585 586 } 587 | Popular Tags |