Skip to content

Switch User, ‘su’ like behavior in Spring Security

Does your spring web application have an admin interface to manage users? Does your admin need to “login as user” in production scenarios to assist user behavior?

If you’re thinking of a feature similar to Unix ‘su’ and if you’re using Spring 3.x then you’re lucky. Spring Security provides an out-of-the-box solution.

The below example assumes a JSF / Spring 3.x webapp. It should work for a JSP or other view technologies.

spring-security.xml: Add the filter bean and configure filter position in http

  ...
  ...

  <!-- Register a 'su' filter -->	
  <bean id="switchUserProcessingFilter" class="org.springframework.security.web.authentication.switchuser.SwitchUserFilter"> 
     <property name="userDetailsService" ref="yourCustomDetailService" />
     <!--No need to change this, unless you need a fancy name that you configure in faces-nav.xml -->
     <property name="switchUserUrl" value="/j_spring_security_switch_user" />
     <property name="switchFailureUrl" value="your-url" />
     <!--No need to change this, unless you need a fancy name that you configure in faces-nav.xml -->     
     <property name="exitUserUrl" value="/j_spring_security_exit_user" />
     <!--The page to redirect to after switchUser is authorized. Typically the same page as 'login success' home page -->
     <property name="targetUrl" value="your-url" />	    
  </bean>

  <http auto-config="false" entry-point-ref="authenticationEntryPoint">
      <!-- other filters -->
      ....
      <custom-filter position="SWITCH_USER_FILTER" ref="switchUserProcessingFilter" />		
   </http>
....

JSF Admin Page for Richfaces 3.x. (For Primefaces or Icefaces their relevant tags would work, too).

<h:form>
  Switch User:		    
  <t:inputText value="#{userController.switchUsername}/>	     	
  Click <h:commandLink value="here" action="#{userController.switchUser}"/> to switch to user.	    	 		    	
</h:form>

Spring @Controller for binding, validating, adding username query param as ‘j_username’ and forwarding it to ‘switchUserUrl’.

If you use jsps, jquery, or other view technologies, you would need similar logic.

Note that unlike a user login flow, you wouldn’t need to send j_password in the query param. SwitchUserFilter assumes a higher authority (super user, admin user) invokes the workflow, and as such, downgrading to a non-admin user is not a security risk.


@Controller
public class UserController {
    private String switchUsername;
    ...

    public String switchUser() throws IOException, ServletException {		
	if ( StringUtils.isEmpty( this.switchUsername ) ) {
            FacesUtils.reportError("username is required");
            return null;
	}
	
	String path = /j_spring_security_switch_user + "?j_username=" + switchUsername;
	
        // Forward the original request with username as query params			
	ExternalContext context = FacesUtils.getExternalContext();
	RequestDispatcher dispatcher = ((ServletRequest) context.getRequest()).getRequestDispatcher(path);
	dispatcher.forward( (ServletRequest) context.getRequest(), (ServletResponse) context.getResponse() );
	FacesUtils.getFacesContext().responseComplete();
	return null;
    }
}

On successful admin login, switchUserFilter now redirects to ‘targeturl’ and with appropriate AuthenticationToken initialized and the rest of your flow should work as is. When user logs off, of course, the switch user logs off. It would be nice to have an option like ‘returnToSuperUser’ so when user logs out, it returns to admin. You can do that by overriding SwitchUserFilter#attemptExitUser.

Can you switchUser from an already Switched user? In theory, it looks like you can. Read SwitchUserFilter. I can’t imagine why you would want to do it though.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

My Latest Emacs Config

I’ve committed my latest emacs configuration on my github repo.

This configuration makes use of the el-get package management system.

Along with configuring el-get to manage add on packages, I’ve added configuration files for org-mode, the naquadah theme, org2blog, and a custom binding for magit.

I’m in the process of adding python development tools, and gnus, so stay tuned.

Useful links, props, and details:

  • The Magit Cheatsheet is a very comprehensive list of examples for using magit, which is itself a comprehensive git client.
  • I am using emacs23, and have not installed elpa, so I check the el-get recipes to make sure they’re not referencing elpa before adding packages.
  • I found the solution for configuring el-get in init.el from this post, props go to kindahero.
