Die Windows Azure AppFabric ist eine äußerst leistungsfähige Kommunikations- und Integrationsplattform, die als Cloud Service im Rahmen der Windows Azure Platform von Microsoft bereitgestellt wird. Dabei setzt Microsoft auf Standard-Schnittstellen, so dass es leicht möglich ist, Java und .NET mit Hilfe der AppFabric miteinander kommunizieren zu lassen. Der Aufbau genau diesen Szenarios ist Gegenstand der folgenden Abschnitte.

Es geht also um den Aufbau des folgenden Szenarios:

Kommunikation von Java mit .NET via Service Bus

Abb 1: Szenario: Kommunikation eines Java Client mit einem .NET Service

Ein Java Client soll über den Windows Azure AppFabric Service Bus Nachrichten an einen .NET Service schicken können. Die Entwicklung dieses Szenarios erfolgt in folgenden Schritten:

  • Anlegen eines Windows Azure AppFabric Namespace
  • Vorbereiten der Entwicklungsumgebung
  • Implementierung des .NET Service
  • Implementierung des Java Client
     

Anlegen eines Windows Azure AppFabric Namespace

Zunächst ist es erforderlich einen neuen Namespace anzulegen. Unter diesem wird später der Endpunkt des Message Buffers registriert, d.h. Client und Server werden für das Versenden bzw. Empfangen den Endpunkt ansprechen. Der Namespace kann im Azure Management Portal über die Ribbon-Schaltfläche New Namespace angelegt werden.

Anlegen eines neuen Namespace

Abb 2: Anlegen eines neuen Namespace

Rechts unten im Portal sieht man nach dem Anlegen des Namespace einen Bereich “Default Key”, in dem eine Schaltfläche “View” angezeigt wird.

Owner und Schlüssel de neuen Namespace

Abb 3: Owner und Schlüssel de neuen Namespace

Klickt man diese Schaltfläche, erhält man den Owner und den Zugriffsschlüssel, die beim Zugriff auf den Namespace angegeben werden müssen, d.h. diese beiden Angaben werden später noch benötigt.

Damit die das Anlegen des Namespace abgeschlossen.

Vorbereiten der Entwicklungsumgebung

Für die Implementierung des .NET Service sollte das Windows Azure AppFabric SDK auf dem Entwicklungsrechner installiert sein.

Für den Java Client wird das Windows Azure AppFabric SDK for Java Developers benötigt. Dieses steht einmal als Quellcode und einmal als Binary zur Verfügung. Daneben müssen noch folgende Pakete installiert sein:

Als Entwicklungsumgebung für Java kommt Eclipse zum Einsatz. Abschließend müssen noch folgende Umgebungsvariablen gesetzt werden:

   1: set JAVA_HOME=C:\Program Files (x86)\Java\jdk1.6.0_20
   2: set ANT_HOME=c:\Dev\apache-ant-1.8.2-bin
   3: set PATH=%PATH%;%ANT_HOME%\bin

Listing 1: Umgebungsvariablen für Java

Die Variablen sollten dabei natürlich auf die auf der Entwicklungsmaschine gültigen Werte gesetzt werden.

Damit ist die Entwicklungsumgebung bereit, und mit der Implementierung kann losgelegt werden.

Implementierung des .NET Service

Der .NET Service soll als einfache Konsolenanwendung angelegt werden, die in regelmäßigen Zeitabständen am Service Bus nachsieht, ob in dem festgelegten Message Buffer eine Nachricht vorhanden ist. Legen Sie nun in Visual Studio eine neue Konsolenanwendung an (File –> New… –> Project… –> Windows –> Console Application).

Fügen Sie dieser Konsolenanwendung Referenzen auf

  • Microsoft.ServiceBus
  • System.ServiceModel
  • System.Runtime.Serialization
     

hinzu. Beachten Sie, dass Visual Studio bei diesem Schritt das Target Framework von “.NET Framework 4 Client Profile” auf “.NET Framework 4” konvertiert.

Nun geht es an die Implementierung der Konsolenanwendung. Der Anwendung müssen erst mal die Informationen des für die Kommunikation benötigten Message Buffer mitgegeben werden. Ich handhabe das gerne so, dass ich diese Informationen in eine Resource-Datei (muss dazu natürlich angelegt werden) schreibe. Nach Hinzufügen einer solchen Datei können die Message Buffer Informationen analog Abb 4 eingetragen werden.

 Resource-Einträge für den Service Bus Message Buffer

