Package com.eviware.soapui.monitor

Source Code of com.eviware.soapui.monitor.JettyMockEngine$CapturingServletOutputStream

/*
*  soapUI, copyright (C) 2004-2011 eviware.com
*
*  soapUI is free software; you can redistribute it and/or modify it under the
*  terms of version 2.1 of the GNU Lesser General Public License as published by
*  the Free Software Foundation.
*
*  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
*  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*  See the GNU Lesser General Public License for more details at gnu.org.
*/

package com.eviware.soapui.monitor;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringReader;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.mortbay.component.AbstractLifeCycle;
import org.mortbay.io.Connection;
import org.mortbay.io.EndPoint;
import org.mortbay.io.nio.SelectChannelEndPoint;
import org.mortbay.jetty.Connector;
import org.mortbay.jetty.HttpConnection;
import org.mortbay.jetty.Request;
import org.mortbay.jetty.RequestLog;
import org.mortbay.jetty.Response;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.handler.AbstractHandler;
import org.mortbay.jetty.handler.RequestLogHandler;
import org.mortbay.jetty.nio.SelectChannelConnector;
import org.mortbay.jetty.security.SslSocketConnector;

import com.eviware.soapui.SoapUI;
import com.eviware.soapui.impl.wsdl.mock.DispatchException;
import com.eviware.soapui.impl.wsdl.mock.WsdlMockService;
import com.eviware.soapui.impl.wsdl.support.soap.SoapMessageBuilder;
import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
import com.eviware.soapui.model.mock.MockResult;
import com.eviware.soapui.model.mock.MockRunner;
import com.eviware.soapui.model.mock.MockService;
import com.eviware.soapui.settings.HttpSettings;
import com.eviware.soapui.settings.SSLSettings;
import com.eviware.soapui.support.StringUtils;
import com.eviware.soapui.support.Tools;
import com.eviware.soapui.support.UISupport;
import com.eviware.soapui.support.log.JettyLogger;

/**
* Core Mock-Engine hosting a Jetty web server
*
* @author ole.matzura
*/

public class JettyMockEngine implements MockEngine
{
  public final static Logger log = Logger.getLogger( JettyMockEngine.class );

  private Server server;
  private Map<Integer, Map<String, List<MockRunner>>> runners = new HashMap<Integer, Map<String, List<MockRunner>>>();
  private Map<Integer, SoapUIConnector> connectors = new HashMap<Integer, SoapUIConnector>();
  private List<MockRunner> mockRunners = new ArrayList<MockRunner>();

  private SslSocketConnector sslConnector;

  private boolean addedSslConnector;

  public JettyMockEngine()
  {
    System.setProperty( "org.mortbay.log.class", JettyLogger.class.getName() );
  }

  public boolean hasRunningMock( MockService mockService )
  {
    for( MockRunner runner : mockRunners )
      if( runner.getMockService() == mockService )
        return true;

    return false;
  }

  public synchronized void startMockService( MockRunner runner ) throws Exception
  {
    if( server == null )
      initServer();

    synchronized( server )
    {
      WsdlMockService mockService = ( WsdlMockService )runner.getMockService();
      int port = mockService.getPort();

      if( SoapUI.getSettings().getBoolean( SSLSettings.ENABLE_MOCK_SSL ) && !addedSslConnector )
      {
        updateSslConnectorSettings();
        server.addConnector( sslConnector );
        addedSslConnector = true;
      }
      else
      {
        if( addedSslConnector )
          server.removeConnector( sslConnector );

        addedSslConnector = false;
      }

      if( !runners.containsKey( port ) )
      {
        SoapUIConnector connector = new SoapUIConnector();
        PropertySupport.applySystemProperties( connector, "soapui.mock.connector", runner.getMockService() );

        connector.setPort( port );
        if( sslConnector != null )
        {
          connector.setConfidentialPort( sslConnector.getPort() );
        }

        if( mockService.getBindToHostOnly() )
        {
          String host = mockService.getHost();
          if( StringUtils.hasContent( host ) )
          {
            connector.setHost( host );
          }
        }

        boolean wasRunning = server.isRunning();

        if( wasRunning )
        {
          server.stop();
        }

        server.addConnector( connector );
        try
        {
          server.start();
        }
        catch( RuntimeException e )
        {
          UISupport.showErrorMessage( e );

          server.removeConnector( connector );
          if( wasRunning )
          {
            server.start();
            return;
          }
        }

        connectors.put( new Integer( port ), connector );
        runners.put( new Integer( port ), new HashMap<String, List<MockRunner>>() );
      }

      Map<String, List<MockRunner>> map = runners.get( port );
      String path = mockService.getPath();
      if( !map.containsKey( path ) )
      {
        map.put( path, new ArrayList<MockRunner>() );
      }
      map.get( path ).add( runner );
      mockRunners.add( runner );

      log.info( "Started mockService [" + mockService.getName() + "] on port [" + port + "] at path [" + path + "]" );
    }
  }