[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Spring MVC 3.1 with Twitter Bootstrap 2.1 Showcase

Spring MVC has come a long way since 2.x and the newer 3.1 MVC, especially, RESTful controllers, is a closer step towards the philosophy of simpler web frameworks like Play! or Grails. Spring MVC Showcase built with JQuery-UI is a great start. It demonstrates the capabilities of the Spring MVC web framework through small, simple examples. After reviewing this showcase, you should have a good understanding of what Spring MVC can do and get a feel for how easy it is to use.

However, Bootstrap is awesome.

It’s the best UI toolkit I’ve seen for a long, long, time:
- Built on Web 2.0 standards
- HTML 5 / CSS 3 ready
- Support for IE6-IE8 HTML 5
- Responsive CSS
- Typography
- Column-based responsive grids, fluid grids for building Layouts
- Dozens of html components, form controls
- Alerts, Modals, Navbars, Menus, Thumbnail generation, Pagination and many more
- In-built javascript plugins (extending JQuery) to simplify common tasks and effects
- A web-based Customizer to make Bootstrap your own
- Several thousands of sites already using Bootstrap

I released a fork that brings Spring MVC and Bootstrap together, along with other goals:
- Use only embedded servers (jetty, h2, etc.,)
- Decorate Layouts with Sitemesh
- Move page-specific js into a commmon js
- Incorporate Themes from Bootswatch
- Build the tutorial into the app?
- Extend showcase with more features, gotchas, best practices?
- Integrate Spring Social and Spring Data?

Watch the Demo on Cloudfoundry.

References
- The original blog
- A screencast with the showcase in action

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Java Logging best practices using slf4j and logback

Overview
Slf4j to logging is what JDBC is to Database access: an interface that streamlines logging api, plugs into several implementations at deploy time, and promotes best practices of logging.

When should you use slf4j?
If you believe coding for Interfaces works well in your project(s), then you need no explanation. Though slf4j is “not necessary” in a standalone application, it’s recommended: what if, after developing several apps, you discover a new logging implementation? Would you rather plug-in a new implementation or rewrite logging for all your apps?

Features
1. Abstraction layer
slf4j’s api provides generic access to many logging frameworks, including advanced features like MDC, along with boilerplate code, allowing existing code to be used easily. Which one you use, is then decided at deployment time, not when you write your code.

2. Plug in logging framework at deployment time
SLF4J statically binds to a particular logging implementation so that there is no automatic discovery for configuration. This gets around the class loading issues with JCL, providing a fail-fast operation and the framework binding will be verified automatically very early on. SLF4J will abort execution with a warning if no binding is present.

3. Parametrized logging

Write

log.debug("hello world {}", a, b);

instead of:

if(log.isDebugEnabled()){
  log.debug("hello " + a + " world" + b);
}

The former code has the same performance if you do not log in debug mode. Note there’s no need of string concatenation and the {}-placeholders delay the actual creation of the full string to be logged as much as possible, notably after the event has been determined to need to be logged.

4. Support legacy logging
For existing projects using legacy logging frameworks, SLF4J bridging removes their dependencies from the project and routes the calls to use SLF4J, effectively swapping the implementation to a new logging library with minimal code changes. Also, a migrator tool utility can help you migrate your source to use SLF4J.

5. Marker Interface for slicing, dicing and filtering specialized events
To expand logging categories beyond info, warn, error, and provide an event-like capability to mark and fire off a message (“business-process”, “fatal”) to notify the logger to respond specifically to such messages. You can even, for instance, process marker messages to hook up an email notification workflow.

Read this for some of the best practices on using Markers.

Note that currently only logback supports the Marker interfaces.

6. Profiler
Slf4j extensions like Profiler can add timer operations around method invocations.

7. Others
- A powerful Logger interface
- A useful Extended Logger forlogging method entry, exit, etc
- As a service provider, limit the use of transitive dependencies

For further info read the excellent FAQ on slf4j.

Usage

Maven:

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.6.6</version>
</dependency>
<dependency> 
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-log4j12</artifactId>
   <version>1.6.6</version>
</dependency>

To exclude commons-logging as a Maven dependency: Declare version 99-empty of commons-logging in the dependencyManagement section of your project will direct all transitive dependencies for commons-logging to import version 99-empty (a bogus jar), thus nicely addressing the commons-logging exclusion problem. The classes for commons-logging will be provided by jcl-over-slf4j.

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>99-empty</version>
    </dependency>
    ... other declarations...
  </dependencies>
</dependencyManagement>

<!-- Do not forget to declare a dependency on jcl-over-slf4j in the        -->
<!-- dependencies section. Note that the dependency on commons-logging     -->
<!-- will be imported transitively. You don't have to declare it yourself. -->
<dependencies>
  <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>1.6.6</version>
  </dependency>
  ... other dependency declarations
</dependencies>

Sample Logging:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Foo {
 
  // Avoid static references to log objects from code that might be deployed in a shared classpath.
  // Declaring a logger as static prevents the declaring class (and associated classloaders) from being garbage
  // collected in J2EE containers that use a shared classloader. This will result in PermGen errors 
  // if you redeploy your application enough times.
  // http://wiki.apache.org/commons/Logging/StaticLog
  // Also, the argument that instance log objects are "expensive" is no longer valid in modern JVMs unless 
  // tens of thousands of classes are created. 
  // http://www.slf4j.org/faq.html#declared_static 
  private final Logger log = LoggerFactory.getLogger(Foo.class);
    
  public void simpleProcessWithExceptions(Bar bar) {
    log.info("Starting Process ... ");
    
    preProcessBar(bar);
    // Use log statements to describe your processing states generously. Unless you have a BigData
    // based persistence to audit behavior, log files are your best friend
    log.debug("After pre-processing Bar: {}, bar);
    
    try { 
    	log.info("Pre processing bar");   
      	doSomething();        	
      	callDatabaseMethod();
    }
    catch (SomeCheckedException e) {
    	// Slf4j automatically converts e into a readable stacktrace
    	log.error("An error occured in {}", e));
    	throw new WrappedRuntimeException(e);
    }
  
     postProcessBar(bar); 
     log.debug("After post-processing Bar: {}, bar);     
     log.info("Finished Process ... ");
   }

   public static void youShouldntHaveAStaticMethod(Bar bar) {
      // Creating a new log within the static method is an appropriate solution
      Log log = LoggerFactory.getLogger(Foo.class);
      log.warn(...);
  } 
}

Who uses slf4j?
All projects in Spring, JBoss, Apache, Mule, and many open-source libraries have already migrated to slf4j, establishing it as the defacto logging api standard.

What is the best implementation for slf4j?
Logback. There are several reasons to switch from log4j to Logback.

References
1. A video Presentation
2. Logger Javadoc

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Integrating ActiveDirectory on Windows NTLM using Spring Security and custom authorization to simulate a single-sign-on web application

Goals
Authenticate a Spring web application deployed on Windows NTLM network using ActiveDirectory, manage Roles in web application (custom authorization), and simulate a single-sign-on environment, where a use can simply access a url and on successful local windows login, application would redirect to home page. So there’s no login screen required. Integrate with Spring Security framework is desirable. If possible, the solution should be reusable across multiple Spring web apps.

STRATEGIES:
Though Spring Security provides tools to integrate LDAP, a seamless integration of ActiveDirectory in a web application using spring security is still a pain. I recently came across this problem and after some research found Waffle Security the best tool for this job. I had to modify the source code to customize the solution based on my requirements. Here’s a writeup of my findings:

Spring Security LDAP
* Spring LDAP Security Reference
* Spring uses ActiveDirectoryLdapAuthenticationProvider, which delegates the work to LdapAuthenticator and LdapAuthoritiesPopulator which are responsible for authenticating the user and retrieving the user’s set of GrantedAuthoritys respectively.UserDetails can be populated using DefaultLdapAuthoritiesPopulator.
* A local LDAP instance can be easily setup (and tested) in a web app.
* You must update ldap properties in users.ldif (sample ldap user info) for authentication/authorization to work. However this doesn’t work as a single-sign on environment, since additional filters need to be written.

Hence this approach was not suited for a single-sign-on requirement.

Tomcat 7 integration
* Not sure how Tomcat integration is useful since configuring Realms and other server settings is an additional step outside of the App. Each environment has to ensure these settings exist, which means local development and test, stage, prod configuration grow exponentially. Also, the authentication object should to be populated in Spring’s context (ie., the application’s context). This leads to Spring being aware of Tomcat’s Realms and settings + the web app supporting Tomcat’s authentication (SPNEGO) etc.,
* Tomcat integration is geared towards plain servlet apps.

Due to the above reasons I didn’t find this solution extensible.

Spring Security Kerberos/SPNEGO Extension
* For Kerberos (unix or windows) based, client based (browser) authentication, this extension from Spring is apt
* You need some knowledge on the server side (setup kerberos etc.,) so this may not be an “out of the box” solution
* Reference example is here

Ideally this solution would’ve been great but at the point of this writing (to my findings), this solution doesn’t integrate with Active Directory on NTLM.

Kerberos + NTLM with Waffle Filter support with Spring Security
* More flexible than the above example since it supports both Kerberos and Windows NTLM. Waffle will allow you to get rid of IIS (as a pass through) as well. Unlike many other implementations WAFFLE on Windows does not usually require any server-side Kerberos keytab setup, it’s a drop-in solution.
* Integrates well with Spring Security
* Project Site is here.
* Reference example is here.
* Was able to get this working with custom classes that extend Waffle’s filter and custom Authentication object. WORKS as a single-sign within a corporate network and roles are correctly mapped into granted authorities.

Implementation Summary
* The above reference example provided by Waffle is a good start, however that code also assumes authorization loaded from ActiveDirectory. In order to customize authorization, you must extend waffle.spring.NegotiateSecurityFilter. Since Waffle doesn’t open up api to override (Duh#TemplatePatternWouldBeSoNice), I had to copy its implementation and make changes myself.


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.context.SecurityContextHolder;
import waffle.servlet.WindowsPrincipal;
import waffle.spring.NegotiateSecurityFilter;
import waffle.util.AuthorizationHeader;
import waffle.windows.auth.IWindowsIdentity;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Custom Authentication Filter extending Waffle's built-in Filter.
 * Loads User Roles from Db and uses custom AuthenticationToken.
 * For the most part its same as NegotiateSecurityFilter. See #Note below for the key difference
 */
public class CustomAuthenticationFilter extends NegotiateSecurityFilter {

    Logger logger = LoggerFactory.getLogger(CustomAuthenticationFilter.class);

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        logger.info(request.getMethod() + " " + request.getRequestURI() + ", contentlength: " + request.getContentLength());
        AuthorizationHeader authorizationHeader = new AuthorizationHeader(request);

        // authenticate user
        if (!authorizationHeader.isNull()
                && getProvider().isSecurityPackageSupported(authorizationHeader.getSecurityPackage())) {

            // log the user in using the token
            IWindowsIdentity windowsIdentity = null;

            try {
                windowsIdentity = getProvider().doFilter(request, response);
                if (windowsIdentity == null) {
                    return;
                }
            } catch (Exception e) {
                logger.warn("error logging in user: " + e.getMessage());
                sendUnauthorized(response, true);
                return;
            }

            if (!getAllowGuestLogin() && windowsIdentity.isGuest()) {
                logger.warn("guest login disabled: " + windowsIdentity.getFqn());
                sendUnauthorized(response, true);
                return;
            }

            try {
                logger.debug("logged in user: " + windowsIdentity.getFqn() +
                        " (" + windowsIdentity.getSidString() + ")");
                WindowsPrincipal principal = new WindowsPrincipal(
                        windowsIdentity, getPrincipalFormat(), getRoleFormat());
                logger.debug("roles: " + principal.getRolesString());

                /// NOTE: This is where you customize auth. You'd need your own token and initialization mechanism different from 
                /// Waffle's built in token implementation
                // Populate Authentication Token along with GrantedAuthorities
                CustomAuthenticationToken authentication = new CustomAuthenticationToken(principal);
                SecurityContextHolder.getContext().setAuthentication(authentication);
                logger.info("successfully logged in user: " + windowsIdentity.getFqn());
            } finally {
                windowsIdentity.dispose();
            }
        }

        chain.doFilter(request, response);
    }

    /**
     * Send a 401 Unauthorized along with protocol authentication headers.
     *
     * @param response HTTP Response
     * @param close    Close connection.
     */
    private void sendUnauthorized(HttpServletResponse response, boolean close) {
        try {
            getProvider().sendUnauthorized(response);
            if (close) {
                response.setHeader("Connection", "close");
            } else {
                response.setHeader("Connection", "keep-alive");
            }
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
            response.flushBuffer();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

Here’s the custom Authentication Token:

import xxx.domain.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import waffle.servlet.WindowsPrincipal;

import java.util.Collection;
import java.util.List;

/**
 * Custom Authentication Token to comply with custom Waffle Authentication mechanism.
 * Variation of Waffle's WindowsAuthenticationToken. See #Note below
 */
public class CustomAuthenticationToken implements Authentication {

    Logger logger = LoggerFactory.getLogger(CustomAuthenticationToken.class);

    private static final long serialVersionUID = 1L;
    private WindowsPrincipal windowsPrincipal = null;
    private org.springframework.security.core.userdetails.User principal = null;
    private Collection<GrantedAuthority> authorities = null;

    // Move this to a config
    public static final String MY_DOMAIN = "<your corporate domain>";

    /**
     * Constructor that fully initializes the principal
     *
     * @param windowsPrincipal windows principal
     */
    public CustomAuthenticationToken(WindowsPrincipal windowsPrincipal) {
        this.windowsPrincipal = windowsPrincipal;
        // Strip domainName in <domainName>\\username to get mapped username in App
        String username = windowsPrincipal.getName().substring(MY_DOMAIN.length()+1);
        logger.debug("App Login Info derived from ActiveDirectory: " + username);

        // Load roles
        Collection<GrantedAuthority> authorities = loadAuthorities(username);

        // Create UserDetails object
        this.principal = new org.springframework.security.core.userdetails.User(username, "", true, true,
                true, true, authorities);
    }

    /**
     * Loads granted authorities by looking up User=>Roles.
     * Throws UsernameNotFoundException if principal isn't mapped mapped to Db
     * @return
     */
    private Collection<GrantedAuthority> loadAuthorities(String username) {

        // Match User Account from Db
        User account = null;
        try {
            // NOTE: I Use Spring Roo's inbuilt finder but you can easily replace the below code by JDBC/JPA/Hibernate Dao or Service
            account = User.findUserByName(username);
        }
        catch (Exception e) {
            logger.info("A unique account " + username + " could not be found: " + e.getMessage());
            throw new UsernameNotFoundException("A unique account " + username + " could not be found");
        }

        // Load User Roles
        List<String> roles = account.getRoleNames();
        logger.debug("Loaded Roles from Database: " + roles.toString());
        Collection<GrantedAuthority> grantedAuthorities = toGrantedAuthorities(roles);
        this.authorities = grantedAuthorities;
        return authorities;
    }

    @Override
    public Collection<GrantedAuthority> getAuthorities() {
        return authorities;
    }

    public Object getCredentials() {
        return null;
    }

    public Object getDetails() {
        return windowsPrincipal;
    }

    public Object getPrincipal() {
        return principal;
    }

    public boolean isAuthenticated() {
        return (principal != null);
    }

    public void setAuthenticated(boolean authenticated) throws IllegalArgumentException {
        throw new IllegalArgumentException();
    }

    public String getName() {
        return principal.getUsername();
    }

    private static Collection<GrantedAuthority> toGrantedAuthorities(List<String> roles) {
        List<GrantedAuthority> result = new ArrayList<GrantedAuthority>();

        for (String role : roles) {
            result.add(new GrantedAuthorityImpl(role));
        }

        return result;
    }
}

And here’s the Spring Config (very similar to the Waffle’s reference example):

<?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:sec="http://www.springframework.org/schema/security"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">

    <bean id="loggerListener" class="org.springframework.security.authentication.event.LoggerListener" />

    <!-- Windows authentication provider -->
    <bean id="waffleWindowsAuthProvider" class="waffle.windows.auth.impl.WindowsAuthProviderImpl"/>

    <!-- Collection of security filters -->
    <bean id="negotiateSecurityFilterProvider" class="waffle.servlet.spi.NegotiateSecurityFilterProvider">
        <constructor-arg ref="waffleWindowsAuthProvider"/>
    </bean>
    <bean id="basicSecurityFilterProvider" class="waffle.servlet.spi.BasicSecurityFilterProvider">
        <constructor-arg ref="waffleWindowsAuthProvider"/>
    </bean>

    <bean id="waffleSecurityFilterProviderCollection" class="waffle.servlet.spi.SecurityFilterProviderCollection">
        <constructor-arg>
            <list>
                <ref bean="negotiateSecurityFilterProvider"/>
                <ref bean="basicSecurityFilterProvider"/>
            </list>
        </constructor-arg>
    </bean>

    <bean id="negotiateSecurityFilterEntryPoint" class="waffle.spring.NegotiateSecurityFilterEntryPoint">
        <property name="provider" ref="waffleSecurityFilterProviderCollection"/>
    </bean>

    <!-- Waffle authentication provider -->
    <sec:authentication-manager alias="authenticationProvider"/>

    <!-- Custom Authentication Filter -->
    <bean id="waffleNegotiateSecurityFilter" class="xxx.CustomAuthenticationFilter">
        <property name="provider" ref="waffleSecurityFilterProviderCollection"/>
        <property name="allowGuestLogin" value="false"/>
        <property name="principalFormat" value="fqn"/>
        <property name="roleFormat" value="both"/>
    </bean>

    <!-- Core config-->
    <sec:http entry-point-ref="negotiateSecurityFilterEntryPoint">
        <sec:custom-filter ref="waffleNegotiateSecurityFilter" position="BASIC_AUTH_FILTER"/>

        <sec:logout logout-url="/app/logout" logout-success-url="/app/home"/>
        <sec:access-denied-handler error-page="/app/accessdenied"/>

        <sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY"/>
        <sec:intercept-url pattern="/app/resource/*" filters="none"/>
        <sec:intercept-url pattern="/app/javax.*/**" filters="none"/>
    </sec:http>

</beans>

That’s it.

The above spring config is loaded via web.xml, along with other spring contexts.

Now when user tries to access the application url, CustomAuthenticationFilter correctly recognizes the authenticated Windows user and redirects to app home page. Yes it’s a single-sign-on!

To simplify testing, I’d recommended having a “Spring-LDAP-security” for dev and switch to Waffle Filter for prod environments.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Generating XML Schema and Classes using JaxB and Maven pom

Xml Binding via JaxB is a standard way to work with Xml objects in Java 6 and beyond. While there are ant tools and cmd line utilities to automate this, externalizing the automation in a dedicated maven module, along with nice wrapper methods for a fluent api would be nice. Below are the steps to generate jaxb objects with a fluent api via Maven Pom configuration.

Source Structure
- src/main/resources/sample.xsd
- src/main/resources/binding/binding.xjb

<bindings xmlns="http://java.sun.com/xml/ns/jaxb" version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <globalBindings>
    <javaType name="java.util.Calendar" xmlType="xs:date"
      parseMethod="javax.xml.bind.DatatypeConverter.parseDate"
      printMethod="javax.xml.bind.DatatypeConverter.printDate"
    />
  </globalBindings>
</bindings>

- Finally, integrate jaxb compile and generate step via pom.xml

<?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">
    <modelVersion>4.0.0</modelVersion>
    <artifactId>common-xml-schema</artifactId>
    <packaging>jar</packaging>
    <name>Common Schema and JaxB Module</name>
  
    <description>Common Module to hold all XML Schemas and JaxB objects</description>
    <dependencies>
         <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.2.2</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.2.4</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>    
            <!-- It's advised not to checkin the generated classes. By default they are generated in target/generated-sources with xmlns namespace provided
            in xsd. If you need the sources to be generated uncomment the below. 
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>jaxb2-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>xjc</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <packagename>xxx.schema</packagename>
                    <schemaDirectory>${basedir}/src/main/resources</schemaDirectory>
                    <outputdirectory>${basedir}/src/main/java/xxx/generated</outputdirectory>
                </configuration>
            </plugin>
            -->
        
            <plugin>
                <groupId>org.jvnet.jaxb2.maven2</groupId>
                <artifactId>maven-jaxb2-plugin</artifactId>

                <configuration>
                    <extension>true</extension>
                    <args>
                        <arg>-Xfluent-api</arg>
                    </args>
                    <plugins>
                        <plugin>
                            <groupId>net.java.dev.jaxb2-commons</groupId>
                            <artifactId>jaxb-fluent-api</artifactId>
                            <version>2.1.8</version>
                        </plugin>
                    </plugins>
                    <bindingDirectory>src/main/resources/binding</bindingDirectory>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Add session user info to log4j logging (custom file appender)

Ever wondered how to add additional session related info in log4j logging?

I like to see logged in user, along with session-id info in logging messages in applications, where analyzing secure operations becomes critical (healthcare, financial apps).

Here’s a sample filter log4j’s MDC to add diagnostic context in log messages.

package com.cramer.srf.web.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.MDC;

import com.cramer.srf.util.SRFUtils;

/**
 * Filter that adds user session info in log4j MDC (Mapped Diagnoistic Context)
 *
 */
public class Log4jSessionFilter implements Filter {

	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain filterChain) throws IOException, ServletException {
		if (request instanceof HttpServletRequest) {
			if (SRFUtils.getLoggedUser() != null) {
			    MDC.put("user", SRFUtils.getLoggedUser());
			}			
		}
		filterChain.doFilter(request, response);
	}

	@Override
	public void destroy() {
		// NO OP
	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
		// NO OP
	}
}

The corresponding log4j file. Note ‘[%X{user}]‘ in the ConversionPattern below.

<!-- File appender -->
<appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender">
    <param name="File" value="logs/rx.log" />
    <param name="Append" value="true" 
    <param name="DatePattern" value="'.'yyyy-ww" />
    <layout class="org.apache.log4j.PatternLayout">
        <param name="ConversionPattern" value="%d{ISO8601}  %-5p [%X{user}] [%t:%X{SESSION}] %c - %m%n" />
    </layout>
</appender>
[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Command Line Dictionary Using Groovy WS

Alas, another 15 years has passed since I’ve last posted. This time it was prompted by a fairly simple need: to lookup a word via the command line. Now, I already had a very simple solution to this using WordNet. That is simple enough:

sudo apt-get install wordnet

Then simply type:

wn hello -over

You should see output similar to this:

Overview of noun hello

The noun hello has 1 sense (first 1 from tagged texts)

1. (1) hello, hullo, hi, howdy, how-do-you-do — (an expression of greeting; “every morning they exchanged polite hellos”)

That’s all well and good, until I typed this:

wn smote -over

And came up empty. Indeed WordNet is useful but it is limited. There are 2 solutions that immediately came to mind.

  1. Figure out how to get more definitions loaded into my instance of WordNet
  2. Find a dictionary service that is much more comprehensive than WordNet, and write a client for it

After a couple of quick Google searches I decided on the latter. And, since I’ve been doing a fair amount of Grails work lately, I thought, why not try this in Groovy?

One of those Google searches brought me to http://services.aonaware.com/DictService/. After a few trials with the simple front-end on the page, I was satisfied. Then it was time to find a Groovy example, which I found quickly enough with Groovy WS.

If you look at the code snippet on that page, it is incredibly simple.

@Grab(group='org.codehaus.groovy.modules', module='groovyws', version='0.5.2')
import groovyx.net.ws.WSClient

proxy = new WSClient("http://www.w3schools.com/webservices/tempconvert.asmx?WSDL", this.class.classLoader)
proxy.initialize()

result = proxy.CelsiusToFahrenheit(0)
println "You are probably freezing at ${result} degrees Farhenheit"

I tried this example as is, but seemed to have problems with the annotation at the top. Being rather impatient, I found a Groovy WS Standalone jar here at:
http://snapshots.dist.codehaus.org/groovy/distributions/groovyws/groovyws-standalone-0.5-SNAPSHOT.jar

I dropped it into my $GROOVY_HOME/lib directory, and then removed the annotation from the code. The example worked perfectly.

So, using the WSDL from the service I mentioned earlier, I made a few modifications and named it Pablo.groovy. Why Pablo? Why not? When speed counts, who cares?!

import groovyx.net.ws.WSClient

proxy = new WSClient("http://services.aonaware.com/DictService/DictService.asmx?WSDL", this.class.classLoader)
proxy.initialize()

//Define is a name of the service method, see the service WSDL
result = proxy.Define(args[0])

if(result != null) {
	for(defin in result.definitions.definition) {
		println "${defin.wordDefinition}"
	}
}

I needed to analyze the WSDL to figure out how to interpret the results, but other than that, it was a pleasantly pain-free experience.

Now I type:

groovy Pablo.groovy smote

And I get a much more satisfying result, save the logging garbage at the top!

Jul 18, 2011 5:11:29 PM org.apache.cxf.endpoint.dynamic.DynamicClientFactory outputDebug
INFO: Created classes: com.aonaware.services.webservices.ArrayOfDefinition, com.aonaware.services.webservices.ArrayOfDictionary, com.aonaware.services.webservices.ArrayOfDictionaryWord, com.aonaware.services.webservices.ArrayOfStrategy, com.aonaware.services.webservices.Define, com.aonaware.services.webservices.DefineInDict, com.aonaware.services.webservices.DefineInDictResponse, com.aonaware.services.webservices.DefineResponse, com.aonaware.services.webservices.Definition, com.aonaware.services.webservices.Dictionary, com.aonaware.services.webservices.DictionaryInfo, com.aonaware.services.webservices.DictionaryInfoResponse, com.aonaware.services.webservices.DictionaryList, com.aonaware.services.webservices.DictionaryListExtended, com.aonaware.services.webservices.DictionaryListExtendedResponse, com.aonaware.services.webservices.DictionaryListResponse, com.aonaware.services.webservices.DictionaryWord, com.aonaware.services.webservices.Match, com.aonaware.services.webservices.MatchInDict, com.aonaware.services.webservices.MatchInDictResponse, com.aonaware.services.webservices.MatchResponse, com.aonaware.services.webservices.ObjectFactory, com.aonaware.services.webservices.ServerInfo, com.aonaware.services.webservices.ServerInfoResponse, com.aonaware.services.webservices.Strategy, com.aonaware.services.webservices.StrategyList, com.aonaware.services.webservices.StrategyListResponse, com.aonaware.services.webservices.WordDefinition
Jul 18, 2011 5:11:30 PM groovyx.net.ws.AbstractCXFWSClient getBindingOperationInfo
WARNING: Using SOAP version: 1.1
Smite \Smite\ (sm[imac]t), v. t. [imp. {Smote} (sm[=o]t), rarely
{Smit} (sm[i^]t); p. p. {Smitten} (sm[i^]t”t’n), rarely
{Smit}, or {Smote}; p. pr. & vb. n. {Smiting}
(sm[imac]t”[i^]ng).] [AS. sm[=i]tan to smite, to soil,
pollute; akin to OFries. sm[=i]ta to smite, LG. smiten, D.
smijten, G. schmeissen, OHG. sm[=i]zan to smear, stroke, OSw.
& dial. Sw. smita to smite, Dan. smide to throw, Goth.
bismeitan, to anoint, besmear; cf. Skr. m[=e]d to be fat. The
original sense seems to have been, to daub on, to smear. Cf.
{Smut}.]
1. To strike; to inflict a blow upon with the hand, or with
any instrument held in the hand, or with a missile thrown
by the hand; as, to smite with the fist, with a rod,
sword, spear, or stone.
[1913 Webster]

Now to smote the logging and be rid of it; simply adding these few lines will do:

import java.util.logging.Level
import java.util.logging.LogManager

LogManager.getLogManager().getLogger("").setLevel(Level.SEVERE)

Now the output is as tidy as I want it to be for now.

$ groovy Pablo.groovy smote
Smite \Smite\ (sm[imac]t), v. t. [imp. {Smote} (sm[=o]t), rarely
{Smit} (sm[i^]t); p. p. {Smitten} (sm[i^]t”t’n), rarely
{Smit}, or {Smote}; p. pr. & vb. n. {Smiting}
(sm[imac]t”[i^]ng).] [AS. sm[=i]tan to smite, to soil,
pollute; akin to OFries. sm[=i]ta to smite, LG. smiten, D.
smijten, G. schmeissen, OHG. sm[=i]zan to smear, stroke, OSw.
& dial. Sw. smita to smite, Dan. smide to throw, Goth.
bismeitan, to anoint, besmear; cf. Skr. m[=e]d to be fat. The
original sense seems to have been, to daub on, to smear. Cf.
{Smut}.]
1. To strike; to inflict a blow upon with the hand, or with
any instrument held in the hand, or with a missile thrown
by the hand; as, to smite with the fist, with a rod,
sword, spear, or stone.
[1913 Webster]

Whosoever shall smite thee on thy right cheek, turn
to him the other also. –Matt. v. 39.
[1913 Webster]

And David . . . took thence a stone, and slang it,
and smote the Philistine in his forehead. –1 Sam.
xvii. 49.
[1913 Webster]

2. To cause to strike; to use as an instrument in striking or
hurling.
[1913 Webster]

Prophesy, and smite thine hands together. –Ezek.
xxi. 14.
[1913 Webster]

Saul . . . smote the javelin into the wall. –1 Sam.
xix. 10.
[1913 Webster]

3. To destroy the life of by beating, or by weapons of any
kind; to slay by a blow; to kill; as, to smite one with
the sword, or with an arrow or other instrument.
[1913 Webster]

4. To put to rout in battle; to overthrow by war.
[1913 Webster]

5. To blast; to destroy the life or vigor of, as by a stroke
or by some visitation.
[1913 Webster]

The flax and the barly was smitten. –Ex. ix. 31.
[1913 Webster]

6. To afflict; to chasten; to punish.
[1913 Webster]

Let us not mistake God’s goodness, nor imagine,
because he smites us, that we are forsaken by him.
–Wake.
[1913 Webster]

7. To strike or affect with passion, as love or fear.
[1913 Webster]

The charms that smite the simple heart. –Pope.
[1913 Webster]

Smit with the love of sister arts we came. –Pope.
[1913 Webster]

{To smite off}, to cut off.

{To smite out}, to knock out, as a tooth. –Exod. xxi. 27.

{To smite with the tongue}, to reproach or upbraid; to
revile. [Obs.] –Jer. xviii. 18.
[1913 Webster]

Smite \Smite\ (sm[imac]t), v. t. [imp. {Smote} (sm[=o]t), rarely
{Smit} (sm[i^]t); p. p. {Smitten} (sm[i^]t”t’n), rarely
{Smit}, or {Smote}; p. pr. & vb. n. {Smiting}
(sm[imac]t”[i^]ng).] [AS. sm[=i]tan to smite, to soil,
pollute; akin to OFries. sm[=i]ta to smite, LG. smiten, D.
smijten, G. schmeissen, OHG. sm[=i]zan to smear, stroke, OSw.
& dial. Sw. smita to smite, Dan. smide to throw, Goth.
bismeitan, to anoint, besmear; cf. Skr. m[=e]d to be fat. The
original sense seems to have been, to daub on, to smear. Cf.
{Smut}.]
1. To strike; to inflict a blow upon with the hand, or with
any instrument held in the hand, or with a missile thrown
by the hand; as, to smite with the fist, with a rod,
sword, spear, or stone.
[1913 Webster]

Whosoever shall smite thee on thy right cheek, turn
to him the other also. –Matt. v. 39.
[1913 Webster]

And David . . . took thence a stone, and slang it,
and smote the Philistine in his forehead. –1 Sam.
xvii. 49.
[1913 Webster]

2. To cause to strike; to use as an instrument in striking or
hurling.
[1913 Webster]

Prophesy, and smite thine hands together. –Ezek.
xxi. 14.
[1913 Webster]

Saul . . . smote the javelin into the wall. –1 Sam.
xix. 10.
[1913 Webster]

3. To destroy the life of by beating, or by weapons of any
kind; to slay by a blow; to kill; as, to smite one with
the sword, or with an arrow or other instrument.
[1913 Webster]

4. To put to rout in battle; to overthrow by war.
[1913 Webster]

5. To blast; to destroy the life or vigor of, as by a stroke
or by some visitation.
[1913 Webster]

The flax and the barly was smitten. –Ex. ix. 31.
[1913 Webster]

6. To afflict; to chasten; to punish.
[1913 Webster]

Let us not mistake God’s goodness, nor imagine,
because he smites us, that we are forsaken by him.
–Wake.
[1913 Webster]

7. To strike or affect with passion, as love or fear.
[1913 Webster]

The charms that smite the simple heart. –Pope.
[1913 Webster]

Smit with the love of sister arts we came. –Pope.
[1913 Webster]

{To smite off}, to cut off.

{To smite out}, to knock out, as a tooth. –Exod. xxi. 27.

{To smite with the tongue}, to reproach or upbraid; to
revile. [Obs.] –Jer. xviii. 18.
[1913 Webster]

Smote \Smote\,
imp. (& rare p. p.) of {Smite}.
[1913 Webster]

smite
v 1: inflict a heavy blow on, with the hand, a tool, or a weapon
2: affect suddenly with deep feeling; “He was smitten with love
for this young girl”
3: cause pain or suffering in; “afflict with the plague”; “That
debasement of the verbal currency that afflicts terms used
in advertisement” [syn: {afflict}]
[also: {smote}, {smitten}, {smit}]

smote
See {smite}

The results are lengthy, but for right now, it’s all that I want. And nay, I shan’t complain!

It was quick and easy, and as long as I use it less than several thousand times per day, I am operating well within the terms of service.

Till next time!

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Understanding OpenJPA InvalidStateException: Detected reentrant flush

Ran into this issue today:

<openjpa-1.2.2-r422266:898935 fatal user error> org.apache.openjpa.persistence.InvalidStateException: Detected reentrant flush.  Make sure your flush-time instance callback methods or event listeners do not invoke any operations that require the in-progress flush to complete.
	at org.apache.openjpa.kernel.BrokerImpl.flushSafe(BrokerImpl.java:1923)
	at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:1698)
	at org.apache.openjpa.kernel.QueryImpl.isInMemory(QueryImpl.java:956)
	at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:838)
	at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:779)
	at org.apache.openjpa.kernel.DelegatingQuery.execute(DelegatingQuery.java:525)

This is a tricky exception since the verbose description does not clarify the intent.

The problem:
I had to write my own Auditing since we weren’t using Hibernate (and so no Envers) but openjpa 1.2.2. Don’t ask me why. It’s a big financial company and they like Websphere 7 (which “ships” openjpa 1.2).

A sample “Profile” entity

@Entity
@EntityListeners({ProfileAuditListener.class})
public class Profile implements Serializable {
 ...
}

The standard JPA Entity Listener:

@Named
public class ProfileAuditListener implements ApplicationContextAware {
        private ProfileAuditDao auditDao;

	@PostUpdate
	@Transactional
	public void postUpdate(Profile newProfile) {
	    ProfileAudit audit = new ProfileAudit();
	    ...
    	    ...
   	    Profile oldProfile = profileDao.read(newProfile.getEmail());
            // InvalidStateException thrown above
            ...
            // Compare field by field for editable fields
	    ...	
	
	    auditDao.audit(audit);
	}
}

A simple Dao

@Repository("profileDao")
public class JPAProfileDao implements ProfileDao {

	@Transactional(readOnly = true)
	public Profile read(String email) {
		List<Profile> profiles = em.createNamedQuery("findByEmail").setParameter("email", email);
		if (profiles.size() != 0) {
			return profiles.get(0);
		}
		return null;
	}
}

As you can see, nothing fancy here. An Audit interceptor trying to see the difference in ‘Profile’ properties just after updated the entity in db. However an exception is thrown where I execute a read-only Transactional query.

Explanation:
The exception indicates that the event listener might be executing a flush accidentally from another operation and OpenJPA doesnt allow a flush to occur during a flush. Wait, a flush? But I’m not flushing anywhere, in fact — I think it’s all default flushing.

That’s the catch. The default querying in openjpa is FlushModeType.AUTO and that causes a flush to occur even if it’s a @Transactional(readOnly=true)

Solution:
set the flush mode to FlushModeType.COMMIT on that particular query.

You can also set a system wide property like setting false flushBeforeQueries = true in persistence.xml but I wouldn’t recommend that unless you want this behavior explicitly. For instance, my unit tests needed the auto flush to work since I persist and read in the same transaction (Spring Transactional tests).

In general, your use case might be different from mine but the underlying concept is same. Look for the accidental flushes from openjpa. If in doubt, always tune up the DEBUG logging.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Mock Unit Testing Services and Daos with Mockito and Spring 3

If you haven’t been mocking yet, check this out. There are other tools in Groovy using DSLs but if you want to stick to Java, Mockito is by far the best BDD-style mock unit testing tool.

Traditional examples provide a List mocking example or foo/bar example which I find it mostly annoying since it doesn’t teach you how to solve real problems. And the documentation is verbose and crams with unnecessary features confusing us further. In this tutorial, I’ll dive straight into a relevant example of mock testing Daos in Service layer. I’m not a big fan of Daos anymore (after the advent of JPA), however for the purposes of this tutorial, it’ll be easier to explain.

Consider a Profile entity (like facebook user profile) with daos/services: ProfileDao/JPAProfileDao, ProfileService/ProfileServiceImpl. To complicate things further, say you are using DTOs since it’s a client server app with a GWT front end. You might need a simple mapper class. Let’s call it ProfileMapper/ProfileMapperImpl.

@Service("profileService")
public class ProfileServiceImpl implements ProfileService {
	private final ProfileDao profileDao;
	private final ProfileMapper profileMapper;

	@Inject
	public ProfileServiceImpl(final ProfileDao profileDao, final ProfileMapper profileMapper) {
		this.profileDao = profileDao;
		this.profileMapper = profileMapper;
	}

	@Transactional
	public void create(ProfileDto profile) throws DuplicateProfileException {
		if (profile == null) {
			throw new IllegalArgumentException("profile cannot be null.");
		}

		Profile profile = profileMapper.toEntity(profile);
		// set default state as active
		profile .setIsActive(true);
		
		try {
			profileDao.save(profile);
		}
		catch (DuplicateKeyException e) {
			logger.warn("Unable to save profile with userId: " + profile.getUserId() + " already exists.");
			throw new DuplicateProfileException();
		}
		logger.debug("Profile saved successfully.");
	}

	@Transactional(readOnly = true)
	public ProfileDto read(String userId) throws InvalidProfileException {
		validateProfileInfo(userId);

		ProfileDto profileDto = null;
		Profile profile = profileDao.read(userId);
		if (profile != null) {
			profileDto = profileMapper.fromEntity(profile);
			logger.debug("Profile retrieved successfully.");
		}
		else {
			logger.debug("...");
		}
		return profileDto;
	}
	
	...
}

Now, in order to test ProfileService, you need to mock out ProfileMapper and ProfileDao, right? Let’s see how we do this in a simple JUnit 4.4+ test.

import static org.mockito.Mockito.*;

@RunWith(MockitoJUnitRunner.class)
public class ProfileServiceTest {

	@Mock
	ProfileDao profileDao;

	@Mock
	ProfileMapper profileMapper;

	// Can't use @InjectMocks because Mockito doesn't support constructor injection
	// As a workaround use @Before below to initialize service with stubs
	ProfileService profileService;

	@Before
	public void init() {
		profileService = new ProfileServiceImpl(profileDao, profileMapper);
	}

	@Test
	public void testRead() throws InvalidProfileException {
		// Simulate InvalidProfileException
		try {
			profileService.read("");
			fail(); // should never execute
		}
		catch (InvalidProfileException e) {
			e.getMessage(); // expected
		}

		// Given
		Profile profile = TestData.createTestProfile("userid"); // test utility to create a test Profile
		when(profileDao.read("userid")).thenReturn(profile);
		when(profileMapper.fromEntity(profile )).thenReturn(TestData.createTestProfileDto("userid"));

		// When
		ProfileDto dto = profileService.read("userid");

		// Then
		assertEquals(dto.getUserId(), "userid");
	}
}

Explanation:
1) Wrapping your test with @RunWith(MockitoJUnitRunner.class) helps create the mock initialization through annotation scanning (@Mock, @InjectMocks)
2) Add @Mock annotations for the components to mock. In this case profileDao, profileMapper
3) As of 1.8.5, Mockito doesn’t provide @InjectMock with construction injection. @Before test initializer is a workaround to inject ProfileService with mocks. Note that this will not be required if ProfileService has setter/getter injection of dependencies. However, I prefer JSR330 construction injection which is a best practice .
4) The actual @Test class with mockito stubs. Let’s dig deep into this.

