Showing posts with label GWT. Show all posts
Showing posts with label GWT. Show all posts

Sunday, February 5, 2012

Spring 3.1: GWT Maven Plugin and GWTHandler Integration (Part 1)

In this tutorial, we will create a simple GWT application and integrate it with Spring. We will use GWTHandler to map GWT's RPC services to Spring beans, and utilize the GWT Maven plugin to manage and build our project. Our application is a Hello World-style application that you typically when creating a new GWT project.


Dependencies

  • Spring core 3.1.0.RELEASE
  • Maven
  • GWT Maven Plugin 2.4.0
  • gwt-sl 1.3-RC1
  • See pom.xml for details

Github

To access the source code, please visit the project's Github repository (click here)

Functional Specs

Before we start, let's define our application's specs as follows:
  • Create a simple Hello World-style application
  • Use GWT Maven plugin to manage the project
  • Integrate Spring

Screenshots

Before we start with the actual development, let's preview how our application will look like.

Entry page
The entry page is the only page that users can access. Here, users can enter their name.
Entry page

After the user has submitted his name, a popup message will appear.
Popup message without Spring

After we've integrated Spring, we shall see a different popup message.
Popup message with Spring

Next

In the next section, we will create our GWT project using the GWT Maven plugin. Click here to proceed
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring 3.1: GWT Maven Plugin and GWTHandler Integration (Part 1) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

Spring 3.1: GWT Maven Plugin and GWTHandler Integration (Part 2)

Review

In the previous section, we have laid down the functional specs of the application. In this section, we will discuss the project's structure and create the GWT application using the GWT Maven plugin.


Project Structure

Our application is a Maven project. It has been auto-generated using the Maven GWT plugin tool.

Starting with GWT Maven

To start this project, you are required to have the following:

Also, take note of the following:
  • You're not required to download the GWT SDK!
  • You can skip Eclipse and opt for command-line style development, but you must have Maven installed.
  • If you use STS, m2eclipse is already installed.

What is GWT Maven Plugin?

The GWT Maven Plugin allows you to setup your GWT web application development using Maven as build tool. It allows you to organize and setup, integrate with a development environment, and run GWT SDK tools from the Maven command line.

If you're new to GWT, please read the GWT documentation. If you're new to Maven, please read the Maven Getting Started Guide

Source: http://mojo.codehaus.org/gwt-maven-plugin/index.html

What is m2eclipse?

The goal of the m2ec project is to provide a first-class Apache Maven support in the Eclipse IDE, making it easier to edit Maven's pom.xml, run a build from the IDE and much more.

Source: http://eclipse.org/m2e/

Creating the Project

1. Open Eclipse (I'm using SpringSource Tool Suite here)

2. Go to File and create a new Maven project

3. On the Select an Archetype section, type gwt-maven-plugin. Then click Next.

4. On the Specify Archetype parameters section, enter the following details (Don't forget to add the module property). Then click Finish.

5. Once the project has been auto-generated, you'll notice some errors. This is because the GreetingServiceAsync and Message are missing! You must generate them by triggering a Maven command or let Maven generate them automatically for you.


Add the Missing Classes

To add the missing classes manually, we need to run the following Maven goals:
  • gwt:generateAsync - it's purpose is to generate the Async interfaces
  • gwt:i18n - it's purpose is to generate internationalization interfaces
For more info regarding these goals, please see Generate Async interfaces for GWT-RPC services and Generate i18n interfaces for message bundles

To generate these interfaces manually, follow these steps:

6. Right-click on your project. Select Run As, then Run Configurations

7. Select the Maven build... option. You should see a new Run Configurations window.

8. Fill it up with the following information (make sure to update the workspace!):

9. Run the goal and you should see the following output:
[INFO] Scanning for projects...
[INFO] -------------------------------------
[INFO] Building GWT Maven Archetype
[INFO]    task-segment: [gwt:generateAsync]
[INFO] -------------------------------------
[INFO] [gwt:generateAsync {execution: default-cli}]
[INFO] -------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] -------------------------------------
[INFO] Total time: 13 seconds
[INFO] Finished at: Tue Jan 31 11:00:42 CST 2012
[INFO] Final Memory: 15M/38M
[INFO] -------------------------------------

10. Now, let's generate the internalization interfaces. Create a new Run Configurations (same with the previous steps).

11. Fill it up with the following information (make sure to update the workspace!):

12. Run the goal and you should see the following output:
[INFO] Scanning for projects...
[INFO] -------------------------------------
[INFO] Building GWT Maven Archetype
[INFO]    task-segment: [gwt:i18n]
[INFO] -------------------------------------
[INFO] [gwt:i18n {execution: default-cli}]
[INFO] -------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] -------------------------------------
[INFO] Total time: 5 seconds
[INFO] Finished at: Tue Jan 31 11:08:39 CST 2012
[INFO] Final Memory: 15M/38M
[INFO] -------------------------------------

Copying the Generated Interfaces

After generating the interfaces, we must copy and paste them on the src/main/java folder

13. Copy the following files: GenerateAsync and Messages

14. Paste them to the src/main/java folder

Running the Project

To run the project using Maven, we will use the gwt:run command.

15. Create a new Run Configurations.

16. Fill it up with the following information (make sure to update the workspace!):

17. Run the goal and you should see the following output:
[INFO] Scanning for projects...
[INFO] -------------------------------------
[INFO] Building GWT Maven Archetype
[INFO]    task-segment: [gwt:run]
[INFO] -------------------------------------
[INFO] Preparing gwt:run
[INFO] [gwt:i18n {execution: default}]
[INFO] [gwt:generateAsync {execution: default}]
[INFO] [resources:resources {execution: default-resources}]
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 3 resources
[INFO] [compiler:compile {execution: default-compile}]
[INFO] Compiling 1 source file to C:\workspace\spring-gwt-tutorial\target\spring-gwt-tutorial-0.0.1-SNAPSHOT\WEB-INF\classes
[INFO] [war:exploded {execution: default}]
[INFO] Exploding webapp
[INFO] Assembling webapp [spring-gwt-tutorial] in [C:\workspace\spring-gwt-tutorial\target\spring-gwt-tutorial-0.0.1-SNAPSHOT]
[INFO] Processing war project
[INFO] Copying webapp resources [C:\workspace\spring-gwt-tutorial\src\main\webapp]
[INFO] Webapp assembled in [126 msecs]
[INFO] [gwt:run {execution: default-cli}]
[INFO] create exploded Jetty webapp in C:\workspace\spring-gwt-tutorial\target\spring-gwt-tutorial-0.0.1-SNAPSHOT
[INFO] auto discovered modules [org.krams.tutorial.gwtmodule]

