All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.continual.http.service.framework.inspection.impl.CHttpTrxObserver Maven / Gradle / Ivy

There is a newer version: 0.3.16
Show newest version
package io.continual.http.service.framework.inspection.impl;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.continual.http.service.framework.context.CHttpRequest;
import io.continual.http.service.framework.context.CHttpRequestContext;
import io.continual.http.service.framework.inspection.CHttpObserver;
import io.continual.http.service.framework.inspection.CHttpObserverMgr;
import io.continual.services.ServiceContainer;
import io.continual.services.SimpleService;
import io.continual.util.data.TypeConvertor;
import io.continual.util.data.json.JsonVisitor;
import io.continual.util.data.json.JsonVisitor.ArrayVisitor;
import io.continual.util.time.Clock;

public class CHttpTrxObserver extends SimpleService implements CHttpObserverMgr
{
	public CHttpTrxObserver ( File baseDir )
	{
		fBaseDir = baseDir;
	}
	
	public CHttpTrxObserver ( ServiceContainer sc, JSONObject config )
	{
		fBaseDir = new File ( config.optString ( "baseDir", "./logs" ) );

		JsonVisitor.forEachElement ( config.optJSONArray ( "filters" ), new ArrayVisitor ()
		{
			@Override
			public boolean visit ( JSONObject filter ) throws JSONException
			{
				final String logName = filter.getString ( "logName" );
				final String method = filter.optString ( "method", ".*" );
				final String path = filter.optString ( "path", ".*" );

				addFilter ( new Filter ()
				{
					@Override
					public String logName () { return logName; }

					@Override
					public boolean matches ( CHttpRequestContext ctx )
					{
						final CHttpRequest req = ctx.request ();
						final String reqMethod = req.getMethod ();
						final String reqPath = req.getPathInContext ();

						return ( reqMethod.matches ( method ) && reqPath.matches ( path ) );
					}
					
				} );
				return true;
			}
		});
	}

	public interface Filter
	{
		String logName ();
		boolean matches ( CHttpRequestContext ctx );
	}

	@Override
	public void consider ( CHttpRequestContext ctx )
	{
		for ( Filter f : fFilters )
		{
			if ( f.matches ( ctx ) )
			{
				try
				{
					final String name = f.logName () + "." + Clock.now () + ".log";
					ctx.install ( new TrxDumper ( new PrintWriter ( new FileOutputStream ( new File ( fBaseDir, name ), true ) ) ) );
				}
				catch ( IOException e )
				{
					log.warn ( "Couldn't install inspector on trx: " + e.getMessage () );
				}
				return;
			}
		}
	}

	public List getFilters ()
	{
		return Collections.unmodifiableList ( fFilters );
	}

	public CHttpObserverMgr addFilter ( Filter f )
	{
		fFilters.add ( f );
		return this;
	}

	public CHttpObserverMgr removeFilter ( Filter f )
	{
		fFilters.remove ( f );
		return this;
	}

	private class TrxDumper implements CHttpObserver
	{
		TrxDumper ( PrintWriter to ) throws IOException
		{
			fOut = to;

			fOut.println (  );
			fOut.println ( "vvv" );
			fOut.println ( "at: " + Clock.now () );
		}

		@Override
		public CHttpObserver method ( String method )
		{
			fOut.println ( "method: " + method );
			return this;
		}

		@Override
		public CHttpObserver onUrl ( String url )
		{
			fOut.println ( "url: " + url );
			return this;
		}

		@Override
		public CHttpObserver queryString ( String qs )
		{
			fOut.println ( "query: " + qs );
			return this;
		}

		@Override
		public CHttpObserver contentTypeRequest ( String type )
		{
			fOut.println ( "contentType: " + type );
			return this;
		}

		@Override
		public CHttpObserver contentLengthRequest ( int length )
		{
			fOut.println ( "contentLength: " + length );
			return this;
		}

		@Override
		public CHttpObserver withHeaders ( HeaderLister hl )
		{
			final Map> headers = hl.getHeaders ();
			final LinkedList keys = new LinkedList<>();
			keys.addAll ( headers.keySet () );
			for ( String key : keys )
			{
				final List values = headers.get ( key );
				final String val = values.size () == 1 ? values.get ( 0 ) : values.toString ();
				fOut.println ( key + ": " + val );
			}
			return this;
		}