  private void initServer() throws Exception
  {
    server = new Server();
    server.setThreadPool( new SoapUIJettyThreadPool() );
    server.setHandler( new ServerHandler() );

    RequestLogHandler logHandler = new RequestLogHandler();
    logHandler.setRequestLog( new MockRequestLog() );
    server.addHandler( logHandler );

    sslConnector = new SslSocketConnector();
    sslConnector.setMaxIdleTime( 30000 );
  }

  private void updateSslConnectorSettings()
  {
    sslConnector.setKeystore( SoapUI.getSettings().getString( SSLSettings.MOCK_KEYSTORE, null ) );
    sslConnector.setPassword( SoapUI.getSettings().getString( SSLSettings.MOCK_PASSWORD, null ) );
    sslConnector.setKeyPassword( SoapUI.getSettings().getString( SSLSettings.MOCK_KEYSTORE_PASSWORD, null ) );
    String truststore = SoapUI.getSettings().getString( SSLSettings.MOCK_TRUSTSTORE, null );
    if( StringUtils.hasContent( truststore ) )
    {
      sslConnector.setTruststore( truststore );
      sslConnector.setTrustPassword( SoapUI.getSettings().getString( SSLSettings.MOCK_TRUSTSTORE_PASSWORD, null ) );
    }

    sslConnector.setPort( ( int )SoapUI.getSettings().getLong( SSLSettings.MOCK_PORT, 443 ) );
    sslConnector.setNeedClientAuth( SoapUI.getSettings().getBoolean( SSLSettings.CLIENT_AUTHENTICATION ) );
  }

  public void stopMockService( MockRunner runner )
  {
    synchronized( server )
    {
      MockService mockService = runner.getMockService();
      final Integer port = new Integer( mockService.getPort() );
      Map<String, List<MockRunner>> map = runners.get( port );

      if( map == null || !map.containsKey( mockService.getPath() ) )
        return;

      map.get( mockService.getPath() ).remove( runner );
      if( map.get( mockService.getPath() ).isEmpty() )
      {
        map.remove( mockService.getPath() );
      }

      mockRunners.remove( runner );

      log.info( "Stopped MockService [" + mockService.getName() + "] on port [" + port + "]" );

      if( map.isEmpty() && !SoapUI.getSettings().getBoolean( HttpSettings.LEAVE_MOCKENGINE ) )
      {
        SoapUIConnector connector = connectors.get( port );
        if( connector == null )
        {
          log.warn( "Missing connectors on port [" + port + "]" );
          return;
        }

        try
        {
          log.info( "Stopping connector on port " + port );
          if( !connector.waitUntilIdle( 5000 ) )
          {
            log.warn( "Failed to wait for idle.. stopping connector anyway.." );
          }
          connector.stop();
        }
        catch( Exception e )
        {
          SoapUI.logError( e );
        }
        server.removeConnector( connector );
        runners.remove( port );
        if( runners.isEmpty() )
        {
          try
          {
            log.info( "No more connectors.. stopping server" );
            server.stop();
            if( sslConnector != null )
            {
              // server.removeConnector( sslConnector );
              // sslConnector.stop();
              // sslConnector = null;
            }
          }
          catch( Exception e )
          {
            SoapUI.logError( e );
          }
        }
      }
    }
  }

  private class SoapUIConnector extends SelectChannelConnector
  {
    private Set<HttpConnection> connections = new HashSet<HttpConnection>();

    @Override
    protected void connectionClosed( HttpConnection arg0 )
    {
      super.connectionClosed( arg0 );
      connections.remove( arg0 );
    }

    @Override
    protected void connectionOpened( HttpConnection arg0 )
    {
      super.connectionOpened( arg0 );
      connections.add( arg0 );
    }