Abb 4: Resource-Einträge für den Service Bus Message Buffer

Der folgende Programmcode lehnt sich sehr stark an die Ausführungen in der MSDN-Library zum Message Buffer an und zeigt die Implementierung der Konsolenanwendung.

   1: using System;
   2: using System.ServiceModel;
   3: using System.ServiceModel.Channels;
   4: using System.Threading;
   5: using Microsoft.ServiceBus;
   6:  
   7: namespace AppFabricMessagBufferService14
   8: {
   9:     class Program
  10:     {
  11:         private static void Main()
  12:         {
  13:             string serviceNamespace = Resource.serviceNamespace;
  14:             string issuerName = Resource.issuerName;
  15:             string issuerKey = Resource.issuerKey;
  16:  
  17:             // Endpoint Credentials
  18:             TransportClientEndpointBehavior endpointBehavior = new TransportClientEndpointBehavior();
  19:             endpointBehavior.CredentialType = TransportClientCredentialType.SharedSecret;
  20:             endpointBehavior.Credentials.SharedSecret.IssuerName = issuerName;
  21:             endpointBehavior.Credentials.SharedSecret.IssuerSecret = issuerKey;
  22:  
  23:             // Get Message Buffer URI            
  24:             Uri messageBufferUri = ServiceBusEnvironment.CreateServiceUri("https", serviceNamespace, "TestMessageBuffer");
  25:             Console.WriteLine("Message Buffer Address:\n " + messageBufferUri.AbsoluteUri);
  26:             Console.WriteLine();
  27:  
  28:             // Message Buffer Policy
  29:             MessageBufferPolicy messageBufferPolicy = new MessageBufferPolicy();
  30:             messageBufferPolicy.Authorization = AuthorizationPolicy.Required;
  31:             messageBufferPolicy.MaxMessageCount = 10;
  32:             messageBufferPolicy.ExpiresAfter = TimeSpan.FromHours(1); // messages in the message buffer expire after 1 hour
  33:             messageBufferPolicy.TransportProtection = TransportProtectionPolicy.None;
  34:  
  35:             MessageBufferClient messageBufferClient = EnsureMessageBufferExists(endpointBehavior, messageBufferUri, ref messageBufferPolicy);
  36:  
  37:             while (true)
  38:             {
  39:                 try
  40:                 {
  41:                     //Message message = messageBufferClient.PeekLock();
  42:                     Message message = messageBufferClient.Retrieve();
  43:  
  44:                     if (message != null)
  45:                     {
  46:                         //Console.WriteLine("Message:");
  47:                         Console.WriteLine(message.GetBody<string>());
  48:  
  49:                         //messageBufferClient.ReleaseLock(message);
  50:                     }
  51:                 }
  52:                 catch (TimeoutException)
  53:                 {
  54:                     //Console.WriteLine("No pending orders...");
  55:                 }
  56:                 catch (FaultException)
  57:                 {
  58:                 }
  59:  
  60:                 //Console.WriteLine("Sleeping...");
  61:                 Thread.Sleep(1000);
  62:             }
  63:         }
  64:  
  65:         private static MessageBufferClient EnsureMessageBufferExists(TransportClientEndpointBehavior endpointBehavior, Uri messageBufferUri, ref MessageBufferPolicy messageBufferPolicy)
  66:         {
  67:             MessageBufferClient client;
  68:  
  69:             try
  70:             {
  71:                 client = MessageBufferClient.GetMessageBuffer(endpointBehavior, messageBufferUri);
  72:                 messageBufferPolicy = client.GetPolicy();
  73:                 Console.WriteLine("Using existing message buffer.");
  74:                 return client;
  75:             }
  76:             catch (EndpointNotFoundException)
  77:             {
  78:                 // Not found; absorb and make a new message buffer below. 
  79:                 // Other exceptions get bubbled up.
  80:             }
  81:             catch (FaultException)
  82:             {
  83:             }
  84:  
  85:             client = MessageBufferClient.CreateMessageBuffer(endpointBehavior, messageBufferUri, messageBufferPolicy);
  86:             Console.WriteLine("New message buffer created.");
  87:             return client;
  88:         }
  89:     }
  90: }