18. When the app starts to run, you should see the following GWT Development Mode windows


19. Click the Launch Default Browser to see the application's entry page.
Entry page

20. Enter a name and click Send. You should get a response similar to the following:
Popup message without Spring

Congratulations! You've just managed to create a simple GWT Maven project!

Next

In the next section we will study how to integrate Spring and GWTHandler in our GWT project. Click here to proceed
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring 3.1: GWT Maven Plugin and GWTHandler Integration (Part 2) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

Spring 3.1: GWT Maven Plugin and GWTHandler Integration (Part 3)

Review

In the previous section, we have discussed how to generate a simple GWT application using the GWT Maven plugin. In this section, we will study how to integrate Spring and GWT using the GWTHandler library via configuration and modifying existing classes.


Integrating GWTHandler

What is GWTHandler?

The GWTHandler is part of the GWT Server Library--a collection of Java server side components for the Google Web Toolkit AJAX framework with the current focus on the Spring framework by facilitating publishing of Spring beans as RPC services.

The GWTHandler allows you to quickly map multiple RPC service beans to different URLs very similar to the way Spring's SimpleUrlHandlerMapping maps URLs to controllers.

Source: http://code.google.com/p/gwt-sl/

Configuration

The initial step in configuring the GWTHandler is to declare our XML configuration files:
  • web.xml
  • gwt-servlet.xml
  • applicationContext.xml

In the web.xml the part that you need to pay extra attention is the url-pattern. Here we've declared the pattern as /gwtmodule/rpc/*. This means all RPC calls should follow that pattern!


The gwt-servlet.xml is nothing but a simple bean declaration. Here we've declared a GWTHandler bean, and it contains one mapping. We've mapped all calls to /greet to be processed by a GreetingService implementation. Remember this is an RPC call,sSo if you have plans of calling this RPC mapping, you must also take account the mapping the gwt-servlet.xml! In other words, the complete path is rpc/greet.


In the applicationContext.xml we've basically enabled annotation scanning.


Classes

The second step in configuring the GWTHandler is to modify our existing classes to take advantage of the GWTHandler.

We will create a new service class:
  • SpringService

And edit the following classes:
  • GreetingService
  • GreetingServiceImpl

The SpringService basically prints out a Hello *name* from Spring 3.1 message.


As discussed earlier, to use the /greet RPC mapping, we have to consider the parent mapping from the gwt-servlet.xml as well. In other words, the complete mapping for this RPC is rpc/greet


Next we modify the GreetingServiceImpl to take advantage of the SpringService implementation. So instead of the original reply that includes server information, we're now returning a simple "hello" message instead.


For completion purposes, we will also show the contents of the gwtmodule class, though nothing has been changed.


Next

In the next section, we will build and run the application using Maven, and show how to import the project in Eclipse. Click here to proceed.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring 3.1: GWT Maven Plugin and GWTHandler Integration (Part 3) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

Spring 3.1: GWT Maven Plugin and GWTHandler Integration (Part 4)

Review

In the previous section, we have studied how to generate a simple GWT application using the GWT Maven plugin. We've also learned how integrate Spring and GWT using the GWTHandler library. In this section, we will build and run the application using Maven, and show how to import the project in Eclipse (if you've decided in Part 2 to use command-line based development).


Running the Application

Access the source code

To download the source code, please visit the project's Github repository (click here)

Building with Maven

  1. Ensure Maven is installed
  2. Open a command window (Windows) or a terminal (Linux/Mac)
  3. Run the following command:
    mvn gwt:run
  4. You should see the following output:
    [INFO] Scanning for projects...
    [INFO] ------------------------------------------
    [INFO] Building GWT Maven Archetype
    [INFO]    task-segment: [gwt:run]
    [INFO] ------------------------------------------
    [INFO] Preparing gwt:run
    [INFO] [gwt:i18n {execution: default}]
    [INFO] [gwt:generateAsync {execution: default}]
    [INFO] [gwt:run {execution: default-cli}]
    [ERROR] INFO: Mapped URL path [/greet] onto handler of type [class org.gwtwidgets.server.spring.GWTRPCServiceExporter]
    [ERROR] Feb 5, 2012 2:49:45 PM org.springframework.web.servlet.FrameworkServlet initServlet
    
  5. Note: If the project will not build due to missing repositories, please enable the repositories section in the pom.xml!

Access the Entry page

  1. Follow the steps with Building with Maven
  2. Open a browser
  3. Enter the following URL (8080 is the default port for Tomcat):
    http://127.0.0.1:8888/gwtmodule.html?gwt.codesvr=127.0.0.1:9997
    Or better yet, on the GWT Development Mode window, click on the Launch Default Browser button.
You should see the following page (the popup message will appear when you submit a name):