    @Override
    protected Connection newConnection( SocketChannel socketChannel, SelectChannelEndPoint selectChannelEndPoint )
    {
      return new SoapUIHttpConnection( SoapUIConnector.this, selectChannelEndPoint, getServer() );
    }

    public boolean waitUntilIdle( long maxwait ) throws Exception
    {
      while( maxwait > 0 && hasActiveConnections() )
      {
        System.out.println( "Waiting for active connections to finish.." );
        Thread.sleep( 500 );
        maxwait -= 500;
      }

      return !hasActiveConnections();
    }

    private boolean hasActiveConnections()
    {
      for( HttpConnection connection : connections )
      {
        if( !connection.isIdle() )
          return true;
      }

      return false;
    }
  }

  private class SoapUIHttpConnection extends HttpConnection
  {
    private CapturingServletInputStream capturingServletInputStream;
    private BufferedServletInputStream bufferedServletInputStream;
    private CapturingServletOutputStream capturingServletOutputStream;

    public SoapUIHttpConnection( Connector connector, EndPoint endPoint, Server server )
    {
      super( connector, endPoint, server );
    }

    @Override
    public ServletInputStream getInputStream()
    {
      if( SoapUI.getSettings().getBoolean( HttpSettings.ENABLE_MOCK_WIRE_LOG ) )
      {
        if( capturingServletInputStream == null )
        {
          capturingServletInputStream = new CapturingServletInputStream( super.getInputStream() );
          bufferedServletInputStream = new BufferedServletInputStream( capturingServletInputStream );
        }
      }
      else
      {
        bufferedServletInputStream = new BufferedServletInputStream( super.getInputStream() );
      }

      return bufferedServletInputStream;
    }

    @Override
    public ServletOutputStream getOutputStream()
    {
      if( SoapUI.getSettings().getBoolean( HttpSettings.ENABLE_MOCK_WIRE_LOG ) )
      {
        if( capturingServletOutputStream == null )
        {
          capturingServletOutputStream = new CapturingServletOutputStream( super.getOutputStream() );
        }
        return capturingServletOutputStream;
      }
      else
        return super.getOutputStream();
    }
  }

  private class BufferedServletInputStream extends ServletInputStream
  {
    private InputStream source = null;
    private byte[] data = null;
    private InputStream buffer1 = null;

    public BufferedServletInputStream( InputStream is )
    {
      super();
      source = is;
    }

    public InputStream getBuffer() throws IOException
    {
      if( source.available() > 0 )
      {
        // New request content available
        data = null;
      }
      if( data == null )
      {
        ByteArrayOutputStream out = Tools.readAll( source, Tools.READ_ALL );
        data = out.toByteArray();
      }
      if( buffer1 == null )
      {
        buffer1 = new ByteArrayInputStream( data );
      }
      return buffer1;
    }

    public int read() throws IOException
    {
      int i = getBuffer().read();
      return i;
    }

    public int readLine( byte[] b, int off, int len ) throws IOException
    {

      if( len <= 0 )
      {
        return 0;
      }
      int count = 0, c;

      while( ( c = read() ) != -1 )
      {
        b[off++ ] = ( byte )c;
        count++ ;
        if( c == '\n' || count == len )
        {
          break;
        }
      }
      return count > 0 ? count : -1;
    }

    public int read( byte[] b ) throws IOException
    {
      int i = getBuffer().read( b );
      return i;
    }

    public int read( byte[] b, int off, int len ) throws IOException
    {
      int result = getBuffer().read( b, off, len );
      return result;
    }

    public long skip( long n ) throws IOException
    {
      return getBuffer().skip( n );
    }

    public int available() throws IOException
    {
      return getBuffer().available();
    }

    public void close() throws IOException
    {
      getBuffer().close();
    }

    public void mark( int readlimit )
    {
      // buffer.mark( readlimit );
    }

    public boolean markSupported()
    {
      return false;
    }

    public void reset() throws IOException
    {
      buffer1 = null;
    }
  }

  private class CapturingServletOutputStream extends ServletOutputStream
  {
    private ServletOutputStream outputStream;
    private ByteArrayOutputStream captureOutputStream = new ByteArrayOutputStream();

    public CapturingServletOutputStream( ServletOutputStream outputStream )
    {
      this.outputStream = outputStream;
    }