Listing 2: Code für den .NET Service

Die Anwendung baut eine Verbindung zum Message Buffer auf (und legt diesen an, sofern er noch nicht existiert) und fragt dort in regelmäßigen Abständen nach, ob eine Nachricht bereit steht.

Implementierung des Java Client

Nachdem die Voraussetzungen beim Aufsetzen der Entwicklungsumgebung geschaffen sind (siehe oben), kann nun auch der Java Client entwickelt werden. Starten Sie hierzu Eclipse und legen ein neues Java Projekt an (File –> New –> Java Project). Fügen Sie dem Build Path noch folgende zwei JAR-Files hinzu (Rechte-Maus-Klick aufs Projekt –> Build Path –> Configure Build Path…):

  • commons-codec-1.5.jar
  • jdotnetservices-1.0.jar
     

Siehe hierzu Abb 5.

Konfiguration des Java Build Paths

Abb 5: Konfiguration des Java Build Paths

Fügen Sie dem Projekt zwei Klassen-Dateien hinzu. Die erste Datei ist die Resource.java, die folgenden Inhalt hat (ersetzen Sie wie auch im .NET Service die Einträge zum Issuer und Namespace entsprechend dem zu Beginn angelegten Namespace):

   1: package com.samples;
   2:  
   3: public class Resource {
   4:     public static final String issuerName = "[ISSUER_NAME]";
   5:     public static final String issuerKey = "[ISSUER_KEY]";
   6:     public static final String serviceNamespace = "[SERVICE_NAMESPACE]";
   7: }

Listing 3: Resource.java

Die zweite Datei ist die eigentliche Client-Datei, die die Angaben aus der Resource.java nutzt, um ihrerseits eine Verbindung zum Message Buffer aufbaut und den Benutzer dann bittet, Texteingaben zu machen, die dann über den Message Buffer zum .NET Service geschickt werden, die dieser dann anzeigt.

   1: package com.samples;
   2:  
   3: import java.io.*;
   4: import com.persistent.appfabric.acs.Credentials;
   5: import com.persistent.appfabric.acs.Credentials.TOKEN_TYPE;
   6: import com.persistent.appfabric.servicebus.MessageBuffer;
   7: import com.persistent.appfabric.servicebus.MessageBufferPolicy;
   8:  
   9: public class AzureAppFabricClient {
  10:  
  11:     /**
  12:      * @param args
  13:      */
  14:     public static void main(String[] args) {
  15:         MessageBufferPolicy messageBufferPolicy = new MessageBufferPolicy("Required", "None", "PT20M", 10);
  16:         Credentials credentials;
  17:         try {
  18:             credentials = new Credentials(TOKEN_TYPE.SharedSecretToken, 
  19:                     Resource.issuerName, Resource.issuerKey);
  20:             MessageBuffer msgBuffer = new MessageBuffer(credentials, 
  21:                     Resource.serviceNamespace);
  22:             
  23:             InputStreamReader converter = new InputStreamReader(System.in);
  24:             BufferedReader in = new BufferedReader(converter);
  25:             String messageText;
  26:             
  27:             while (true)
  28:             {
  29:                 messageText = in.readLine();
  30:                 if(!messageText.equals(""))
  31:                 {
  32:                     msgBuffer.sendMessage("TestMessageBuffer", messageText);
  33:                     System.out.printf("Message '%s' sent.\n", messageText);
  34:                 }    
  35:                 else
  36:                     break;
  37:             }
  38:        } catch (Exception e) {
  39:            e.printStackTrace();    
  40:        }
  41:     }
  42: }

Listing 4: AzureAppFabricClient.java

Damit ist auch die Implementierung des Java Client abgeschlossen.

Test der Kommunikation

Das Gesamtszenario kann nun getestet werden. Starten sie hierzu in Visual Studio den Service. Starten Sie anschließend in Eclipse den Java Client. Der Client ermöglicht nun die Eingabe von Textzeilen, die der Client über den Message Buffer an den Service schickt. Eine Beispielausführung auf meinem Entwicklungsrechner sieht wie folgt aus:

Test der Kommunikationsbeziehung

Abb 6: Test der Kommunikationsbeziehung

Im Vordergrund ist der .NET Server zu sehen, der die Testnachrichten “Test1”, “Test2” und “Test3” empfangen hat.

Weitere Informationen