A .NET class library for accessing to the HornetQ REST interface

This is the third article of my series about the HornetQ REST interface, in the first post I wrote about the building and deployment of a customized version of the Web application that implements the interface, in the second post I talked about the development of a Java class library for accessing to the HornetQ REST interface, this time I want to develop a .NET API with the same goal.

I was an enthusiastic VB6 programmer long, long time ago. I also participated in some projects that made use of Visual Basic .NET and I even made some things in ASP.NET, but, to be perfectly honest, I’ve been focused in Java based technologies last years, so I’ve had to bring myself up to date on .NET!

The first task was to setup a development environment. I decided to use the free tool Microsoft Visual Web Developer 2010 Express and I also installed the extension NuGet Package Manager, which made the setup of Microsoft ASP.NET Web API Client Libraries easier. These libraries helped me to access to the HornetQ REST interface, like RESTEasy helped me in Java. This post of Mike Wasson was very useful to get a quick introduction, although he programs in C#!

My idea was to rewrite the library I created in Java using Visual Basic .NET, as simple as that. The first thing I realized is that nowadays both languages have similar capacities, a quick proof, this is the messaging interface in Java:


public interface MessagingInterface {

    void start() throws MessagingException;

    <T> void sendMessage(T message) throws MessagingException;

    <T> T receiveNextMessage(Class<T> type) throws MessagingException;

    void ackLastMessageReceived() throws MessagingException;

    void stop() throws MessagingException;
}

And this .NET:


Public Interface MessagingInterface(Of T)

    Sub ClientStart()

    Sub SendMessage(ByRef Mensaje As T)

    Function ReceiveNextMessage() As T

    Sub AckLastMessageReceived()

    Sub ClientStop()

End Interface

The HTTP messages to send in each case are determined by the HornetQ REST Interface user’s manual, so the algorithms are the same in Java and in Visual Basic .NET, I just had to adapt the code to the language and the special features of .NET
Another interesting comparison, this the Java method to send a message:


@Override
public <T> void sendMessage(T message) throws MessagingException {
    ClientResponse response;

    try {
        if (!this.isStarted) {
            throw new IllegalStateException("The client is not started");
        }

        response = this.msgCreateLink.request().body(MediaType.APPLICATION_XML, message).post();

        if (response.getStatus() == 307) {
            this.msgCreateLink = response.getLocation();

            response = this.msgCreateLink.request().body(MediaType.APPLICATION_XML, message).post();
        }

        if (response.getResponseStatus().equals(Response.Status.CREATED)) {
            this.msgCreateLink = response.getHeaderAsLink("msg-create-next");
        } else {
            throw new MessagingException("Response code  " + response.getStatus() + " not supported");
        }
    } catch (MessagingException ex) {
        throw ex;
    } catch (Exception ex) {
        throw new MessagingException(ex);
    }
}

And this is the .NET one:


Public Sub SendMessage(ByRef Message As T) Implements MessagingInterface(Of T).SendMessage
    Dim Response As HttpResponseMessage
    Dim XmlFormatter As XmlMediaTypeFormatter

    Try
        If Not Me.IsStarted Then
            Throw New InvalidOperationException("The client is not started")
        End If

        XmlFormatter = New XmlMediaTypeFormatter
        XmlFormatter.UseXmlSerializer = True

        Response = Me.HornetQHttpClient.PostAsync(Me.MsgCreateUri, 
                                                  Message, 
                                                  XmlFormatter).Result

        If Response.StatusCode = HttpStatusCode.RedirectKeepVerb Then
            Me.MsgCreateUri = Response.Headers.GetValues("Location").First
            Response = Me.HornetQHttpClient.PostAsync(Me.MsgCreateUri, 
                                                      Message, 
                                                      XmlFormatter).Result
        End If

        If Response.StatusCode = HttpStatusCode.Created Then
            Me.MsgCreateUri = Response.Headers.GetValues("msg-create-next").First
        Else
            Throw New MessagingException("Response code " + Response.StatusCode + " not supported")
        End If
    Catch ex As MessagingException
        Throw ex
    Catch ex As Exception
        Throw New MessagingException(ex.Message, ex)
    End Try
End Sub

References


Fighting with sockets!

Last week, I was appointed to develop a Java program that should connect to an external secure socket, in order to get data provided by a partner company. Another requisite was that the module should be stored on an Oracle 11g Database, so I must use a 1.5 JDK. Easy, I thought!

First of all, I review Java Secure Socket Extension (JSSE) Reference Guide. Our company partner IT team provided me with the key store containing the certificate I should trust and I decide to program a custom SSL context:

   ...
   KeyStore keyStoreTrust = KeyStore.getInstance("PKCS12");
   keyStoreTrust.load(this.getClass().getResourceAsStream("KeyStoreTrust.pfx"),
                      "password".toCharArray());
   TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX");
   trustManagerFactory.init(keyStoreTrust);

   SSLContext sslContext = SSLContext.getInstance("SSL");
   sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
   ...

The first problem arose when the server socket (developed in Microsoft .NET C#) unexpectedly closed the connection during the handshake, the support guy of my partner company said me that they got the following error message: “The client and server cannot communicate, because they do not possess a common algorithm”. Therefore, I delved into the problem and finally I realized that the server wanted to use a TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA cipher suite, which wasn’t supported by the security providers shipped with the JDK 1.5 I’d like to point out that a key point to find out the source of the error was to activate the debug of the SSL connection:

System.setProperty("javax.net.debug", "ssl");

Hence, I decided to add to my program the well-known Bouncy Castle security provider, which supports the required cipher suite and it’s 1.5 compliant:

Security.addProvider(new BouncyCastleProvider());

Once I sorted out the problem, everything started to work properly, at least as an stand-alone client! So, I created a “Loadjava and Java Stored Procedures” profile in my JDeveloper IDE, in order to deploy the software to the Oracle Database 11.2, but when I tried to do it I got the following errors:

Invoking loadjava on connection 'Test11g_Paco' with arguments:
 -order -resolve -definer -thin -resolver ((* TEST) (* PUBLIC) (* -)) -synonym
 errors   : class org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey
 ORA-29552: verification warning: java.lang.NoClassDefFoundError: java/security/interfaces/ECPrivateKey

 errors   : class org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey
 ORA-29552: verification warning: java.lang.NoClassDefFoundError: java/security/interfaces/ECPublicKey

 errors   : class org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey
 ORA-29552: verification warning: java.lang.NoClassDefFoundError: java/security/interfaces/ECPrivateKey

 errors   : class org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey
 ORA-29552: verification warning: java.lang.NoClassDefFoundError: java/security/interfaces/ECPublicKey

 errors   : class org/bouncycastle/jce/provider/JCEECPrivateKey
 ORA-29552: verification warning: java.lang.NoClassDefFoundError: java/security/interfaces/ECPrivateKey

 errors   : class org/bouncycastle/jce/provider/JCEECPublicKey
 ORA-29552: verification warning: java.lang.NoClassDefFoundError: java/security/interfaces/ECPublicKey

 Loadjava finished.

I can’t understand the problem because the interfaces java.security.interfaces.ECPublicKey and java.security.interfaces.ECPrivateKey are available in 1.5 and the Oracle Database 11.2 JVM is supposed to be 1.5 compliant, but I couldn’t find any satisfactory solution.