As a template, it’s a good practice to view tests like a BDD style test.

// Given 

// When


// Then 

The above template forces you to think on the explicit conditions during which we run our unit test.

Next, we need to figure out a way to stub our mock component’s methods,

when(operation).thenReturn(object) 

In our example we want to mock profileDao.read(userId). So that translates to

when(profileDao.read("userid")).thenReturn(profile);		

Note that we’re letting the mocked dao return a profile object that we just created in the previous step. This will be 50% of most of your mocking use cases.

The next common used use case is to simulate exceptions from the mocked classes. Consider a test for create(…) that simulates the DuplicateProfileException.

@Test
	public void testCreateDuplicate() {
		// Given
		ProfileDto dto = TestData.createTestProfileDto("userid");
		Profile profile = TestData.createTestProfile("userid");
		when(profileMapper.toEntity(dto)).thenReturn(profile);
		doThrow(new DuplicateKeyException("duplicate profile")).when(profileDao).save(profile);

		// When
		try {
			profileService.create(dto);
			assertEquals(1, 2); // should never execute
		}
		// Then
		catch (DuplicateProfileException e) {
			e.getMessage();
		}
	}

Notice the line

doThrow(new DuplicateKeyException("duplicate profile")).when(profileDao).save(profile);

Quite simple, isn’t it?

If you’ve read so far, you can succuessfully write mock unit tests for 80% of your use cases. There are other advanced features like finding redundant invocations, spying on objects to simulate partial mocking, most of which I don’t see implementing for majority of my use cases.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]