You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1621 lines
47 KiB
1621 lines
47 KiB
using System;
|
|
using System.Collections;
|
|
using System.Data;
|
|
using System.IO;
|
|
using System.Net;
|
|
using System.Security.Cryptography.X509Certificates;
|
|
using System.Text;
|
|
using System.Web.Services;
|
|
using System.Web.Services.Description;
|
|
using System.Web.Services.Protocols;
|
|
using System.Xml;
|
|
using System.Xml.Schema;
|
|
using System.Xml.Serialization;
|
|
using System.Data.SqlClient;
|
|
|
|
using UDDI;
|
|
using UDDI.API;
|
|
using UDDI.Diagnostics;
|
|
|
|
namespace UDDI.Replication
|
|
{
|
|
/// ********************************************************************
|
|
/// class ReplicationHelper
|
|
/// --------------------------------------------------------------------
|
|
/// <summary>
|
|
/// </summary>
|
|
/// ********************************************************************
|
|
///
|
|
public class ReplicationHelper
|
|
{
|
|
private static OperatorNode LocalOperator = null;
|
|
private static X509Certificate LocalCertificate = null;
|
|
private static OperatorNodeCollection RemoteOperators = null;
|
|
private static ChangeRecordVectorCollection ChangesAlreadySeen = null;
|
|
private static ReplicationSoapClient SoapClient = null;
|
|
private static Hashtable NodeChangeRecordCounts = null;
|
|
private static Hashtable SessionChangeRecordCounts = null;
|
|
|
|
|
|
/// ****************************************************************
|
|
/// private Initialize [static]
|
|
/// ----------------------------------------------------------------
|
|
/// <summary>
|
|
/// Initializes replication variables.
|
|
/// </summary>
|
|
/// ****************************************************************
|
|
///
|
|
private static void Initialize()
|
|
{
|
|
Debug.Enter();
|
|
Debug.VerifySetting( "OperatorKey" );
|
|
|
|
//
|
|
// Get information about the local operator node.
|
|
//
|
|
LocalOperator = new OperatorNode( Config.GetString( "OperatorKey" ) );
|
|
LocalOperator.Get();
|
|
|
|
//
|
|
// Get the local certificate.
|
|
//
|
|
LocalCertificate = new X509Certificate( LocalOperator.Certificate );
|
|
|
|
//
|
|
// Get the list of operator nodes to which we can send
|
|
// get_changeRecords messages. Remove ourself from the
|
|
// list!
|
|
//
|
|
RemoteOperators = new OperatorNodeCollection();
|
|
|
|
RemoteOperators.Get();
|
|
RemoteOperators.Remove( LocalOperator.OperatorNodeID );
|
|
|
|
//
|
|
// Get a ChangesAlreadySeen list for each operator node (not
|
|
// just the ones we are replicating with).
|
|
//
|
|
GetHighWaterMarks();
|
|
|
|
//
|
|
// Initialize our soap client.
|
|
//
|
|
string proxy = Config.GetString( "Proxy", null );
|
|
|
|
SoapClient = new ReplicationSoapClient();
|
|
|
|
SoapClient.ClientCertificates.Add( LocalCertificate );
|
|
|
|
if( !Utility.StringEmpty( proxy ) )
|
|
SoapClient.Proxy = new WebProxy( proxy, true );
|
|
|
|
//
|
|
// Setup the context for a replication session.
|
|
//
|
|
Context.ApiVersionMajor = 2;
|
|
Context.ContextType = ContextType.Replication;
|
|
Context.LogChangeRecords = false;
|
|
|
|
//
|
|
// Setup logging.
|
|
//
|
|
SessionChangeRecordCounts = new Hashtable();
|
|
|
|
foreach( int payloadType in Enum.GetValues( typeof( ChangeRecordPayloadType ) ) )
|
|
{
|
|
SessionChangeRecordCounts[ payloadType ] = 0;
|
|
}
|
|
|
|
Debug.Leave();
|
|
}
|
|
|
|
private static void GetHighWaterMarks()
|
|
{
|
|
try
|
|
{
|
|
GetHighWaterMarks getHighWaterMarks = new GetHighWaterMarks();
|
|
|
|
HighWaterMarkDetail detail = getHighWaterMarks.Get();
|
|
ChangesAlreadySeen = detail.HighWaterMarks;
|
|
}
|
|
catch( Exception e )
|
|
{
|
|
#if never
|
|
Debug.OperatorMessage(
|
|
SeverityType.Error,
|
|
CategoryType.Replication,
|
|
OperatorMessageType.CannotRetrieveHighWaterMarks,
|
|
"Could not retrive high water marks for operator nodes.\r\n\r\nDetail:\r\n" + e.ToString() );
|
|
#endif
|
|
Debug.OperatorMessage(
|
|
SeverityType.Error,
|
|
CategoryType.Replication,
|
|
OperatorMessageType.CannotRetrieveHighWaterMarks,
|
|
new UDDIText( "UDDI_ERROR_REPLICATION_HIGHWATER_MARKS", e.ToString() ).GetText() );
|
|
|
|
throw new UDDIException( ErrorType.E_fatalError, "UDDI_ERROR_REPLICATION_HIGHWATER_MARKS", e );
|
|
}
|
|
}
|
|
|
|
/// ****************************************************************
|
|
/// public Replicate [static]
|
|
/// ----------------------------------------------------------------
|
|
/// <summary>
|
|
/// </summary>
|
|
/// ****************************************************************
|
|
///
|
|
public static void Replicate()
|
|
{
|
|
//
|
|
// Initialize the replication session.
|
|
//
|
|
Initialize();
|
|
|
|
//
|
|
// Verify that we do in fact have operators to replicate
|
|
// with.
|
|
//
|
|
if( RemoteOperators.Count < 1 )
|
|
{
|
|
#if never
|
|
Debug.OperatorMessage(
|
|
SeverityType.Info,
|
|
CategoryType.Replication,
|
|
OperatorMessageType.NoReplicationOperators,
|
|
"There are no operators to replicate with. Please check the replication configuration." );
|
|
#endif
|
|
Debug.OperatorMessage(
|
|
SeverityType.Info,
|
|
CategoryType.Replication,
|
|
OperatorMessageType.NoReplicationOperators,
|
|
new UDDIText( "UDDI_ERROR_REPLICATION_NO_OPERATORS" ).GetText() );
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// TODO: Get the node id of the last operator we replicated
|
|
// with.
|
|
//
|
|
|
|
//
|
|
// TODO: Re-order the operator node list so that we replicate
|
|
// in a round-robin fashion.
|
|
//
|
|
|
|
|
|
//
|
|
// Create the start replication session log entry.
|
|
//
|
|
LogSessionStart();
|
|
|
|
//
|
|
// Replicate with each operator node.
|
|
//
|
|
foreach( OperatorNode remoteNode in RemoteOperators )
|
|
{
|
|
ReplicationResult result = null;
|
|
|
|
//
|
|
// Log the node replication start.
|
|
//
|
|
LogOperatorStart( remoteNode );
|
|
|
|
//
|
|
// Get the branch list for the node. The branch list is
|
|
// the remote node itself, plus any alternatives that we
|
|
// may try if we have trouble communicating with the first
|
|
// node. For now, we don't support alternate nodes, so
|
|
// the remote node is the only node we add to this list.
|
|
//
|
|
OperatorNodeCollection branchNodes = new OperatorNodeCollection();
|
|
|
|
branchNodes.Add( remoteNode );
|
|
|
|
foreach( OperatorNode branchNode in branchNodes )
|
|
{
|
|
//
|
|
// Get the last replication status for this node.
|
|
//
|
|
result = ReplicateWithNode( branchNode );
|
|
|
|
if( ReplicationStatus.Success == result.ReplicationStatus )
|
|
break;
|
|
|
|
//
|
|
// Determine what we should do based on this attempts result
|
|
// and the result of the last replication cycle with this
|
|
// node. TODO: if it is a communication error, we'll need
|
|
// to try alternate edges. This is reserved until alternate
|
|
// edges are actually used.
|
|
//
|
|
}
|
|
|
|
//
|
|
// Log the node replication end.
|
|
//
|
|
LogOperatorEnd( remoteNode, result );
|
|
}
|
|
|
|
//
|
|
// Create the end replication session log entry.
|
|
//
|
|
LogSessionEnd();
|
|
|
|
Debug.Leave();
|
|
}
|
|
|
|
|
|
/// ****************************************************************
|
|
/// public ReplicateWithNode [static]
|
|
/// ----------------------------------------------------------------
|
|
/// <summary>
|
|
/// </summary>
|
|
/// ****************************************************************
|
|
///
|
|
public static ReplicationResult ReplicateWithNode( string operatorNodeID )
|
|
{
|
|
OperatorNode remoteNode = null;
|
|
|
|
//
|
|
// Initialize the replication session.
|
|
//
|
|
Initialize();
|
|
|
|
//
|
|
// Replicate with the specified node.
|
|
//
|
|
try
|
|
{
|
|
remoteNode = new OperatorNode( operatorNodeID );
|
|
remoteNode.Get();
|
|
}
|
|
catch( Exception e )
|
|
{
|
|
#if never
|
|
string message = String.Format(
|
|
"Could not get details for operator {{{0}}}.\r\n\r\nDetails:\r\n{1}",
|
|
operatorNodeID,
|
|
e.ToString() );
|
|
|
|
Debug.OperatorMessage(
|
|
SeverityType.Error,
|
|
CategoryType.Replication,
|
|
OperatorMessageType.UnknownOperator,
|
|
message );
|
|
|
|
throw new Exception( message, e );
|
|
#endif
|
|
UDDIText uddiText = new UDDIText( "UDDI_ERROR_REPLICATION_OPERATOR_DETAILS", operatorNodeID, e.ToString() );
|
|
|
|
Debug.OperatorMessage(
|
|
SeverityType.Error,
|
|
CategoryType.Replication,
|
|
OperatorMessageType.UnknownOperator,
|
|
uddiText.GetText() );
|
|
|
|
throw new UDDIException( ErrorType.E_fatalError, uddiText.GetText() );
|
|
}
|
|
|
|
//
|
|
// Log the node replication start.
|
|
//
|
|
LogOperatorStart( remoteNode );
|
|
|
|
//
|
|
// Replicate
|
|
//
|
|
ReplicationResult result = ReplicateWithNode( remoteNode );
|
|
|
|
//
|
|
// Log the node replication end.
|
|
//
|
|
LogOperatorEnd( remoteNode, result );
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/// ****************************************************************
|
|
/// private ReplicateWithNode [static]
|
|
/// ----------------------------------------------------------------
|
|
/// <summary>
|
|
/// </summary>
|
|
/// ****************************************************************
|
|
///
|
|
private static ReplicationResult ReplicateWithNode( OperatorNode remoteNode )
|
|
{
|
|
//
|
|
// Retrieve the change records from the remote node and process
|
|
// them.
|
|
//
|
|
ChangeRecordCollection changeRecords = null;
|
|
|
|
//
|
|
// Keep track of the number of times we call GetChangeRecords on each operator. We
|
|
// don't want to be in a situation where we call them infinitely if they keep updating
|
|
// their data.
|
|
//
|
|
int maxIterations = Config.GetInt( "Replication.MaxGetChangeIterations", 100 );
|
|
int iterations = 0;
|
|
|
|
//
|
|
// Keep getting change records until there are no more; we need to do this because some
|
|
// operators will limit the number of change records that they send back.
|
|
//
|
|
do
|
|
{
|
|
try
|
|
{
|
|
changeRecords = GetChangeRecords( remoteNode );
|
|
}
|
|
catch( Exception e )
|
|
{
|
|
return ReplicationResult.LogCommunicationError( remoteNode, e, ChangesAlreadySeen );
|
|
}
|
|
|
|
foreach( ChangeRecord changeRecord in changeRecords )
|
|
{
|
|
//
|
|
// Make sure we haven't seen this change record before.
|
|
//
|
|
if( ChangesAlreadySeen.IsProcessed( changeRecord.ChangeID ) )
|
|
{
|
|
Debug.Write(
|
|
SeverityType.Info,
|
|
CategoryType.Replication,
|
|
String.Format(
|
|
"Change already seen.\r\nSkipping record {0}:{1} retrieved from node {2}",
|
|
changeRecord.ChangeID.NodeID,
|
|
changeRecord.ChangeID.OriginatingUSN,
|
|
remoteNode.OperatorNodeID ) );
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Make sure we aren't trying to replicate one of our own
|
|
// change records.
|
|
//
|
|
if( 0 == String.Compare( changeRecord.ChangeID.NodeID, LocalOperator.OperatorNodeID, true ) )
|
|
{
|
|
Debug.Write(
|
|
SeverityType.Info,
|
|
CategoryType.Replication,
|
|
String.Format(
|
|
"Skipping replication of local change record.\r\nSkipping record {0}:{1} retrieved from node {2}",
|
|
changeRecord.ChangeID.NodeID,
|
|
changeRecord.ChangeID.OriginatingUSN,
|
|
remoteNode.OperatorNodeID ) );
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Begin a transaction.
|
|
//
|
|
ConnectionManager.BeginTransaction();
|
|
|
|
try
|
|
{
|
|
//
|
|
// Set user context information and process the
|
|
// change record.
|
|
//
|
|
Context.User.ID = changeRecord.ChangeID.NodeID;
|
|
Context.TimeStamp = DateTime.Now;
|
|
|
|
//
|
|
// Validate the change record, then process it. There is a very good
|
|
// reason for doing this validation on a change record by change record
|
|
// basis: if there is one error in the incoming change record stream,
|
|
// we would reject the entire stream, not just the errant change record.
|
|
//
|
|
SchemaCollection.Validate( changeRecord );
|
|
|
|
try
|
|
{
|
|
changeRecord.Process();
|
|
}
|
|
catch( Exception innerException )
|
|
{
|
|
//
|
|
// Exceptions that are related to IN 60 are ignored.
|
|
//
|
|
if( Context.ExceptionSource == ExceptionSource.PublisherAssertion ||
|
|
Context.ExceptionSource == ExceptionSource.BrokenServiceProjection )
|
|
{
|
|
//
|
|
// Log the error
|
|
//
|
|
ReplicationResult.LogInvalidKeyWarning( remoteNode, changeRecord, innerException );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Otherwise, throw the exception for real.
|
|
//
|
|
throw innerException;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Commit the transaction.
|
|
//
|
|
ConnectionManager.Commit();
|
|
|
|
//
|
|
// Update our changeAlreadySeen vector for the
|
|
// originating node.
|
|
//
|
|
ChangesAlreadySeen.MarkAsProcessed( changeRecord.ChangeID );
|
|
|
|
//
|
|
// Update log counts.
|
|
//
|
|
LogCounts( changeRecord );
|
|
}
|
|
catch( Exception e )
|
|
{
|
|
ConnectionManager.Abort();
|
|
|
|
return ReplicationResult.LogValidationError( remoteNode, changeRecord, e, ChangesAlreadySeen );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Refresh our highwater mark vector. We do this instead of calling gethighwatermarks on the
|
|
// operator because hitting our DB is faster then making the SOAP call across HTTP.
|
|
//
|
|
GetHighWaterMarks();
|
|
|
|
iterations++;
|
|
|
|
}while( 0 != changeRecords.Count && iterations < maxIterations );
|
|
|
|
//
|
|
// Log success!
|
|
//
|
|
return ReplicationResult.LogSuccess( remoteNode, null );
|
|
}
|
|
|
|
/// ****************************************************************
|
|
/// private GetChangeRecords [static]
|
|
/// ----------------------------------------------------------------
|
|
/// <summary>
|
|
/// </summary>
|
|
/// ****************************************************************
|
|
///
|
|
private static ChangeRecordCollection GetChangeRecords( OperatorNode remoteNode )
|
|
{
|
|
GetChangeRecords getChangeRecords = new GetChangeRecords();
|
|
|
|
getChangeRecords.RequestingNode = LocalOperator.OperatorNodeID;
|
|
getChangeRecords.ChangesAlreadySeen = ChangesAlreadySeen;
|
|
|
|
SoapClient.Url = remoteNode.SoapReplicationURL;
|
|
|
|
ChangeRecordDetail detail = SoapClient.GetChangeRecords( getChangeRecords );
|
|
|
|
return detail.ChangeRecords;
|
|
}
|
|
|
|
|
|
/// ****************************************************************
|
|
/// private LogSessionStart [static]
|
|
/// ----------------------------------------------------------------
|
|
/// <summary>
|
|
/// </summary>
|
|
/// ****************************************************************
|
|
///
|
|
private static void LogSessionStart()
|
|
{
|
|
StringWriter log = new StringWriter();
|
|
|
|
try
|
|
{
|
|
// log.WriteLine( "Replication cycle started." );
|
|
log.WriteLine( new UDDIText( "UDDI_MSG_REPLICATION_START" ).GetText() );
|
|
|
|
log.WriteLine();
|
|
// log.WriteLine( "REPLICATION NODES:" );
|
|
log.WriteLine( new UDDIText( "UDDI_MSG_REPLICATION_NODES" ).GetText() );
|
|
|
|
foreach( OperatorNode operatorNode in RemoteOperators )
|
|
{
|
|
log.Write( " " );
|
|
log.WriteLine( operatorNode.Name );
|
|
log.Write( " {" );
|
|
log.Write( operatorNode.OperatorNodeID );
|
|
log.WriteLine( "}" );
|
|
log.Write( " " );
|
|
log.WriteLine( operatorNode.SoapReplicationURL );
|
|
log.WriteLine();
|
|
}
|
|
|
|
// log.WriteLine( "CURRENT HIGHWATER MARKS:" );
|
|
log.WriteLine( new UDDIText( "UDDI_MSG_REPLICATION_CURRENT_HIGHWATER_MARKS" ).GetText() );
|
|
|
|
foreach( ChangeRecordVector vector in ChangesAlreadySeen )
|
|
{
|
|
log.Write( " {" );
|
|
log.Write( vector.NodeID );
|
|
log.Write( "} : " );
|
|
log.WriteLine( vector.OriginatingUSN );
|
|
}
|
|
|
|
Debug.OperatorMessage(
|
|
SeverityType.Info,
|
|
CategoryType.Replication,
|
|
OperatorMessageType.StartingReplicationSession,
|
|
log.ToString() );
|
|
}
|
|
finally
|
|
{
|
|
log.Close();
|
|
}
|
|
}
|
|
|
|
|
|
/// ****************************************************************
|
|
/// private LogOperatorStart [static]
|
|
/// ----------------------------------------------------------------
|
|
/// <summary>
|
|
/// </summary>
|
|
/// ****************************************************************
|
|
///
|
|
private static void LogOperatorStart( OperatorNode remoteNode )
|
|
{
|
|
NodeChangeRecordCounts = new Hashtable();
|
|
|
|
foreach( int payloadType in Enum.GetValues( typeof( ChangeRecordPayloadType ) ) )
|
|
{
|
|
NodeChangeRecordCounts[ payloadType ] = 0;
|
|
}
|
|
|
|
StringWriter log = new StringWriter();
|
|
|
|
try
|
|
{
|
|
// log.WriteLine( "Starting replication with node.\r\n" );
|
|
log.WriteLine( new UDDIText( "UDDI_MSG_REPLICATION_NODE_START" ).GetText() );
|
|
|
|
// log.WriteLine( "REPLICATION NODE:" );
|
|
log.WriteLine( new UDDIText( "UDDI_MSG_REPLICATION_NODE" ).GetText() );
|
|
|
|
log.Write( " " );
|
|
log.WriteLine( remoteNode.Name );
|
|
log.Write( " {" );
|
|
log.Write( remoteNode.OperatorNodeID );
|
|
log.WriteLine( "}" );
|
|
log.Write( " " );
|
|
log.WriteLine( remoteNode.SoapReplicationURL );
|
|
log.WriteLine();
|
|
|
|
// log.WriteLine( "CURRENT HIGHWATER MARKS:" );
|
|
log.WriteLine( new UDDIText( "UDDI_MSG_REPLICATION_CURRENT_HIGHWATER_MARKS" ).GetText() );
|
|
|
|
foreach( ChangeRecordVector vector in ChangesAlreadySeen )
|
|
{
|
|
log.Write( " {" );
|
|
log.Write( vector.NodeID );
|
|
log.Write( "} : " );
|
|
log.WriteLine( vector.OriginatingUSN );
|
|
}
|
|
|
|
Debug.OperatorMessage(
|
|
SeverityType.Info,
|
|
CategoryType.Replication,
|
|
OperatorMessageType.StartingReplicationWithNode,
|
|
log.ToString() );
|
|
}
|
|
finally
|
|
{
|
|
log.Close();
|
|
}
|
|
}
|
|
|
|
|
|
/// ****************************************************************
|
|
/// private LogOperatorEnd [static]
|
|
/// ----------------------------------------------------------------
|
|
/// <summary>
|
|
/// </summary>
|
|
/// ****************************************************************
|
|
///
|
|
private static void LogOperatorEnd( OperatorNode remoteNode, ReplicationResult result )
|
|
{
|
|
StringWriter log = new StringWriter();
|
|
|
|
try
|
|
{
|
|
if( ReplicationStatus.Success == result.ReplicationStatus )
|
|
{
|
|
// log.WriteLine( "Replication with node complete." );
|
|
log.WriteLine( new UDDIText( "UDDI_MSG_REPLICATION_COMPLETE" ).GetText() );
|
|
}
|
|
else
|
|
{
|
|
// log.Write( "Replication with node interrupted\r\n ERROR: " );
|
|
log.Write( new UDDIText( "UDDI_MSG_REPLICATION_INTERRUPTED" ).GetText() );
|
|
|
|
log.WriteLine( result.ReplicationStatus.ToString() );
|
|
}
|
|
|
|
log.WriteLine();
|
|
|
|
// log.WriteLine( "REPLICATION NODE:" );
|
|
log.WriteLine( new UDDIText( "UDDI_MSG_REPLICATION_NODE" ).GetText() );
|
|
|
|
log.Write( " " );
|
|
log.WriteLine( remoteNode.Name );
|
|
log.Write( " {" );
|
|
log.Write( remoteNode.OperatorNodeID );
|
|
log.WriteLine( "}" );
|
|
log.Write( " " );
|
|
log.WriteLine( remoteNode.SoapReplicationURL );
|
|
log.WriteLine();
|
|
|
|
// log.WriteLine( "CHANGE RECORDS PROCESSED:" );
|
|
log.WriteLine( new UDDIText( "UDDI_MSG_REPLICATION_CHANGE_RECORDS_PROCESSED" ).GetText() );
|
|
|
|
foreach( int payloadType in Enum.GetValues( typeof( ChangeRecordPayloadType ) ) )
|
|
{
|
|
string name = Enum.GetName( typeof( ChangeRecordPayloadType ), payloadType ) + ":";
|
|
|
|
log.Write( " " );
|
|
log.Write( name.PadRight( 30 ) );
|
|
log.Write( "\t" );
|
|
log.WriteLine( NodeChangeRecordCounts[ payloadType ] );
|
|
}
|
|
|
|
log.WriteLine();
|
|
//log.WriteLine( "NEW HIGHWATER MARKS:" );
|
|
log.WriteLine( new UDDIText( "UDDI_MSG_REPLICATION_NEW_HIGHWATER_MARKS" ).GetText() );
|
|
|
|
foreach( ChangeRecordVector vector in ChangesAlreadySeen )
|
|
{
|
|
log.Write( " {" );
|
|
log.Write( vector.NodeID );
|
|
log.Write( "} : " );
|
|
log.WriteLine( vector.OriginatingUSN );
|
|
}
|
|
|
|
SeverityType severity = SeverityType.Info;
|
|
|
|
if( ReplicationStatus.Success != result.ReplicationStatus )
|
|
severity = SeverityType.Error;
|
|
|
|
string message = log.ToString();
|
|
|
|
//
|
|
// Log results
|
|
//
|
|
Debug.OperatorMessage(
|
|
severity,
|
|
CategoryType.Replication,
|
|
OperatorMessageType.EndingReplicationWithNode,
|
|
message );
|
|
|
|
//
|
|
// Only send mail on success; if there was a failure, mail will be sent at the point of failure.
|
|
//
|
|
if( ReplicationStatus.Success == result.ReplicationStatus )
|
|
{
|
|
Debug.OperatorMail(
|
|
SeverityType.None,
|
|
CategoryType.Replication,
|
|
OperatorMessageType.EndingReplicationWithNode,
|
|
message );
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
log.Close();
|
|
}
|
|
|
|
//
|
|
// Add the operator node counts to the totals.
|
|
//
|
|
foreach( int payloadType in Enum.GetValues( typeof( ChangeRecordPayloadType ) ) )
|
|
{
|
|
SessionChangeRecordCounts[ payloadType ] = (int)SessionChangeRecordCounts[ payloadType ] + (int)NodeChangeRecordCounts[ payloadType ];
|
|
}
|
|
}
|
|
|
|
/// ****************************************************************
|
|
/// private LogSessionEnd [static]
|
|
/// ----------------------------------------------------------------
|
|
/// <summary>
|
|
/// </summary>
|
|
/// ****************************************************************
|
|
///
|
|
private static void LogSessionEnd()
|
|
{
|
|
StringWriter log = new StringWriter();
|
|
|
|
try
|
|
{
|
|
// log.WriteLine( "Replication cycle complete." );
|
|
log.WriteLine( new UDDIText( "UDDI_MSG_REPLICATION_END" ).GetText() );
|
|
|
|
log.WriteLine();
|
|
|
|
//log.WriteLine( "CHANGE RECORDS PROCESSED:" );
|
|
log.WriteLine( new UDDIText( "UDDI_MSG_REPLICATION_CHANGERECORDS_PROCESSED" ).GetText() );
|
|
|
|
foreach( int payloadType in Enum.GetValues( typeof( ChangeRecordPayloadType ) ) )
|
|
{
|
|
string name = Enum.GetName( typeof( ChangeRecordPayloadType ), payloadType ) + ":";
|
|
|
|
log.Write( " " );
|
|
log.Write( name.PadRight( 30 ) );
|
|
log.Write( "\t" );
|
|
log.WriteLine( SessionChangeRecordCounts[ payloadType ] );
|
|
}
|
|
|
|
log.WriteLine();
|
|
// log.WriteLine( "NEW HIGHWATER MARKS:" );
|
|
log.WriteLine( new UDDIText( "UDDI_MSG_REPLICATION_NEW_HIGHWATER_MARKS" ).GetText() );
|
|
|
|
foreach( ChangeRecordVector vector in ChangesAlreadySeen )
|
|
{
|
|
log.Write( " {" );
|
|
log.Write( vector.NodeID );
|
|
log.Write( "} : " );
|
|
log.WriteLine( vector.OriginatingUSN );
|
|
}
|
|
|
|
Debug.OperatorMessage(
|
|
SeverityType.Info,
|
|
CategoryType.Replication,
|
|
OperatorMessageType.EndingReplicationWithNode,
|
|
log.ToString() );
|
|
}
|
|
finally
|
|
{
|
|
log.Close();
|
|
}
|
|
}
|
|
|
|
/// ****************************************************************
|
|
/// private LogCounts [static]
|
|
/// ----------------------------------------------------------------
|
|
/// <summary>
|
|
/// </summary>
|
|
/// ****************************************************************
|
|
///
|
|
private static void LogCounts( ChangeRecord changeRecord )
|
|
{
|
|
int payloadType = (int)changeRecord.Payload.ChangeRecordPayloadType;
|
|
|
|
NodeChangeRecordCounts[ payloadType ] = (int)NodeChangeRecordCounts[ payloadType ] + 1;
|
|
}
|
|
}
|
|
|
|
/// ********************************************************************
|
|
/// class ReplicationResult
|
|
/// --------------------------------------------------------------------
|
|
/// <summary>
|
|
/// </summary>
|
|
/// ********************************************************************
|
|
///
|
|
public class ReplicationResult
|
|
{
|
|
public UDDI.Replication.ReplicationStatus ReplicationStatus;
|
|
public string OperatorNodeID;
|
|
public string Description;
|
|
public string LastNodeID;
|
|
public long LastUSN;
|
|
public long LastChange;
|
|
|
|
|
|
/// ****************************************************************
|
|
/// public GetLast
|
|
/// ----------------------------------------------------------------
|
|
/// <summary>
|
|
/// </summary>
|
|
/// ****************************************************************
|
|
///
|
|
public void GetLast( string operatorNodeID, bool inboundStatus )
|
|
{
|
|
Debug.Enter();
|
|
|
|
SqlStoredProcedureAccessor sp = new SqlStoredProcedureAccessor();
|
|
|
|
sp.ProcedureName = "net_operatorLogLast_get";
|
|
|
|
sp.Parameters.Add( "@operatorKey", SqlDbType.UniqueIdentifier );
|
|
sp.Parameters.Add( "@inboundStatus", SqlDbType.Bit );
|
|
sp.Parameters.Add( "@replStatusID", SqlDbType.TinyInt, ParameterDirection.Output );
|
|
sp.Parameters.Add( "@description", SqlDbType.NVarChar, UDDI.Constants.Lengths.Description, ParameterDirection.Output );
|
|
sp.Parameters.Add( "@lastOperatorKey", SqlDbType.UniqueIdentifier, ParameterDirection.Output );
|
|
sp.Parameters.Add( "@lastUSN", SqlDbType.BigInt, ParameterDirection.Output );
|
|
sp.Parameters.Add( "@lastChange", SqlDbType.BigInt, ParameterDirection.Output );
|
|
|
|
sp.Parameters.SetGuidFromString( "@operatorKey", operatorNodeID );
|
|
sp.Parameters.SetBool( "@inboundStatus", inboundStatus );
|
|
|
|
sp.ExecuteNonQuery();
|
|
|
|
this.OperatorNodeID = operatorNodeID;
|
|
this.ReplicationStatus = (ReplicationStatus)sp.Parameters.GetShort( "@replStatusID" );
|
|
this.Description = sp.Parameters.GetString( "@description" );
|
|
this.LastNodeID = sp.Parameters.GetGuidString( "@lastOperatorKey" );
|
|
this.LastUSN = sp.Parameters.GetLong( "@lastUSN" );
|
|
this.LastChange = sp.Parameters.GetLong( "@lastChange" );
|
|
|
|
Debug.Leave();
|
|
}
|
|
|
|
|
|
/// ****************************************************************
|
|
/// public Save
|
|
/// ----------------------------------------------------------------
|
|
/// <summary>
|
|
/// </summary>
|
|
/// ****************************************************************
|
|
///
|
|
public void Save()
|
|
{
|
|
Debug.Enter();
|
|
|
|
try
|
|
{
|
|
SqlStoredProcedureAccessor sp = new SqlStoredProcedureAccessor();
|
|
|
|
sp.ProcedureName = "net_operatorLog_save";
|
|
|
|
sp.Parameters.Add( "@operatorKey", SqlDbType.UniqueIdentifier );
|
|
sp.Parameters.Add( "@replStatusID", SqlDbType.TinyInt );
|
|
sp.Parameters.Add( "@description", SqlDbType.NVarChar, UDDI.Constants.Lengths.Description );
|
|
sp.Parameters.Add( "@lastOperatorKey", SqlDbType.UniqueIdentifier );
|
|
sp.Parameters.Add( "@lastUSN", SqlDbType.BigInt );
|
|
sp.Parameters.Add( "@lastChange", SqlDbType.BigInt );
|
|
|
|
sp.Parameters.SetGuidFromString( "@operatorKey", OperatorNodeID );
|
|
sp.Parameters.SetShort( "@replStatusID", (short)ReplicationStatus );
|
|
sp.Parameters.SetString( "@description", Description );
|
|
sp.Parameters.SetGuidFromString( "@lastOperatorKey", LastNodeID );
|
|
sp.Parameters.SetLong( "@lastUSN", LastUSN );
|
|
sp.Parameters.SetLong( "@lastChange", LastChange );
|
|
|
|
sp.ExecuteNonQuery();
|
|
}
|
|
catch
|
|
{
|
|
#if never
|
|
Debug.OperatorMessage(
|
|
SeverityType.Error,
|
|
CategoryType.Replication,
|
|
OperatorMessageType.ValidationError,
|
|
String.Format(
|
|
"Could not store last replication result.\r\n\r\n" +
|
|
"REPLICATION NODE:\r\n" +
|
|
" {{{0}}}\r\n\r\n" +
|
|
"CHANGE RECORD:\r\n" +
|
|
" {{{1}}} : {2}",
|
|
OperatorNodeID,
|
|
LastNodeID,
|
|
LastUSN ) );
|
|
#endif
|
|
Debug.OperatorMessage(
|
|
SeverityType.Error,
|
|
CategoryType.Replication,
|
|
OperatorMessageType.ValidationError,
|
|
new UDDIText( "UDDI_ERROR_REPLICATION_COULD_NOT_STORE_RESULT", OperatorNodeID, LastNodeID, LastUSN ).GetText() );
|
|
}
|
|
|
|
Debug.Leave();
|
|
}
|
|
|
|
|
|
/// ****************************************************************
|
|
/// public LogSuccess [static]
|
|
/// ----------------------------------------------------------------
|
|
/// <summary>
|
|
/// </summary>
|
|
/// ****************************************************************
|
|
///
|
|
public static ReplicationResult LogSuccess( OperatorNode remoteNode, string description )
|
|
{
|
|
ReplicationResult result = new ReplicationResult();
|
|
|
|
result.ReplicationStatus = ReplicationStatus.Success;
|
|
result.Description = description;
|
|
result.OperatorNodeID = remoteNode.OperatorNodeID;
|
|
result.LastNodeID = null;
|
|
result.LastUSN = 0;
|
|
result.LastChange = DateTime.UtcNow.Ticks;
|
|
|
|
result.Save();
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/// ****************************************************************
|
|
/// public LogCommunicationError [static]
|
|
/// ----------------------------------------------------------------
|
|
/// <summary>
|
|
/// </summary>
|
|
/// ****************************************************************
|
|
///
|
|
public static ReplicationResult LogCommunicationError( OperatorNode remoteNode, Exception e, ChangeRecordVectorCollection changesAlreadySeen )
|
|
{
|
|
ReplicationResult result = new ReplicationResult();
|
|
|
|
result.ReplicationStatus = ReplicationStatus.CommunicationError;
|
|
result.Description = e.ToString();
|
|
result.OperatorNodeID = remoteNode.OperatorNodeID;
|
|
result.LastNodeID = null;
|
|
result.LastUSN = 0;
|
|
result.LastChange = DateTime.UtcNow.Ticks;
|
|
|
|
result.Save();
|
|
|
|
string response = e.ToString();
|
|
|
|
if( e is WebException )
|
|
{
|
|
WebException we = (WebException)e;
|
|
|
|
if( null != we.Response )
|
|
{
|
|
StreamReader reader = null;
|
|
|
|
try
|
|
{
|
|
reader = new StreamReader( we.Response.GetResponseStream() );
|
|
|
|
response += "\r\nRESPONSE:\r\n\r\n";
|
|
response += reader.ReadToEnd();
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
finally
|
|
{
|
|
if( null != reader )
|
|
reader.Close();
|
|
}
|
|
}
|
|
}
|
|
else if( e is SoapException )
|
|
{
|
|
SoapException se = (SoapException)e;
|
|
|
|
if( null != se.Detail )
|
|
{
|
|
response += "\r\nSOAP FAULT DETAILS:\r\n\r\n";
|
|
response += se.Detail.OuterXml;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Also send the highwater marks.
|
|
//
|
|
StringWriter highWaterMarks = new StringWriter();
|
|
|
|
foreach( ChangeRecordVector vector in changesAlreadySeen )
|
|
{
|
|
highWaterMarks.Write( " {" );
|
|
highWaterMarks.Write( vector.NodeID );
|
|
highWaterMarks.Write( "} : " );
|
|
highWaterMarks.WriteLine( vector.OriginatingUSN );
|
|
}
|
|
#if never
|
|
//
|
|
// Communications Error
|
|
//
|
|
string message = String.Format(
|
|
"Error communicating with operator.\r\n\r\n" +
|
|
"REPLICATION NODE:\r\n" +
|
|
" {0}\r\n" +
|
|
" {{{1}}}\r\n" +
|
|
" {2}\r\n\r\n" +
|
|
"DETAILS:\r\n\r\n{3}\r\n\r\nCURRENT HIGHWATER MARKS:\r\n\r\n{4}",
|
|
remoteNode.Name,
|
|
remoteNode.OperatorNodeID,
|
|
remoteNode.SoapReplicationURL,
|
|
response,
|
|
highWaterMarks.ToString() );
|
|
#endif
|
|
//
|
|
// Communications Error
|
|
//
|
|
UDDIText message = new UDDIText( "UDDI_ERROR_REPLICATION_OPERATOR_COMMUNICATION_ERROR",
|
|
remoteNode.Name,
|
|
remoteNode.OperatorNodeID,
|
|
remoteNode.SoapReplicationURL,
|
|
response,
|
|
highWaterMarks.ToString() );
|
|
Debug.OperatorMessage(
|
|
SeverityType.Error,
|
|
CategoryType.Replication,
|
|
OperatorMessageType.ErrorCommunicatingWithNode,
|
|
message.GetText() );
|
|
|
|
Debug.OperatorMail(
|
|
SeverityType.Error,
|
|
CategoryType.Replication,
|
|
OperatorMessageType.ErrorCommunicatingWithNode,
|
|
message.GetText() );
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/// ****************************************************************
|
|
/// public LogValidationError [static]
|
|
/// ----------------------------------------------------------------
|
|
/// <summary>
|
|
/// </summary>
|
|
/// ****************************************************************
|
|
///
|
|
public static ReplicationResult LogValidationError( OperatorNode remoteNode, ChangeRecord changeRecord, Exception e, ChangeRecordVectorCollection changesAlreadySeen )
|
|
{
|
|
ReplicationResult result = new ReplicationResult();
|
|
|
|
result.ReplicationStatus = ReplicationStatus.ValidationError;
|
|
result.Description = e.ToString();
|
|
result.OperatorNodeID = remoteNode.OperatorNodeID;
|
|
result.LastNodeID = changeRecord.ChangeID.NodeID;
|
|
result.LastUSN = changeRecord.ChangeID.OriginatingUSN;
|
|
result.LastChange = DateTime.UtcNow.Ticks;
|
|
|
|
result.Save();
|
|
|
|
//
|
|
// Also send the highwater marks.
|
|
//
|
|
StringWriter highWaterMarks = new StringWriter();
|
|
|
|
foreach( ChangeRecordVector vector in changesAlreadySeen )
|
|
{
|
|
highWaterMarks.Write( " {" );
|
|
highWaterMarks.Write( vector.NodeID );
|
|
highWaterMarks.Write( "} : " );
|
|
highWaterMarks.WriteLine( vector.OriginatingUSN );
|
|
}
|
|
#if never
|
|
string message = String.Format(
|
|
"Could not process entity from remote operator.\r\n\r\n" +
|
|
"REPLICATION NODE:\r\n" +
|
|
" {0}\r\n" +
|
|
" {{{1}}}\r\n" +
|
|
" {2}\r\n\r\n" +
|
|
"DETAILS:\r\n\r\n" +
|
|
"{3}\r\n\r\n" +
|
|
"CHANGE RECORD:\r\n" +
|
|
" {{{4}}} : {5}\r\n\r\n" +
|
|
"{6}\r\n\r\nCURRENT HIGHWATER MARKS:\r\n\r\n{7}",
|
|
remoteNode.Name,
|
|
remoteNode.OperatorNodeID,
|
|
remoteNode.SoapReplicationURL,
|
|
e.ToString(),
|
|
changeRecord.ChangeID.NodeID,
|
|
changeRecord.ChangeID.OriginatingUSN,
|
|
changeRecord.ToString(),
|
|
highWaterMarks.ToString() );
|
|
#endif
|
|
UDDIText message = new UDDIText( "UDDI_ERROR_REPLICATION_COULD_NOT_PROCESS_ENTITY",
|
|
remoteNode.Name,
|
|
remoteNode.OperatorNodeID,
|
|
remoteNode.SoapReplicationURL,
|
|
e.ToString(),
|
|
changeRecord.ChangeID.NodeID,
|
|
changeRecord.ChangeID.OriginatingUSN,
|
|
changeRecord.ToString(),
|
|
highWaterMarks.ToString() );
|
|
Debug.OperatorMessage(
|
|
SeverityType.Error,
|
|
CategoryType.Replication,
|
|
OperatorMessageType.ValidationError,
|
|
message.GetText() );
|
|
|
|
Debug.OperatorMail(
|
|
SeverityType.Error,
|
|
CategoryType.Replication,
|
|
OperatorMessageType.ValidationError,
|
|
message.GetText() );
|
|
|
|
return result;
|
|
}
|
|
|
|
public static void LogInvalidKeyWarning( OperatorNode remoteNode, ChangeRecord changeRecord, Exception e )
|
|
{
|
|
ReplicationResult result = new ReplicationResult();
|
|
|
|
result.ReplicationStatus = ReplicationStatus.CommunicationError;
|
|
result.Description = e.ToString();
|
|
result.OperatorNodeID = remoteNode.OperatorNodeID;
|
|
result.LastNodeID = changeRecord.ChangeID.NodeID;
|
|
result.LastUSN = changeRecord.ChangeID.OriginatingUSN;
|
|
result.LastChange = DateTime.UtcNow.Ticks;
|
|
|
|
result.Save();
|
|
#if never
|
|
string message = String.Format(
|
|
"Invalid key from remote operator.\r\n\r\n" +
|
|
"REPLICATION NODE:\r\n" +
|
|
" {0}\r\n" +
|
|
" {{{1}}}\r\n" +
|
|
" {2}\r\n\r\n" +
|
|
"DETAILS:\r\n\r\n" +
|
|
"{3}\r\n\r\n" +
|
|
"CHANGE RECORD:\r\n" +
|
|
" {{{4}}} : {5}\r\n\r\n" +
|
|
"{6}",
|
|
remoteNode.Name,
|
|
remoteNode.OperatorNodeID,
|
|
remoteNode.SoapReplicationURL,
|
|
e.ToString(),
|
|
changeRecord.ChangeID.NodeID,
|
|
changeRecord.ChangeID.OriginatingUSN,
|
|
changeRecord.ToString() );
|
|
#endif
|
|
UDDIText message = new UDDIText( "UDDI_ERROR_REPLICATION_INVALID_KEY",
|
|
remoteNode.Name,
|
|
remoteNode.OperatorNodeID,
|
|
remoteNode.SoapReplicationURL,
|
|
e.ToString(),
|
|
changeRecord.ChangeID.NodeID,
|
|
changeRecord.ChangeID.OriginatingUSN,
|
|
changeRecord.ToString() );
|
|
Debug.OperatorMessage(
|
|
SeverityType.Warning,
|
|
CategoryType.Replication,
|
|
OperatorMessageType.InvalidKey,
|
|
message.GetText() );
|
|
|
|
//
|
|
// TODO for now don't send mail on a warning.
|
|
//
|
|
#if never
|
|
Debug.OperatorMail(
|
|
SeverityType.Error,
|
|
CategoryType.Replication,
|
|
OperatorMessageType.ValidationError,
|
|
message );
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
/// ********************************************************************
|
|
/// class ReplicationSoapClient
|
|
/// --------------------------------------------------------------------
|
|
/// <summary>
|
|
/// </summary>
|
|
/// ********************************************************************
|
|
///
|
|
[ WebServiceBinding( Name="ExternalMessagesSoap", Namespace=UDDI.Replication.Constants.Namespace ) ]
|
|
internal sealed class ReplicationSoapClient : SoapHttpClientProtocol
|
|
{
|
|
/// ****************************************************************
|
|
/// public GetChangeRecords
|
|
/// ----------------------------------------------------------------
|
|
/// <summary>
|
|
/// </summary>
|
|
/// ****************************************************************
|
|
///
|
|
[ System.Diagnostics.DebuggerStepThrough ]
|
|
[ SoapDocumentMethod( "", Use=SoapBindingUse.Literal, ParameterStyle=SoapParameterStyle.Bare ) ]
|
|
[ return: XmlElement( "changeRecords", Namespace=UDDI.Replication.Constants.Namespace, IsNullable=false ) ]
|
|
public ChangeRecordDetail GetChangeRecords( GetChangeRecords get_changeRecords )
|
|
{
|
|
object[] results = Invoke( "GetChangeRecords", new object[] { get_changeRecords } );
|
|
return (ChangeRecordDetail)results[ 0 ];
|
|
}
|
|
|
|
protected override WebRequest GetWebRequest( Uri uri )
|
|
{
|
|
WebRequest innerWebRequest = base.GetWebRequest( uri );
|
|
UDDIWebRequest webRequest = new UDDIWebRequest( innerWebRequest );
|
|
|
|
return webRequest;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// UDDIWebResponse allows us to return our own Stream object.
|
|
/// </summary>
|
|
internal class UDDIWebResponse : WebResponse
|
|
{
|
|
WebResponse innerWebResponse;
|
|
UDDIResponseStream uddiResponseStream;
|
|
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
/// <param name="innerWebResponse">This object should come from the WebResponse created by HttpSoapClientProtocol.</param>
|
|
public UDDIWebResponse( WebResponse innerWebResponse )
|
|
{
|
|
this.innerWebResponse = innerWebResponse;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Return our response stream (UDDIResponseStream) instead of the Stream associated with our inner response.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public override Stream GetResponseStream()
|
|
{
|
|
if( null == uddiResponseStream )
|
|
{
|
|
uddiResponseStream = new UDDIResponseStream( innerWebResponse.GetResponseStream() );
|
|
}
|
|
|
|
return uddiResponseStream;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delegates to the inner web response.
|
|
/// </summary>
|
|
public override void Close()
|
|
{
|
|
innerWebResponse.Close();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delegates to the inner web response.
|
|
/// </summary>
|
|
public override long ContentLength
|
|
{
|
|
get { return innerWebResponse.ContentLength; }
|
|
set { innerWebResponse.ContentLength = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delegates to the inner web response.
|
|
/// </summary>
|
|
public override string ContentType
|
|
{
|
|
get { return innerWebResponse.ContentType; }
|
|
set { innerWebResponse.ContentType = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delegates to the inner web response.
|
|
/// </summary>
|
|
public override Uri ResponseUri
|
|
{
|
|
get { return innerWebResponse.ResponseUri; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delegates to the inner web response.
|
|
/// </summary>
|
|
public override WebHeaderCollection Headers
|
|
{
|
|
get { return innerWebResponse.Headers; }
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// UDDIResponseStream allows us to manipulate the XML sent back from the web service.
|
|
/// </summary>
|
|
internal class UDDIResponseStream : MemoryStream
|
|
{
|
|
//
|
|
// TODO: at some point it may be necessary to pass in the current version as a parameter if the transforms become
|
|
// more complicated.
|
|
//
|
|
|
|
/// <summary>
|
|
/// Constructor. We read all the XML sent from the server, do our version manipulation, then write the new XML
|
|
/// into our inner responseStream object.
|
|
/// </summary>
|
|
/// <param name="responseStream">This object should be the responseStream from a WebResponse object.</param>
|
|
public UDDIResponseStream( Stream responseStream )
|
|
{
|
|
try
|
|
{
|
|
//
|
|
// Get the XML the server sent to us.
|
|
//
|
|
StreamReader reader = new StreamReader( responseStream );
|
|
string responseXml = reader.ReadToEnd();
|
|
reader.Close();
|
|
|
|
//
|
|
// Write this transformed XML into ourselves.
|
|
//
|
|
StreamUtility.WriteStringToStream( this, responseXml );
|
|
|
|
//
|
|
// Rewind ourselves
|
|
//
|
|
this.Position = 0;
|
|
|
|
//
|
|
// Validate the incoming XML. We have to read the data from the stream first because it is not seekable
|
|
//
|
|
try
|
|
{
|
|
SchemaCollection.Validate( this );
|
|
}
|
|
catch( XmlSchemaException schemaException )
|
|
{
|
|
string message = schemaException.ToString() + "\r\n\r\nResponse XML:\r\n\r\n" + responseXml;
|
|
Debug.OperatorMessage( SeverityType.Error, CategoryType.Replication, OperatorMessageType.ValidationError, message );
|
|
|
|
throw schemaException;
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
//
|
|
// Rewind ourselves
|
|
//
|
|
this.Position = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// UDDIWebRequest allows us to return our own request and response objects.
|
|
/// </summary>
|
|
/// <summary>
|
|
/// UDDIWebRequest allows us to return our own request and response objects.
|
|
/// </summary>
|
|
internal class UDDIWebRequest : WebRequest
|
|
{
|
|
WebRequest innerWebRequest;
|
|
UDDIRequestStream uddiRequestStream;
|
|
UDDIWebResponse uddiWebResponse;
|
|
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
/// <param name="uri">Uri to the web service we are calling</param>
|
|
/// <param name="uddiVersion">UDDI version to use for requests</param>
|
|
public UDDIWebRequest( WebRequest innerWebRequest )
|
|
{
|
|
this.innerWebRequest = innerWebRequest;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Return a UDDIRequestStream object instead of the default one.
|
|
/// </summary>
|
|
/// <returns>UDDIRequestStream object</returns>
|
|
public override Stream GetRequestStream()
|
|
{
|
|
if( null == uddiRequestStream )
|
|
{
|
|
uddiRequestStream = new UDDIRequestStream( innerWebRequest.GetRequestStream() );
|
|
}
|
|
|
|
return uddiRequestStream;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Return a UDDIWebRequest object instead of the default one.
|
|
/// </summary>
|
|
/// <returns>UDDIWebResponse object</returns>
|
|
public override WebResponse GetResponse()
|
|
{
|
|
if( null == uddiWebResponse )
|
|
{
|
|
uddiWebResponse = new UDDIWebResponse( innerWebRequest.GetResponse() );
|
|
}
|
|
return uddiWebResponse;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delegates to our inner WebRequest
|
|
/// </summary>
|
|
public override string Method
|
|
{
|
|
get { return innerWebRequest.Method; }
|
|
set { innerWebRequest.Method = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delegates to our inner WebRequest
|
|
/// </summary>
|
|
public override Uri RequestUri
|
|
{
|
|
get { return innerWebRequest.RequestUri; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delegates to our inner WebRequest
|
|
/// </summary>
|
|
public override string ConnectionGroupName
|
|
{
|
|
get { return innerWebRequest.ConnectionGroupName; }
|
|
set { innerWebRequest.ConnectionGroupName = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delegates to our inner WebRequest
|
|
/// </summary>
|
|
public override WebHeaderCollection Headers
|
|
{
|
|
get { return innerWebRequest.Headers; }
|
|
set { innerWebRequest.Headers = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delegates to our inner WebRequest
|
|
/// </summary>
|
|
public override long ContentLength
|
|
{
|
|
get { return innerWebRequest.ContentLength; }
|
|
set { innerWebRequest.ContentLength = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delegates to our inner WebRequest
|
|
/// </summary>
|
|
public override string ContentType
|
|
{
|
|
get { return innerWebRequest.ContentType; }
|
|
set { innerWebRequest.ContentType = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delegates to our inner WebRequest
|
|
/// </summary>
|
|
public override ICredentials Credentials
|
|
{
|
|
get { return innerWebRequest.Credentials; }
|
|
set { innerWebRequest.Credentials = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delegates to our inner WebRequest
|
|
/// </summary>
|
|
public override IWebProxy Proxy
|
|
{
|
|
get { return innerWebRequest.Proxy; }
|
|
set { innerWebRequest.Proxy = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delegates to our inner WebRequest
|
|
/// </summary>
|
|
public override bool PreAuthenticate
|
|
{
|
|
get { return innerWebRequest.PreAuthenticate; }
|
|
set { innerWebRequest.PreAuthenticate = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delegates to our inner WebRequest
|
|
/// </summary>
|
|
public override int Timeout
|
|
{
|
|
get { return innerWebRequest.Timeout; }
|
|
set { innerWebRequest.Timeout = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delegates to our inner WebRequest
|
|
/// </summary>
|
|
public override IAsyncResult BeginGetResponse(AsyncCallback callback, object state)
|
|
{
|
|
return innerWebRequest.BeginGetResponse( callback, state );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delegates to our inner WebRequest
|
|
/// </summary>
|
|
public override WebResponse EndGetResponse(IAsyncResult asyncResult)
|
|
{
|
|
return innerWebRequest.EndGetResponse( asyncResult );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delegates to our inner WebRequest
|
|
/// </summary>
|
|
public override IAsyncResult BeginGetRequestStream(AsyncCallback callback, Object state)
|
|
{
|
|
return innerWebRequest.BeginGetRequestStream( callback, state );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delegates to our inner WebRequest
|
|
/// </summary>
|
|
public override Stream EndGetRequestStream(IAsyncResult asyncResult)
|
|
{
|
|
return innerWebRequest.EndGetRequestStream( asyncResult );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delegates to our inner WebRequest
|
|
/// </summary>
|
|
public override void Abort()
|
|
{
|
|
innerWebRequest.Abort();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// UDDIRequestStream allows us to manipulate the XML before we send it to the client. This class will accept all data that
|
|
/// is written to it from the ASP.NET web service framework. When the framework closes the stream (ie. wants to send the data), we
|
|
/// will manipulate this XML so that it has the right UDDI version, then send it out using our innerStream object.
|
|
/// </summary>
|
|
internal class UDDIRequestStream : MemoryStream
|
|
{
|
|
Stream innerStream;
|
|
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
/// <param name="innerStream">Should be from a WebRequest object.</param>
|
|
/// <param name="uddiVersion">The UDD version we should use to send to the server</param>
|
|
public UDDIRequestStream( Stream innerStream )
|
|
{
|
|
this.innerStream = innerStream;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Before we actually close the request stream, we want to manipulate the XML.
|
|
/// </summary>
|
|
public override void Close()
|
|
{
|
|
try
|
|
{
|
|
//
|
|
// Rewind ourselves.
|
|
//
|
|
this.Position = 0;
|
|
|
|
//
|
|
// Read the XML that was written; this is the XML request that will be sent to the UDDI server.
|
|
//
|
|
StreamReader reader = new StreamReader( this );
|
|
string requestXml = reader.ReadToEnd();
|
|
|
|
//
|
|
// Rewind ourselves.
|
|
//
|
|
this.Position = 0;
|
|
|
|
#if DEBUG
|
|
try
|
|
{
|
|
//
|
|
// Validate the XML that we are about to send.
|
|
//
|
|
SchemaCollection.Validate( this );
|
|
}
|
|
catch( XmlSchemaException schemaException )
|
|
{
|
|
string message = schemaException.ToString() + "\r\n\r\nRequest XML:\r\n\r\n" + requestXml;
|
|
Debug.OperatorMessage( SeverityType.Error, CategoryType.Replication, OperatorMessageType.ValidationError, message );
|
|
|
|
throw schemaException;
|
|
}
|
|
#endif
|
|
//
|
|
// Write the transformed data to the 'real' stream.
|
|
//
|
|
StreamUtility.WriteStringToStream( innerStream, requestXml );
|
|
}
|
|
finally
|
|
{
|
|
//
|
|
// Make sure we clean up properly.
|
|
//
|
|
innerStream.Close();
|
|
base.Close();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Simple utility class to help us write string data to Stream objects.
|
|
/// </summary>
|
|
internal sealed class StreamUtility
|
|
{
|
|
public static void WriteStringToStream( Stream stream, string stringToWrite )
|
|
{
|
|
StreamWriter writer = new StreamWriter( stream );
|
|
writer.Write( stringToWrite );
|
|
writer.Flush();
|
|
}
|
|
}
|
|
}
|