    public void print( String s ) throws IOException
    {
      outputStream.print( s );
    }

    public void print( boolean b ) throws IOException
    {
      outputStream.print( b );
    }

    public void print( char c ) throws IOException
    {
      outputStream.print( c );
    }

    public void print( int i ) throws IOException
    {
      outputStream.print( i );
    }

    public void print( long l ) throws IOException
    {
      outputStream.print( l );
    }

    public void print( float v ) throws IOException
    {
      outputStream.print( v );
    }

    public void print( double v ) throws IOException
    {
      outputStream.print( v );
    }

    public void println() throws IOException
    {
      outputStream.println();
    }

    public void println( String s ) throws IOException
    {
      outputStream.println( s );
    }

    public void println( boolean b ) throws IOException
    {
      outputStream.println( b );
    }

    public void println( char c ) throws IOException
    {
      outputStream.println( c );
    }

    public void println( int i ) throws IOException
    {
      outputStream.println( i );
    }

    public void println( long l ) throws IOException
    {
      outputStream.println( l );
    }

    public void println( float v ) throws IOException
    {
      outputStream.println( v );
    }

    public void println( double v ) throws IOException
    {
      outputStream.println( v );
    }

    public void write( int b ) throws IOException
    {
      captureOutputStream.write( b );
      outputStream.write( b );
    }

    public void write( byte[] b ) throws IOException
    {
      captureOutputStream.write( b );
      outputStream.write( b );
    }

    public void write( byte[] b, int off, int len ) throws IOException
    {
      captureOutputStream.write( b, off, len );
      outputStream.write( b, off, len );
    }

    public void flush() throws IOException
    {
      outputStream.flush();
    }

    public void close() throws IOException
    {
      outputStream.close();
      // log.info( "Closing output stream, captured: " +
      // captureOutputStream.toString() );
    }
  }

  private class CapturingServletInputStream extends ServletInputStream
  {
    private ServletInputStream inputStream;
    private ByteArrayOutputStream captureOutputStream = new ByteArrayOutputStream();

    public CapturingServletInputStream( ServletInputStream inputStream )
    {
      this.inputStream = inputStream;
    }

    public int read() throws IOException
    {
      int i = inputStream.read();
      captureOutputStream.write( i );
      return i;
    }

    public int readLine( byte[] bytes, int i, int i1 ) throws IOException
    {
      int result = inputStream.readLine( bytes, i, i1 );
      captureOutputStream.write( bytes, i, i1 );
      return result;
    }

    public int read( byte[] b ) throws IOException
    {
      int i = inputStream.read( b );
      captureOutputStream.write( b );
      return i;
    }

    public int read( byte[] b, int off, int len ) throws IOException
    {
      int result = inputStream.read( b, off, len );
      if( result != -1 )
        captureOutputStream.write( b, off, result );
      return result;
    }

    public long skip( long n ) throws IOException
    {
      return inputStream.skip( n );
    }

    public int available() throws IOException
    {
      return inputStream.available();
    }

    public void close() throws IOException
    {
      inputStream.close();
      // log.info( "Closing input stream, captured: " +
      // captureOutputStream.toString() );
    }

    public void mark( int readlimit )
    {
      inputStream.mark( readlimit );
    }

    public boolean markSupported()
    {
      return inputStream.markSupported();
    }

    public void reset() throws IOException
    {
      inputStream.reset();
    }
  }

