using System; using System.Collections; using System.IO; using System.Data; using System.Data.SqlClient; using System.Xml; using System.Xml.Serialization; using System.Windows.Forms; using System.Security.Principal; using Microsoft.Win32; using UDDI; using UDDI.API; using UDDI.API.Business; using UDDI.Replication; namespace UDDI.Tools { class FixDefaultURL { // // Enumerated Types // enum LogType { ConsoleAndLog, ConsoleOnly, LogOnly } // // Constants // const string LogFileName = "fixdefaulturl.log.txt"; const string ExceptionFileName = "fixdefaulturl.exceptions.txt"; // // Globals // static StreamWriter logFile; static StreamWriter exceptionsFile; static void FixDefaultURLs() { // // Get a list of business keys that have non-default discovery URLs. // ArrayList businessEntities = GetBusinessEntities(); int total = businessEntities.Count; int current = 1; int numberFixed = 0; foreach( BusinessEntity businessEntity in businessEntities ) { // // Get values for this business. // businessEntity.Get(); // // BusinessEntity.Get() may add the default one, we don't want it. // DiscoveryUrlCollection originalList = new DiscoveryUrlCollection(); originalList.Get( businessEntity.BusinessKey ); businessEntity.DiscoveryUrls = originalList; Log( "*** Processing " + current++ + "/" + total + " *** " ); LogStartBusinessEntity( businessEntity ); DiscoveryUrlCollection filteredList = GetFilterList( businessEntity ); if( filteredList.Count < businessEntity.DiscoveryUrls.Count ) { try { numberFixed++; LogFixStart( filteredList ); ConnectionManager.BeginTransaction(); // // Remove duplicate discovery URLs // businessEntity.DiscoveryUrls = filteredList; // // Fix change records // FixChangeRecords( businessEntity ); // // Fix data. Saving the BusinessEntity will also create a ChangeRecordNew data in our replication stream. // Other operators will consume this change record, which will update their databases. // FixData( businessEntity ); #if never ChangeRecordNewData changeRecordNewData = new ChangeRecordNewData( businessEntity ); ChangeRecord fixData = new ChangeRecord( changeRecordNewData ); fixData.Process(); #endif ConnectionManager.Commit(); LogFixEnd( businessEntity ); } catch( Exception e) { WriteException( e ); ConnectionManager.Abort(); } } LogDoneBusinessEntity( businessEntity ); } Log( "BusinessEntities fixed: " + numberFixed ); } static void FixData( BusinessEntity businessEntity ) { Log( "\t\tSTART Fixing Data" ); // // Save the current user ID // string currentUserID = Context.User.ID; try { // // Set the current user to this user to the PUID for this business entity. // Context.User.ID = GetPUIDForBusinessEntity( businessEntity.BusinessKey ); // // Save our business // businessEntity.Save(); Log( "\t\tDONE Fixing Data" ); } finally { // // Restore the ID // Context.User.ID = currentUserID; } } static string GetPUIDForBusinessEntity( string businessKey ) { SqlStoredProcedureAccessor puidSP = new SqlStoredProcedureAccessor(); puidSP.ProcedureName = "net_getPUIDForBusinessEntity"; puidSP.Parameters.Add( "@businessKey", SqlDbType.UniqueIdentifier ); puidSP.Parameters.SetGuidFromString( "@businessKey", businessKey ); SqlDataReaderAccessor reader = puidSP.ExecuteReader(); string puid = ""; try { reader.Read(); puid = reader.GetString( 0 ); } finally { reader.Close(); } return puid; } static void FixChangeRecords( BusinessEntity businessEntity ) { // // Get all related change records // ArrayList newDataChangeRecords = GetChangeRecordsForEntity( businessEntity ); // // Create and process a correction for each change record. // Log( "\t\tSTART Processing Corrections" ); foreach( ChangeRecord changeRecord in newDataChangeRecords ) { ChangeRecord changeRecordCorrection = CreateCorrection( changeRecord, businessEntity ); changeRecordCorrection.Process(); LogChangeRecordCorrection( changeRecord, changeRecordCorrection ); } Log( "\t\tDONE Processing Corrections" ); } static ChangeRecord CreateCorrection( ChangeRecord originalChangeRecord, BusinessEntity businessEntity ) { ChangeRecordNewData changeRecordNewData = originalChangeRecord.Payload as ChangeRecordNewData; changeRecordNewData.Entity = businessEntity; ChangeRecordCorrection changeRecordCorrection = new ChangeRecordCorrection(); changeRecordCorrection.ChangeRecord = originalChangeRecord; return new ChangeRecord( changeRecordCorrection ); } static ArrayList GetChangeRecordsForEntity( BusinessEntity businessEntity ) { string contextID = Guid.NewGuid().ToString(); string operatorKey = Config.GetString( "OperatorKey" ); ArrayList changeRecords = new ArrayList(); SqlDataReaderAccessor resultsReader = null; try { // // Get all the ChangeRecordNewData change records associated with this entity. // SqlStoredProcedureAccessor findSP = new SqlStoredProcedureAccessor(); findSP.ProcedureName = "net_find_changeRecordsByChangeType"; findSP.Parameters.Add( "@contextID", SqlDbType.UniqueIdentifier ); findSP.Parameters.Add( "@operatorKey", SqlDbType.UniqueIdentifier ); findSP.Parameters.Add( "@entityKey", SqlDbType.UniqueIdentifier ); findSP.Parameters.Add( "@changeTypeID", SqlDbType.TinyInt ); findSP.Parameters.Add( "@rows", SqlDbType.Int, ParameterDirection.Output ); findSP.Parameters.SetGuidFromString( "@contextID", contextID ); findSP.Parameters.SetGuidFromString( "@operatorKey", operatorKey ); findSP.Parameters.SetGuidFromString( "@entityKey", businessEntity.BusinessKey ); findSP.Parameters.SetShort( "@changeTypeID", ( short )ChangeRecordPayloadType.ChangeRecordNewData ); findSP.ExecuteNonQuery(); // // Retrieve results // SqlStoredProcedureAccessor resultsSP = new SqlStoredProcedureAccessor(); resultsSP.ProcedureName = "net_find_changeRecords_commit"; resultsSP.Parameters.Add( "@contextID", SqlDbType.UniqueIdentifier ); resultsSP.Parameters.Add( "@responseLimitCount", SqlDbType.Int ); resultsSP.Parameters.SetGuidFromString( "@contextID", contextID ); resultsSP.Parameters.SetInt( "@responseLimitCount", 0 ); // // Read our results and create change records from them. // resultsReader = resultsSP.ExecuteReader(); while( resultsReader.Read() ) { ChangeRecord changeRecord = CreateChangeRecord( resultsReader ); if( null != changeRecord ) { changeRecords.Add( changeRecord ); } else { throw new Exception( "Could not create change record!" ); } } } catch { // // Cleanup on failure. // SqlStoredProcedureAccessor cleanupSP = new SqlStoredProcedureAccessor(); cleanupSP.ProcedureName = "net_find_changeRecords_cleanup"; cleanupSP.Parameters.Add( "@contextID", SqlDbType.UniqueIdentifier ); cleanupSP.Parameters.SetGuidFromString( "@contextID", contextID ); cleanupSP.ExecuteNonQuery(); } finally { if( null != resultsReader ) { resultsReader.Close(); } } return changeRecords; } static ChangeRecord CreateChangeRecord( SqlDataReaderAccessor reader ) { ChangeRecord changeRecord = null; XmlSerializer serializer = null; switch( (ChangeRecordPayloadType)reader.GetShort( "changeTypeID" ) ) { case ChangeRecordPayloadType.ChangeRecordNull: serializer = new XmlSerializer( typeof( ChangeRecordNull ) ); break; case ChangeRecordPayloadType.ChangeRecordNewData: serializer = new XmlSerializer( typeof( ChangeRecordNewData ) ); break; case ChangeRecordPayloadType.ChangeRecordDelete: serializer = new XmlSerializer( typeof( ChangeRecordDelete ) ); break; case ChangeRecordPayloadType.ChangeRecordPublisherAssertion: serializer = new XmlSerializer( typeof( ChangeRecordPublisherAssertion ) ); break; case ChangeRecordPayloadType.ChangeRecordHide: serializer = new XmlSerializer( typeof( ChangeRecordHide ) ); break; case ChangeRecordPayloadType.ChangeRecordDeleteAssertion: serializer = new XmlSerializer( typeof( ChangeRecordDeleteAssertion ) ); break; case ChangeRecordPayloadType.ChangeRecordAcknowledgement: serializer = new XmlSerializer( typeof( ChangeRecordAcknowledgement ) ); break; case ChangeRecordPayloadType.ChangeRecordCorrection: serializer = new XmlSerializer( typeof( ChangeRecordCorrection ) ); break; } StringReader stringReader = new StringReader( reader.GetString( "changeData" ) ); try { changeRecord = new ChangeRecord(); changeRecord.AcknowledgementRequested = ( reader.GetInt( "flag" ) & (int)ChangeRecordFlags.AcknowledgementRequested ) > 0; changeRecord.ChangeID.NodeID = reader.GetString( "OperatorKey" ); changeRecord.ChangeID.OriginatingUSN = reader.GetLong( "USN" ); ChangeRecordBase changeRecordBase = ( ChangeRecordBase ) serializer.Deserialize( stringReader ); if( changeRecordBase is ChangeRecordCorrection ) { // // The query to find change records will do correction 'fixups'. That is, the changeData of this // change record will be replaced with the changeData from the correction. The problem with this is // that the original change data will now look like a correction. To distinguish these types of // change records, we look to see if the OriginatingUSN's match. If the OriginatingUSN's match, // we want they payload of the change record in this correction. This payload will contain the // corrected data that we want. // ChangeRecordCorrection changeRecordCorrection = ( ChangeRecordCorrection ) changeRecordBase; if( changeRecordCorrection.ChangeRecord.ChangeID.OriginatingUSN == changeRecord.ChangeID.OriginatingUSN ) { changeRecordBase = changeRecordCorrection.ChangeRecord.Payload; } } changeRecord.Payload = changeRecordBase; } finally { stringReader.Close(); } return changeRecord; } static DiscoveryUrlCollection GetFilterList( BusinessEntity businessEntity ) { DiscoveryUrlCollection filterList = new DiscoveryUrlCollection(); // // Get the default URL // string defaultDiscoveryUrl= Config.GetString( "DefaultDiscoveryURL" ) + businessEntity.BusinessKey; foreach( DiscoveryUrl discoveryUrl in businessEntity.DiscoveryUrls ) { // // Do a case in-sensitive search // if( string.Compare( discoveryUrl.Value, defaultDiscoveryUrl, true ) != 0 ) { filterList.Add( discoveryUrl ); } } return filterList; } static ArrayList GetBusinessEntities() { ArrayList businessKeyList = new ArrayList(); SqlStoredProcedureAccessor sp = new SqlStoredProcedureAccessor(); sp.ProcedureName = "net_find_businessKeysWithDiscoveryURLs"; SqlDataReaderAccessor reader = sp.ExecuteReader(); ArrayList businessEntities = new ArrayList(); try { while( reader.Read() ) { BusinessEntity businessEntity = new BusinessEntity( reader.GetGuidString( 0 ) ); businessEntities.Add( businessEntity ); } } finally { reader.Close(); } return businessEntities; } [STAThread] static void Main(string[] args) { Log( "Microsoft (R) FixDefaultURL Migrate Utility", FixDefaultURL.LogType.ConsoleOnly ); Log( "Copyright (C) Microsoft Corp. 2002. All rights reserved.\n", FixDefaultURL.LogType.ConsoleOnly ); try { // // Process command line arguments // ProcessCommandLineArgs( args ); // // Init // Initialize(); // // Fix our URLs // FixDefaultURLs(); } catch( Exception e ) { WriteException( "Uncaught exception: " + e.ToString() ); } finally { logFile.Close(); if( null != exceptionsFile ) { exceptionsFile.Close(); } } } static void ProcessCommandLineArgs( string[] commandLineArgs ) { // // No command line args. // } static bool ValidatePublisher() { bool validPublisher = Context.User.IsRegistered; // // Make sure the user is a UDDI publisher. // if( false == validPublisher ) { DialogResult dialogResult = MessageBox.Show( "You are not registered as a publisher on this UDDI Site? You must register before performing this operation. Would you like to register now?", "UDDI", MessageBoxButtons.YesNo ); if( DialogResult.Yes == dialogResult ) { try { Context.User.Register(); validPublisher = Context.User.IsRegistered; } catch( Exception registrationException ) { MessageBox.Show( "An exception occurred when trying to register:\r\n\r\n" + registrationException.ToString() ); } } } return validPublisher; } static void Initialize() { // // Open a connection to our UDDI database. // ConnectionManager.Open( true, false ); // // Create our log file. // logFile = new StreamWriter( File.Open( LogFileName, FileMode.Append, FileAccess.Write, FileShare.Read ) ); logFile.WriteLine( "--------------------- STARTING NEW LOG (" + DateTime.Now.ToString() + ")--------------------- " ); // // Get UDDI site configuration settings. // Config.Refresh(); // // Make sure the user is allowed to run this program. // WindowsIdentity identity = WindowsIdentity.GetCurrent(); WindowsPrincipal principal = new WindowsPrincipal( identity ); Context.User.SetRole( principal ); if( !Context.User.IsAdministrator ) { MessageBox.Show( "Access denied.\r\n\r\nThis program must be executed by a member of the '" + Config.GetString( "GroupName.Administrators" ) + "'\r\ngroup. The current user '" + identity.Name + "' is not a member of this group." ); return; } // // Make sure the user is a valid publisher. // if( false == ValidatePublisher() ) { Log( "You must be a UDDI publisher in order to run this program", LogType.ConsoleOnly ); System.Environment.Exit( 1 ); } } static void WriteException( Exception e ) { WriteException( e.ToString() ); } static void WriteException( string msg ) { if( null == exceptionsFile ) { // // Create our exceptions file. // exceptionsFile = new StreamWriter( File.Open( ExceptionFileName, FileMode.Append, FileAccess.Write, FileShare.Read ) ); exceptionsFile.WriteLine( "--------------------- STARTING NEW LOG (" + DateTime.Now.ToString() + ")--------------------- " ); } Log( exceptionsFile, msg, LogType.ConsoleAndLog ); } static void Log( string message ) { Log( message, LogType.ConsoleAndLog ); } static void Log( string message, LogType logType ) { Log( logFile, message, logType ); } static void Log( StreamWriter log, string message, LogType logType ) { switch ( logType ) { case LogType.ConsoleAndLog: { Console.WriteLine( message ); log.WriteLine( "{0}: {1}", DateTime.Now.ToLongTimeString(), message ); break; } case LogType.ConsoleOnly: { Console.WriteLine( message ); break; } default: { log.WriteLine( "{0}: {1}", DateTime.Now.ToLongTimeString(), message ); break; } } } private static string Serialize( object obj ) { UTF8EncodedStringWriter stringWriter = new UTF8EncodedStringWriter(); try { XmlSerializer serializer = new XmlSerializer( obj.GetType() ); XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces(); namespaces.Add( "", "urn:uddi-org:api_v2" ); serializer.Serialize( stringWriter, obj, namespaces ); } finally { stringWriter.Close(); } return stringWriter.ToString(); } static void LogStartBusinessEntity( BusinessEntity businessEntity ) { Log( "START Examining: " + businessEntity.BusinessKey ); Log( "\tOriginal DiscoveryUrls:" ); foreach( DiscoveryUrl discoveryUrl in businessEntity.DiscoveryUrls ) { Log( "\t\t" + discoveryUrl.Value ); } } static void LogDoneBusinessEntity( BusinessEntity businessEntity ) { Log( "DONE Examining: " + businessEntity.BusinessKey ); } static void LogFixStart( DiscoveryUrlCollection filteredList ) { Log( "\tSTART Fixing duplicates; new DiscoveryUrl list will be:" ); if( filteredList.Count == 0 ) { Log( "\t\tNo Discovery Urls besides default." ); } else { foreach( DiscoveryUrl discoveryUrl in filteredList ) { Log( "\t\t" + discoveryUrl.Value ); } } } static void LogFixEnd( BusinessEntity businessEntity ) { Log( "\tDONE Fixing duplicates" ); } static void LogChangeRecordCorrection( ChangeRecord changeRecord, ChangeRecord changeRecordCorrection ) { Log( "\t\t\tCorrecting USN: " + changeRecord.ChangeID.OriginatingUSN ); } } }