Showing posts with label glassfish. Show all posts
Showing posts with label glassfish. Show all posts

January 31, 2012

Easy OAuth using DaliCore and Glassfish: the service consumer

After having completed the first part of this OAuth story, it is now time to implement the second part: the service consumer. While the our service provider made use of the DaliCore module dalicore-oauth, the service consumer will use the module dalicore-externalnetwork to make our connection to the service provider easier.

As in part 1, it is probably best to download the sample service consumer application, which will make this tutorial a bit easier to follow.

Manage service consumers

Before we start with the service consumer application itself, we need to be able to register service consumers in our service provider. Create a new class in the service provider application with the name ServiceConsumerHandler next to the already existing OAuthHandler class.

@Path("serviceconsumer")
@ManagedBean
public class ServiceConsumerHandler {
  @Inject
  OAuthBean oauthBean;

  @GET
  @Produces("text/html")
  public String create(@QueryParam("name") String name) {
    if (name != null && ! name.trim().isEmpty()) {
      DaliServiceConsumer daliServiceConsumer = new DaliServiceConsumer();
      daliServiceConsumer.setName(name);
      daliServiceConsumer.setConsumerKey(StringUtil.getSecureRandomString(16));
      daliServiceConsumer.setConsumerSecret(StringUtil.getSecureRandomString(16));
      daliServiceConsumer.setStatus(DaliServiceConsumer.Status.ACTIVE);
      oauthBean.createDaliServiceConsumer(daliServiceConsumer);

      return "consumer key: " + daliServiceConsumer.getKey() + "
consumer secret: " + daliServiceConsumer.getSecret() + ""; } else { return "No name provided. Add ?name=service_consumer_name at the end of the URL."; } } }

After redeploying the application, we can create a service consumer by calling http://localhost:8080/oauthprovider/rest/serviceconsumer?name=ServiceConsumerName. The response will show us the service consumer key and secret that we will need later on when connecting to the service provider.

Creating the service consumer application

Now we can start with the creation of our oauth service consumer. Create a new Maven Web Application project in NetBeans.

Create a new Maven Web Application project in NetBeans

Maven setup

As in the first part of the series, we need to change the maven pom.xml file so that it will be able to download the LodgON artifacts. Include the following repository in your pom.xml:

<repositories>
  <repository>
    <id>lodgon</id>
    <url>http://maven.lodgon.com/maven2</url>
  </repository>
</repositories>

Afterwards add the following maven dependencies:

<dependency>
  <groupId>com.lodgon.dalicore</groupId>
  <artifactId>dalicore-externalnetwork</artifactId>
  <version>0.9.11-SNAPSHOT</version>
</dependency>
<dependency>
  <groupId>com.sun.jersey</groupId>
  <artifactId>jersey-server</artifactId>
  <version>1.8</version>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>com.sun.jersey.contribs.jersey-oauth</groupId>
  <artifactId>oauth-signature</artifactId>
  <version>1.8</version>
</dependency>

Jersey handler and jsp's

Now we can create a handler that will handle the connection to the service provider. Create a new class called HomeHandler with the following code:

@Path("home")
public class HomeHandler {
  private static final String PROVIDER_URL = "http://localhost:8080/oauthprovider/rest";
  private static final String CONSUMER_KEY = "";
  private static final String CONSUMER_SECRET = "";
  private static final String CONSUMER_CALLBACK = "http://localhost:8080/oauthconsumer/rest/home/callback";

  @Context
  HttpServletRequest request;

  @GET
  public Response home() throws URISyntaxException {
    ExternalToken accessToken = (ExternalToken) request.getSession().getAttribute("accessToken");
    if (accessToken == null) {
      DaliCoreExternalNetwork externalNetwork = new DaliCoreExternalNetwork(PROVIDER_URL,
            CONSUMER_KEY, CONSUMER_SECRET);
      return externalNetwork.connect(CONSUMER_CALLBACK);
    } else {
      return Response.ok(new Viewable("/home.jsp", accessToken)).build();
    }
  }

  @GET
  @Path("callback")
  public Response callback(@QueryParam("oauth_token") String requestToken,
          @QueryParam("oauth_verifier") String verifier) throws URISyntaxException {
    DaliCoreExternalNetwork externalNetwork = new DaliCoreExternalNetwork(PROVIDER_URL,
            CONSUMER_KEY, CONSUMER_SECRET);
    ExternalToken accessToken = externalNetwork.callback(requestToken, verifier);
    request.getSession().setAttribute("accessToken", accessToken);
    return Response.seeOther(new URI("/home")).build();
  }
}

This class contains two entry points. The home entry point is the URL that is being called to initiate a connection with our service provider. It detects if an access token exists on the active session. If an access token does not exist, we will connect with the dalicore-oauth service provider, by using the utility class DaliCoreExternalNetwork. The constructor of this class takes three parameters: the URL to the service provider, our consumer key and our consumer secret. Update the static fields at the top with the consumer key and secret you received by creating a service consumer as mentioned previously. When we have an instance of the DaliCoreExternalNetwork we simply call the connect method and provide the callback where the user will be redirected to after it authorized the service consumer.

The callback is handled by the second entry point, named callback. It accepts the request token and a verifier that we will need to request our access token. This can also be done through the DaliCoreExternalNetwork helper class. By calling the callback method we will finally receive a valid access token which we store on the active session. Finally, we redirect the user back to the home page, which will print our access token information in the browser.

web.xml configuration

Next we need to activate Jersey so our handler will be processed. Create a Standard Deployment Descriptor and put in the following code:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
        version="3.0">
  <servlet>
    <servlet-name>jerseyservlet</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>jerseyservlet</servlet-name>
    <url-pattern>/rest/*</url-pattern>
  </servlet-mapping>
  <session-config>
    <session-timeout>
      30
    </session-timeout>
  </session-config>
</web-app>

JPA Configuration

Finally, we need to configure a connection with the database where the tokens will be stored. Create a persistence.xml file in the directory src/main/resources/META-INF with the following content:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="oauth_provider_pu" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>jdbc/oauthconsumerdb</jta-data-source>
    <class>com.lodgon.dali.core.entity.Application</class>
    <class>com.lodgon.dali.core.entity.Content</class>
    <class>com.lodgon.dali.core.entity.ContentPermission</class>
    <class>com.lodgon.dali.core.entity.Field</class>
    <class>com.lodgon.dali.core.entity.Group</class>
    <class>com.lodgon.dali.core.entity.GroupPermission</class>
    <class>com.lodgon.dali.core.entity.TypePermission</class>
    <class>com.lodgon.dali.core.entity.User</class>
    <class>com.lodgon.dali.core.entity.UserPermission</class>
    <class>com.lodgon.dali.core.externalnetwork.entity.ExternalToken</class>
    <class>com.lodgon.dali.core.externalnetwork.entity.OnlineAccount</class>
    <properties>
      <property name="eclipselink.ddl-generation" value="create-tables"/>
    </properties>
  </persistence-unit>
</persistence>

Pre-deployment configuration

Again, just like we did when setting up the service provider, we need to add the JDBC resources to glassfish. Create a file called sun-resources.xml with the following content:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 9.0 Resource Definitions //EN" "http://www.sun.com/software/appserver/dtds/sun-resources_1_3.dtd">
<resources>
  <jdbc-connection-pool connection-validation-method="auto-commit" datasource-classname="org.apache.derby.jdbc.EmbeddedDataSource" res-type="javax.sql.DataSource" name="derby_oauthconsumerdb_j2eepool" wrap-jdbc-objects="false">
    <property name="ConnectionAttributes" value=";create=true" />
    <property name="DatabaseName" value="memory:oauthconsumerdb" />
  </jdbc-connection-pool>
  <jdbc-resource enabled="true" jndi-name="jdbc/oauthconsumerdb" object-type="user" pool-name="derby_oauthconsumerdb_j2eepool"/>
</resources>

And add the resources to glassfish by calling the add-resources asadmin command:

$ asadmin add-resources sun-resources.xml

Building and deployment

Finally, you can build and deploy the application by pressing F6. Afterwards point your browser to http://localhost:8080/oauthconsumer/rest/home. Login with any username and password, authorize the service consumer and you should have your access token!

Easy OAuth using DaliCore and Glassfish: the service provider

DaliCore is really starting to get some momentum recently, so I thought it is time to write something about it. DaliCore currently contains three modules:
dalicore-ejb
contains everything related to managing the dalicore entities: User, Content, Group and Permission
dalicore-oauth
allows web applications to become an oauth service provider
dalicore-externalnetwork
allows web applications to setup a connection with oauth providers

This blog entry will focus on the second module. I'll show you how easy it is with dalicore-oauth to create a web application that can serve as an oauth service provider. In the next blog entry, we'll make a second web application that serves as the oauth service consumer that will use dalicore-externalnetwork to connect to our service provider. Our application server of choice is glassfish 3.1.1 and we'll be using Jersey for our web related components.

It's probably better to download the sample service provider application already. This should make it easier to follow all the steps below.

Creating an application

Allright, time to get started. We start with creating the web application that will act as our oauth service provider. Fire up NetBeans and create a new Maven Web Application project.

Create a new Maven Web Application project in NetBeans

Maven setup

To be able to make use of dalicore-oauth, we need to change the pom.xml and add LodgOn's maven repository. Include the following code in your pom.xml:

<repositories>
  <repository>
    <id>lodgon</id>
    <url>http://maven.lodgon.com/maven2</url>
  </repository>
</repositories>

Now we can add the maven dependency to dalicore-oauth and other modules that we will need. Add the following dependencies in your pom.xml, in the dependencies section:

<dependency>
  <groupId>com.lodgon.dalicore</groupId>
  <artifactId>dalicore-ejb</artifactId>
  <version>0.9.11-SNAPSHOT</version>
</dependency>
<dependency>
  <groupId>com.lodgon.dalicore</groupId>
  <artifactId>dalicore-oauth</artifactId>
  <version>0.9.11-SNAPSHOT</version>
</dependency>
<dependency>
  <groupId>com.sun.jersey</groupId>
  <artifactId>jersey-server</artifactId>
  <version>1.8</version>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>com.sun.jersey.contribs.jersey-oauth</groupId>
  <artifactId>oauth-signature</artifactId>
  <version>1.8</version>
</dependency>

Jersey handler and jsp's

An oauth service provider typically needs to provide three end points: one for requesting a request token, one to authenticate a user and a third to request an access token. The creation of the request and access tokens are automatically handled by dalicore-oauth. So, the only thing we need to add is the handling of user authentication. Create a new class called OAuthHandler with the following code:

@Path("oauth")
@ManagedBean
public class OAuthHandler {
  @Inject
  OAuthBean oauthBean;
  @Inject
  UserBean userBean;

  @GET
  @Path("authenticate")
  public Viewable authenticate(@QueryParam("oauth_token") String oauthToken) {
    return new Viewable("/login.jsp", new Model(oauthToken));
  }

  @POST
  @Path("login")
  public Viewable login(@FormParam("oauth_token") String oauthToken,
          @FormParam("username") String userName,
          @FormParam("password") String password) throws DaliCoreException {
    User user = userBean.getByUserId(userName);
    if (user == null) {
      user = new OAuthUser();
      user.setUserId(userName);
      user = userBean.create(user);
      userBean.setPassword(user.getId(), password);
    }

    if (userBean.validatePassword(user.getId(), password)) {
      DaliToken requestToken = oauthBean.findDaliToken(oauthToken, DaliToken.Type.OAUTH_REQUEST_TOKEN);
      return new Viewable("/authorize.jsp", new Model(oauthToken, user, oauthToken.getDaliServiceConsumer()));
    } else {
      return new Viewable("/login.jsp", new Model(oauthToken, "Login failed."));
    }
  }

  @POST
  @Path("authorize")
  public Response authorize(@FormParam("oauth_token") String oauthToken,
          @FormParam("userUid") String userUid,
          @DefaultValue("no") @FormParam("authorized") String authorized) throws DaliCoreException, URISyntaxException, UnsupportedEncodingException {
    DaliToken requestToken = oauthBean.findDaliToken(oauthToken, DaliToken.Type.OAUTH_REQUEST_TOKEN);

    if ("yes".equals(authorized)) {
      User user = userBean.getByUid(userUid);
      if (user != null) {
        String verifier = oauthBean.authorizeServiceConsumer(user.getId(), oauthToken, true);
        return Response.seeOther(new URI(requestToken.getCallback() + "?" + OAuthParameters.TOKEN + "=" + URLEncoder.encode(oauthToken, "UTF-8") + "&" + OAuthParameters.VERIFIER + "=" + URLEncoder.encode(verifier, "UTF-8"))).build();
      } else {
        return Response.ok(new Viewable("/login.jsp", new Model(oauthToken))).build();
      }
    } else {
      return Response.seeOther(new URI(requestToken.getCallback())).build();
    }
  }

  public static class Model {
    private String message;
    private String oauthToken;
    private DaliServiceConsumer serviceConsumer;
    private User user;

    public Model(String oauthToken) {
      this.oauthToken = oauthToken;
    }

    public Model(String oauthToken, String message) {
      this.oauthToken = oauthToken;
      this.message = message;
    }

    public Model(String oauthToken, User user, DaliServiceConsumer serviceConsumer) {
      this.oauthToken = oauthToken;
      this.user = user;
      this.serviceConsumer = serviceConsumer;
    }

    public String getMessage() {
      return message;
    }

    public void setMessage(String message) {
      this.message = message;
    }

    public String getOauthToken() {
      return oauthToken;
    }

    public void setOauthToken(String oauthToken) {
      this.oauthToken = oauthToken;
    }

    public DaliServiceConsumer getServiceConsumer() {
      return serviceConsumer;
    }

    public void setServiceConsumer(DaliServiceConsumer serviceConsumer) {
      this.serviceConsumer = serviceConsumer;
    }

    public User getUser() {
      return user;
    }

    public void setUser(User user) {
      this.user = user;
    }
  }
}

The class is a Jersey handler that contains three endpoints. The first endpoint authenticate will be called by service consumers that would like to authenticate a user for their application. We will show a basic login page where a user can provide a username and password.

The second endpoint login handles a user that tries to login. For the sake of simplicity, we will create a new user when no user was found with the provided username. Notice, that this user must be of type OAuthUser, which is an extension of the dalicore-ejb User. Upon successful login, the user will be redirected to an authorization page where he/she can choose whether to allow the service consumer to access his/her user data.

Which brings us to the third endpoint authorize, where a user authorizes the service consumer. When the user allows access to the service consumer, we will call the service consumer's callback. A service consumer should have provided this callback when it requested the request token earlier on in the oauth process. We will come back to that when we create the service consumer application.

Below you will find the two jsp's (login.jsp and authorize.jsp) that we will need, one to allow a user to login and another one to authorize a specific service consumer.

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>dalicore-oauth service provider</title>
  </head>
  <body>
    <h1>Authenticate</h1>

    <form method="POST" action="${pageContext.request.contextPath}/rest/oauth/login">
      <input type="hidden" name="oauth_token" value="${it.oauthToken}"/>
      username: <input type="text" name="username"/><br/>
      password: <input type="password" name="password"/><br/>
      <input type="submit" value="login"/>
    </form>
  </body>
</html>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>dalicore-oauth service provider</title>
  </head>
  <body>
    <h1>Authorize</h1>

    <h4>Do you want to allow the service consumer <b>${it.serviceConsumer.name}</b> to access your data:</h4>

    <form method="POST" action="${pageContext.request.contextPath}/rest/oauth/authorize">
      <input type="hidden" name="oauth_token" value="${it.oauthToken}"/>
      <input type="hidden" name="userUid" value="${it.user.uid}"/>
      <input type="submit" name="authorize" value="yes"/>
      <input type="submit" name="authorize" value="no"/>
    </form>
  </body>
</html>

CDI configuration

You probably noticed that at the top of the OAuthHandler class, we use CDI to inject a reference to the UserBean and the OAuthBean. In order for CDI to work, we need to add a beans.xml in the WEB-INF directory. So, create the directory WEB-INF in the Web Pages directory and add the following beans.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>

web.xml configuration

The next steps are required to allow the dalicore-oauth module to be plugged in correctly. We need to configure the Jersey servlet so it can handle oauth requests. This is all done in the standard deployment descriptor (probably better known as web.xml). In NetBeans you can right-click on Web Pages and choose "New -> Standard Deployment Descriptor (web.xml)". In the web.xml file we will add the section for the jersey servlet:

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0">
  <servlet>
    <servlet-name>jerseyservlet</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
      <param-name>com.sun.jersey.config.property.oauth.ignorePathPattern</param-name>
      <param-value>requestToken|accessToken</param-value>
    </init-param>
    <init-param>
      <param-name>com.sun.jersey.config.property.packages</param-name>
      <param-value>com.sun.jersey.oauth.server.api.resources;com.lodgon.dali.core.oauth;com.mycompany.oauthprovider</param-value>
    </init-param>
  </servlet>

  <servlet-mapping>
    <servlet-name>jerseyservlet</servlet-name>
    <url-pattern>/rest/*</url-pattern>
  </servlet-mapping>

  <session-config>
    <session-timeout>
      30
    </session-timeout>
  </session-config>
</web-app>

There are two init parameters for the Jersey servlet that require some explanation. When a URL on our web application is called with the Authorization HTTP header, it will be filtered by the Jersey OAuth filter. However, getting a request token or access token also contains the Authorization HTTP header. Since these aren't regular OAuth requests, these should be ignored by the OAuth filter. This can be done by specifying the com.sun.jersey.config.property.oauth.ignorePathPattern init parameter.

The second init parameter com.sun.jersey.config.property.packages is required to tell Jersey which packages to scan for providers and handlers. Be sure not to forget to specify the package in which you created the OAuthHandler class. Otherwise it won't be detected by Jersey and you'll receive 404 responses when trying to authenticate a user.

JPA configuration

The final requirement is to configure our connection to the database. This is needed because dalicore-oauth persistently stores its request and access tokens, its users and its list of service consumers. Create a persistence.xml file in the directory src/main/resources/META-INF with the following content:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="oauth_provider_pu" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>jdbc/oauthproviderdb</jta-data-source>
    <class>com.lodgon.dali.core.entity.Application</class>
    <class>com.lodgon.dali.core.entity.Content</class>
    <class>com.lodgon.dali.core.entity.ContentPermission</class>
    <class>com.lodgon.dali.core.entity.Field</class>
    <class>com.lodgon.dali.core.entity.Group</class>
    <class>com.lodgon.dali.core.entity.GroupPermission</class>
    <class>com.lodgon.dali.core.entity.TypePermission</class>
    <class>com.lodgon.dali.core.entity.User</class>
    <class>com.lodgon.dali.core.entity.UserPermission</class>
    <class>com.lodgon.dali.core.oauth.entity.Attribute</class>
    <class>com.lodgon.dali.core.oauth.entity.DaliToken</class>
    <class>com.lodgon.dali.core.oauth.entity.DaliServiceConsumer</class>
    <class>com.lodgon.dali.core.oauth.entity.OAuthUser</class>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties>
      <property name="eclipselink.ddl-generation" value="create-tables"/>
    </properties>
  </persistence-unit>
</persistence>

Pre-deployment configuration

We're almost there. Before we can actually deploy our application, we need to add the JDBC resources to glassfish. Create a file called sun-resources.xml with the following content:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 9.0 Resource Definitions //EN" "http://www.sun.com/software/appserver/dtds/sun-resources_1_3.dtd">
<resources>
  <jdbc-connection-pool connection-validation-method="auto-commit" datasource-classname="org.apache.derby.jdbc.EmbeddedDataSource" res-type="javax.sql.DataSource" name="derby_oauthproviderdb_j2eepool" wrap-jdbc-objects="false">
    <property name="ConnectionAttributes" value=";create=true" />
    <property name="DatabaseName" value="memory:oauthproviderdb" />
  </jdbc-connection-pool>
  <jdbc-resource enabled="true" jndi-name="jdbc/oauthproviderdb" object-type="user" pool-name="derby_oauthproviderdb_j2eepool"/>
</resources>

I choose to connect to an in memory derby database here, but you can of course configure your resources to connect to a real database. Add the resources to glassfish by calling the following asadmin command:

$ asadmin add-resources sun-resources.xml

Building and deployment

Now you can build the application and deploy it in glassfish. Building can be done in NetBeans by pressing F11 and deploying is done with the shortkey F6. You can of course also use the command line if you prefer that:

$ mvn clean install
$ asadmin deploy --name oauthprovider --contextroot oauthprovider target/oauthprovider-1.0-SNAPSHOT.war

The application should deploy successfully and now you can point your browser to the following location: http://localhost:8080/oauthprovider/rest/oauth/authenticate. This should show the login screen.

Now it's time to head over to part 2, where we will create the service consumer side that will connect to the service provider application we created here.

March 01, 2011

Load balancing with Glassfish 3.1 and Apache

Glassfish 3.1 was released on February 28th. This is the first application server that supports Java EE 6 in a clustered and high available environment. We at LodgON have a high interest in this, as Johan Vos already mentioned in his blog and we are eager to find out how easy it is to configure Glassfish to let it run multiple instances using Apache as a load balancer. I'll describe the steps I had to go through for setting up the following configuration:

  • machine1: Glassfish DAS, 1 instance, Apache HTTP server with mod_jk enabled

  • machine2: 1 instance


Configuring the nodes



Install Glassfish 3.1 on machine1. Once that is completed, we need to setup ssh so we can manage node machine2 centrally from machine1. So on machine1 enter the following command:

$ asadmin setup-ssh machine2


This is basically a frontend for the ssh-keygen tool. It will ask for the password of your user on machine2 and copies the necessary keyfiles over to that machine. We are now ready to install glassfish on machine2 by using the install-node command:

$ asadmin install-node --installdir /opt/glassfish3 machine2


This copies glassfish over to the node with the host name specified in the last parameter and installs it in the specified installation directory. I encountered a problem where it said that the command jar was not found. To resolve this in Ubuntu, make sure you specify java in your PATH in ~/.bashrc before the following lines:

# If not running interactively, don't do anything
[ -z "$PS1" ] && return


Everything after these lines will not be executed when logging in with an non-interactive shell like in our case, via ssh.

Now we can start the DAS on machine1 and begin configuring our instances.

$ asadmin start-domain


Configuring the cluster



We will now create a remote and a local instance into one cluster. We will first let the DAS know that we have another node on machine2 that we want to use by creating an ssh node:

$ asadmin create-node-ssh --installdir /opt/glassfish3 --nodehost machine2 node1


After that we can create the cluster and add two instances to it: one remote instance on node node1 and a local instance on the local node. This local node, with name localhost-domain1, is automatically available when installing glassfish.

$ asadmin create-cluster cluster1
$ asadmin create-instance --cluster cluster1 --node node1 inst1
$ asadmin create-instance --cluster cluster1 --node localhost-domain1 inst2


We can now start the cluster and deploy an application into it. It doesn't really matter which application you want to deploy. I will use a simple application containing only 1 jsp (download the application):

$ asadmin start-cluster cluster1
$ asadmin deploy --target cluster1 --name simple simple-application.war


When deploying, you specify our cluster1 as the target. This will deploy the application into every instance that was added to the cluster. When deployment was successful, you should be able to browse to the application using the following URL: http://machine2:28080/simple. It should also be running on the second instance at the following URL: http://machine1:28081/simple.

Configuring the load balancer



We have both instances running our application, so now we can start configuring Apache to run as the load balancer. To let Apache connect with Glassfish, you'll have to use the mod_jk module. Installing it in Ubuntu is very easy:

$ sudo apt-get install libapache2-mod-jk


Once the module is installed, create a file called jk.conf in the mods-available directory in your apache configuration directory (mine is located in /etc/apache2/mods-available) and link it into the mods-enabled directory.

$ sudo touch /etc/apache2/mods-available/jk.conf
$ sudo ln -s /etc/apache2/mods-available/jk.conf /etc/apache2/mods-enabled/jk.conf


In that file you can copy the following configuration:

JkWorkersFile /etc/apache2/worker.properties
JkLogFile /var/log/apache2/mod_jk.log
JkLogLevel error
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories
JkRequestLogFormat "%w %V %T"


The first line specifies the location of the workers file in which we will configure our Glassfish instances. So, create the file in the directory /etc/apache2 and add the following properties:

worker.list=worker1,worker2,loadbalancer

# default properties for workers
worker.template.type=ajp13
worker.template.port=28009
worker.template.lbfactor=50
worker.template.connection_pool_timeout=600
worker.template.socket_keepalive=1
worker.template.socket_timeout=300

# properties for worker1
worker.worker1.reference=worker.template
worker.worker1.host=machine1

# properties for worker2
worker.worker2.reference=worker.template
worker.worker2.host=machine2

# properties for loadbalancer
worker.loadbalancer.type=lb
worker.loadbalancer.balance_workers=worker1,worker2


Finally, in the default virtual host configuration file (on my machine this is located at /etc/apache2/sites-available/default) we add a line to tell mod_jk which URLs have to be forwarded to the load balancer:

JkMount /simple/* loadbalancer


You can read more about all these configuration directives and properties on the website of the Apache Tomcat Connector:


When you are done with this, we restart the Apache HTTP server to let the settings take effect:

$ sudo apache2ctl graceful


Finally, we need to add a HTTP listener in the Glassfish cluster that will listen for the calls from mod_jk. As we specified in the workers.properties file, this listener will be listening on port 28009. Adding this listener works with the following command:

$ asadmin create-network-listener --protocol http-listener-1 --listenerport 28009 --jkenabled true --target cluster1-config jk-connector


Restart the cluster and we should be able to connect to our application through Apache at the following URL: http://machine1/simple.

$ asadmin stop-cluster cluster1
$ asadmin start-cluster cluster1


Conclusion



You can see that it was quite easy to set up a clustered Glassfish with Apache running as the load balancer. You might want to watch the following video about the new features in Glassfish 3.1. It might give you a bit more insight in the way that clustering and load balancing works. It will also show you that you can configure everything by using the admin website (running at port 4848) instead of using the asadmin command as I did in this blog.

October 03, 2009

Easy file upload in Java using Jersey and Uploadify

Uploading a bunch of files to your server. I have come across this particular requirement a few times now during my web development career, but only recently did I discover a very easy way to implement it. And by easy I mean easy on both the client side and the server side.

Server

On the server side we develop our web applications in Java using Glassfish for our deployement server. You can have your standard Servlet class that catches your requests, but recently we bumped into Jersey. And I must say, I really love it. Here is for example the code to accept a file upload request.

@Path("/file")
public class FileHandler {
@POST
@Path("/upload")
@Consumes("multipart/form-data")
@Produces("text/plain")
public String uploadFile(@FormParam("file") File file, @FormParam("file") FormDataContentDisposition fcdsFile) {
String fileLocation = "/files/" + fcdsFile.getFileName();
File destFile = new File(fileLocation);

// your code here to copy file to destFile

return "1";
}
}

That's it. The FormDataContentDisposition is a recent addition to Jersey which allows you to retrieve the name of the file that is being uploaded.

Client

For the client side, I decided to make use of Uploadify. They basically provided a wrapper around SWFUpload using JQuery. Here is the code I used on the client side:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>SimpleFileUpload</title>
<script type="text/javascript" src="js/swfobject.js"></script>
<script type="text/javascript" src="js/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="js/jquery.uploadify.v2.1.0.min.js"></script>
<link rel="stylesheet" href="css/uploadify.css" type="text/css" media="screen"/>

<script type="text/javascript">
$(function() {
$('#file_upload').uploadify({
'uploader' : 'swf/uploadify.swf',
'script' : 'rest/file/upload',
'fileDataName' : 'file',
'cancelImg' : 'img/cancel.png',
'multi' : true
});
});
</script>
</head>
<body>
<h1>Simple File Upload</h1>

<h3>Multiple file upload made easy</h3>

<div id="file_upload"></div>
<br/>
<input type="button" value="Clear Queue" onclick="$('#file_upload').uploadifyClearQueue();"/>
<input type="button" value="Submit Queue" onclick="$('#file_upload').uploadifyUpload();"/>
</body>
</html>

Voila, now you have a simple web application that is able to upload files to your server. You can download a sample application here.

August 09, 2007

UTF-8 encoding with MySQL and Glassfish

Allright, after 6 hours of coding, googling, experimenting and swearing, I finally managed to develop a website that fully supports UTF-8. The website is running on Glassfish Application Server (build V2 50g to be more precise) with a MySQL database underneath. Listed below, you can find all the steps I had to go through in order to get the website running.

JSP's

  • With the JSP @page directive you can specify the desired encoding by specifying both the page encoding and the content type:
    <%@ page pageEncoding="UTF-8" contentType="text/html;charset=UTF-8" language="java" %>
    pageEncoding specifies in which encoding the jsp page has been saved. contentType defines what content type should be sent in the response to the browser.

  • It is further recommended to provide the content type through the meta-tag within the head-tag of the HTML-document:
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    ...
    </head>
    ...
    </html>
  • To be complete, you can also specify the @charset directive at the top of every external css page you are using:
    @charset "utf-8";
    ...

Servlets

  • With every request you get in a Servlet, you'll have to set the encoding on the Request object:
    public void doXXXX(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    request.setCharacterEncoding("UTF-8");
    ...
    }
    Beware that if you use a filter that already reads from the Request, you will need to set the character encoding in the filter.

  • At the same time, when you build your response, for example to return XML or JSON data, you set the content type of the Response object:
    response.setContentType("application/json; charset=UTF-8");
    As you probably know, this response header has to be set before you start writing your data.

Database

  • MySQL supports Unicode as of version 4.1 and by that it is possible to store data in de database in UTF-8 encoding. Activating the UTF-8 encoding on a MySQL table is done during its creation by specifying a CHARACTER SET and a COLLATION:
    CREATE TABLE `USER` (
    ...
    ) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_unicode_ci;
    For more information about character sets in MySQL, you can read the document Character Set Support.

  • At least your data is now stored in UTF-8, but it doesn't end there. In Glassfish, you still have to create a JDBC Connection Pool with the correct settings allowing the JDBC driver to actually read and write your data in UTF-8. In the Admin Console you select the desired Connection Pool and then you navigate to Additional Properties. You will already see a number of properties being filled in (like DatabaseName, url, username and password). To enable UTF-8 support for JDBC, you'll have to add two extra properties:
    useUnicode = true
    characterEncoding = utf8

Mail

  • To be able to send e-mail messages encoded in UTF-8, you will also need to provide the encoding type on the subject and the content of the message. Finally, you also need to set the content type of the e-mail message itself.
    MimeMessage msg = new MimeMessage(session);
    msg.setSubject(subject, "UTF-8");
    msg.setText(body, "UTF-8");
    if (asHtml) {
    msg.setContent(mailMessage.getBody(), "text/html; charset=UTF-8");
    msg.setHeader("Content-Type", "text/html; charset=UTF-8");
    } else {
    msg.setHeader("Content-Type", "text/plain; charset=UTF-8");
    }


And that's it. You should now have a website that doesn't give problems showing and storing your UTF-8 content. Below you can see a screenshot of my web application that shows data in Georgian (username), in Japanese (Location) and even in Runic alphabet (Tags):