Maven setup

The latest stable release 2.0.6

<dependency>
  <groupId>com.britesnow</groupId>
  <artifactId>snow</artifactId>
  <version>2.0.6</version>
</dependency>

Setup your Web App

In the /WEB-INF/snow.properties file, set the snow.properties that point to your Guice App Module

# The Application Guice Modules (1 or more, comma seperated)
snow.webApplicationModules=com.example.MyAppConfig

# TODO: need to change the "com.example.starter.MyAppModule" to the application package 
#       and application module class name. 


# NOTE: Any property in this file can be injected via Google using 
#        @Named(propertyName)String propertyValue
# So, if we have here: 
# myApp.prop1=value1
# Then, in any Guice managed class, we can have
# @Inject
# private @Named(myApp.prop1) String value

In the /WEB-INF/web.xml, make all pages point to web.xml

<web-app id="WebApp_ID" version="2.4" 
    xmlns="http://java.sun.com/xml/ns/j2ee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
  
  <display-name>
    SnowApplication
  </display-name>
  <servlet>
    <servlet-name>
      snowServlet
    </servlet-name>
    <servlet-class>
      com.britesnow.snow.web.SnowServlet
    </servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>
      snowServlet
    </servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

Guice Module class

Snow applications are configured via one or more Google Guice modules. At initialization time, Snow gets the list of application Guice modules from the snow.webApplicationModules property from the WEB-INF/snow.properties file.

Create your src/main/java/com/example/MyAppConfig.java as something like:

package com.example;

public class MyAppConfig extends AbstractModule {
    
    @Override
    protected void configure() {
        // some bindings
    }
}

Note: The first Google Guice module defined in the snow.webApplicationModules property (here the only AppConfig ) specifies the base package from where Snow scans classes for Snow method annotations (e.g., @WebGet, @WebModelHandler, ...) to do the appropriate "Web bindings." So, make sure that the first Guice module is at the root package of your application.

Authentication & Login

Implementing login and authentication in Snow is dead simple. The only things needed are to bind a AuthRequest implementation, which will attempt to authenticate any incoming request, and implement the @WebPost for the for the login and logoff REST api (in this application, we use "/api/user-login" for login, and "/api/user-logoff") to perform the login and logoff.

So, the request authentication and login/logoff request flow will look like:


The AuthRequest.authRequest returns null until the user does a POST at the "/api/user-login" with the appropriate credential.

To implement AuthRequest we just need to "Google Guice" bind AuthRequest.class interface to an application implementation, such as:

package com.example.samplebookmarks;

public class AppConfig extends AbstractModule {
  protected void configure() {
      bind(AuthRequest.class).to(AppAuthRequest.class);
  }
}

This AuthRequest interface just have one method, AuthRequest.authRequest which takes a RequestContext object (a Snow convenient wrapper of HttpServletRequest and HttpServletResponse), and need to return a AuthToken with a given user when the user has been logged-in, or just return null (meaning, no user authenticated for this request).

com.example.samplebookmarks.web.AppAuthRequest

public class AppAuthRequest implements AuthRequest<User> {

  @Override
  public AuthToken<User> authRequest(RequestContext rc) {
      // Note for this sample app, we store the user in the session, 
      // but for production application, use stateless authentication mechanism for 
      // better sclability.
      
      // RequestContext is a convenient Snow wrapper on top of HttpServletRequest, 
      //  and HttpServletResponse
      // rc.getReq() return the HttpServletRequest 
      User user = (User) rc.getReq().getSession().getAttribute("user");
      
      if (user != null){
          AuthToken authToken = new AuthToken();
          authToken.setUser(user);
          return authToken;
      }else{
          return null;
      }
  }

}

Note: Below the generic type User belong to the application, and not to Snow. This allows developer to have any User model they think is the most appropriate to their application. See AuthRequest documentation for more information.

Doing a login API is as simple as annotating the login and logoff with @WebPost as:


@Singleton
public class LoginWebHandlers {

    @Inject
    private UserDao userDao;
    
    /**
     * Note: Here the RequestContext will be injected by Snow 
     *          
     */
    @WebPost("/api/user-login")
    public WebResponse login(@WebParam("userName")String userName, 
                             @WebParam("pwd")String pwd, 
                             RequestContext rc){
        User user = userDao.getUserByUserName(userName);
        
        if (user != null && pwd != null && pwd.equals(user.getPassword())){
            rc.getReq().getSession().setAttribute("user", user);
            return WebResponse.success();
        }else{
            return WebResponse.fail("Wrong username or password.");
        }

    }

    /**
     * Note: Here we show how we can inject HttpServletRequest directly
     * @param req
     */
    @WebPost("/api/user-logoff")
    public void logoff(HttpServletRequest req){
        req.getSession().removeAttribute("user");
    }
    
}