  private class ServerHandler extends AbstractHandler
  {
    public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch )
        throws IOException, ServletException
    {
      // find mockService
      Map<String, List<MockRunner>> map = runners.get( request.getLocalPort() );

      // ssl?
      if( map == null && sslConnector != null && request.getLocalPort() == sslConnector.getPort() )
      {
        for( Map<String, List<MockRunner>> runnerMap : runners.values() )
        {
          if( runnerMap.containsKey( request.getPathInfo() ) )
          {
            map = runnerMap;
            break;
          }
        }
      }

      if( map != null )
      {
        List<MockRunner> wsdlMockRunners = map.get( request.getPathInfo() );
        if( wsdlMockRunners == null )
        {
          for( String root : map.keySet() )
          {
            if( request.getPathInfo().startsWith( root ) )
            {
              wsdlMockRunners = map.get( root );
            }
          }
        }

        if( wsdlMockRunners != null )
        {
          try
          {
            DispatchException ex = null;
            MockResult result = null;

            for( MockRunner wsdlMockRunner : wsdlMockRunners )
            {
              if( !wsdlMockRunner.isRunning() )
                continue;

              try
              {
                result = wsdlMockRunner.dispatchRequest( request, response );
                if( result != null )
                {
                  result.finish();
                  break;
                }
              }
              catch( DispatchException e )
              {
                // log.debug( wsdlMockRunner.getMockService().getName()
                // + " was unable to dispatch mock request ",
                // e );

                ex = e;
              }
            }

            if( ex != null && result == null )
              throw ex;
          }
          catch( Exception e )
          {
            SoapUI.logError( e );

            response.setStatus( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
            response.setContentType( "text/html" );
            response.getWriter().print(
                SoapMessageBuilder.buildFault( "Server", e.getMessage(), SoapVersion.Utils
                    .getSoapVersionForContentType( request.getContentType(), SoapVersion.Soap11 ) ) );
            // throw new ServletException( e );
          }
        }
        else
        {
          printMockServiceList( response );
        }
      }
      else
      {
        printMockServiceList( response );
      }

      response.flushBuffer();
    }

    private void printMockServiceList( HttpServletResponse response ) throws IOException
    {
      response.setStatus( HttpServletResponse.SC_OK );
      response.setContentType( "text/html" );

      MockRunner[] mockRunners = getMockRunners();
      PrintWriter out = response.getWriter();
      out.print( "<html><body><p>There are currently " + mockRunners.length + " running soapUI MockServices</p><ul>" );

      for( MockRunner mockRunner : mockRunners )
      {
        out.print( "<li><a href=\"" );
        out.print( mockRunner.getMockService().getPath() + "?WSDL" );
        out.print( "\">" + mockRunner.getMockService().getName() + "</a></li>" );
      }

      out.print( "</ul></p></body></html>" );
    }
  }

  public MockRunner[] getMockRunners()
  {
    return mockRunners.toArray( new MockRunner[mockRunners.size()] );
  }

  private class MockRequestLog extends AbstractLifeCycle implements RequestLog
  {
    public void log( Request request, Response response )
    {
      if( !SoapUI.getSettings().getBoolean( HttpSettings.ENABLE_MOCK_WIRE_LOG ) )
        return;

      if( SoapUI.getLogMonitor() == null || SoapUI.getLogMonitor().getLogArea( "jetty log" ) == null
          || SoapUI.getLogMonitor().getLogArea( "jetty log" ).getLoggers() == null )
        return;

      Logger logger = SoapUI.getLogMonitor().getLogArea( "jetty log" ).getLoggers()[0];

      try
      {
        ServletInputStream inputStream = request.getInputStream();
        if( inputStream instanceof CapturingServletInputStream )
        {
          ByteArrayOutputStream byteArrayOutputStream = ( ( CapturingServletInputStream )inputStream ).captureOutputStream;
          String str = request.toString() + byteArrayOutputStream.toString();
          BufferedReader reader = new BufferedReader( new StringReader( str ) );
          ( ( CapturingServletInputStream )inputStream ).captureOutputStream = new ByteArrayOutputStream();

          String line = reader.readLine();
          while( line != null )
          {
            logger.info( ">> \"" + line + "\"" );
            line = reader.readLine();
          }
        }
      }
      catch( Throwable e )
      {
        SoapUI.logError( e );
      }

      try
      {
        ServletOutputStream outputStream = response.getOutputStream();
        if( outputStream instanceof CapturingServletOutputStream )
        {
          ByteArrayOutputStream byteArrayOutputStream = ( ( CapturingServletOutputStream )outputStream ).captureOutputStream;
          String str = request.toString() + byteArrayOutputStream.toString();
          BufferedReader reader = new BufferedReader( new StringReader( str ) );
          ( ( CapturingServletOutputStream )outputStream ).captureOutputStream = new ByteArrayOutputStream();

          String line = reader.readLine();
          while( line != null )
          {
            logger.info( "<< \"" + line + "\"" );
            line = reader.readLine();
          }
        }
      }
      catch( Throwable e )
      {
        SoapUI.logError( e );
      }
    }
  }
}
TOP

Related Classes of com.eviware.soapui.monitor.JettyMockEngine$CapturingServletOutputStream

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.