Pagina's

zondag 3 november 2013

Using war class dependencies in Maven

Sometimes it is necessary to use classes from a Maven war project in another project. The dependent project therefore needs a dependency upon the war project. This sounds easy but including a war dependency like in the following example is not going to work:

<dependency>
    <groupId>example</groupId>
    <artifactId>exampleWeb</artifactId>
    <version>1.0</version>
    <type>war</type>
 </dependency>


In a Maven project you simply cannot use classes directly from a war dependency because they won't be added to the Maven classpath. Of course, there are many (complicated) ways to get around this but there is also an easy and clean way to get this working.

The solution lies within the Maven project in which the war file is created. This war file is created by the Maven war plugin. This plugin can be configured to create an additional artifact that contains the classes of the project. So the build will result in both a war file and a jar file.
In order to do this, configure the war plugin as follows:

<build>
    <plugins>
        <plugin>
            <artifactId>maven-war-plugin</artifactId>
            <version>2.4</version>
            <configuration>
                <attachClasses>true</attachClasses>
            </configuration>
        </plugin>
    </plugins>
</build> 


The attachClasses configuration parameter will result in the extra classes jar. Note that this classes jar will contain a classifier in its name. By default, this classifier is 'classes'. This means that the resulting name will for example be: example.exampleWeb-1.0-classes.jar. Instead of 'attachClasses' you can also use the 'archiveClasses' parameter. When using archiveClasses, the Maven war plugin will put all classes in the separate jar file instead of in the war file.

Now in the dependent project you can use the generated jarfile by using a dependency like:
<dependency>
    <groupId>example</groupId>
    <artifactId>exampleWeb</artifactId>
    <version>1.0</version>
    <classifier>classes</classifier>
</dependency>


So this is an easy way to get a dependency upon the classes from a war project.
In case you don't like the default classifier 'classes', you can change it into something else by using the war plugin configuration parameter 'classesClassifier'.

zaterdag 2 november 2013

Easy LDAP access with Unboundid

Lately I have been evaluating a couple of LDAP SDK's. The mean reason for this evaluation is the fact that the standard API provided with Java is not very coder-friendly. A lot of boilerplate code needs to be written even to do simple things.

The frameworks i've been looking at are: Unboundid, Ldaptive and Spring LDAP. In this article I will show an example of LDAP access using Unboundid LDAP SDK. Unboundid contains a sub-framework they call 'Unboundid LDAP SDK Persistence framework'. It contains annotation-based persistence support to/from LDAP. In this example I will add a user to LDAP and then read it again. The user can be annotated with Unboundid annotations and this makes it very easy to do a basic implementation.
First of all we create a new Maven project and add the following dependencies:

<dependencies>
    <dependency>
        <groupId>com.unboundid</groupId>
        <artifactId>unboundid-ldapsdk</artifactId>
        <version>2.3.4</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
    </dependency>
</dependencies> 


Next, we define a User POJO which represents the User domain type. The POJO will be annotated by a couple of Unboundid annotations which indicate how the User is stored within LDAP.
package example;

import com.unboundid.ldap.sdk.persist.FilterUsage;
import com.unboundid.ldap.sdk.persist.LDAPField;
import com.unboundid.ldap.sdk.persist.LDAPObject;

@LDAPObject(structuralClass = "inetOrgPerson", defaultParentDN = "ou=people,dc=example,dc=com")
public class User {

    @LDAPField(attribute = "uid", inRDN = true, filterUsage = FilterUsage.ALWAYS_ALLOWED)
    private String id;
    @LDAPField(attribute = "cn")
    private String name;
    @LDAPField(attribute = "sn")
    private String surName;
    @LDAPField(attribute = "mail")
    private String emailAddress;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSurName() {
        return surName;
    }

    public void setSurName(String surName) {
        this.surName = surName;
    }

    public String getEmailAddress() {
        return emailAddress;
    }

    public void setEmailAddress(String emailAddress) {
        this.emailAddress = emailAddress;
    }
}

The @LDAPObject annotation indicates that the User object is stored in LDAP and is based on the structural LDAP class 'inetOrgPerson'. Furthermore, a parent DN is specified so Unboundid knows where to store/retrieve LDAP user records. The @LDAPField annotation specifies the way each User property is stored in LDAP. More info about these annotation can be found here: https://www.unboundid.com/products/ldap-sdk/docs/persist/index.php

Next we will define a Dao class which can be used to store/retrieve User's:

package example;


import com.unboundid.ldap.sdk.LDAPInterface;
import com.unboundid.ldap.sdk.persist.LDAPPersistException;
import com.unboundid.ldap.sdk.persist.LDAPPersister;

public class UserDao {

    private LDAPInterface ldapServer;
    private LDAPPersister<User> persister;

    public UserDao(LDAPInterface ldapServer) throws LDAPPersistException {
        this.ldapServer = ldapServer;
        this.persister = LDAPPersister.getInstance(User.class);
    }

    public User findUser(String id) throws LDAPPersistException {
        User userToFind = new User();
        userToFind.setId(id);
        User foundUser = persister.searchForObject(userToFind, ldapServer);
        return foundUser;
    }

    public void addUser(User user) throws LDAPPersistException {
        persister.add(user, ldapServer, null);
    }
}

This Dao class receives an ldap server obect through its constructor. This ldap server object provides a lot of low-level LDAP manipulation operations. It is used by a higher-level persister to persist annotated objects. The findUser and addUser methods show how easy this is. Just create a User instance and pass it to the persister.

To show how this works, we create a basic unit test. In this unit test, an in-memory directory server is created and an LDAP schema is loaded. After that, we add a user and then retrieve it again. It's as easy as this:

package example;

import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import org.junit.Assert;
import org.junit.Test;

public class AppTest {

    @Test
    public void testUnboundid() throws Exception {
        InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig("dc=example, dc=com");
        config.addAdditionalBindCredentials("cn=Directory Manager", "password");

        InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
        ds.importFromLDIF(true, "src/test/resources/ldap.ldif");
        ds.startListening();
       
        UserDao userDao = new UserDao(ds);
       
        User newUser = new User();
        newUser.setId("jdoe");
        newUser.setName("John Doe");
        newUser.setSurName("doe");
        userDao.addUser(newUser);
               
        User foundUser = userDao.findUser("jdoe");
        Assert.assertEquals("John Doe", foundUser.getName());
    }

}
My conclusion is that Unboundid is a very useful framework for LDAP access. It takes away much of the low-level coding that would otherwise be necessary when using the basic JNDI classes.