Import the project in Eclipse

  1. Ensure Maven is installed
  2. Open a command window (Windows) or a terminal (Linux/Mac)
  3. Run the following command:
    mvn eclipse:eclipse -Dwtpversion=2.0
  4. You should see the following output:
    [INFO] Scanning for projects...
    [INFO] Searching repository for plugin with prefix: 'eclipse'.
    [INFO] org.apache.maven.plugins: checking for updates from central
    [INFO] org.apache.maven.plugins: checking for updates from snapshots
    [INFO] org.codehaus.mojo: checking for updates from central
    [INFO] org.codehaus.mojo: checking for updates from snapshots
    [INFO] artifact org.apache.maven.plugins:maven-eclipse-plugin: checking for updates from central
    [INFO] artifact org.apache.maven.plugins:maven-eclipse-plugin: checking for updates from snapshots
    [INFO] -----------------------------------------
    [INFO] Building GWT Maven Archetype
    [INFO]    task-segment: [eclipse:eclipse]
    [INFO] -----------------------------------------
    [INFO] Preparing eclipse:eclipse
    [INFO] [gwt:i18n {execution: default}]
    [INFO] [gwt:generateAsync {execution: default}]
    [INFO] [eclipse:eclipse {execution: default-cli}
    [INFO] Adding support for WTP version 2.0.
    [INFO] -----------------------------------------
    [INFO] BUILD SUCCESSFUL
    [INFO] -----------------------------------------
    
    This command will add the following files to your project:
    .classpath
    .project
    .settings
    target
    You may have to enable "show hidden files" in your file explorer to view them
  5. Open Eclipse and import the project

Maven Issues

If in case you have Maven repository issues, you can always download the depedencies directly from Sonatype OSS for Google GWT.

Conclusion

That's it! We've have successfully completed our GWT and Spring integration. We've learned how to generate a simple GWT project using the GWT Maven plugin, and integrate Spring using the GWTHandler library.

I hope you've enjoyed this tutorial. Don't forget to check my other tutorials at the Tutorials section.

Revision History


Revision Date Description
1 Feb 5 2012 Uploaded tutorial and Github repository

StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring 3.1: GWT Maven Plugin and GWTHandler Integration (Part 4) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

Saturday, January 8, 2011

Spring and GWT: Security via Spring Security

In this tutorial we will secure our existing GWT application through Spring Security. We will create a transparent layer for managing our application's security. We will be using the application we built in the following tutorial: Spring and GWT Integration using Maven and GWTHandler (Part 1). Please read that first, so that you have a basic idea of the project's structure. Also, please read Spring Security 3 - MVC: Using a Simple User-Service Tutorial for a basic introduction in setting-up Spring Security.

What is Spring Security?
Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications

Spring Security is one of the most mature and widely used Spring projects. Founded in 2003 and actively maintained by SpringSource since, today it is used to secure numerous demanding environments including government agencies, military applications and central banks.

Source: http://static.springsource.org/spring-security/site/index.html

What is GWT?
Google Web Toolkit (GWT) is a development toolkit for building and optimizing complex browser-based applications. GWT is used by many products at Google, including Google AdWords and Orkut. It's open source, completely free, and used by thousands of developers around the world.

Source: http://code.google.com/webtoolkit/

We start by editing the web.xml file to enable the Spring Security filters (We will not discuss again what we've covered in the previous tutorials).

web.xml





 
 
  contextConfigLocation    /WEB-INF/spring-security.xml
  /WEB-INF/applicationContext.xml
   
 
 
   
         springSecurityFilterChain
         org.springframework.web.filter.DelegatingFilterProxy
 
 
 
 
         springSecurityFilterChain
         /*
 

 
 
  org.springframework.web.context.ContextLoaderListener
 

 
 
  gwt
  org.springframework.web.servlet.DispatcherServlet
  1
 
 
 
 
  spring
  org.springframework.web.servlet.DispatcherServlet
  1
 
 
 
 
  gwt
  gwtmodule/rpc/*
 
 
 
 
  spring
  krams/*
 

We have declared a reference to a spring-security.xml configuration. This contains the Spring Security settings for our application.

spring-security.xml


 
 
 
 
  
  
  
  
  
  
  
  
  
  
  
     
  
  
   
  
 
 
 
 
 
         
           
         
 
 
 
 

  
  
  
     
     
   
 
   
 
 
   
 
 
  
 
  
The defining configuration here are the custom beans we've created. Here's the reason: In a normal Spring MVC application with Spring Security enabled regardless whether the user is authorized or not, he will be redirected to a corresponding View, i.e a JSP page. However, GWT is an AJAX application that operates in the RPC level. If you try redirecting to a page, it will not work. The solution is to provide a custom HttpServletResponse response to tell GWT that the user is authorized or not. These responses are HTTP status codes:
200 - Authenticated and authorized
401 - Not authenticated and not authorized
401 - (Or) authenticated but not authorized

The developer's job is to interpret what to do next for these set of responses. Here are the custom beans.

CustomAuthenticationEntryPoint
/**
 * 
 */
package org.krams.tutorial.security;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;

public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {

 protected static Logger logger = Logger.getLogger("security");
 
 public void commence(HttpServletRequest request, HttpServletResponse response,
   AuthenticationException exception) throws IOException, ServletException {

   logger.debug("Authentication required");
   
    HttpServletResponse httpResponse = (HttpServletResponse) response;
         httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication required");
 }

}
CustomAuthenticationSuccessHandler
package org.krams.tutorial.security;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

public class CustomAuthenticationSuccessHandler implements
  AuthenticationSuccessHandler {

 protected static Logger logger = Logger.getLogger("security");

 public void onAuthenticationSuccess(HttpServletRequest request,
   HttpServletResponse response, Authentication authentication) throws IOException,
   ServletException {
  
   logger.debug("Authentication success");
   
     HttpServletResponse httpResponse = (HttpServletResponse) response;
         httpResponse.sendError(HttpServletResponse.SC_OK, "Authentication success");
 }

}
CustomAuthenticationFailureHandler
package org.krams.tutorial.security;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;

public class CustomAuthenticationFailureHandler implements
  AuthenticationFailureHandler {

 protected static Logger logger = Logger.getLogger("security");
 
 public void onAuthenticationFailure(HttpServletRequest request,
   HttpServletResponse response, AuthenticationException exception)
   throws IOException, ServletException {
  
   logger.debug("Authentication failure");
   
   HttpServletResponse httpResponse = (HttpServletResponse) response;
   httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication failure");  
 }

}
Let's run our application and see what will happen. Again, we use the Maven gwt:run goal to execute the application.


After sending our name, we get a server error message. How do we know that this is caused by Spring Security and not by a missing RPC service? We check the logs!

Here's the Jetty log:
00:00:18.667 [WARN] 401 - POST /gwtmodule/rpc/greet (127.0.0.1) 1433 bytes

Here's the log4j log:
[DEBUG] [btpool0-0 04:34:46] (CustomAuthenticationEntryPoint.java:commence:23) Authentication required

Clearly it's because we're not authorized. At this point, we know our services are secured! However, the error message is misleading. We need to provide a friendly message.

Go the client package of our project. Open the gwtmodule.java, and replace the contents of the sendNametoServer() method with the following:

gwtmodule.java
  /**
       * Send the name from the nameField to the server and wait for a response.
       */
      private void sendNameToServer() {
        // First, we validate the input.
        errorLabel.setText("");
        final String textToServer = nameField.getText();
        if (!FieldVerifier.isValidName(textToServer)) {
          errorLabel.setText("Please enter at least four characters");
          return;
        }

        // Then, we send the input to the server.
        sendButton.setEnabled(false);
        textToServerLabel.setText(textToServer);
        serverResponseLabel.setText("");
        
        // We first check if user is authorized by checking a flag URL
        
        // Create a new request
        RequestBuilder rb = new RequestBuilder(RequestBuilder.GET, "/krams/main/admin");
  rb.setCallback(new RequestCallback() {
   
      public void onError(Request request, Throwable exception) {
       // Error in sending request
      }
      
      public void onResponseReceived(Request request, Response response) {
          if (response.getStatusCode() == 200) {
           
           // Send the input to the server.
           greetingService.greetServer(textToServer, new AsyncCallback() {
                  public void onFailure(Throwable caught) {
                    // Show the RPC error message to the user
                    dialogBox.setText("Remote Procedure Call - Failure");
                    serverResponseLabel.addStyleName("serverResponseLabelError");
                    //serverResponseLabel.setHTML(SERVER_ERROR);
                    serverResponseLabel.setHTML(caught.getMessage());
                    dialogBox.center();
                    closeButton.setFocus(true);
                  }

                  public void onSuccess(String result) {
                    dialogBox.setText("Remote Procedure Call");
                    serverResponseLabel.removeStyleName("serverResponseLabelError");
                    serverResponseLabel.setHTML(result);
                    dialogBox.center();
                    closeButton.setFocus(true);
                  }
                });
     
          } else {
             // User is not authorized!
             // Show the RPC error message to the user
                   dialogBox.setText("Remote Procedure Call - Failure");
                   serverResponseLabel.addStyleName("serverResponseLabelError");
                   serverResponseLabel.setHTML("You are not authorized!");
                   dialogBox.center();
                   closeButton.setFocus(true);
          }
      }
  });
  
  try {
   rb.send();
  } catch (RequestException re) {
   //Log.error("Exception in sending RequestBuilder: " + re.toString());
  }
  
      }
    }
What we did here is wrap our RPC service request inside GWT's RequestBuilder. Also, we called a custom URL that points to a JSP page to verify the authentication of the user. This JSP page as declared in the spring-security.xml has the following access level:

<security:intercept-url pattern="/krams/main/admin" access="hasRole('ROLE_ADMIN')"/>
This URL is only accessible if the user is authenticated and has admin rights. If we can access this then the current user has the rights.

What is RequestBuilder?
Provides the client-side classes and interfaces for making HTTP requests and processing the associated responses.

Most applications will be interested in the Request, RequestBuilder, RequestCallback and Response classes.

Source: http://www.gwtapps.com/doc/html/com.google.gwt.http.client.html

For more info about RequestBuilder, please visit this link.

Notice in the code, we only execute the GreetingService's greetServer() method when the status code is equal to 200
if (response.getStatusCode() == 200) {
  ...
}
If the status code is different, we send a customized error message:
...
else {
 // User is not authorized!
 // Show the RPC error message to the user
 dialogBox.setText("Remote Procedure Call - Failure");
 serverResponseLabel.addStyleName("serverResponseLabelError");
 serverResponseLabel.setHTML("You are not authorized!");
 dialogBox.center();
 closeButton.setFocus(true);
}
Let's run our application again and verify the results.


We now have a friendlier error message. That's great. But how do we log in? We can't.

We have to create a custom login screen either via a JSP page (if you have Spring MVC enabled) or via GWT (this means you'll need to know how to use widgets, similar with the greet server interface). To make our lives easier, we'll use a JSP page because in the first place Spring MVC is already enabled in the web.xml, spring-servlet.xml, and applicationContext.xml

This means we need to add corresponding controllers and JSP pages. If you to refresh your memory on Spring MVC and integration with Spring Security, please visit the following tutorial: Spring Security 3 - MVC Integration Tutorial.

Here are our controllers:

LoginLogoutController
/**
 * 
 */
package org.krams.tutorial.controller;


import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * Handles and retrieves the login or denied page depending on the URI template
 */
@Controller
@RequestMapping("/auth")
public class LoginLogoutController {
        
 protected static Logger logger = Logger.getLogger("controller");

 /**
  * Handles and retrieves the login JSP page
  * 
  * @return the name of the JSP page
  */
 @RequestMapping(value = "/login", method = RequestMethod.GET)
 public String getLoginPage(@RequestParam(value="error", required=false) boolean error, 
   ModelMap model) {
  logger.debug("Received request to show login page");

  // Add an error message to the model if login is unsuccessful
  // The 'error' parameter is set to true based on the when the authentication has failed. 
  // We declared this under the authentication-failure-url attribute inside the spring-security.xml
  // However this doesn't seem to work when GWT is enabled
  if (error == true) {
   // Assign an error message
   model.put("error", "You have entered an invalid username or password!");
  } else {
   model.put("error", "");
  }
  
  // This will resolve to /WEB-INF/jsp/loginpage.jsp
  return "loginpage";
 }
 
 /**
  * Handles and retrieves the denied JSP page. This is shown whenever a regular user
  * tries to access an admin only page.
  * 
  * @return the name of the JSP page
  */
 @RequestMapping(value = "/denied", method = RequestMethod.GET)
  public String getDeniedPage() {
  logger.debug("Received request to show denied page");
  
  // This will resolve to /WEB-INF/jsp/deniedpage.jsp
  return "deniedpage";
 }
}
MainController
package org.krams.tutorial.controller;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * Handles and retrieves the common or admin page depending on the URI template.
 * A user must be log-in first he can access these pages.  Only the admin can see
 * the adminpage, however.
 */
@Controller
@RequestMapping("/main")
public class MainController {

 protected static Logger logger = Logger.getLogger("controller");
 
 /**
  * Handles and retrieves the common JSP page that everyone can see
  * 
  * @return the name of the JSP page
  */
    @RequestMapping(value = "/common", method = RequestMethod.GET)
    public String getCommonPage() {
     logger.debug("Received request to show common page");
    
     // Do your work here. Whatever you like
     // i.e call a custom service to do your business
     // Prepare a model to be used by the JSP page
     
     // This will resolve to /WEB-INF/jsp/commonpage.jsp
     return "commonpage";
 }
    
    /**
     * Handles and retrieves the admin JSP page that only admins can see
     * 
     * @return the name of the JSP page
     */
    @RequestMapping(value = "/admin", method = RequestMethod.GET)
    public String getAdminPage() {
     logger.debug("Received request to show admin page");
    
     // Do your work here. Whatever you like
     // i.e call a custom service to do your business
     // Prepare a model to be used by the JSP page
     
     // This will resolve to /WEB-INF/jsp/adminpage.jsp
     return "adminpage";
 }
}
Here are the JSP pages.

loginpage.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

<h1>Login</h1>

<div id="login-error">${error}</div>

<form action="../../j_spring_security_check" method="post" >

<p>
 <label for="j_username">Username</label>
 <input id="j_username" name="j_username" type="text" />
</p>

<p>
 <label for="j_password">Password</label>
 <input id="j_password" name="j_password" type="password" />
</p>

<input  type="submit" value="Login"/>        
 
</form>

</body>
</html>
deniedpage.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>Access Denied!</h1>
<p>Only admins can see this page!</p>
</body>
</html>
adminpage.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>Admin Page</h1>
<p>Only admins have access to this page.</p>
<p>Curabitur quis libero elit, dapibus iaculis nisl. Nullam quis velit eget odio 
adipiscing tristique non sed ligula. In auctor diam eget nisl condimentum laoreet..</p>
</body>
</html>
commonpage.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>Common Page</h1>
<p>Everyone has access to this page.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ac velit et ante 
laoreet eleifend. Donec vitae augue nec sem condimentum varius.</p>
</body>
</html>

To login using the JSP page, open a new browser or a new tab. Then use the following URL:
http://127.0.0.1:8888/krams/auth/login
Here's the login page.

Notice there's an error ${error}. In a normal Spring MVC application, this should be hidden and only populated via a model object. I decided to include this error here anyway to remind my readers that integrating GWT and Spring have some disadvantages as well.

Try logging-in. Use john for the username and admin for the password.

You should see the following message:
HTTP ERROR: 200

Authentication success
RequestURI=/j_spring_security_check

Powered by Jetty://
We receive an HTTP error because the URL that we'd been redirected http://127.0.0.1:8888/j_spring_security_check doesn't exist for viewing. But notice we're authenticated.

Now, try sending a message again. Go the GWT application, and send a message. Here's what we should get:

That's it. We're created a simple GWT application that's secured by Spring Security. We've explored ways of integrating both technologies, including Spring MVC. We've also discussed how we can use RequestBuilder for requesting standard resources.

As a side note, you can create a GWT login-page that delegates the authentication via RequestBuilder. For example:
RequestBuilder rb = new RequestBuilder(RequestBuilder.POST, "/j_spring_security_check");

rb.setHeader("Content-Type", "application/x-www-form-urlencoded");

rb.setRequestData("j_username=" + URL.encode(myusername + "&j_password=" + URL.encode("mypassword")));


Notice how it's similar with a standard JSP login page:
<form action="../../j_spring_security_check" method="post" >

<p>
 <label for="j_username">Username</label>
 <input id="j_username" name="j_username" type="text" />
</p>

<p>
 <label for="j_password">Password</label>
 <input id="j_password" name="j_password" type="password" />
</p>

<input  type="submit" value="Login"/>        
 
</form>

The best way to learn further is to try the actual application.

Download the project
You can access the project site at Google's Project Hosting at http://code.google.com/p/spring-mvc-gwt/

You can download the project as a Maven build. Look for the spring-gwt-security.zip in the Download sections.

You can run the project directly using the Maven GWT plugin.
mvn gwt:run

If you want to learn more about Spring MVC and integration with other technologies, feel free to read my other tutorials in the Tutorials section.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring and GWT: Security via Spring Security ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

Spring and GWT Integration using Maven and GWTHandler (Part 2)

In this tutorial we will continue what we had left off from Spring and GWT Integration using Maven and GWTHandler (Part 1). Last time we set-up a simple GWT project using Maven. We generated the Async interfaces and run the application using specialized Maven goals. Now we will start integrating Spring with our current GWT application.

Note: An updated version of this guide is available at Spring 3.1: GWT Maven Plugin and GWTHandler Integration

We start by declaring the necessary XML configurations. We will do a side-by-side (actually top-by-down) comparison of the old and new configurations. Let's begin with the web.xml.

web.xml (old)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

  <!-- Servlets -->
  <servlet>
    <servlet-name>greetServlet</servlet-name>
    <servlet-class>org.krams.tutorial.server.GreetingServiceImpl</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>greetServlet</servlet-name>
    <url-pattern>/gwtmodule/greet</url-pattern>
  </servlet-mapping>

  <!-- Default page to serve -->
  <welcome-file-list>
    <welcome-file>gwtmodule.html</welcome-file>
  </welcome-file-list>

</web-app>
web.xml (new)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

  <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>

 <!-- Front Controller for all GWT Spring based servlets -->
 <servlet>
  <servlet-name>gwt</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>
 
 <!-- Front Controller for all Spring based servlets -->
 <servlet>
  <servlet-name>spring</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>
 
 <!-- Don't forget to declare a gwt-servlet.xml -->
 <servlet-mapping>
  <servlet-name>gwt</servlet-name>
  <url-pattern>gwtmodule/rpc/*</url-pattern>
 </servlet-mapping>
 
 <!-- Don't forget to declare a spring-servlet.xml -->
 <servlet-mapping>
  <servlet-name>spring</servlet-name>
  <url-pattern>krams/*</url-pattern>
 </servlet-mapping>

</web-app>
We've declared two servlets:
gwt-servlet - for displaying GWT 
spring-servlet - for displaying JSPs
We actually just need the gwt-servlet, but we set-up the spring-servlet here to demonstrate that we can combine JSPs and GWT in the same application

Here's gwt-servlet.xml

gwt-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
 <!-- 
  The GWTHandler allows you to quickly map multiple RPC service beans to different URLs
  very similar to the way Spring's SimpleUrlHandlerMapping maps URLs to controllers. The
  mapped beans are internally wrapped into GWTRPCServiceExporter
  instances, with the notable difference that you cannot specify a service interface in the configuration
  and the service beans must implement the RemoteService interface (as a matter of fact there is
  a workaround even for that by providing your own implementation of a RPCServiceExporter -
  interested readers please consult the javadocs for GWTHandler).
  
  See 3.2 Publishing multiple beans - GWTHandler 
  http://gwt-widget.sourceforge.net/?q=node/54 -->
 
 <!--  If you wanna research further about annotation support with GWT Handler.
   See http://groups.google.com/group/gwt-sl/browse_thread/thread/f563b200aa0af307# -->
   
 <!-- Or create our own implementation: 
     Seehttp://groups.google.com/group/gwt-sl/msg/3677e59c4a7c2dee -->
   
  <!-- A GWT Spring bean -->   
 <bean id ="greetingService" class="org.krams.tutorial.server.GreetingServiceImpl" >
  <property name="springService" ref="springService" />
 </bean>
 
 <!-- A Spring bean-->
 <bean id="springService" class="org.krams.tutorial.service.SpringService" />
 
 <!-- The GWT handler. Watch out the mappings! -->
 <bean class="org.gwtwidgets.server.spring.GWTHandler">
  <property name="mappings">
   <map>
    <entry key="/greet" value-ref="greetingService"/></map>
  </property>
 </bean>
 
</beans>
Here we declared a GWTHandler. This is basically similar to SimpleUrlHandlerMapping where a URL is mapped to a particular bean. In order for GWTHandler to match the mapping request, we need to modify the GreetingService interface (I'll show you the old implementation and the new one)

GreetingService (old)
package org.krams.tutorial.client;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

/**
 * The client side stub for the RPC service.
 */
@RemoteServiceRelativePath("greet")
public interface GreetingService extends RemoteService {
  String greetServer(String name) throws IllegalArgumentException;
}

GreetingService (new)
package org.krams.tutorial.client;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

/**
 * The client side stub for the RPC service.
 */
@RemoteServiceRelativePath("rpc/greet")
public interface GreetingService extends RemoteService {
  String greetServer(String name) throws IllegalArgumentException;
}
We've changed the path from greet to rpc/greet. Remember in the web.xml we've declared a url pattern:
<!-- Don't forget to declare a gwt-servlet.xml -->
 <servlet-mapping>
  <servlet-name>gwt</servlet-name>
  <url-pattern>gwtmodule/rpc/*</url-pattern>
 </servlet-mapping>
Make sure you correctly map your paths! Let me summarize that for you:
web.xml declaration: gwtmodule/rpc/*
interface declaration: rpc/greet
gwt-servlet.xml declaration: /greet

For a thorough discussion of GWTHandler, see 3.2 Publishing multiple beans - GWTHandler at http://gwt-widget.sourceforge.net/?q=node/54

In this configuration we mapped the /greet URL to the greetingService bean.
<entry key="/greet" value-ref="greetingService"/></map>
This greetingService bean is actually the default service implementation that was provided to us when we created the application. It references GreetingServiceImpl. We need to modify this class!

Let me show you first the original implementation (the one that's auto-generated for us):

GreetingServiceImpl (auto-generated)
package org.krams.tutorial.server;

import org.krams.tutorial.client.GreetingService;
import org.krams.tutorial.shared.FieldVerifier;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

/**
 * The server side implementation of the RPC service.
 */
@SuppressWarnings("serial")
public class GreetingServiceImpl extends RemoteServiceServlet implements
    GreetingService {

  public String greetServer(String input) throws IllegalArgumentException {
    // Verify that the input is valid.
    if (!FieldVerifier.isValidName(input)) {
      // If the input is not valid, throw an IllegalArgumentException back to
      // the client.
      throw new IllegalArgumentException(
          "Name must be at least 4 characters long");
    }

    String serverInfo = getServletContext().getServerInfo();
    String userAgent = getThreadLocalRequest().getHeader("User-Agent");

    // Escape data from the client to avoid cross-site script vulnerabilities.
    input = escapeHtml(input);
    userAgent = escapeHtml(userAgent);

    return "Hello, " + input + "!<br><br>I am running " + serverInfo
        + ".<br><br>It looks like you are using:<br>" + userAgent;
  }

  /**
   * Escape an html string. Escaping data received from the client helps to
   * prevent cross-site script vulnerabilities.
   *
   * @param html the html string to escape
   * @return the escaped string
   */
  private String escapeHtml(String html) {
    if (html == null) {
      return null;
    }
    return html.replaceAll("&", "&").replaceAll("<", "<").replaceAll(
        ">", ">");
  }
}
We need to remove the following in order for GWTHandler to recognize this class
extends RemoteServiceServlet
After you remove this reference, some parts of the code will get flagged. Just delete those, and replace it with this new implementation:

GreetingServiceImpl (new)
package org.krams.tutorial.server;

import org.krams.tutorial.client.GreetingService;
import org.krams.tutorial.service.SpringService;
import org.krams.tutorial.shared.FieldVerifier;

/**
 * The server side implementation of the RPC service.
 */
@SuppressWarnings("serial")
public class GreetingServiceImpl implements
    GreetingService {
  
  // Our custom Spring Service bean
  private SpringService springService;
  
  public String greetServer(String input) throws IllegalArgumentException {
    // Verify that the input is valid.
    if (!FieldVerifier.isValidName(input)) {
      // If the input is not valid, throw an IllegalArgumentException back to
      // the client.
      throw new IllegalArgumentException(
          "Name must be at least 4 characters long");
    }

    // Escape data from the client to avoid cross-site script vulnerabilities.
    input = escapeHtml(input);

    // Delegate to SpringService and return the result
    return springService.echo(input);
  }

  /**
   * Escape an html string. Escaping data received from the client helps to
   * prevent cross-site script vulnerabilities.
   *
   * @param html the html string to escape
   * @return the escaped string
   */
  private String escapeHtml(String html) {
    if (html == null) {
      return null;
    }
    return html.replaceAll("&", "&").replaceAll("<", "<").replaceAll(
        ">", ">");
  }

   /**
    * Retrieves the SpringService bean
    */
 public SpringService getSpringService() {
  return springService;
 }

 /**
  * Assigns the SpringService bean
 */
 public void setSpringService(SpringService springService) {
  this.springService = springService;
 }

}
Notice we've declared a custom Spring service bean and added getters and setters. Whenever an RPC request is made to the GWT GreetingService interface, the application calls the service-side implementation, GreetingServiceImpl. This is the standard process with GWT RPC. However, we provided another flow in this cycle. After calling the GreetingServiceImpl, it then delegates to a SpringService bean for the actual retrieval of the output.

We need to create a new package in the project that corresponds to the package we declared in the gwt-servlet.xml. In my case I created org.krams.tutorial.service and created the following Spring service bean:

SpringService
package org.krams.tutorial.service;

import org.apache.log4j.Logger;

public class SpringService {

 protected static Logger logger = Logger.getLogger("service");
 
 public String echo(String msg) {
  logger.debug("Entering SpringService");
  
  return "Hello " + msg + " from Spring!";
 }
}
Here's the project structure:

Let's continue with the remaining XML configurations.

Here's spring-servlet.xml

spring-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:p="http://www.springframework.org/schema/p" 
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
 <!-- Declare a view resolver -->
 <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" 
      p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />

</beans>

Next, we declare the applicationContext.xml

applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:mvc="http://www.springframework.org/schema/mvc"
 xmlns:p="http://www.springframework.org/schema/p"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-3.0.xsd
         http://www.springframework.org/schema/mvc 
         http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd" >

 <!-- Activates various annotations to be detected in bean classes -->
 <context:annotation-config />
 
 <!-- Scans the classpath for annotated components that will be auto-registered as Spring beans.
  For example @Controller and @Service. Make sure to set the correct base-package-->
 <context:component-scan base-package="org.krams.tutorial" />
 
 <!-- Configures the annotation-driven Spring MVC Controller programming model.
  Note that, with Spring 3.0, this tag works in Servlet MVC only!  
  Commented out because of conflict with GWTHandler 
  Instead we declare the elements declaratively!-->
 <!-- <mvc:annotation-driven /> -->
 
 <!-- This allows us to use @Controller and @Service annotations -->
 <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>

 <!-- Commented out because of conflict with GWTHandler. You lost @ResponseBody,
  @RequestBody, @PathVariable
 <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
  <property name="webBindingInitializer">
   <bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer"/>
  </property>
  <property name="messageConverters">
   <list>
    <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
    <bean class="org.springframework.http.converter.StringHttpMessageConverter" />
    <bean class="org.springframework.http.converter.FormHttpMessageConverter" />
    <bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />
   </list>
  </property>
 </bean> -->

 <!-- Not really needed but it's part of the mvc:annotation-driven tag-->
 <bean id="conversion-service" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />
</beans>
The applicationContext.xml contains some interesting information. All the beans we've declared here aren't really required for our GWT application. However these beans enable us to use special annotations like @Service and @Controller. This allows us to have a Spring MVC application separate from the GWT application within this same project.

However, we cannot use the mvc:annotation-driven tag here because of a conflict with the GWTHandler. There are possible workarounds for these (I suggest you look at the comments in the configuration). Since we cannot declare the mvc:annotation tag, we declare its equivalent beans separately. However it turns out the real source of the conflict is the AnnotationMethodHandlerAdapter. It swallows all requests, and ignores the GWTHandler. Please bear that in mind.

Let's look again at the current project structure:

Notice we have four XML configurations. But also I have a highlighted the gwt-sl-1.1.jar. We need to create a lib folder and manually place a copy of this jar. Why? Because the author of this library doesn't support Maven yet. (See the discussion here)

That's it! We're done with all the required configuration. We've added and modified our classes as well. Let's run this application and see what we'll get.

To run the application, use the Maven gwt:run goal we've created from the previous tutorial: Spring and GWT Integration using Maven and GWTHandler (Part 1).

This is what see after running the application:


We changed the greeting from the typical server info message to a custom echo message.

Before we end this tutorial, let's preview our pom.xml. We'll compare the initial pom and the final pom.

pom.xml (initial, auto-generated)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  <!-- POM file generated with GWT webAppCreator -->
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.krams.tutorial</groupId>
  <artifactId>spring-gwt-integration</artifactId>
  <packaging>war</packaging>
  <version>1.0.0-SNAPSHOT</version>
  <name>GWT Maven Archetype</name>

  <properties>
    <!-- Convenience property to set the GWT version -->
    <gwtVersion>2.1.0</gwtVersion>
    <!-- GWT needs at least java 1.5 -->
    <maven.compiler.source>1.5</maven.compiler.source>
    <maven.compiler.target>1.5</maven.compiler.target>
    <webappDirectory>${project.build.directory}/${project.build.finalName}</webappDirectory>
  </properties>

  <dependencies>
    <dependency>
      <groupId>com.google.gwt</groupId>
      <artifactId>gwt-servlet</artifactId>
      <version>2.1.0</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>com.google.gwt</groupId>
      <artifactId>gwt-user</artifactId>
      <version>2.1.0</version>
      <scope>provided</scope>
    </dependency>  
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.7</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <!-- Generate compiled stuff in the folder used for developing mode -->
    <outputDirectory>${webappDirectory}/WEB-INF/classes</outputDirectory>

    <plugins>

      <!-- GWT Maven Plugin -->
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>gwt-maven-plugin</artifactId>
        <version>2.1.0-1</version>
        <executions>
          <execution>
            <goals>
              <goal>compile</goal>
              <goal>test</goal>
              <goal>i18n</goal>
              <goal>generateAsync</goal>
            </goals>
          </execution>
        </executions>
        <!-- Plugin configuration. There are many available options, see gwt-maven-plugin 
          documentation at codehaus.org -->
        <configuration>
          <runTarget>gwtmodule.html</runTarget>
          <hostedWebapp>${webappDirectory}</hostedWebapp>
          <i18nMessagesBundle>org.krams.tutorial.client.Messages</i18nMessagesBundle>
        </configuration>
      </plugin>

      <!-- Copy static web files before executing gwt:run -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.1.1</version>
        <executions>
          <execution>
            <phase>compile</phase>
            <goals>
              <goal>exploded</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <webappDirectory>${webappDirectory}</webappDirectory>
        </configuration>
      </plugin>

    </plugins>
  </build>

</project>

pom.xml (final)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  <!-- POM file generated with GWT webAppCreator -->
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.krams.tutorial</groupId>
  <artifactId>spring-gwt-integration</artifactId>
  <packaging>war</packaging>
  <version>1.0.0-SNAPSHOT</version>
  <name>GWT Maven Archetype</name>

  <properties>
    <!-- Convenience property to set the GWT version -->
    <gwtVersion>2.1.0</gwtVersion>
    <!-- GWT needs at least java 1.5 -->
    <maven.compiler.source>1.5</maven.compiler.source>
    <maven.compiler.target>1.5</maven.compiler.target>
    <webappDirectory>${project.build.directory}/${project.build.finalName}</webappDirectory>
  </properties>

  <dependencies>
    <dependency>
      <groupId>com.google.gwt</groupId>
      <artifactId>gwt-servlet</artifactId>
      <version>2.1.0</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>com.google.gwt</groupId>
      <artifactId>gwt-user</artifactId>
      <version>2.1.0</version>
      <scope>provided</scope>
    </dependency>  
   <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.8.1</version>
    <type>jar</type>
    <scope>compile</scope>
   </dependency>
   <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-web</artifactId>
     <version>3.0.5.RELEASE</version>
     <type>jar</type>
     <scope>compile</scope>
    </dependency>
    <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-core</artifactId>
     <version>3.0.5.RELEASE</version>
     <type>jar</type>
     <scope>compile</scope>
    </dependency>
    <dependency>
     <groupId>log4j</groupId>
     <artifactId>log4j</artifactId>
     <version>1.2.14</version>
     <type>jar</type>
     <scope>compile</scope>
    </dependency>
    <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-tx</artifactId>
     <version>3.0.5.RELEASE</version>
     <type>jar</type>
     <scope>compile</scope>
    </dependency>
    <dependency>
     <groupId>jstl</groupId>
     <artifactId>jstl</artifactId>
     <version>1.1.2</version>
     <type>jar</type>
     <scope>compile</scope>
    </dependency>
    <dependency>
     <groupId>taglibs</groupId>
     <artifactId>standard</artifactId>
     <version>1.1.2</version>
     <type>jar</type>
     <scope>compile</scope>
    </dependency>
    <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-webmvc</artifactId>
     <version>3.0.5.RELEASE</version>
     <type>jar</type>
     <scope>compile</scope>
    </dependency>
    <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-aop</artifactId>
     <version>3.0.5.RELEASE</version>
     <type>jar</type>
     <scope>compile</scope>
    </dependency>
  </dependencies>

  <build>
    <!-- Generate compiled stuff in the folder used for developing mode -->
    <outputDirectory>${webappDirectory}/WEB-INF/classes</outputDirectory>

    <plugins>

      <!-- GWT Maven Plugin -->
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>gwt-maven-plugin</artifactId>
        <version>2.1.0-1</version>
        <executions>
          <execution>
            <goals>
              <goal>compile</goal>
              <goal>test</goal>
              <goal>i18n</goal>
              <goal>generateAsync</goal>
            </goals>
          </execution>
        </executions>
        <!-- Plugin configuration. There are many available options, see gwt-maven-plugin 
          documentation at codehaus.org -->
        <configuration>
          <runTarget>gwtmodule.html</runTarget>
          <hostedWebapp>${webappDirectory}</hostedWebapp>
          <i18nMessagesBundle>org.krams.tutorial.client.Messages</i18nMessagesBundle>
        </configuration>
      </plugin>

      <!-- Copy static web files before executing gwt:run -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.1.1</version>
        <executions>
          <execution>
            <phase>compile</phase>
            <goals>
              <goal>exploded</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <webappDirectory>${webappDirectory}</webappDirectory>
        </configuration>
      </plugin>

    </plugins>
  </build>

</project>

That's it. We're done. I hope you learned something new with this tutorial.

The best way to learn further is to try the actual application.

Download the project
You can access the project site at Google's Project Hosting at http://code.google.com/p/spring-mvc-gwt/

You can download the project as a Maven build. Look for the spring-gwt-integration.zip in the Download sections.

You can run the project directly using the Maven GWT plugin.
mvn gwt:run

If you want to learn more about Spring MVC and integration with other technologies, feel free to read my other tutorials in the Tutorials section.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring and GWT Integration using Maven and GWTHandler (Part 2) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

Spring and GWT Integration using Maven and GWTHandler (Part 1)

In this tutorial we will setup a simple GWT application and integrate it with Spring. We will use GWTHandler to map GWT's RPC services to Spring beans, and utilize Maven to manage and build our project. Our application is the typical GWT Hello application we see when we create a new GWT project.

Note: An updated version of this guide is available at Spring 3.1: GWT Maven Plugin and GWTHandler Integration

What is GWTHandler?
The GWTHandler allows you to quickly map multiple RPC service beans to different URLs very similar to the way Spring's SimpleUrlHandlerMapping maps URLs to controllers. The
mapped beans are internally wrapped into GWTRPCServiceExporter
instances

Source: http://gwt-widget.sourceforge.net/?q=node/54
What is GWT?
Google Web Toolkit (GWT) is a development toolkit for building and optimizing complex browser-based applications. GWT is used by many products at Google, including Google AdWords and Orkut. It's open source, completely free, and used by thousands of developers around the world.

Source: http://code.google.com/webtoolkit/
What is Spring?
[T]he leading platform to build and run enterprise Java applications. Led and sustained by SpringSource, Spring delivers significant benefits for many projects, increasing development productivity and runtime performance while improving test coverage and application quality.

Source: http://www.springsource.org/
What is Maven?
Apache Maven is a software project management and comprehension tool. Based on the concept of a project object model (POM), Maven can manage a project's build, reporting and documentation from a central piece of information.

Source: http://maven.apache.org/
Here's what we will be building:

Initial run: plain GWT

Final run: GWT and Spring

Now that you've seen what we'll be building, let's create our project.

I assume you're running Eclipse with m2eclipse installed (or Spring's STS). If you don't have any of these, please visit the following links:
- Eclipse: http://www.eclipse.org/downloads/
- m2eclipse: http://m2eclipse.sonatype.org/
or
- STS: http://www.springsource.com/products/springsource-download-center

1. Open your IDE. Create a New Project

2. Select Maven. Then select Maven Project.

3. On the Select an Archetype screen, choose gwt-maven-plugin. Make sure the version is 2.1.0-1 or greater! If not, update your catalog.

4. Click Next. On the Specify Archetype parameters window, enter an appropriate Artifact Id and Package. Then make sure you add a value on the module parameter. If you're new to GWT, just follow the values from the screenshot below:

5. Click Finish when you're done. You should see the following project structure:

Notice there are multiple red markers. These mean something is wrong with our project. Upon checking all files, we realize the Async interfaces needs to be created first!

To resolve this, we can manually create the Async interfaces. However, Maven has a goal support to automatically generate the Async interfaces. For more info, please visit http://mojo.codehaus.org/gwt-maven-plugin/examples/asyn.html

We will be using the generateAsync goal to generate the interfaces.

6. Right-click on your project. Select Run As. Then Select Run Configurations

7. Find the Maven Build section on the Run Configurations window

8. Press the New button to create a new Maven Build configuration.

9. Enter the following details for this new configuration:
Name: generateAsync
Base directory: (click on Browse and find your project)
Goals: gwt:generateAsync

10. Click Apply. Click Run. You should see the following output on the Console window:
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building GWT Maven Archetype 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- gwt-maven-plugin:2.1.0-1:generateAsync (default-cli) @ spring-gwt-integration ---
[WARNING] Encoding is not set, your build will be platform dependent
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.316s
[INFO] Finished at: Fri Jan 07 23:49:31 2011
[INFO] Final Memory: 6M/124M
[INFO] ------------------------------------------------------------------------
The Async interfaces are generated automatically. But where are they saved?

11. Go your project directory. Open the target folder, and you will see the generated-sources folder. This is where Maven saved the Async interfaces. Expand the sub-folders until you find the Async interfaces: GreetingServiceAsync.java and Messages.java

12. Copy these files and paste them on the client package. In my case, it's org.krams.tutorial.client

Notice most of the red warnings are now gone, but there's still one left. That's because Eclipse is complaining that we have set the wrong output directory, but in fact, we didn't. You can safely ignore this warning.

Now let's run our project and see how it would look like. We will be using Maven again to run the application. We cannot use the usual Run As >> Web Application command here because we're using Maven.

To run the application, we'll use the gwt:run goal.

13. To create the Maven gwt:run goal, follow the same exact steps when we created the generateAsync goal. But of course, you will need to change the details to the following:
Name: gwt-run
Base directory: (click on Browse and find your project)
Goals: gwt:run

14. Click Apply. Click Run. The GWT Development Mode window will appear.

15. Click on Launch Default Browser to run the application. Or you may copy the link and paste it in your browser.

You should see the following application:

Play with the application. Close it when you're done. What we saw here is the GWT application.

Our next task is to integrate this application with Spring. Visit the following link for the continuation: Spring and GWT Integration using Maven and GWTHandler (Part 2)
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring and GWT Integration using Maven and GWTHandler (Part 1) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share