Apache Wake a.k.a. Kune

Installing the Kune/Apache Wake Debian package

This is a small guide to install Kune in Debian and derivative distributions (Ubuntu, etc).

Continue reading

Posted in Java | Leave a comment

Using the Java Native Interface in C#

Hier ein fremder Artikel, den ich aber für extrem interessant halte

By 22 Apr 2013

Introduction

The JNI or Java Native Interface is a set of features available in the Java platform. Applications that use the JNI can incorporate Java code with code written in other languages such as C++, Delphi, and C#.

In my example, I will show you how to call a couple of Java methods from a C# client.

Advantages

You can reuse your existing libraries/classes that were previously written in Java from your new application written in C#. This means that you do not have to abandon your legacy code written in Java and reinvent the wheel again in C#.

Background

One of the most important things to be familiar in JNI is Field Descriptors. As you will notice in the test harness, when I call a Java method that takes a string parameter, I pass in “Ljava/lang/String;”. This represents a field type in the Java programming language. For example, if you wanted to represent an int field, then you would use “I”, a float field would be “F”, and a boolean field would be “Z”, etc.

The table below describes the primitive types in the Java programming language and the corresponding types in JNI. All field descriptors that start with L are dealt with as objects (note: a string is passed as an object) and must be terminated by a “;” character. An array type is always prefixed with the “[” character.

JNI Field Descriptor Java Language Type
Z boolean
B byte
C char
S short
I int
J long
F float
D double
Ljava/lang/String; string
[Ljava/lang/Object; object[]

Method descriptors make use of the fields descriptors and describe the structure of a Java method. There are no spaces between the field descriptors in a method descriptor.

Apart from the void return type which is denoted by V, all other return types use the field descriptor. The table below describes the Java method declaration and the corresponding JNI descriptor. The JNI method descriptor is used when calling a Java method from C# via JNI.

Java Method Declaration JNI Method Descriptor
String foo(); "()Ljava/lang/String;"
Void bar(int I, bool b); (IZ)V

Using the code

An example of calling Java code from a .NET GUI application

Once a reference is set to the assembly JNI located in the download section of my code, you can start to call Java methods in only a few lines of code.

The first thing that needs to be done is to create a dictionary object that will contain all of the parameters to pass to the Java Virtual Machine. In the example below, I am doing the minimum of setting the class path that will tell the JVM where to look for the classes and packages.

private Dictionary<string, string> jvmParameters = new Dictionary<string, string>();
jvmParameters.Add("-Djava.class.path", Location of the java class);

Once the JVM parameters have been assigned to the dictionary object, an instance of JavaNativeInterface can be created. Once created, the method LoadJVM needs to be called with the JVM parameters, and this will then load up the Java Virtual Machine. Once loaded, the user calls the method to instantiate the Java object (note that the use of the method InstantiateJavaObject is optional as the user may just want to call a static method, in which case, this method does not need to be called; however, it will not case any harm).

Java = new JavaNativeInterface();
Java.LoadVM(jvmParameters, false);
Java.InstantiateJavaObject(Name of the java class excluding the extension);

Once the JVM has been loaded and a class instantiated, the user may call any method they wish. First create an object list that will contain all of the parameters to pass into the Java method. As it is an object list, it can hold parameters of different types as everything inherits from an object.

List<object> olParameters = new List<object>();
olParameters.Add(Value of the parameter to be passed to the java method);

Next, simply call the generic method CallMethod passing in the return type of the Java method as the template type. In the example below, I am calling CallMethod<string> which means that the return type of my Java method that I want to call is a string.

Next, pass in the name of the Java method to call and the method descriptor (see above); finally, pass in the list of all of the parameters. (Note: If no parameters are required, then pass in an empty list.)

Java.CallMethod<string>("AddTwoNumbers", "(IILjava/lang/String;)I", olParameters);

Well, I guess that wraps it all up, but remember that there is so much more you can do with JNI. The test application was just a quick and dirty way to demonstrate the basics of the JNI component. For a full understanding of JNI, I advise you to read this book: http://docs.oracle.com/javase/7/docs/technotes/guides/jni/.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Simon Agholor

United Kingdom United Kingdom
No Biography provided
Posted in .NET, Java | Leave a comment

NTLM Authentication Scheme for HTTP

Introduction

This is an attempt at documenting the undocumented NTLM authentication scheme used by M$’s browsers, proxies, and servers (MSIE and IIS); this scheme is also sometimes referred to as the NT challenge/response (NTCR) scheme. Most of the info here is derived from three sources (see also the Resources section at the end of this document): Paul Ashton’s work on the NTLM security holes, the encryption documentation from Samba, and network snooping. Since most of this info is reverse-engineered it is bound to contain errors; however, at least one client and one server have been implemented according to this data and work successfully in conjunction with M$’s browsers, proxies and servers.

Note that this scheme is not as secure as Digest and some other schemes; it is slightly better than the Basic authentication scheme, however.

Also note that this scheme is not an http authentication scheme – it’s a connection authentication scheme which happens to (mis-)use http status codes and headers (and even those incorrectly).

NTLM Handshake

When a client needs to authenticate itself to a proxy or server using the NTLM scheme then the following 4-way handshake takes place (only parts of the request and status line and the relevant headers are shown here; “C” is the client, “S” the server):

    1: C  --> S   GET ...
    
    2: C <--  S   401 Unauthorized
                  WWW-Authenticate: NTLM
    
    3: C  --> S   GET ...
                  Authorization: NTLM <base64-encoded type-1-message>
    
    4: C <--  S   401 Unauthorized
                  WWW-Authenticate: NTLM <base64-encoded type-2-message>
    
    5: C  --> S   GET ...
                  Authorization: NTLM <base64-encoded type-3-message>
    
    6: C <--  S   200 Ok

Messages

The three messages sent in the handshake are binary structures. Each one is descri​bed below as a pseudo-C struct and in a memory layout diagram. byte is an 8-bit field; short is a 16-bit field. All fields are unsigned. Numbers are stored in little-endian order. Struct fields named zero contain all zeroes. An array length of “*” indicates a variable length field. Hexadecimal numbers and quoted characters in the comments of the struct indicate fixed values for the given field.

The field flags is presumed to contain flags, but their significance is unknown; the values given are just those found in the packet traces.

Type-1 Message

This message contains the host name and the NT domain name of the client.

    struct {
        byte    protocol[8];     // 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'
        byte    type;            // 0x01
        byte    zero[3];
        short   flags;           // 0xb203
        byte    zero[2];

        short   dom_len;         // domain string length
        short   dom_len;         // domain string length
        short   dom_off;         // domain string offset
        byte    zero[2];

        short   host_len;        // host string length
        short   host_len;        // host string length
        short   host_off;        // host string offset (always 0x20)
        byte    zero[2];

        byte    host[*];         // host string (ASCII)
        byte    dom[*];          // domain string (ASCII)
    } type-1-message
                 0       1       2       3
             +-------+-------+-------+-------+
         0:  |  'N'  |  'T'  |  'L'  |  'M'  |
             +-------+-------+-------+-------+
         4:  |  'S'  |  'S'  |  'P'  |   0   |
             +-------+-------+-------+-------+
         8:  |   1   |   0   |   0   |   0   |
             +-------+-------+-------+-------+
        12:  | 0x03  | 0xb2  |   0   |   0   |
             +-------+-------+-------+-------+
        16:  | domain length | domain length |
             +-------+-------+-------+-------+
        20:  | domain offset |   0   |   0   |
             +-------+-------+-------+-------+
        24:  |  host length  |  host length  |
             +-------+-------+-------+-------+
        28:  |  host offset  |   0   |   0   |
             +-------+-------+-------+-------+
        32:  |  host string                  |
             +                               +
             .                               .
             .                               .
             +             +-----------------+
             |             | domain string   |
             +-------------+                 +
             .                               .
             .                               .
             +-------+-------+-------+-------+

The host and domain strings are ASCII (or possibly ISO-8859-1), are uppercased, and are not nul-terminated. The host name is only the host name, not the FQDN (e.g. just “GOOFY”, not “GOOFY.DISNEY.COM”). The offsets refer to the offset of the specific field within the message, and the lengths are the length of specified field. For example, in the above message host_off = 32 and dom_off = host_off + host_len. Note that the lengths are included twice (for some unfathomable reason).

Type-2 Message

This message contains the server’s NTLM challenge.

    struct {
        byte    protocol[8];     // 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'
        byte    type;            // 0x02
        byte    zero[7];
        short   msg_len;         // 0x28
        byte    zero[2];
        short   flags;           // 0x8201
        byte    zero[2];

        byte    nonce[8];        // nonce
        byte    zero[8];
    } type-2-message
                 0       1       2       3
             +-------+-------+-------+-------+
         0:  |  'N'  |  'T'  |  'L'  |  'M'  |
             +-------+-------+-------+-------+
         4:  |  'S'  |  'S'  |  'P'  |   0   |
             +-------+-------+-------+-------+
         8:  |   2   |   0   |   0   |   0   |
             +-------+-------+-------+-------+
        12:  |   0   |   0   |   0   |   0   |
             +-------+-------+-------+-------+
        16:  |  message len  |   0   |   0   |
             +-------+-------+-------+-------+
        20:  | 0x01  | 0x82  |   0   |   0   |
             +-------+-------+-------+-------+
        24:  |                               |
             +          server nonce         |
        28:  |                               |
             +-------+-------+-------+-------+
        32:  |   0   |   0   |   0   |   0   |
             +-------+-------+-------+-------+
        36:  |   0   |   0   |   0   |   0   |
             +-------+-------+-------+-------+

The nonce is used by the client to create the LanManager and NT responses (see Password Hashes). It is an array of 8 arbitrary bytes. The message length field contains the length of the complete message, which in this case is always 40.

Type-3 Message

This message contains the username, host name, NT domain name, and the two “responses”.

    struct {
        byte    protocol[8];     // 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'
        byte    type;            // 0x03
        byte    zero[3];

        short   lm_resp_len;     // LanManager response length (always 0x18)
        short   lm_resp_len;     // LanManager response length (always 0x18)
        short   lm_resp_off;     // LanManager response offset
        byte    zero[2];

        short   nt_resp_len;     // NT response length (always 0x18)
        short   nt_resp_len;     // NT response length (always 0x18)
        short   nt_resp_off;     // NT response offset
        byte    zero[2];

        short   dom_len;         // domain string length
        short   dom_len;         // domain string length
        short   dom_off;         // domain string offset (always 0x40)
        byte    zero[2];

        short   user_len;        // username string length
        short   user_len;        // username string length
        short   user_off;        // username string offset
        byte    zero[2];

        short   host_len;        // host string length
        short   host_len;        // host string length
        short   host_off;        // host string offset
        byte    zero[6];

        short   msg_len;         // message length
        byte    zero[2];

        short   flags;           // 0x8201
        byte    zero[2];

        byte    dom[*];          // domain string (unicode UTF-16LE)
        byte    user[*];         // username string (unicode UTF-16LE)
        byte    host[*];         // host string (unicode UTF-16LE)
        byte    lm_resp[*];      // LanManager response
        byte    nt_resp[*];      // NT response
    } type-3-message
                 0       1       2       3
             +-------+-------+-------+-------+
         0:  |  'N'  |  'T'  |  'L'  |  'M'  |
             +-------+-------+-------+-------+
         4:  |  'S'  |  'S'  |  'P'  |   0   |
             +-------+-------+-------+-------+
         8:  |   3   |   0   |   0   |   0   |
             +-------+-------+-------+-------+
        12:  |  LM-resp len  |  LM-Resp len  |
             +-------+-------+-------+-------+
        16:  |  LM-resp off  |   0   |   0   |
             +-------+-------+-------+-------+
        20:  |  NT-resp len  |  NT-Resp len  |
             +-------+-------+-------+-------+
        24:  |  NT-resp off  |   0   |   0   |
             +-------+-------+-------+-------+
        28:  | domain length | domain length |
             +-------+-------+-------+-------+
        32:  | domain offset |   0   |   0   |
             +-------+-------+-------+-------+
        36:  |  user length  |  user length  |
             +-------+-------+-------+-------+
        40:  |  user offset  |   0   |   0   |
             +-------+-------+-------+-------+
        44:  |  host length  |  host length  |
             +-------+-------+-------+-------+
        48:  |  host offset  |   0   |   0   |
             +-------+-------+-------+-------+
        52:  |   0   |   0   |   0   |   0   |
             +-------+-------+-------+-------+
        56:  |  message len  |   0   |   0   |
             +-------+-------+-------+-------+
        60:  | 0x01  | 0x82  |   0   |   0   |
             +-------+-------+-------+-------+
        64:  | domain string                 |
             +                               +
             .                               .
             .                               .
             +           +-------------------+
             |           | user string       |
             +-----------+                   +
             .                               .
             .                               .
             +                 +-------------+
             |                 | host string |
             +-----------------+             +
             .                               .
             .                               .
             +   +---------------------------+
             |   | LanManager-response       |
             +---+                           +
             .                               .
             .                               .
             +            +------------------+
             |            | NT-response      |
             +------------+                  +
             .                               .
             .                               .
             +-------+-------+-------+-------+

The host, domain, and username strings are in Unicode (UTF-16, little-endian) and are not nul-terminated; the host and domain names are in upper case. The lengths of the response strings are 24.

Password Hashes

To calculate the two response strings two password hashes are used: the LanManager password hash and the NT password hash. These are described in detail at the beginning of the Samba ENCRYPTION.html document. However, a few things are not clear (such as what the magic constant for the LanManager hash is), so here is some almost-C code which calculates the two responses. Inputs are passw and nonce, the results are in lm_resp and nt_resp.

    /* setup LanManager password */

    char  lm_pw[14];
    int   len = strlen(passw);
    if (len > 14)  len = 14;

    for (idx=0; idx<len; idx++)
        lm_pw[idx] = toupper(passw[idx]);
    for (; idx<14; idx++)
        lm_pw[idx] = 0;


    /* create LanManager hashed password */

    unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
    unsigned char lm_hpw[21];
    des_key_schedule ks;

    setup_des_key(lm_pw, ks);
    des_ecb_encrypt(magic, lm_hpw, ks);

    setup_des_key(lm_pw+7, ks);
    des_ecb_encrypt(magic, lm_hpw+8, ks);

    memset(lm_hpw+16, 0, 5);


    /* create NT hashed password */

    int   len = strlen(passw);
    char  nt_pw[2*len];
    for (idx=0; idx<len; idx++)
    {
        nt_pw[2*idx]   = passw[idx];
        nt_pw[2*idx+1] = 0;
    }

    unsigned char nt_hpw[21];
    MD4_CTX context;
    MD4Init(&context);
    MD4Update(&context, nt_pw, 2*len);
    MD4Final(nt_hpw, &context);

    memset(nt_hpw+16, 0, 5);


    /* create responses */

    unsigned char lm_resp[24], nt_resp[24];
    calc_resp(lm_hpw, nonce, lm_resp);
    calc_resp(nt_hpw, nonce, nt_resp);

Helpers:

    /*
     * takes a 21 byte array and treats it as 3 56-bit DES keys. The
     * 8 byte plaintext is encrypted with each key and the resulting 24
     * bytes are stored in the results array.
     */
    void calc_resp(unsigned char *keys, unsigned char *plaintext, unsigned char *results)
    {
        des_key_schedule ks;

        setup_des_key(keys, ks);
        des_ecb_encrypt((des_cblock*) plaintext, (des_cblock*) results, ks, DES_ENCRYPT);

        setup_des_key(keys+7, ks);
        des_ecb_encrypt((des_cblock*) plaintext, (des_cblock*) (results+8), ks, DES_ENCRYPT);

        setup_des_key(keys+14, ks);
        des_ecb_encrypt((des_cblock*) plaintext, (des_cblock*) (results+16), ks, DES_ENCRYPT);
    }


    /*
     * turns a 56 bit key into the 64 bit, odd parity key and sets the key.
     * The key schedule ks is also set.
     */
    void setup_des_key(unsigned char key_56[], des_key_schedule ks)
    {
        des_cblock key;

        key[0] = key_56[0];
        key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
        key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
        key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
        key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
        key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
        key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
        key[7] =  (key_56[6] << 1) & 0xFF;

        des_set_odd_parity(&key);
        des_set_key(&key, ks);
    }

Keeping the connection alive

As mentioned above, this scheme authenticates connections, not requests. This manifests itself in that the network connection must be kept alive during the second part of the handshake, i.e. between the receiving of the type-2 message from the server (step 4) and the sending of the type-3 message (step 5). Each time the connection is closed this second part (steps 3 through 6) must be repeated over the new connection (i.e. it’s not enough to just keep sending the last type-3 message). Also, once the connection is authenticated, the Authorization header need not be sent anymore while the connection stays open, no matter what resource is accessed.

For implementations wishing to work with M$’s software this means that they must make sure they use either HTTP/1.0 keep-alive’s or HTTP/1.1 persistent connections, and that they must be prepared to do the second part of the handshake each time the connection was closed and is reopened. Server implementations must also make sure that HTTP/1.0 responses contain a Content-length header (as otherwise the connection must be closed after the response), and that HTTP/1.1 responses either contain a Content-length header or use the chunked transfer encoding.

Example

Here is an actual example of all the messages. Assume the host name is “LightCity”, the NT domain name is “Ursa-Minor”, the username is “Zaphod”, the password is “Beeblebrox”, and the server sends the nonce “SrvNonce”. Then the handshake is:

    C -> S   GET ...
    
    S -> C   401 Unauthorized
             WWW-Authenticate: NTLM
    
    C -> S   GET ...
             Authorization: NTLM TlRMTVNTUAABAAAAA7IAAAoACgApAAAACQAJACAAAABMSUdIVENJVFlVUlNBLU1JTk9S
    
    S -> C   401 Unauthorized
             WWW-Authenticate: NTLM TlRMTVNTUAACAAAAAAAAACgAAAABggAAU3J2Tm9uY2UAAAAAAAAAAA==
    
    C -> S   GET ...
             Authorization: NTLM TlRMTVNTUAADAAAAGAAYAHIAAAAYABgAigAAABQAFABAAAAADAAMAFQAAAASABIAYAAAAAAAAACiAAAAAYIAAFUAUgBTAEEALQBNAEkATgBPAFIAWgBhAHAAaABvAGQATABJAEcASABUAEMASQBUAFkArYfKbe/jRoW5xDxHeoxC1gBmfWiS5+iX4OAN4xBKG/IFPwfH3agtPEia6YnhsADT
    
    S -> C   200 Ok

and the unencoded messages are:

Type-1 Message:

       0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
   0:  4e 54 4c 4d 53 53 50 00 01 00 00 00 03 b2 00 00  "NTLMSSP........."
  10:  0a 00 0a 00 29 00 00 00 09 00 09 00 20 00 00 00  "....)....... ..."
  20:  4c 49 47 48 54 43 49 54 59 55 52 53 41 2d 4d 49  "LIGHTCITYURSA-MI"
  30:  4e 4f 52                                         "NOR"

Type-2 Message:

       0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
   0:  4e 54 4c 4d 53 53 50 00 02 00 00 00 00 00 00 00  "NTLMSSP........."
  10:  28 00 00 00 01 82 00 00 53 72 76 4e 6f 6e 63 65  "(.......SrvNonce"
  20:  00 00 00 00 00 00 00 00                          "........"

Type-3 Message:

       0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
   0:  4e 54 4c 4d 53 53 50 00 03 00 00 00 18 00 18 00  "NTLMSSP........."
  10:  72 00 00 00 18 00 18 00 8a 00 00 00 14 00 14 00  "r..............."
  20:  40 00 00 00 0c 00 0c 00 54 00 00 00 12 00 12 00  "@.......T......."
  30:  60 00 00 00 00 00 00 00 a2 00 00 00 01 82 00 00  "`..............."
  40:  55 00 52 00 53 00 41 00 2d 00 4d 00 49 00 4e 00  "U.R.S.A.-.M.I.N."
  50:  4f 00 52 00 5a 00 61 00 70 00 68 00 6f 00 64 00  "O.R.Z.a.p.h.o.d."
  60:  4c 00 49 00 47 00 48 00 54 00 43 00 49 00 54 00  "L.I.G.H.T.C.I.T."
  70:  59 00 ad 87 ca 6d ef e3 46 85 b9 c4 3c 47 7a 8c  "Y....m..F...<Gz."
  80:  42 d6 00 66 7d 68 92 e7 e8 97 e0 e0 0d e3 10 4a  "B..f}h.........J"
  90:  1b f2 05 3f 07 c7 dd a8 2d 3c 48 9a e9 89 e1 b0  "...?....-<H....."
  a0:  00 d3                                            ".."

For reference, the intermediate hashed passwords are:

lm_hpw (LanManager hashed password):
91 90 16 f6 4e c7 b0 0b a2 35 02 8c a5 0c 7a 03 00 00 00 00 00
nt_hpw (NT hashed password):
8c 1b 59 e3 2e 66 6d ad f1 75 74 5f ad 62 c1 33 00 00 00 00 00

Resources

* LM authentication in SMB/CIFS
http://www.ubiqx.org/cifs/SMB.html#SMB.8.3
* A document on cracking NTLMv2 authentication
http://www.blackhat.com/presentations/win-usa-02/urity-winsec02.ppt
* Squid’s NLTM authentication project
http://squid.sourceforge.net/ntlm/
* Encryption description for Samba
http://de.samba.org/samba/ftp/docs/htmldocs/ENCRYPTION.html
* Info on the MSIE security hole
http://oliver.efri.hr/~crv/security/bugs/NT/ie6.html
* FAQ: NT Cryptographic Password Attacks & Defences
http://www.ntbugtraq.com/default.asp?sid=1&pid=47&aid=17
* M$’s hotfix to disable the sending of the LanManager response
ftp://ftp.microsoft.com/bussys/winnt/winnt-public/fixes/usa/NT40/hotfixes-postSP3/lm-fix
* A description of M$’s hotfix
http://www.tryc.on.ca/archives/bugtraq/1997_3/0070.html

Acknowledgements

Special thanks to the following people who helped with the collection and debugging of the above information:

Posted in .NET, Allgemein, Java | Leave a comment

Gehversuche mit Mule

Die Integration unterschiedlicher Softwaresysteme in einer heterogenen Systemlandschaft ist bis heute für viele IT-Architekten eine der anspruchsvollsten Aufgaben, sowohl aus technischer als auch aus betriebswirtschaftlicher Sicht. In der Vergangenheit wurden daher viele unterschiedliche Integrationslösungen entwickelt, die sich mehr oder weniger gut in der Praxis bewährt haben. Das unermüdliche Streben nach einer idealen Lösung, um der steigenden Komplexität gerecht zu werden, hat uns heute letztendlich neben dem SOA Paradigma den Enterprise Service Bus (ESB) beschert.

Was ist ein ESB?

Ein ESB ist eine standardisierte Integrationsplattform für verteilte Systeme, welche unterschiedlichen Diensten (engl. Services) erlaubt, mit Hilfe von definierten End-Punkten, über einen Kommunikationsbus Nachrichten (engl. Messages) auszutauschen.

Zu den wichtigsten Aufgaben eines ESB gehören:

  • Das Routing von Nachrichten
  • Das Transformieren von Nachrichten
  • Das Bereitstellen von unterschiedlichen Protokollen (Technologien)
  • Sicherstellung von Quality of Service
  • Die Unterstützung von unterschiedlichen Enterprise Integration Pattern (EIP)

Man findet heute bei fast allen großen Software Unternehmen, die Systemintegrationslösungen anbieten, kommerzielle ESB Produkte im Portfolio wie z.B. Oracle ESB, Sonic ESB, IBM WebSphere ESB. Es existieren aber auch eine Vielzahl von Open-Source-Produkten wie Mule, Apache Service Mix oder Open ESB. Das Mule Projekt kann mittlerweile mehr als 1 Millionen Downloads verzeichnen und hat sicherlich damit ein besonderes Augenmerk verdient.

Der Open-Source ESB Mule

Mule ist ein Java basierter Open-Souce ESB, der sich einer immer größer werdenden Beliebtheit erfreut und sich in der Praxis sehr bewährt hat. Mule steht unter der Common Public Attribution License (CPAL) und wird von der stetig größer werdenden Community permanent weiterentwickelt, was ein wichtiger Faktor bei der Wahl bzw. für die Entscheidung eines Open-Source Produktes ist.

Eine gute Kurzbeschreibung von Mule ist auf der Internetseite  „www.mulesource.org“ zu finden:

Mule is a lightweight integration platform and service container that allows you to quickly and easily connect your applications together. Mule provides a robust, secure and scalable platform to build enterprise applications offering an array of transports such as JMS, HTTP, E-mail, FTP, JDBC and many more. It also offers rich set of features for web services, message routing, mediation, transformation and transaction management. Designed around the ESB (Enterprise Service Bus) concpet, Mule ist the most widely used open source integration platform.

Mule ist insofern leichtgewichtig, dass seit der Verion 2.0 die Mule Plattform komplett auf dem Spring Framework basiert. Dies erleichtert einerseits die Einarbeitung für all diejenigen, die sich bereits mit Spring auskennen und erlaubt gleichzeitig alle Servicekomponenten in Mule als Plain Old Java Objects (POJO’s) zu implementieren. Mule kann damit ohne einen Enterprise Application Server betrieben und ohne größere Aufwände in bestehende Software-Architekturen integriert werden.

Mule Architektur und Programmiermodell

Da die Mule Plattform auf dem SOA Konzept basiert, ist es nicht verwunderlich, dass Services eine zentrale Rolle im Mule Framework spielen. Interne und externe Service-Komponenten tauschen über Message Channels Informationen aus. Diese Services werden in Mule wiederum zu einem Modul zusammengefasst. Wie bei vielen anderen ESBs geschieht der Nachrichtenaustausch über einen JMS Message Broker. Mule gibt dabei aber selbst keine Implementierung vor. Stattdessen können unterschiedliche JMS Systeme wie beispielsweise Apache Active MQ, IBM MQSeries oder Oracle EMS integriert werden. Bei den Nachrichten, die über die Channels ausgetauscht werden, muss es sich aber nicht zwingend um XML-Dokumente handeln. So können beispielsweise auch beliebige Java Objekte transportiert werden.

Ein Service besteht in Mule aus der Service-Komponente, welche die Businesslogik für die Datenverarbeitung beinhaltet, und ihren Endpunkten (Adressen und Protokoll). Die Service-Komponente kann dabei ein einfaches POJO sein aber auch ein Servlet oder ein Web Service. Das Programmiermodell von Mule ist sehr einfach und sieht drei Phasen vor:

  1. Inbound Flow Stage
  2. Componente Flow Stage
  3. Outbound Flow Stage

Im Inbound Flow Stage werden mehrere Eingangs-Endpunkte (Einstiegsmöglichkeiten) für die Service-Komponente defieniert. So kann beispielsweise eine Service-Komponente bei einer eingehenden JMS Message, E-Mail oder das Kopieren einer XML-Datei in ein Verzeichnis gestartet werden. Wie bereits erwähnt sind mehrere Einstiegspunkte für eine Service-Komponente denkbar. Im Inbound Flow Stage lassen sich nun auch sogenannte Message Router und Transformer definieren, die z.B. im Vorfeld bestimmte Nachrichten ausfiltern (Filtering-Router) und transformieren.

Der Component Flow Stage führt nun die eigentliche Businesslogik durch und gibt das Ergebnis der Komponente an den optionalen Outbound Flow Stage weiter.

Im Outbound Flow Stage können ebenfalls mehrere Endpunkte definiert werden. Durch entsprechende Router und Transformer kann die Ausgangsnachricht nochmals manipuliert und durch die gewünschten Endpunkte verschickt werden (siehe Abb. 1).

Mule unterstützt von Haus aus eine ganze Palette von Protokollen, Routern, Filtern und Transformatoren, so dass sich der Implementierungsaufwand nahezu auf die Businesslogik in den Service-Komponenten und das Schreiben von eigenen Transformatoren beschränkt.

Service Komponente in Mule

Beispielanwendung: Hello ESB

Traditionell wollen wir mit einem Hello ESB Beispiel beginnen, wozu folgendes benötigt wird:

  • Maven 2.0.9
  • Mule 2.2.1
  • Apache Active MQ 5.2
  • Ein Jabber Client (z.B. Pidgin, Spark)
  • und ein Jabber Account (http://jabber.org)
  • Optional eine Java IDE (Eclipse Platform, Jetbrains IDEA)

Mule selbst muss nicht heruntergeladen und installiert werden, dies übernimmt Maven für uns. Wer sich nicht mit Maven auskennt, findet eine kurze Einführung in unserem Einstiegstutorial zu Maven. Der Beispielcode ist als Zip-Archive hier zu finden. Nachdem wir den Beispielcode entpackt haben, finden wir im Root-Verzeichnis eine „pom.xml“ File (Konfigurationsdatei für Maven) und ein „src“ Verzeichnis, in dem sich die Mule Konfigurationsdatei und die restlichen Java Sourcen befinden.

  • MuleHelloESBTutorial

    • src

      • main

        • java

          • com

            • soabpmn

              • tutorial

                • mule

                  • service

                    • impl

                      • SendMessageImpl.java
                    • MessageType.java
                    • SendMessage.java
                  • transformer

                    • InputMessageTransformer.java
                    • MessagingSystemTransformer.java
                  • xmpp

                    • MessagingComponent.java
                  • StartHelloESB.java
        • resources

          • hello-esb-config.xml
          • hello-esb-config.xml~
          • log4j.properties
    • pom.xml

Um unsere Hello ESB Anwendung zu kompilieren, reicht es, im Root-Verzeichnis Maven zu starten:

1 mvn

Maven kompiliert damit den Source-Code und läd alle benötigten Bibliotheken automatisch aus dem Internet und kopiert diese ins Maven Repository (per defautl: userhomer/.m2).

Um die Arbeit mit unserer Beispielanwendung etwas komfortabler zu gestalten, wollen wir nun unsere Anwendung in einer Java IDE öffnen. Auch hier nimmt uns Maven die Arbeit ab. Je nachdem ob wir nun Eclipse oder IDEA verwenden, können wir uns mit Maven ein Projektfile für unsere IDE erzeugen lassen.

1 mvn idea:idea

oder

1 mvn eclipse:eclipse

Das von Maven erzeugte Projektfile können wir jetzt in unserer IDE öffnen. Falls Eclipse verwendet wird, muss unter Preferences/Java/Build Path/Classpath Variables/ eine Umgebungsvariable mit dem Namen „M2_REPO“, welche auf das Maven Repository (userhome/.m2/repository) verweist, angelegt werden.

Bevor wir nun unsere Beispielanwendung starten können, muss zuerst noch Active MQ gestartet werden. Dazu muss lediglich im „bin“ Verzeichnis von Active MQ das Startskript ausgeführt werden:

1 apache-activemq-5.2.0/bin$ ./activemq

Um die Beispielanwendung letztendlich zu starten, führen wir die Main-Methode in com.soabpmn.tutorial.mule.StartHelloESB aus.

Was macht nun unsere Hello ESB Anwendung?

Unsere Beispielanwendung soll einen Service zum Verschicken von Nachrichten realisieren. Dazu soll ein Web Service bereitgestellt werden, welcher die zu versendenden Nachrichten entgegennimmt. Anschließend soll anhand des Nachrichtentyps entschieden werden, ob die Nachricht lediglich auf der Konsole ausgegeben werden soll oder an einen XMPP (Jabber) Client verschickt wird.

Die Anwendung definiert dazu zwei Mule Services: SendMessage und JabberSystem.

Der „SendMessage“ Service stellt mit Hilfe des Apache CXF Framework einen Webservice bereit, der die Eingangsnachricht entgegennimmt. Anschließend wird über einen Filter-Router anhand des Nachrichtentyps entschieden, ob die Nachricht auf der Konsole ausgegeben oder in eine JMS Message-Queue „xmppMessageQueue“ abgelegt wird.

Der „JabberSystem“ Service wartet darauf, dass Nachrichten in die JMS Message-Queue „xmppMessageQueue“ eingehen. Liegt eine Nachricht in der Queue vor, wird zunächst von der Service-Komponente der XMPP Empfänger der Nachricht ermittelt. Ein Transformator extrahiert anschließend den eigentlichen Nachrichtentext, bevor die Nachricht letztendlich über den Mule XMPP Transporter verschickt wird.

Hier die Mule Konfiguration:

01     <!-- ActiveMQ message broker -->
02     <jms:activemq-connector name="activeMqJmsConnector"brokerURL="tcp://localhost:61616" />
03         
04     <!-- Transformers -->
05     <jms:jmsmessage-to-object-transformer  name="JMSMessageToObject"/>
06     <jms:object-to-jmsmessage-transformer name="ObjectToJMSMessage"/>
07     <custom-transformer name="InputMessageTransformer"class="com.soabpmn.tutorial.mule.transformer.InputMessageTransformer"/>
08     <custom-transformer name="JabberTransformer"class="org.mule.transport.xmpp.transformers.ObjectToXmppPacket"/>
09     <custom-transformer name="MessagingSystemTransformer"class="com.soabpmn.tutorial.mule.transformer.MessagingSystemTransformer" />
10         
11     
12     <!-- Global endpoints  -->
13     <jms:endpoint name="statusTopic" topic="flight.status"/>
14     <jms:endpoint name="xmppMessageQueue" queue="xmppMessageQueue"/>
15
16
17     <model name="HelloESB">
18
19         <service name="SendMessage">
20             <inbound>
21                 <cxf:inbound-endpointaddress="http://localhost:65082/services/SendMessage" />
22             </inbound>
23             
24             <component>
25                 <singleton-objectclass="com.soabpmn.tutorial.mule.service.impl.SendMessageImpl" />
26             </component>
27             
28             <outbound>
29                 <filtering-router transformer-refs="InputMessageTransformer">
30                     <jms:outbound-endpoint ref="xmppMessageQueue" transformer-refs="ObjectToJMSMessage"/>
31                     <message-property-filter pattern="messageType=xmpp"/>
32                 </filtering-router>
33
34                 <filtering-router transformer-refs="InputMessageTransformer">
35                     <stdio:outbound-endpoint system="OUT" transformer-refs="MessagingSystemTransformer" />
36                     <message-property-filter pattern="messageType=stdio"/>
37                 </filtering-router>
38             </outbound>
39         </service>
40
41         <service name="JabberSystem">
42             <inbound>
43                 <jms:inbound-endpoint ref="xmppMessageQueue"/>
44                 <vm:inbound-endpoint path="jabberSystem"/>
45             </inbound>
46             
47             <componentclass="com.soabpmn.tutorial.mule.xmpp.MessagingComponent"/>
48             
49             <outbound >
50                 <pass-through-router>
51                     <xmpp:outbound-endpoint host="jabber.com"
52                                             recipient=""
53                                             user="AUser" password="ThePassword"port="5222"
54                                             transformer-refs="MessagingSystemTransformer JabberTransformer"/>
55                 </pass-through-router>
56             </outbound>
57         </service>     

Um unsere Beispielanwendung zu testen, benötigen wir einen Webservice Client wie beispielsweisesoapUI. SoapUI ist ein Webservice Testing Tool, das sowohl standalone als auch in Eclipse integriert werden kann. Nachdem wir unsere Beispielanwendung gestartet haben, sollten wir unter http://localhost:65082/services/SendMessage?wsdl unseren Webservice finden. Um den Service mit soapUI zu testen legen wir ein neues soapUI Projekt an und geben dort die Service-Adresse ein.

New soapUI Project

SoapUI erzeugt nun für uns eine Request-Message, in der wir unsere Service-Parameter eingeben und anschließend unsere Nachricht verschicken können.

02    <soapenv:Header/>
03    <soapenv:Body>
04       <ser:sendMessage>
05          <!--Optional:-->
06          <message>HelloESB</message>
07          <!--Optional:-->
08          <recipient>user@jabber.com</recipient>
09          <!--Optional:-->
10          <messageType>xmpp</messageType>
11       </ser:sendMessage>
12    </soapenv:Body>
13 </soapenv:Envelope>

Wenn wir nun nirgendwo gestolpert sind, sollte unser Jabber Client uns mit „HelloESB“ begrüßen.

Anhang Größe
MuleHelloESBTutorial.zip 10.79 KB​
Posted in Java | Leave a comment

Maven in den Griff bekommen

Schritt 1 – Maven installieren

Im ersten Schritt muss man Maven installieren. Maven ist ein Satz von Werkzeugen zur Verwaltung von Softwarebauprozessen. Maven wird über Konfigurationsdateien (pom.xml) gesteuert und von der Kommandozeile aus angestoßen. Die Installation auf einem aktuellen Ubuntu System ist denkbar einfach und gelingt mit folgendem Befehl auf der Kommandozeile:

1 user@hostnamesudo aptitude install maven2

Den Erfolg der Installation kann man durch folgenden Befehl auf der Kommandozeile überprüfen:

1 user@hostname$ mvn -v
2 Maven version: 2.0.9
3 Java version: 1.6.0_13
4 OS name: "linux" version: "2.6.28-13-generic" arch: "amd64" Family: "unix"

Erhält man die gezeigte Ausgabe, war die Installation erfolgreich.

Unter Windows verläuft die Installation sehr ähnlich. Man lädt sich das entsprechende Paket von der Maven Homepage und installiert es. Anschließend muss man lediglich noch darauf achten, dass das Verzeichnis, welches die mvn Programmdatei enthält, im Suchpfad (PATH) enthalten ist. Den Suchpfad kann man über die Systemsteuerung konfigurieren.

Schritt 2 – Quelldateien generieren

Nun kann man auch schon die Java Web Applikation von Maven generieren lassen. Dazu nutzt man prinzipiell folgenden Befehl:

1 user@hostname$ mvn archetype:create -DgroupId=XYZ -DartifactId=ABC -DarchetypeArtifactId=maven-archetype-webapp

Puh, auf den ersten Blick sieht dies mächtig komplex aus, doch was passiert hier genau? Maven (mvn) ruft den create Befehl des archetype Plugins auf. Alle anderen Angaben sind lediglich Parameter für dieses Plugin und den create Befehl. Die Parameter werden als Java Kommandozeilenparameter in der Form

1 -Dparameter=wert

übergeben. Für den create Befehl des archetype Plugins werden im obigen Beispiel die folgenden 3 Parameter übergeben:

  • groupId – der Paketname für unser Projekt
  • artifactId – der Projektname
  • archetypeArtifactId – die vom create Befehl zu verwendende Vorlage (Template); Würden wir diesen Parameter weglassen, würde der create Befehl standardmäßig ein einfaches Java Projekt erzeugen und keine Java Web Applikation.

Bevor wir den Befehl ausführen, sollten wir sinnvolle Namen für die Parameter groupId undartifactId auswählen. Als groupId könnte man zum Beispiel den Domainnamen verwenden, unter dem später die Web Applikation erreichbar sein sollte. Die einzelnen Bestandteile des Domainnamen gibt man dabei in umgekehrter Reihenfolge an.

In diesem einfachen Beispiel ist der Wert des artifactId Parameters wichtiger, denn der Wert wird als Verzeichnisname für das Projekt genutzt. Später wird die Web Applikation auch über die URL http://localhost:8080/artifactID erreichbar sein.

Nachdem wir die Bedeutung aller Parameter geklärt haben, können wir nun den Befehl mit folgenden Angaben ausführen:

1 user@hostname$ mvn archetype:create -DgroupId=com.soa-bpm-integration.webapp-expl -DartifactId=webapp-expl_web -DarchetypeArtifactId=maven-archetype-webapp

Die ersten Aufrufe von Maven werden einige Zeit benötigen, denn Maven lädt nun die notwendigen Plugins herunter. So muss Maven zum Beispiel erst einmal das archetype Plugin samt der verschiedenen Befehle nachladen.

Nachdem der Befehl ausgeführt wurde, hat man folgende neue Verzeichnisstruktur:

  • webapp-expl_web

    • src

      • main

        • resources
        • webapp

          • WEB-INF

            • web.xml
          • index.jsp
    • pom.xml

Die gesamte Verzeichnisstruktur sowie der Inhalt der 3 Dateien (web.xml, index.jsp und pom.xml) wurde von Maven automatisch ohne manuelle Eingriffe generiert. Die Dateien sind so vollständig, dass wir im nächsten Schritt automatisch die ausführbare und deploybare Java Web Applikation generieren können.

Schritt 3 – WAR Archiv erzeugen

Im vorherigen Schritt haben wir die Projektstruktur der Java Web Applikation samt aller notwendigen Quell- und Konfigurationsdateien durch Maven erzeugt. Nun müssen wir die Java Web Applikation noch kompilieren und die zugehörige WAR Datei erzeugen. Für unser obiges Beispiel, geht dies wiederum mit einem einzigen Maven Befehl. Bevor der Befehl ausgeführt werden kann, müssen wir in das Verzeichnis wechseln, in dem sich die pom.xml Datei befindet.

1 user@hostname$ mvn package

Beim ersten Aufruf dieses Befehls wird Maven wieder eine Reihe von Dateien aus dem Internet runterladen müssen. Nachdem der Befehl ausgeführt wurde, enthält das Hauptverzeichnis ein neues Unterverzeichnis target/. In diesem ist die kompilierte und archivierte Java Web Applikation abgelegt. Im folgenden Verzeichnisbaum wurde das Quellverzeichnis (src/) zur besseren Übersicht zugeklappt, aber es kann durch einen Klick auf den Verzeichnisbaum aufgeklappt werden.

  • webapp-expl_web

    • target

      • classes
      • war

        • work

          • webapp-cache.xml
      • webapp-expl_web

        • META-INF
        • WEB-INF

          • classes
          • web.xml
        • index.jsp
      • webapp-expl_web.war
    • pom.xml

An dieser Stelle könnten wir das Tutorial eigentlich beenden. Die webapp-expl_web.war Datei kann nun auf einem beliebigen Java Servlet Container wie Apache Tomcat installiert werden. Gerade im Entwicklungszyklus wäre es aber sehr umständlich, wenn man jedesmal von Hand die Datei im Applikationsserver installieren müsste. Hier kann Maven wiederum behilflich sein, wie der nächste Schritt zeigt.

Schritt 4 – Java Web Applikation mit Jetty testen

Für Maven gibt es ein Jetty Plugin. Damit kann man direkt aus einem Maven Aufruf heraus die zuvor erzeugte Web Applikation in eine Jetty Instanz laden. Damit das funktioniert, muss diepom.xml Datei händisch erweitert werden. Bis zu diesem Zeitpunkt haben wir keinen einzigen manuellen Eingriff vorgenommen! Die vollständige pom.xml Datei sieht folgendermaßen aus.

02   <modelversion>4.0.0</modelversion>
03   <groupid>com.soa-bpm-integration.webapp-expl</groupid>
04   <artifactid>webapp-expl_web</artifactid>
05   <packaging>war</packaging>
06   <version>1.0-SNAPSHOT</version>
07   <name>webapp-expl_web Maven Webapp</name>
08   <url>http://maven.apache.org</url>
09   <dependencies>
10     <dependency>
11       <groupid>junit</groupid>
12       <artifactid>junit</artifactid>
13       <version>3.8.1</version>
14       <scope>test</scope>
15     </dependency>
16   </dependencies>
17   <build>
18     <finalname>webapp-expl_web</finalname>
19       <!-- Beginn hinzugefuegter Teil -->
20       <plugins>
21         <plugin>
22           <groupid>org.mortbay.jetty</groupid>
23           <artifactid>maven-jetty-plugin</artifactid>
24         </plugin>
25       </plugins>
26       <!-- Ende hinzugefuegter Teil -->
27   </build>
28 </project>

In der gezeigten pom.xml Datei wurden lediglich die Zeilen 19 bis 26 händisch eingefügt. Mit diesen Zeilen wird ausgedrückt, dass während der Build Phase von Maven das Plugin Jetty zu laden ist. Jetzt kann man genau dieses Jetty Plugin mit folgendem Maven Befehl aufrufen.

1 user@hostname$ mvn jetty:run

Maven startet nun eine lokale Jetty Instanz und deployt die Web Applikation auf diesem Server. Dieser Vorgang ist abgeschlossen, wenn folgende Ausgabe erscheint.

1 [INFO] Started Jetty Server

Man kann nun die eigene Web Applikation im Browser aufrufen unter der URL: http://localhost:8080/artifactId. Dabei ist natürlich artifactId durch den Wert zu ersetzen, den man in Schritt 2 dafür verwendet hat. In unserem Beispiel müsste man also die URLhttp://localhost:8080/webapp-expl_web/ aufrufen.

Wenn alles geklappt hat, erhält man eine “Hello World” Seite. Der Inhalt dieser Seite wird natürlich aus der index.jsp Datei gesteuert.

Die Abhängigkeit auf Jetty hat keinen negativen Einfluss auf die Web Applikation. Möchte man zum Beispiel nur das Web Archiv (WAR) erzeugen, führt man den mvn package Befehl aus. Die Maven Build Phase kommt nach der Package Phase und hat damit keinen Einfluss auf die Erstellung des Web Archivs.

Dieses Tutorial hat natürlich nur an einem ganz einfachen Beispiel gezeigt, wie man mit Maven eine Web Applikation generieren kann. Dieses Beispiel lässt sich nun beliebig komplex ausbauen. Bei Gelegenheit werden wir hier auf weitere Möglichkeiten eingehen, etwa wie man das Maven Projekt in verschiedene Teilprojekte aufteilt oder wie man ein Web Framework wie Spring und Struts einbinden kann.counter

Posted in Java | Leave a comment