-- Ten skrypt konfiguruje bazę nadawcy z przykładu ilustrującego rejestrowanie zdalnych loginów.  
-- Używana jest tu metoda przesyłania danych przedstawiona w rozdziale.

CREATE DATABASE LogSendExample
GO
USE LogSendExample
GO
-- Bazy Service Brokera zawsze potrzebują głównego klucza szyfrowania
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'YourSecurePassword1!'
GO
-- Będziemy przełączać się między bazami. Dla uproszczenia nie konfigurujemy zabezpieczeń Service Brokera
-- i certyfikatów, dlatego bazy muszą być zaufane
ALTER DATABASE LogSendExample SET TRUSTWORTHY ON
GO
-- Możesz nie potrzebować tego kodu, jest on jednak wymagany, jeśli nie jesteś połączony z domeną.
-- Używamy tu konta SA, jednak można też wykorzystać konto uwierzytelnionego użytkownika z systemu SQL Server
ALTER AUTHORIZATION ON DATABASE::LogSendExample TO SA
GO

-- Tworzenie obiektów potrzebnych do nawiązania konwersacji z serwerem

CREATE MESSAGE TYPE LoginMessage
AUTHORIZATION dbo
VALIDATION = NONE
GO

CREATE CONTRACT LoginContract
AUTHORIZATION dbo
(LoginMessage SENT BY ANY)
GO

-- Ta procedura obsługuję kolejkę serwera inicjującego. Tu serwer nie wysyła odpowiedzi, dlatego jedyne
-- typy komunikatów, które trzeba obsłużyć, to błędy i koniec konwersacji
CREATE PROCEDURE dbo.SendQueueHandler
AS
BEGIN -- SendQueueHandler
	DECLARE  @dialog_handle UNIQUEIDENTIFIER, @messagetype nvarchar(128);
	WHILE (1 = 1)
		BEGIN	
		BEGIN TRY
		BEGIN TRANSACTION;

			RECEIVE TOP (1) @dialog_handle = [conversation_handle], 
				 @messagetype = [message_type_name]
			FROM LoginSendQueue
			IF @@ROWCOUNT = 0 
				BEGIN
					COMMIT TRANSACTION;
					BREAK;
				END
			ELSE IF @messagetype = N'http://schemas.microsoft.com/SQL/ServiceBroker/Error'
				BEGIN
					-- Rejestrowanie błędu w dzienniku aplikacji
					END CONVERSATION @dialog_handle;
					COMMIT TRANSACTION;
					BREAK;
				END
			ELSE IF @messagetype = N'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'
				BEGIN
					END CONVERSATION @dialog_handle;
					COMMIT TRANSACTION;
					BREAK;
				END
		END TRY 
		Begin Catch
			Rollback Transaction;
			DECLARE @ErrorMessage NVARCHAR(4000);
			DECLARE @ErrorSeverity INT;
			DECLARE @ErrorState INT;
			DECLARE @ErrorNumber INT;
			DECLARE @ErrorLine INT;
			DECLARE @ErrorProcedure NVARCHAR(128);
			SET		@ErrorLine = ERROR_LINE();
			SET		@ErrorSeverity = ERROR_SEVERITY();
			SET		@ErrorState = ERROR_STATE();
			SET		@ErrorNumber = ERROR_NUMBER();
			SET		@ErrorMessage = ERROR_MESSAGE();
			SET		@ErrorProcedure = ISNULL(ERROR_PROCEDURE(), 'None');
			RAISERROR (99123, @ErrorSeverity, 1 , @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine, @ErrorMessage);
		End Catch;
	END -- WHILE
END -- SendQueueHandler
GO


-- Kolejka serwera inicjującego odbiera tylko komunikaty systemowe
CREATE QUEUE LoginSendQueue
WITH STATUS=ON,
     RETENTION=OFF,
     ACTIVATION
         (STATUS=ON,
          PROCEDURE_NAME=dbo.SendQueueHandler,
          MAX_QUEUE_READERS=2,
          EXECUTE AS OWNER),
     POISON_MESSAGE_HANDLING (STATUS = ON);
GO

CREATE SERVICE LoginSendSvc
AUTHORIZATION dbo
ON QUEUE dbo.LoginSendQueue
(LoginContract)
GO

-- Ta tabela przechowuje uchwyty konwersacji z serwerem.
-- Zapisanie ich w tabeli pozwala na ich ponowne wykorzystanie
CREATE TABLE dbo.SSB_Settings
([Source] sysname NOT NULL,
[Destination] sysname NOT NULL,
[Contract] sysname NOT NULL,
[dialog_handle] uniqueidentifier 
CONSTRAINT PK_SSB_Setting PRIMARY KEY ([Source], [Destination], [Contract]))
GO

-- Ta procedura wysyła rekordy z danymi o loginach na serwer
CREATE PROCEDURE dbo.SendUserLog
     @Destination sysname,
     @Source sysname,
     @Contract sysname,
     @MessageType sysname,
     @MessageBody varchar(MAX)
AS
DECLARE      @dialog_handle uniqueidentifier

BEGIN TRANSACTION

/* Pobieranie identyfikatora konwersacji */
SELECT @dialog_handle = dialog_handle
FROM dbo.SSB_Settings 
WHERE [Source] = @Source 
     AND [Destination] = @Destination 
     AND [Contract] = @Contract;
/* Jeśli nie istnieje aktualny uchwyt, należy utworzyć nową konwersację */
IF @dialog_handle IS NULL 
BEGIN
     /* Jeśli utworzono uchwyt konwersacji, należy zasygnalizować odbiorcy, że
        poprzednia konwersacja została zakończona */
     IF @dialog_handle IS NOT NULL
     BEGIN
          UPDATE dbo.SSB_Settings 
          SET dialog_handle = NULL
          WHERE [Source] = @Source
               AND [Destination] = @Destination 
               AND [Contract] = @Contract;
          SEND ON CONVERSATION @dialog_handle
          MESSAGE TYPE EndOfConversation;
     END
     /* Konfigurowanie nowej konwersacji */
     BEGIN DIALOG CONVERSATION @dialog_handle
     FROM SERVICE @Source
     TO SERVICE @Destination
     ON CONTRACT @Contract;
     /* Zapisywanie identyfikatora nowej konwersacji */
     UPDATE dbo.SSB_Settings 
          SET dialog_handle = @dialog_handle 
     WHERE [Source] = @Source
          AND [Destination] = @Destination 
          AND [Contract] = @Contract;
	 -- Jeśli w trakcie aktualizacji nie znaleziono potrzebnego rekordu, należy go dodać
     IF @@ROWCOUNT = 0
          INSERT INTO dbo.SSB_Settings 
           ([Source], [Destination], [Contract], [dialog_handle])
          VALUES
           (@Source, @Destination, @Contract, @dialog_handle);
END;
/* Wysyłanie komunikatu */
SEND ON CONVERSATION @dialog_handle
MESSAGE TYPE @MessageType
(@MessageBody);

COMMIT TRANSACTION
GO
