Click here to Skip to main content
15,884,472 members
Articles / Programming Languages / C#

Distributed Command Pattern - an extension of command pattern for connected systems

Rate me:
Please Sign up or sign in to vote.
4.87/5 (74 votes)
25 Jan 2005CPOL16 min read 262.5K   2.7K   252  
Distributed Command Pattern is a pattern for connected systems which implements command pattern. It frees designers from thinking about the communication and helps them concentrate on implementing commands as if it is a regular desktop application. The framework takes care of the communication.
using System;
using System.Net.Sockets;
using System.Collections;
using System.Text;
using System.IO;

namespace DistributedCommand.HTTPProvider
{
	public class HttpMessageException : Exception
	{
		public HttpMessageException( String status, String reason )
		{
			Error = new HttpMessage( );
			Error.Status = status;
			Error.Reason = reason;
			Error.Version = "HTTP/1.1";
		}

		public HttpMessage Error;
	}

	public class HttpMessage
	{
		public HttpMessage( )
		{
			CorrelationID = String.Empty;
		}

		public void Send( NetworkStream stream )
		{
			StringBuilder sb = new StringBuilder( );
			// build first line
			if ( IsResponse )
			{
				sb.Append( Version );
				sb.Append( ' ' );
				sb.Append( Status );
				sb.Append( ' ' );
				sb.Append( Reason );
			}
			else
			{
				sb.Append( Verb );
				sb.Append( ' ' );
				sb.Append( RequestUri );
				sb.Append( ' ' );
				sb.Append( Version );
				if ( CorrelationID == String.Empty )
					CorrelationID = Guid.NewGuid( ).ToString( );
			}
			sb.Append( "\r\n" );

			if ( body.Length > 0 )
				ContentLength = body.Length;

			// build headers
			IDictionaryEnumerator itr = Headers.GetEnumerator( );
			while ( itr.MoveNext( ) )
			{
				sb.Append( itr.Key as String );
				sb.Append( ": " );
				sb.Append( itr.Value as String );
				sb.Append( "\r\n" );
			}
			sb.Append( "\r\n" );

			// convert to bytes
			Byte[] bytes = Encoding.UTF8.GetBytes( sb.ToString( ) );

			stream.Write( bytes, 0, bytes.Length );
			stream.Write( body, 0, body.Length );
			stream.Flush( );

		}

		private void ThrowBadRequest( )
		{
			throw new HttpMessageException( "400", "Bad request" );
		}

		public void Receive( NetworkStream stream )
		{
			// allocate inital buffer
			MemoryStream mem = new MemoryStream( );

			// read the HTTP headers
			bool completed = false;
			do
			{
				int b = 0;
				b = stream.ReadByte( );

				if ( b == 0x0d )
				{
					mem.WriteByte( (byte) b ); // add '\r'
					b = stream.ReadByte( );
					mem.WriteByte( (byte) b ); // add '\n'
					completed = true;
					break;
				}

				while ( b != 0x0d )
				{
					mem.WriteByte( (byte) b );
					b = stream.ReadByte( );
				}
				mem.WriteByte( (byte) b ); // add '\r'
				b = stream.ReadByte( );
				mem.WriteByte( (byte) b ); // add '\n'

			} while ( stream.DataAvailable );

			if ( !completed )
				ThrowBadRequest( );

			mem.Position = 0;
			StreamReader reader = new StreamReader( mem, Encoding.UTF8 );

			// read and process first line
			String line = reader.ReadLine( );

			int n = line.IndexOf( ' ' );
			if ( n == -1 )
				ThrowBadRequest( );

			String str = line.Substring( 0, n );
			if ( str.ToUpper( ).StartsWith( "HTTP" ) )
			{
				Version = str;

				line = line.Substring( n + 1 );
				n = line.IndexOf( ' ' );
				if ( n == -1 )
					ThrowBadRequest( );

				Status = line.Substring( 0, n );
				Reason = line.Substring( n + 1 );

			}
			else
			{
				Verb = str;

				line = line.Substring( n + 1 );
				n = line.IndexOf( ' ' );
				if ( n == -1 )
					ThrowBadRequest( );

				RequestUri = line.Substring( 0, n );
				Version = line.Substring( n + 1 );
			}


			// read all the headers
			String[] tokens;
			line = reader.ReadLine( );
			while ( line != null && line != String.Empty )
			{
				tokens = line.Split( ':' );
				String name = tokens[0].Trim( );
				Headers[name] = tokens[1].Trim( );
				line = reader.ReadLine( );
			}

			// now go for the message body if there is one
			int len = ContentLength;
			if ( len == 0 )
				return;

			int totalBytesRead = 0;

			// Read until specified content length is fully read
			MemoryStream bodyStream = new MemoryStream(ContentLength);
			Byte[] buffer = new Byte[len];
			while( totalBytesRead < ContentLength )
			{
				int bytesRead = stream.Read( buffer, 0, buffer.Length );
				bodyStream.Write( buffer, 0, bytesRead );

				totalBytesRead += bytesRead;
			}

			body = bodyStream.GetBuffer();
		}


		public bool IsResponse
		{
			get { return Verb == null || Verb == String.Empty; }
		}


		public Hashtable Headers = new Hashtable( );

		public String CorrelationID
		{
			get { return Headers["Correlation-Id"] as String; }
			set { Headers["Correlation-Id"] = value; }
		}


		public int ContentLength
		{
			get
			{
				String tmp = Headers["Content-Length"] as String;
				return (tmp != null) ? int.Parse( tmp ) : 0;
			}
			set { Headers["Content-Length"] = value.ToString( ); }
		}


		private Byte[] body = new Byte[0];

		public Byte[] Body
		{
			get { return body; }
			set
			{
				body = value;
				if ( body.Length > 0 )
					ContentLength = body.Length;
			}
		}

		// first line tokens 
		public String Verb;
		public String RequestUri;
		public String Version;
		public String Status;
		public String Reason;
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect BT, UK (ex British Telecom)
United Kingdom United Kingdom

Comments and Discussions