		@Override
		public InputStream wrap ( InputStream inputStream )
		{
			fInStream = new TracingInputStream ( inputStream, fOut );
			return fInStream;
		}

		@Override
		public PrintWriter wrap ( PrintWriter writer )
		{
			fPwStream = new TracingPrintWriter ( writer, fOut );
			return fPwStream;
		}

		@Override
		public OutputStream wrap ( OutputStream outputStream )
		{
			fOutStream = new TracingOutputStream ( outputStream, fOut );
			return outputStream;
		}

		@Override
		public CHttpObserver replyWith ( int status, String msg )
		{
			checkReplyStart ();
			fOut.println ( "reply: " + status + " " + msg );
			return this;
		}

		@Override
		public CHttpObserver replyWith ( int code )
		{
			checkReplyStart ();
			fOut.println ( "reply: " + code );
			return this;
		}

		@Override
		public CHttpObserver replyHeader ( String key, String value )
		{
			checkReplyStart ();
			fOut.println ( "reply header: " + key + ": " + value );
			return this;
		}

		@Override
		public void closeTrx ()
		{
			if ( fInStream != null )
			{
				fInStream.flushLog ();
			}
			if ( fOutStream != null )
			{
				fOutStream.flushLog ();
			}
			if ( fPwStream != null )
			{
				fPwStream.flush ();
			}
			fOut.println ( "^^^" );
			fOut.close ();
		}

		private void checkReplyStart ()
		{
			if ( !fReplyStarted )
			{
				fOut.println ( "" );
				fOut.println ( "---" );
				fOut.println ( "" );
				fReplyStarted = true;
			}
		}
		
		private final PrintWriter fOut;
		private TracingInputStream fInStream;
		private TracingPrintWriter fPwStream;
		private TracingOutputStream fOutStream;
		private boolean fReplyStarted = false;
	}

	private class TracingInputStream extends InputStream
	{
		public TracingInputStream ( InputStream to, PrintWriter dump )
		{
			fTo = to;
			fLog = dump;
		}

	    public int read() throws IOException
	    {
	    	final int b = fTo.read ();
	    	if ( b > -1 ) out ( b );
	    	return b;
	    }

	    public int read(byte b[]) throws IOException
	    {
	    	final int result = fTo.read ( b );
	    	out ( b, 0, result );
	    	return result;
	    }

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

	    public long skip(long n) throws IOException
	    {
	    	out ( "skip " + n );
	    	return fTo.skip ( n );
	    }

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

	    public void close() throws IOException
	    {
	    	flushLog ();
	    	fTo.close ();
	    }

		public synchronized void mark ( int readlimit )
	    {
			out ( "mark(" + readlimit + ")" );
	    	fTo.mark ( readlimit );
	    }

		public synchronized void reset () throws IOException
	    {
			out ( "reset()" );
	    	fTo.reset ();
	    }

	    public boolean markSupported()
	    {
	        return fTo.markSupported ();
	    }
	    
		private final InputStream fTo;
		private final PrintWriter fLog;

		private static final int kLineLength = 16;
		private StringBuilder fHexBytes = new StringBuilder ();
		private StringBuilder fPrintableBytes = new StringBuilder ();
		private int fPendingLength = 0;
		
		private void out ( int b )
		{
			final byte[] bs = new byte[] { (byte)b };
			out ( bs, 0, 1 );
		}

		private void out ( byte[] bytes, int off, int len )
		{
			for ( int i=off; i= kLineLength )
			{
				flushLog ();
			}
		}

		public void flushLog ()
		{
			if ( fPendingLength > 0 )
			{
				fLog.print ( fHexBytes.toString () );

				final int lacking = kLineLength - fPendingLength;
				for ( int i=0; i= kLineLength )
			{
				flushLog ();
			}
		}

		public void flushLog ()
		{
			if ( fPendingLength > 0 )
			{
				fLog.print ( fHexBytes.toString () );

				final int lacking = kLineLength - fPendingLength;
				for ( int i=0; i fFilters = new LinkedList<> ();

	private static final Logger log = LoggerFactory.getLogger ( CHttpTrxObserver.class );
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy