Analysis (Code Coverage, Design Metrics) on Groovy Code

On my other project in Groovy, I finished integrating Cobertura Code Coverage and JDepend for Design Metrics. This post builds up on my earlier post Streamline build scripts creation with Gant and ConfigSlurper. Essentially, I have two reports directories xml and html, underneath them are folders containing Coverage, Design Metrics and Test reports. Below is my project structure:

Below is the sample Gant file that shows how to do this. It defines folders related to Code Coverage output, defines baselines for line coverage (81%) and branch coverage (68%) as properties (see the Code Coverage Properties section) and so are folders for JDepend output (see the Design Metrics Properties section).

// Properties
final srcDir = 'src/'
final testDir = 'test/'
final libDir = 'lib/'
final buildDir = 'build/'
final classesDir = buildDir + 'classes/'
final reportsDir = buildDir + 'reports/'
final xmlReportsDir = reportsDir + 'xml/'
final htmlReportsDir = reportsDir + 'html/'
final xmlTestReportsDir = xmlReportsDir + 'test/'
final htmlTestReportsDir = htmlReportsDir + 'test/'
final baseFolder = 'com/company/product/'

//Code Coverage Properties
final instrumentedDir = buildDir + 'instrumented/'
final xmlCoverageReportsDir = xmlReportsDir + 'coverage/'
final htmlCoverageReportsDir = htmlReportsDir + 'coverage/'
final coverageDataFile = 'cobertura.ser'
final int lineCoverageBaseline = 81
final int branchCoverageBaseline = 68

//Design Metrics 
final designMetricsFile = ''
final xmlDesignMetricsReportsDir = xmlReportsDir + 'design/'
final htmlDesignMetricsReportsDir = htmlReportsDir + 'design/'

def antProperty = ant.project.properties 
final antHomeDir = antProperty.'ant.home' + '/'
final antLibDir = antHomeDir + 'lib/'

ant.path(id:"libs") {
	fileset(dir:libDir, includes:"**/*.jar")
}

ant.path(id:"source.path") {
	fileset(dir:srcDir, includes:"**/*.groovy")
}

ant.path(id:"behaviors") {
	fileset(dir:testDir, includes:"**/*.story")
	fileset(dir:testDir, includes:"**/*.specification")
}

ant.path(id:"compile.class.path") {
	path(refid:"libs")
	path(location:classesDir)
}

ant.path(id:"ant.class.path") {
	fileset(dir:"${antLibDir}", includes: "**/*.jar")
}

ant.path(id:"cobertura.class.path") {
	fileset(dir:"${libDir}", includes: "cobertura.jar, **/*.jar")
}

ant.path(id:"instrumented.class.path") {
	path(refid:"libs")
	path(location:instrumentedDir)
}

ant.taskdef(classpathref:"cobertura.class.path", resource:"tasks.properties")

ant.taskdef(name:"jdepend", classname:"org.apache.tools.ant.taskdefs.optional.jdepend.JDependTask") {
	classpath() {
		path(location:antLibDir + "ant-jdepend.jar")
		path(location:libDir + "jdepend-2.9.1.jar")
	}
}

ant.taskdef(name:"easyb", classname:"org.easyb.ant.BehaviorRunnerTask") {
	classpath() {
		path(location:libDir + "easyb-0.9.6.jar")
	}
}

def easyb(testDir, htmlTestReportsDir, xmlTestReportsDir) {
	ant.easyb(failureProperty:"easyb.failed") {
		classpath() {
		    //Do not change the order, else you will get 0% coverage
			path(refid:"instrumented.class.path")
			path(refid:"compile.class.path")
		}
		behaviors(dir:testDir, includes:"**/*.specification, **/*.story")
		report(location:xmlTestReportsDir + "testReport.xml", format:'xml')
		report(location:htmlTestReportsDir + "testReport.html", format:'html')
	}
	ant.fail(message:"OOooo my my...Stopped the build as Behaviors Failed To Run As Expected", if:"easyb.failed")
}

target ("run-test" : 'Run all Easyb Stories and Specifications') {
	depends("compile-source")
	depends("instrument-coverage")
	
	easyb(testDir, htmlTestReportsDir, xmlTestReportsDir)
	
    "cobertura-report"(format:'html', datafile:coverageDataFile, destdir:htmlCoverageReportsDir, srcdir:srcDir)
    "cobertura-report"(format:'xml',  datafile:coverageDataFile, destdir:xmlCoverageReportsDir, srcdir:srcDir)
    "cobertura-check"(totalbranchrate:branchCoverageBaseline, totallinerate:lineCoverageBaseline)
}


target (metrics: 'Static Analysis') {
	depends("run-test")
	depends("design-metrics")
}

def removeOldInstrumentationData(coverageDataFile, instrumentedDir) {
	ant.delete(file:coverageDataFile)
	ant.delete(dir:instrumentedDir)
}

target ("instrument-coverage" : 'Instruments Cobertura Coverage') {
	removeOldInstrumentationData(coverageDataFile, instrumentedDir)
	"cobertura-instrument"(todir:instrumentedDir) {
		ignore(regex:"org.apache.*, org.easyb.*")
		fileset(dir:classesDir, includes:'**/*.class', excludes:'**/*Test.class')
	}
}

target ("design-metrics" : 'Generate Design Quality Metrics') {
  ant.jdepend(format:'xml', outputfile:xmlDesignMetricsReportsDir + 'jdepend.xml') {
      classespath() {
        pathelement(location:classesDir)
      }
      classpath() {
      	path(refid:"compile.class.path")
      }
      exclude(name:"java.*")
      exclude(name:"org.*")
      exclude(name:"groovy.*")
  }

  ant.xslt(basedir:xmlDesignMetricsReportsDir, destdir:htmlDesignMetricsReportsDir, includes:'jdepend.xml', style: antHomeDir + '/etc/jdepend.xsl') {
  	  classpath() {
      	   path(refid:"ant.class.path")
      }
  }
}

target (clean: 'Clean') {
	removeOldInstrumentationData(coverageDataFile, instrumentedDir)
	ant.delete(dir:buildDir)
}

Additionally, I did not want the developers to create a .ant/lib folders in their home directory and throw in jdepend-2.9.1.jar (as gant reads gant-starter.conf and loads user specific libraries that are Ant specific), instead, leaning in favor of making the build self-contained, without the above chores, I chose to use the lib folder for all the libraries...

If you feel this article has helped you, leave a comment below and if others can benefit from this article, share it:

Comments [0]

Brevity with Groovy's groupBy

Lets say you have a Row with number and a tag. Tag is used to annotate rows with rules and a unique tag Id. More than one row can have the same tag and hence tag Id. The two abstractions are represented as
public final class Row extends LinkedList {
    final int number
    Tag tag
}
Here is the Tag class
public class Tag {
    String id
    private final rules = [] as Set
}
Here is the Easyb scenario that groups the rows by tag Id.
scenario "groups by tags and publishes them in the result", {
	given "that I have tagged rows", {
		row1 = new Row(1, [id:'tag2', rule:'Rule 1'] as Tag, ["348", "dalald"])
		row2 = new Row(3, [id:'tag1', rule:'Rule 2'] as Tag, ["345", "tomty"])
		row3 = new Row(2, [id:'tag2', rule:'Rule 1'] as Tag, ["348", "dhaval"])
		row4 = new Row(4, [id:'tag1', rule:'Rule 2'] as Tag, ["345", "tyber"])
		rows = [row1, row2, row3, row4]
	}
	when "I group the rows by tag id", {
		rowsByTag = groupByTag(rows)
	}
	then "I should see rows that are grouped by tag id", {
		rowsByTag.size().shouldBe 2
		ensure(rowsByTag['tag2'].flatten()) {
			contains(["348", "dalald", "348", "dhaval"])
		}
		ensure(rowsByTag['tag1'].flatten()) {
			contains(["345", "tomty", "345", "tyber"])
		}
	}
}
Initially I had written the code for groupByTag() like this
//Client code
def rowsByTags = groupByTag(rows)
rowsByTags.each { tag, row ->
   // Do something with each tag and row
}


def groupByTag(rows) {
    def taggedMap = [:]
    rows.each { row ->
        def taggedRows = [] 
        if (taggedMap[row.tag.id]) {
            taggedRows = taggedMap[row.tag.id]
        } 
        taggedRows << row
        taggedMap.put(row.tag.id, taggedRows)
    }
    taggedMap
}
But, I while reading Venkat Subramaniam's Programming Groovy I came across this groupBy(Closure closure) method for collections and here is the refactored groupByTag():
def groupByTag(rows) {
    rows.groupBy { row ->
        row.tag.id
    }
}
Indeed beauty in brevity!

If you feel this article has helped you, leave a comment below and if others can benefit from this article, share it:

Comments [0]

Agile Mumbai Conference 2010

I'll be co-organizing the Mumbai Agile Conference 2010 for the third consecutive time along with Naresh on the 16th and 17th Jan 2010. The conference theme is "Post-Modern Agile - Be done with the Dogma". It will be hosted by Mukesh Patel School of Technology Management & Engineering

This year we have 3 international speakers:

  1. David Hussman
  2. Jeff Patton
  3. J. B. Rainsberger

The program can be found on http://www.agileindia.org/agilemumbai2010/agile-mumbai-2010-program. If you are interested in

If you feel this article has helped you, leave a comment below and if others can benefit from this article, share it:

Comments [0]

Plumbing Spring, Hibernate, Gilead and GWT-SL

Based on my earlier post on Architectural Note on frameworks used with GWT and Session Handling in GWT....in this post, I'll show the plumbing that I put in place in order to get the application components work in synergism. Based on the functionality needed on my project, I had the need to evolve few custom components:
  1. Need for Custom ApplicationGWTRPCServiceExporter and ApplicationServiceExporterFactory
  2. Need for Custom ApplicationGWTHandler
  3. Need for injecting SecurityContext

Starting with web.xml, I have Spring configuration being read using ContextLoaderListener from the config location and Spring Dispatcher Servlet - application front-ending all the service requests, a standard spring usage.

<web-app>
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:applicationContext.xml</param-value>
	</context-param>
	
    <filter>
        <filter-name>session-in-view</filter-name>
        <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
        <init-param>
            <param-name>singleSession</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>

   <filter-mapping>
    	<filter-name>session-in-view</filter-name>
    	<servlet-name>application</servlet-name>
    </filter-mapping>

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

	<servlet>
		<servlet-name>application</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	
	<servlet-mapping>
		<servlet-name>application</servlet-name>
		<url-pattern>/application/services/*</url-pattern>
	</servlet-mapping>
        ...
        ...
</web-app>
Here is the application-servlet.xml which is consulted by Spring to dispatch the incoming request to the appropriate service. It delegates the responsibility of service instance creation to ApplicationServiceExporterFactory (I'll talk about other dependency injections to this one later). Also, I had to inject the GileadPersistentBeanManager in the Handler (a dependency used by the HB4GWTRPCServiceExporter to glue Gilead)
<?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-2.5.xsd">

	<bean id="handlerMapping" class="com.company.product.web.spring.ApplicationGWTHandler">
		<property name="beanManager" ref="gileadPersistentBeanManager"/>
		<property name="serviceExporterFactory">
			<bean class="com.company.product.web.spring.ApplicationServiceExporterFactory">
				<constructor-arg ref="securityContext" />
				<constructor-arg ref="httpContext" />
				<constructor-arg ref="userRepository" />
			</bean>
		</property>
		<property name="mappings"\>
			<map>
				<entry key="/gatewayService" value-ref="gatewayService"/>
				<entry key="/someOtherService" value-ref="someOtherService"/>
			</map>
		</property>
	</bean>
</beans>
I have extended the GWT-SL's GWTHandler to accomodate Gilead's PersistentBeanManager (as we are using the older GWT-SL v0.1.5b, while the newer release GWT-SL v1.0 has added GileadRPCServiceExporterFactory for use with GWTHandler)
public class ApplicationGWTHandler extends GWTHandler {
	
	// temporary mapping, void after bean initialisation
	private Map<String, Object> _mapping;
	private PersistentBeanManager beanManager;
	
	public void setBeanManager(PersistentBeanManager beanManager) {
		this.beanManager = beanManager;
	}
	
	public void setMappings(Map<String, Object> mapping) {
		this._mapping = mapping;
	}

	private RPCServiceExporter initServiceInstance(RPCServiceExporter exporter, Object service, Class<RemoteService>[] serviceInterfaces) {
		try {
			if (exporter instanceof HB4GWTRPCServiceExporter) {
				HB4GWTRPCServiceExporter hB4GWTRPCServiceExporter = (HB4GWTRPCServiceExporter) exporter;
				hB4GWTRPCServiceExporter.setBeanManager(beanManager);
			}
			exporter.setResponseCachingDisabled(disableResponseCaching);
			exporter.setServletContext(getServletContext());
			exporter.setService(service);
			exporter.setServiceInterfaces(serviceInterfaces);
			exporter.afterPropertiesSet();
			return exporter;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public void afterPropertiesSet() throws Exception {
		for (Map.Entry<String, Object> entry : _mapping.entrySet()) {
			RPCServiceExporter exporter = factory.create();
			registerHandler(entry.getKey(), initServiceInstance(exporter, entry.getValue(), ReflectionUtils
					.getExposedInterfaces(entry.getValue().getClass())));
		}
		this._mapping = null;
	}
}
Here is the ApplicationServiceExporterFactory that creates a ApplicationGWTRPCServiceExporter to wrap and export every service specified in the ApplicationGWTHandler mappings (application-servlet.xml) as a GWT-RPC Service. So, in a nutshell, ApplicationGWTRPCServiceExporter is a interceptor that sits in between the actual service and the client intercepting every method call and choosing to allow or disallow the call under certain conditions.
public class ApplicationServiceExporterFactory implements RPCServiceExporterFactory {
	private final SecurityContext securityContext;
	private final UserRepository userRepository;
	private final HttpContext httpContext;
	
	public ApplicationServiceExporterFactory(SecurityContext securityContext, HttpContext httpContext, UserRepository userRepository) {
		this.securityContext = securityContext;
		this.httpContext = httpContext;
		this.userRepository = userRepository;
	}

	public RPCServiceExporter create() {
		return new ApplicationGWTRPCServiceExporter(securityContext, httpContext, userRepository);
	}
}
ApplicationGWTRPCServiceExporter is primarily responsible for allowing or disallowing a method call to the target service. Following are the responsibilities of this class:
  1. It makes all the services HttpServletRequest and HttpServletReponse aware by injecting a Threadlocal based HttpContext.
  2. Essentially, it allows or disallows a method call (with exception of Login method) on services.
    • It disallows the call, if the HttpSession has timed-out or user is not in session. For these scenarios, it basically inspects the current called-method signature for the declared exceptions and programatically wraps SESSION_TIMEOUT or NOT_LOGGED_IN messages (for the client-side session handling mechanism to respond to, refer to my earlier post on Session Handling in GWT) in one of the exceptions declared by the method (Look at the wrapInTargetMethodException() method). It then calls HB4GWTRPCServiceExporterto handle the exception by invoking the super.handleInvocationTargetException().
    • If above checks are passed, then it allows the call to proceed...but before that it injects the SecurityContext and thus makes the services aware of the User Principal (User who is calling the service). It uses SecurityContextInjector to do this job.
public class ApplicationGWTRPCServiceExporter extends HB4GWTRPCServiceExporter {
	
	private SecurityContextInjector injector;
	private final HttpContext httpContext;
	private static final String LOGIN_METHOD = "login";
	
	public ApplicationGWTRPCServiceExporter(SecurityContext securityContext, HttpContext httpContext, UserRepository userRepository) {
		this.httpContext = httpContext;
		injector = new SecurityContextInjector(securityContext, userRepository);
	}

	@Override
	public String invokeMethodOnService(Object service, Method targetMethod,
			Object[] targetParameters, RPCRequest rpcRequest) throws Exception {
		HttpServletRequest request = getHttpRequest();
		HttpServletResponse response = getHttpResponse();
		
		injectHttpContext(request, response);
		HttpSession session = request.getSession(false);
		if (doesNotExist(session)) {
			if (targetMethod.getName().equals(LOGIN_METHOD)) {
				return super.invokeMethodOnService(service, targetMethod, targetParameters, rpcRequest);
			}
			logger.info("HttpSession Timedout");
			InvocationTargetException invocationException = wrapInTargetMethodException(targetMethod, 
GatewayMessageKeys.SESSION_TIMEOUT);
			return handleInvocationTargetException(invocationException, service, targetMethod, rpcRequest);
		}
		if (userNotInSession(session)) {
			logger.info("User not in existing HttpSession..invalidating session");
			session.invalidate();
			InvocationTargetException invocationException = wrapInTargetMethodException(targetMethod, 
GatewayMessageKeys.NOT_LOGGED_IN);
			return super.handleInvocationTargetException(invocationException, service, targetMethod, rpcRequest);
		}
		try {
			injectSecurityContext(request, response);
		} catch (Throwable problem) {
			wrapInTargetMethodException(targetMethod, GatewayMessageKeys.NOT_LOGGED_IN);
		}
		logger.debug("User in existing HttpSession...allowing service call");
		return super.invokeMethodOnService(service, targetMethod, targetParameters, rpcRequest);
	}

	private void injectHttpContext(HttpServletRequest request, HttpServletResponse response) {
		httpContext.setHttpServletRequest(request);
		httpContext.setHttpServletResponse(response);
	}

	private void injectSecurityContext(HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
		injector.injectSecurityContext(httpRequest, httpResponse);
	}

	private InvocationTargetException wrapInTargetMethodException(Method targetMethod, String messageKey) throws Exception {
		Class<?>[] exceptionTypes = targetMethod.getExceptionTypes();
		if(exceptionTypes.length > 0) {
			Constructor<?> constructor = exceptionTypes[0].getConstructor(String.class);
			Exception newExceptionInstance = (Exception) constructor.newInstance(messageKey);
			return new InvocationTargetException(newExceptionInstance);
		}
		return new InvocationTargetException(new ApplicationException("Make sure your Service Method throws subclass of ApplicationException!!"));
	}

	protected HttpServletRequest getHttpRequest() {
		return getThreadLocalRequest();
	}
	
	protected HttpServletResponse getHttpResponse() {
		return getThreadLocalResponse();
	}
}
Here is the SecurityContext interface and the corresponding Threadlocal based ApplicationSecurityContext implementation.
public interface SecurityContext {
	public Date getSystemDate();
	public User getCurrentUser();
	public void setCurrentUser(User user);
	public void setSystemDate(Date systemDate);
}

//Threadlocal based SecurityContext implementation
public class ApplicationSecurityContext implements SecurityContext {
	
	private static ThreadLocal<User> userThreadLocal = new ThreadLocal<User>();
	private static ThreadLocal<Date> systemDateThreadLocal = new ThreadLocal<Date>();

	public User getCurrentUser() {
		return userThreadLocal.get();
	}

	public Date getSystemDate() {
		return systemDateThreadLocal.get();
	}
	
	public void setCurrentUser(User user) {
		userThreadLocal.set(user);
	}
	
	public void setSystemDate(Date systemDate) {
		systemDateThreadLocal.set(systemDate);
	}
}
SecurityContextInjector is reponsible for getting the user from the repository based on the UID and injecting it as the current calling user in the SecurityContext. It also injects current system date and time. Thus, along with being HttpContext aware, the services are also aware of the Current Calling User and Current System time, referred as SecurityContext. This helps me implement one of the standard requirements of a web app that is to track the user who created/modified the entity with creation/modification time stamps.
public class SecurityContextInjector {

	public static final String TICKET = "__APPLICATION_TICKET__";
	public static final String NO_UID = "[NO UID]";
	private SecurityContext securityContext;
	private UserRepository userRepository;
	
	public SecurityContextInjector(SecurityContext securityContext, UserRepository userRepository) {
		this.securityContext = securityContext;
		this.userRepository = userRepository;
	}
	
	public void injectSecurityContext(HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
		String uid = getUid(httpRequest);
		User user = userRepository.findUniqueBy(uid);
		logger.debug("Injecting Security Context For User = " + user.getUid());
		securityContext.setSystemDate(getSystemDate());
		securityContext.setCurrentUser(user);
	}

	protected Date getSystemDate() {
		return DateTime.now();
	}

	private String getUid(HttpServletRequest httpRequest) {
		Cookie[] cookies = httpRequest.getCookies();
		Cookie applicationTicket = null;
		for (Cookie cookie : cookies) {
			if (TICKET.equals(cookie.getName())) {
				applicationTicket = cookie;
				break;
			}
		}
		return (applicationTicket == null)? NO_UID : applicationTicket.getValue();
	}
}

Finally, here is the snippet of applicationContext.xml that shows the wirings.
	<bean id="securityContext" class="com.company.product.server.core.security.ApplicationSecurityContext" />
	
	<bean id="httpContext" class="com.company.product.server.core.http.ApplicationHttpContext" />
	
	<bean id="trackableInterceptor" class="com.company.product.server.core.hibernate.interceptors.TrackableInterceptor" >
		<constructor-arg ref="securityContext" />
	</bean>
	
	<!-- Hibernate Setup -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" scope="singleton">
    	<property name="configLocations" value="classpath:hibernate.cfg.xml"/>
	<property name="entityInterceptor" ref="trackableInterceptor"/>    	
    </bean>
    
    <bean id="sessionProvider" class="com.company.product.server.core.hibernate.HibernateSessionProvider">
    	<constructor-arg ref="sessionFactory"/>
    </bean>
    
    <!-- Transaction Manager Setup -->
    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    	<constructor-arg ref="sessionFactory" />
    </bean>
    
	<!-- Gilead Setup (Stateful Mode) -->
	<bean id="gileadPersistenceUtil" class="net.sf.gilead.core.hibernate.spring.HibernateSpringUtil">
		<property name="sessionFactory" ref="sessionFactory"/>
	</bean>

	<bean id="gileadProxyStore" class="net.sf.gilead.core.store.stateful.InMemoryProxyStore">
		<property name="persistenceUtil" ref="gileadPersistenceUtil" />
	</bean>

	<bean id="gileadPersistentBeanManager" class="net.sf.gilead.core.PersistentBeanManager">
		<property name="proxyStore" ref="gileadProxyStore" />
		<property name="persistenceUtil" ref="gileadPersistenceUtil" />
	</bean>
	
 	<!-- Add Application Related services from this point onwards -->
	<bean id="userRepository" class="com.company.product.server.gateway.repository.HibernateUserRepository">
		<constructor-arg ref="sessionProvider" />
	</bean>

	<!-- Gateway Service Setup -->
	<bean id="gatewayService" class="com.company.product.server.gateway.DefaultGatewayService">
		<constructor-arg ref="userRepository"/>
		<constructor-arg ref="authenticator"/>
		<constructor-arg ref="httpContext"/>
	</bean>

If you feel this article has helped you, leave a comment below and if others can benefit from this article, share it:

Comments [3]

Styling Excel Sheets with Decorator and Strategy Patterns

We have an Exporter abstraction in our System, with CsvExporter and ExcelExporter as concretes exporting data in Csv and Excel formats respectively. ExcelExporter is a plain vanilla implementation exporting data as Excel workbook without any styles (bold-fonts, colored cells etc...) applied.

Next was this story of coloring the Cells, making the Header Bold, adding cell borders etc... in an Excel Sheet that gets downloaded to the user desktop. Colleague of mine (who was playing this story) asked me whether modifying the vanilla version of ExcelExporter would be a good idea to achieve this functionality? I said, the functionality that you are trying to achieve is basically decorating (styling) existing cells and I see that we can apply the decorator pattern here. Lets create a DecoratingExcelExporter that decorates based on decorating rules/information present within Stylist. Using the Stylist, the DecoratingExcelExporter will the job of styling the cells/rows accordingly.

Here is the Exporter.
public interface Exporter {
	
	String contentType();

	String fileExtension();

	void exportHeader(OutputStream outputStream, List<String> header) throws IOException;
	
	void exportRow(OutputStream outputStream, List<String> row) throws IOException;
	
	void flush(OutputStream outputStream) throws IOException;
	
}
and here is the plain vanilla version of ExcelExporter...BTW, We are using the Poi library for generating Excel.
public class ExcelExporter implements Exporter {
	private Workbook workbook;
	private Sheet sheet;
	private short rowIndex = 0;
	private Row row;
	
	public ExcelExporter(String sheetName) {
		workbook = createWorkbook();
		sheet = createSheet(workbook, sheetName);
	}
	
	public String contentType() {
		return "application/vnd.ms-excel";
	}

	public String fileExtension() {
		return ".xls";
	}

	public void exportHeader(OutputStream outputStream, List<String> header) throws IOException {
		writeRow(outputStream, header);
	}

	public void exportRow(OutputStream outputStream, List<String> row) throws IOException {
		writeRow(outputStream, row);
	}
	
	private void writeRow(OutputStream outputStream, List<String> rowData) throws IOException {
		Row row = createRow(sheet, rowIndex);
		int columns = row.size();
		
		for (int index = 0; index < columns; index++) {
			String data = rowData.get(index);
			Cell cell = createCell(row, index);
			cell.setCellValue(data);
		}
		rowIndex++;
	}

	protected Workbook createWorkbook() {
		return new HSSFWorkbook();
	}

	protected Sheet createSheet(Workbook workbook, String sheetName) {
		return workbook.createSheet(sheetName);
	}
	
	protected Row createRow(Sheet sheet, short rowIndex) {
		return sheet.createRow(rowIndex);
	}

	protected Cell createCell(Row row, int columnIndex) {
		return row.createCell(columnIndex);
	}
	
	public void flush(OutputStream outputStream) throws IOException {
		workbook.write(outputStream);
	}

	public Row getCurrentRow() {
		return row;
	}

	public Workbook getCurrentWorkbook() {
		return workbook;
	}
}

Again, in our project there are couple of places where we need to export table views as Excel that are styled differently and the things change are styling rules, and these variants can then be concrete implementations of the interface Stylist. Thus, Stylist embodies the Strategy for Styling.

public interface Stylist {

	public abstract void styleHeader(Workbook workBook, Row header);

	public abstract void styleRow(Workbook workbook, Row row);

}

DecoratingExcelExporter wraps in ExcelExporter to which it delegates the business of exporting header and rows. Once that is done, styles are applied to the current row using Stylist's styleHeader() and styleRow() methods. DecoratingExcelExporter confirms to SRP, because its sole responsibility in life is to decorate excel sheets and is strategically closed for modification (OCP).

public class DecoratingExcelExporter implements Exporter {

	private ExcelExporter excelExporter;
	private Stylist stylist;

	public DecoratingExcelExporter(ExcelExporter exporter, Stylist stylist) {
		this.excelExporter = exporter;
		this.stylist = stylist;
	}

	@Override
	public void exportHeader(OutputStream outputStream, List<String> header) throws IOException {
		excelExporter.exportHeader(outputStream, header);
		
		Row headerRow = excelExporter.getCurrentRow();
		Workbook workbook = excelExporter.getCurrentWorkbook();
		stylist.styleHeader(workbook, headerRow);
	}

	@Override
	public void exportRow(OutputStream outputStream, List<String> rowData) throws IOException {
		excelExporter.exportRow(outputStream, rowData);

		Row row = excelExporter.getCurrentRow();
		Workbook workbook = excelExporter.getCurrentWorkbook();
		stylist.sytleRow(workbook, row);
	}

	@Override
	public String contentType() {
		return excelExporter.contentType();
	}

	@Override
	public String fileExtension() {
		return excelExporter.fileExtension();
	}

	@Override
	public void flush(OutputStream outputStream) throws IOException {
		excelExporter.flush(outputStream);
	}
}
Here is TableViewStylist...
public class TableViewStylist implements Stylist {

	@Override
	public void styleHeader(Workbook workbook, Row header) {
		CellStyle headerStyle = CellDecorator.decorate(workbook)
						.withBorder(CellStyle.BORDER_THICK)
						.withBoldWeight()
						.style();
		for(Cell cell : header) {
			cell.setCellStyle(headerStyle);
		}
		autosizeAllColumns(workbook, header);
	}

	@Override
	public void styleRow(Workbook workbook, Row row) {
		CellStyle rowStyle = CellDecorator.decorate(workbook)
						.withBorder(CellStyle.BORDER_THIN)
						.style();

		for(Cell cell : row) {
			cell.setCellStyle(rowStyle);
		}
		autosizeAllColumns(workbook, row);
	}
	
	private void autosizeAllColumns(Workbook workbook, Row row) {
		Sheet sheet = workbook.getSheetAt(0);
		CellDecorator.autoSizeAllColumns(sheet , row);
	}
}
Here is the CellDecorator utility class that is used by the above class.
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.ss.usermodel.*;

public class CellDecorator {
	private CellStyle style;
	private Font font;
	
	@Deprecated
	private CellDecorator(Workbook workBook) {
		style = workBook.createCellStyle();
		font = workBook.createFont();
	}
	
	public CellDecorator withBorder(final short border) {
		style.setBorderBottom(border);
		style.setBorderTop(border);
		style.setBorderLeft(border);
		style.setBorderRight(border);
		return this;
	}
	
	public CellDecorator withColor(IndexedColors color) {
		style.setFillForegroundColor(color.getIndex());
		style.setFillPattern(CellStyle.SOLID_FOREGROUND);
		return this;
	}
	
	public CellDecorator withBoldWeight() {
		font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
		style.setFont(font);
		return this;
	}
	
	public CellStyle style() {
		return style;
	}
	
	public static CellDecorator decorate(Workbook workBook) {
		return new CellDecorator(workBook);
	}
	
	public static void autoSizeAllColumns(Sheet sheet, Row row) {
		for(Cell cell : row) {
			sheet.autoSizeColumn(cell.getColumnIndex(), true);
		}
	}
}
Thats all to this decorating Excel sheets!

If you feel this article has helped you, leave a comment below and if others can benefit from this article, share it:

Comments [3]

Downloading CSV, Excel files in GWT

Alright, this one needs some plumbing, I would have expected GWT to provide some out-of-box solution for this one (just like the File-Upload widget), as its a very common feature needed by almost all web applications. Anyways, quite a bit of server-side and client-side plumbing needs to be done in order to achieve this functionality. As on my current project, we need to export various table-views as CSV and as Excel, I have used the approach shown below.

First of all, when a user clicks a download link or button, this has to be a Synchronous request and cannot work with the Aynchronous callback handler that GWT provides. So, I have broken this post in two parts:
A. The Client-Side Plumbing.
B. The Server-Side Plumbing.

Also, I have BDDed the design and won't show the Scenarios and Specs, instead will focus on the key design components in this post.

A. The Client-Side Plumbing:
  1. Starting from the UI, I have created a SyncAction that embodies the notion of Synchronous Action with a single method execute() on it.
    public interface SyncAction {
    	public abstract void execute();
    }
    
  2. DownloadCsvAction is a implementation of SyncAction. So, basically, populate this action with a Url and fire execute()...thats all! Inside the execute() method, I had to make a GET synchronous request to Server Resource on HiddenIFrame. This will ensure that we do not refresh the page that we are already in. Once execute(), is called, the server-side starts processing the incoming request.
    public class DownloadCsvAction implements SyncAction {
    	
    	private String encodedUrl;
    	
    	public void setEncodedUrl(String encodedUrl) {
    		this.encodedUrl = encodedUrl;
    	}
    
    	public void execute() {
    		HiddenIFrame frame = new HiddenIFrame(encodedUrl);
    	}
    }
    
    Here is the HiddenIFrame class (I obtained this from one of the blogs and have renamed to HiddenIFrame a more meaningful name, thanks to the author, but don't recollect the blog-url, sorry!).
    public class HiddenIFrame extends Frame {
       
       public HiddenIFrame(String url) {
          super();
          setSize("0px", "0px");
          setVisible(false);
          sinkEvents(Event.ONLOAD);
          // TODO: Add Form here so that it will POST instead of GET
          RootPanel.get().add(this);
          // Do a GET currently
          setUrl(url);
       }
    
       public void onBrowserEvent(Event event) {
          if (DOM.eventGetType(event) == Event.ONLOAD) {
             unsinkEvents(Event.ONLOAD);
             DOM.eventCancelBubble(event, true);
             RootPanel.get().remove(this);
          } else {
             super.onBrowserEvent(event);
          }
       }
    }
    
  3. In order to populate the action with URL, GetRequestBuilder generates a GET URL request based on the base Url, target Url, and request params. Here is the breakdown of the GET parameters:
    • Base Url will be fixed and it will almost always be GWT.getModuleBaseURL().
    • Target Url is also fixed and will always be exporter.
    • There are few reserved parameters that are required to be passed. They are:
      1. serviceName (This is used by server side plumbing code)
      2. exportAs (This is used by server side plumbing code)
    • Add remaining parameters as per your business case (Remember its GET request, so it does have length limitation).
    public class GetRequestBuilder {
    	private static final String QUESTIONMARK = "?";
    	private static final String EQUAL_TO = "=";
    	private static final String PARAMETER_DELIMITER = "&";
    	
    	private Map<String, String> params = new LinkedHashMap<String, String>();
    	private String baseUrl;
    	private String targetUrl;
    	
    	public GetRequestBuilder withBaseUrl(String baseUrl) {
    		this.baseUrl = baseUrl;
    		return this;
    	}
    
    	public GetRequestBuilder withTargetUrl(String targetUrl) {
    		this.targetUrl = targetUrl;
    		return this;
    	}
    	
    	public GetRequestBuilder havingParameterWithValue(String name, String value) {
    		if(value != null){
    			params.put(name, value);
    		}
    		return this;
    	}
    
    	public String toEncodedUrl() {
    		StringBuilder url = new StringBuilder();
    		if(baseUrl != null) {
    			url.append(baseUrl);
    		}
    		if(targetUrl != null) {
    			url.append(targetUrl);
    		}
    		if(!params.entrySet().isEmpty()) {
    			url.append(QUESTIONMARK);
    		}
    		int size = params.size();
    		int count = 0;
    		for (Map.Entry<String, String> requestParameter : params.entrySet()) {
    			url.append(requestParameter.getKey());
    			url.append(EQUAL_TO);
    			url.append(requestParameter.getValue());
    			if (count < size - 1) {
    				url.append(PARAMETER_DELIMITER);
    				count++;
    			}
    		}
    		
    		return URL.encode(url.toString());
    	}
    }
    
    
    
Finally, here is the client code in action using the above abstractions:
Button csvExport = new Button();
AbstractImagePrototype csvIcon = IconHelper.createStyle("csv");
csvExport.setIcon(csvIcon);
csvExport.setToolTip("Download CSV");
final DownloadCsvAction downloadCsvAction = new DownloadCsvAction();
String encodedUrl = 
	new GetRequestBuilder()
		.withBaseUrl(GWT.getModuleBaseURL())
		.withTargetUrl("exporter")
		.havingParameterWithValue("exportAs", "csv")
		.havingParameterWithValue("serviceName", "searchResultsExporterService")
		.havingParameterWithValue("paramOne", "someValue")
		.havingParameterWithValue("paramTwo", "someOtherValue")
		.toEncodedUrl();

downloadCsvAction.setEncodedUrl(encodedUrl));
csvExport.addSelectionListener(new SelectionListener<ButtonEvent>() {
	public void componentSelected(ButtonEvent ce) {
		downloadCsvAction.execute();
	}
});
B. The Server-Side Plumbing:
  1. ExporterServlet is the front-ending servlet for all export requests from Web. Look at web.xml for the settings/wiring of this servlet.
    	<servlet>
    		<servlet-name>exporter</servlet-name>
    		<servlet-class>com.company.product.web.servlets.ExporterServlet</servlet-class>
    		<load-on-startup>2</load-on-startup>
    	</servlet>
    	
    	<servlet-mapping>
    		<servlet-name>exporter</servlet-name>
    		<url-pattern>/application/exporter</url-pattern>
    	</servlet-mapping>
    

    ExporterServlet converts the reserved parameters for you already. In the service() method, you will want to add in section of code to forward the request to a particular exporter service that is represented by the serviceName parameter in the request.

    public class ExporterServlet extends HttpServlet {
    
    	private ApplicationContext spring;
    	private SearchResultsExporterService searchResultsExporterService;
    
    	public void init(ServletConfig servletConfig) throws ServletException {
    		spring = WebApplicationContextUtils.getWebApplicationContext(servletConfig.getServletContext());
    		searchResultsExporterService = (SearchResultsExporterService) spring.getBean("searchResultsExporterService");
    	}
    
    	protected void service(HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws ServletException, IOException {
    		String serviceName = httpRequest.getParameter("serviceName");
    		String exportAs = httpRequest.getParameter("exportAs").toUpperCase();
    		ExportAs format = ExportAs.valueOf(exportAs);
    
    		if("searchResultsExporterService".equals(serviceName)) {
    			exportSearchResults(httpRequest, httpResponse, format);
    			return;
    		}
    		httpResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
    	}
    
    	private void exportSearchResults(HttpServletRequest httpRequest, HttpServletResponse httpResponse, ExportAs format) throws IOException {
    		SearchCriteria criteria = new SearchCriteria();
    		criteria.setParamOne(httpRequest.getParameter("paramOne"));
    		criteria.setParamTwo(httpRequest.getParameter("paramTwo"));
    		searchResultsExporterService.export(httpResponse, format, criteria);
    	}
    }
    
    Here is the ExportAs enumeration.
    public enum ExportAs {
    	CSV, EXCEL
    }
    
  2. ExporterServlet already has Spring application context, all you have to do is spring.getBean(serviceName) to get handle to your spring configured service. For example, look at SearchResultsExporterService and DefaultSearchResultsExporterService as reference implementation. Here, SearchResultsExporterService is a facade over SearchResultsService with additional responsibility of exporting search results. In short, the exporter service will use delegation to appropriate type of Exporter (CsvExporter, ExcelExporter) as the case may be. For additional parameters that your service method needs, you will have to reconstruct the objects on the server-side by hand if your service requires it (as this is case based, you do this by hand)...take a look at the SearchCriteria construction.
    public interface SearchResultsExporterService {
    
    	void export(HttpServletResponse httpResponse, ExportAs format, SearchCriteria criteria) throws IOException;
    
    }
    
    
    public class DefaultSearchResultsExporterService implements SearchResultsExporterService {
    
    	private static final String CONTENT_DISPOSITION = "Content-Disposition";
    	private static final String ATTACHMENT_FILENAME = "attachment; filename=";
    	private static final String filename = "SearchResults";
    	private final SearchResultsService searchResultsService;
    	
    	public DefaultSearchResultsExporterService(SearchResultsService searchResultsService) {
    		this.searchResultsService = searchResultsService;
    	}
    
    	public void export(HttpServletResponse httpResponse, ExportAs format, SearchCriteria criteria) throws IOException {
    		setContentType(httpResponse, exporter);
    		setContentDisposition(httpResponse, exporter, filename);
    		exporter = getExporter(format);
    
    		OutputStream outputStream = httpResponse.getOutputStream();
    		exporter.exportHeader(outputStream, getHeader());
    		try {
    			//Invoke the actual service and loop through the results
    			for (Result result : searchResultsservice.getResults()) {
    				exporter.exportRow(outputStream, resultAsRow(result));
    			}
    		} finally {
    			exporter.flush(outputStream);
    		}
    	}
    
    	private Exporter getExporter(ExportAs exportAs) {
    		switch (exportAs){
    			case CSV: 
    				exporter = new CsvExporter();
    				break;
    			case EXCEL:
    				exporter = new ExcelExporter();
    				break;
    			default:
    				exporter = new CsvExporter();
    		}
    	}
    
    	private void setContentType(HttpServletResponse httpResponse, Exporter exporter) {
    		httpResponse.setContentType(exporter.contentType());
    	}
    
    	private void setContentDisposition(HttpServletResponse httpResponse, Exporter exporter, String filename) {
    		httpResponse.setHeader(CONTENT_DISPOSITION, ATTACHMENT_FILENAME + filename + exporter.fileExtension());
    	}
    	
    	private void setCharacterSet(HttpServletResponse httpResponse) {
    		httpResponse.setCharacterEncoding("UTF-16");		
    	}
    	
    }
    
  3. Finally here is the exporter interface and a reference CSVExporter Reference implementation.
    public interface Exporter {
    	
    	String contentType();
    
    	String fileExtension();
    
    	void exportHeader(OutputStream outputStream, List<String> header) throws IOException;
    	
    	void exportRow(OutputStream outputStream, List<String> row) throws IOException;
    	
    	void flush(OutputStream outputStream) throws IOException;
    	
    }
    
    public class CsvExporter implements Exporter {
    
    	private static final String COMMA = ",";
    	private static final String NEWLINE = System.getProperty("line.separator");
    	private static final String QUOTE = "\"";
    	private String charset = "utf-8";
    
    	public CsvExporter() {
    	}
    	
    	public void setCharset(String charset) {
    		this.charset = charset;
    	}
    
    	public String fileExtension() {
    		return ".csv";
    	}
    	
    	public String contentType() {
    		return "text/csv";
    	}
    
    	public void exportHeader(OutputStream outputStream, List<String> header) throws IOException {
    		writeRow(outputStream, header);
    	}
    
    	public void exportRow(OutputStream outputStream, List<String> row) throws IOException {
    		writeRow(outputStream, row);
    	}
    	
    	private void writeRow(OutputStream outputStream, List<String> row) throws IOException {
    		int columns = row.size();
    		for(int index = 0; index < columns; index++) {
    			String data = row.get(index);
    			if(data.contains(COMMA)) {
    				write(outputStream, escape(data));
    			} else {
    				write(outputStream, data);
    			}
    			if (index < columns - 1) {
    				write(outputStream, COMMA);
    			} else {
    				write(outputStream, NEWLINE);
    			}
    		}
    	}
    
    	private void write(OutputStream outputStream, String data) throws IOException {
    		outputStream.write(data.getBytes(Charset.forName(charset)));
    	}
    
    	private String escape(String data) {
    		return QUOTE + data + QUOTE;
    	}
    
    	public void flush(OutputStream outputStream) throws IOException {
    	}
    }
    

So that completes the entire design description. Now, what can impact this design?

  1. Large number of parameters that GET cannot handle, at that point in time, we need to change the HiddenIFrame implementation to do a POST via a form...right now, my project does not need it and I am following YAGNI approach (You Ain't Gonna Need It) taking a minimalist approach.
  2. Need to take care of Session Timeout.
  3. Right now as it stands, the its fixed url (and open - no authentication required), unauthorized users will be able to download.
First point is a scalability thing, whereas the last two points would be applicable in general to any servlet.

Also, if you have a better and efficient approach, please share that with me, cheers!

If you feel this article has helped you, leave a comment below and if others can benefit from this article, share it:

Comments [8]

Session Handling in GWT

On my current GWT project, I needed to re-direct the user to the Login Dialog box upon session timeout on the server. In traditional web applications, it can be done either by taking a Filter-based approach or a inheriting from a common Controller Servlet; with GWT, it gets a little different...especially on the client-side...and depending on the frameworks that you use, you may need to do some additional work other than the server-side. On my project, I chose the Spring, Hibernate, Gilead and GWT-SL as a stack of technologies that will allow me to use the DDD approach so that I do not have to code a DTO layer, refer to my earlier post for tech frameworks stack.

First of all, some context on GWT method exceptions. In GWT, call to an asynchronous method throws an exception or it returns the Object that you want to do something with on the client-side. So, the strategy that I adopted for session handling is to throw an Exception upon Session-Timeout and let each response handler in the application deal with that exception. But this means that each response handler has to deal with Session-Timeout related exception....this calls for creating a generic mechanism for handling session timeout for all reponse handlers within the application. Hence, I came up with ApplicationResponseHandler, from which all the other response handlers will derive from. ApplicationResponse handler will take care of client-side handling of session timeout and/or other generic stuff. In the code below, when I receive message keys pertaining to session timeout, or not-logged-in or logout error, I dispatch a Logout event using the GWT's event Dispatcher. But, if the message keys are not the ones that ApplicationResponseHandler is not interested in handling, it calls the uponFailure(), and so with uponSuccess().

public abstract class ApplicationResponseHandler<T> implements AsyncCallback<T> {

	public ApplicationResponseHandler() {
	}
	
	public final void onFailure(Throwable caught) {
		String messageKey = caught.getMessage();
		if (
			(GatewayMessageKeys.SESSION_TIMEOUT.equals(messageKey)) ||
			(GatewayMessageKeys.NOT_LOGGED_IN.equals(messageKey)) ||
			(GatewayMessageKeys.LOGOUT_ERROR.equals(messageKey))) {
			dispatchLogoutEvent();
			return;
		}
		uponFailure(caught);
	}

	protected void dispatchLogoutEvent() {
		Dispatcher.get().dispatch(GatewayEvents.Logout);
	}
	
	public final void onSuccess(T result) {
		uponSuccess(result);
	};
	
	public abstract void uponSuccess(T result);
	public abstract void uponFailure(Throwable problem);
}

Here are the GatewayMessage keys, packed in GatewayMessageKeys interface

public final class GatewayMessageKeys {
	private GatewayMessageKeys() {
	}
	public static final String INCORRECT_CREDENTIALS = "incorrectCredentials"; 
	public static final String ACCOUNT_DOES_NOT_EXIST = "accountDoesNotExist";
	public static final String SERVICE_UNAVAILABLE = "serviceUnavailable";
	
	public static final String NOT_LOGGED_IN = "notLoggedIn";
	public static final String LOGOUT_SUCCESSFUL = "logoutSuccessful";
	public static final String LOGOUT_ERROR = "logoutError";
	public static final String SESSION_TIMEOUT = "sessionTimeout";
}

Having taken care of the client-side plumbing, lets move on to the server-side. Further, the GWT's RPC encoding and processing logic examines interfaces for declared exceptions and if your method encounters an exception that is NOT declared in the throws clause of the RPC interface, then GWT throws an UnexpectedException instead to the client and you will see..."Call failed on server...See server log for details". This implies that GWT demands that server-side RPC method needs to throw a Checked Exception. So, I came up with this class called ApplicationException, from which all our other Exception subclasses will inherit from.

/**
 * Please do not add Throwable cause constructors, because we do 
 * not want to reveal the stack trace to the client...obvious security 
 * risk! In your exception class, if you still need to provide a 
 * throwable cause constructor (due to some third party library 
 * dependency or due to any other reason), then make a call to 
 * super(message) constructor of this class.
 */
public class ApplicationException extends Exception {

	public ApplicationException() {
		super();
	}

	public ApplicationException(String message) {
		super(message);
	}
}

Below is the GatewayService that is called when the user logs-in to and logs-out of the application.

@RemoteServiceRelativePath("services/gatewayService")
public interface GatewayService extends RemoteService {
	User login(String userName, String password) throws LoginFailure;
	public String logout(String uid) throws LogoutFailure;
}
In the DefaultGatewayService implementation, as I am using the GWT-SL, it helps me export regular Spring-configured services as GWT-RPC services, the only problem is that these services are not HttpServletRequest/Response aware. Hence, I make them HttpServletRequest/Response aware by injecting HttpContext when the service is created by Spring. Apart from that, I inject the authenticator used by the login() method to authenticate the user.
public class DefaultGatewayService implements GatewayService {
	
	public static final String TICKET = "__APPLICATION_TICKET__";
	private final Authenticator authenticator;
	private final HttpContext httpContext;

	public DefaultGatewayService(Authenticator authenticator, HttpContext httpContext) {
		this.authenticator = authenticator;
		this.httpContext = httpContext;
	}
	
	@Transactional(readOnly = true)
	public User login(String uid, String password) throws LoginFailure {
		HttpSession session = getHttpServletRequest().getSession(false);
		if(exists(session)) {
			session.invalidate();
		}
		User user = authenticator.authenticate(uid, password);
		createNewSession(user);
		return user;
	}

	private void createNewSession(User user) {
		HttpSession session = getHttpServletRequest().getSession();
		session.setAttribute(USER, user.getUid());
	}
	
	public String logout(String uid) throws LogoutFailure {
		if (doesNotExists(uid)) {
			throw new LogoutFailure(GatewayMessageKeys.NOT_LOGGED_IN);
		}
		
		HttpServletRequest httpServletRequest = getHttpServletRequest();
		HttpSession session = httpServletRequest.getSession(false);
		String userIdInSession = (String) session.getAttribute(USER);
		if(uid.equals(userIdInSession)) {
			session.setAttribute(USER, null);
			logger.info(GatewayMessageKeys.LOGOUT_SUCCESSFUL + " For User: " + uid);
		} else {
			logger.error("User " + uid + "Not in HttpSession");
		}
		session.invalidate();
		return GatewayMessageKeys.LOGOUT_SUCCESSFUL;
	}

	private String getApplicationTicketFromCookie() {
		HttpServletRequest httpRequest = getHttpServletRequest();
		Cookie[] cookies = httpRequest.getCookies();
		for (Cookie cookie : cookies) {
			if(TICKET.equals(cookie.getName())) {
				return cookie.getValue();
			}
		}
		return null;
	}
	
	private boolean doesNotExists(String uid) {
		return uid == null || uid == "";
	}

	protected HttpServletRequest getHttpServletRequest() {
		return httpContext.getHttpServletRequest();
	}
}

Here is the HttpContext, that uses a simple ThreadLocal based implementation.

public interface HttpContext {
	
	public void setHttpServletRequest(HttpServletRequest request);
	
	public HttpServletRequest getHttpServletRequest();
	
	public void setHttpServletResponse(HttpServletResponse response);
	
	public HttpServletResponse getHttpServletResponse();

}

// Implementation
public class ApplicationHttpContext implements HttpContext {
	
	private static ThreadLocal<HttpServletRequest> requestThreadLocal = new ThreadLocal<HttpServletRequest>();
	
	private static ThreadLocal<HttpServletResponse> responseThreadLocal = new ThreadLocal<HttpServletResponse>();

	@Override
	public HttpServletRequest getHttpServletRequest() {
		return requestThreadLocal.get();
	}

	@Override
	public HttpServletResponse getHttpServletResponse() {
		return responseThreadLocal.get();
	}

	@Override
	public void setHttpServletRequest(HttpServletRequest request) {
		requestThreadLocal.set(request);
	}

	@Override
	public void setHttpServletResponse(HttpServletResponse response) {
		responseThreadLocal.set(response);
	}
}

The next most interesting thing, is the ApplicationGWTRPCServiceExporter which would be used by all the Spring managed services to wrap themselves in. It is in this interceptor where session timeout validation is performed for all calls made to any of the services within the system. Here are the steps that happen in the invokeMethodOnService() method:

  • Inject HttpContext
  • Check whether a session exists or not:
    • If the session does not exist:
      • If the incoming service all is that of login() method, then allow the user to login and return.
      • Else use reflection to examine the interface method called and use the declared exception of that method to throw it to the caller with message GatewayMessageKeys.SESSION_TIMEOUT.
    • If session exists: Determine whether user is present in the session:
      • If user is in session, allow the service call
      • If user is not in session, wrap in target method exception and throw it and thus don't allow the service call

public class ApplicationGWTRPCServiceExporter extends HB4GWTRPCServiceExporter {
	
	private final HttpContext httpContext;
	private static final String LOGIN_METHOD = "login";
	
	public ApplicationGWTRPCServiceExporter(HttpContext httpContext, UserRepository userRepository) {
		this.httpContext = httpContext;
	}

	@Override
	public String invokeMethodOnService(Object service, Method targetMethod, Object[] targetParameters, RPCRequest rpcRequest) throws Exception {
		HttpServletRequest request = getHttpRequest();
		HttpServletResponse response = getHttpResponse();
		
		injectHttpContext(request, response);
		HttpSession session = request.getSession(false);
		if (doesNotExist(session)) {
			if (targetMethod.getName().equals(LOGIN_METHOD)) {
				return super.invokeMethodOnService(service, targetMethod, targetParameters, rpcRequest);
			}
			logger.info("HttpSession Timedout");
			InvocationTargetException invocationException = wrapInTargetMethodException(targetMethod, GatewayMessageKeys.SESSION_TIMEOUT);
			return handleInvocationTargetException(invocationException, service, targetMethod, rpcRequest);
		}
		if (userNotInSession(session)) {
			logger.info("User not in existing HttpSession..invalidating session");
			session.invalidate();
			InvocationTargetException invocationException = wrapInTargetMethodException(targetMethod, GatewayMessageKeys.NOT_LOGGED_IN);
			return handleInvocationTargetException(invocationException, service, targetMethod, rpcRequest);
		}
		logger.debug("User in existing HttpSession...allowing service call");
		return super.invokeMethodOnService(service, targetMethod, targetParameters, rpcRequest);
	}

	private void injectHttpContext(HttpServletRequest request, HttpServletResponse response) {
		httpContext.setHttpServletRequest(request);
		httpContext.setHttpServletResponse(response);
	}

	private InvocationTargetException wrapInTargetMethodException(Method targetMethod, String messageKey) throws Exception {
		Class[] exceptionTypes = targetMethod.getExceptionTypes();
		if(exceptionTypes.length > 0) {
			Constructor constructor = exceptionTypes[0].getConstructor(String.class);
			Exception newExceptionInstance = (Exception) constructor.newInstance(messageKey);
			return new InvocationTargetException(newExceptionInstance);
		}
		return new InvocationTargetException(new ApplicationException("Make sure your Service Method throws subclass of ApplicationException!!"));
	}

	protected HttpServletRequest getHttpRequest() {
		return getThreadLocalRequest();
	}
	
	protected HttpServletResponse getHttpResponse() {
		return getThreadLocalResponse();
	}
}

If you feel this article has helped you, leave a comment below and if others can benefit from this article, share it:

Comments [9]

A Note on Technology frameworks stack used with GWT

I am presently working on this GWT-GXT application (not a huge one, but relatively small) and have successfully applied the following technology frameworks
  • For architectural plumbing:
    1. Spring
    2. Hibernate
    3. Gilead (Avoid DTOs and allows DDD to be applied. Ship out the Domain Objects that are persisted using Hibernate without problems), http://noon.gilead.free.fr
    4. GWT-SL (GWT Server Library, for necessary plumbing to export a service from Spring as a GWT-RPC Service Exporter, so now my services need not be extending GWT's RemoteServiceServlet and are thus independent of GWT), http://gwt-widget.sourceforge.net
  • For BDDing (Unit and Integration tests):
    1. JUnit
    2. Mockito
  • For Build and Database Schema Mgt:
    1. Ant for builds/deployment
    2. DBDeploy for database schema management
  • For Static Analysis:
    1. Panopticode (it includes Cobertura, JDepend, JavaNCSS, CheckStyle etc...)

If you feel this article has helped you, leave a comment below and if others can benefit from this article, share it:

Comments [0]

Visualize metrics with Panopticode

I can't stop appreciating Neal Ford's book The Productive Programmer, full of good tips, one of which is "Generate Metrics with Panopticode". I finished integrating Panopticode (http://www.panopticode.org) on my current Java Project to visualize metrics. Panopticode uses Tree Maps to display the code complexity and coverage. On my earlier projects, I have used several tools, and all generated different types of metrics, which I would have to then collate and make sense out of it, especially to strategize and prioritize parts of code that need Refactoring.

With Panopticode, my collation and analysis task simply vanishes, instead now I can look at the Interactive Tree Map and the parts in RED refer to highly complex method. Click on the RED square and all the metrics, CC, NCSS etc... for a method appear on the side. Here is the Code Complexity Tree Map of my project.


Panopticode makes this novel use of Tree Maps for metrics visualization. To know more about Tree Maps, read this article by Ben Shneiderman. I also am not going to go into the details of how Panopticode works, but talking about it in a nutshell, it basically uses other tools like Checkstyle, JDepend, JavaNCSS, Cobertura/Emma, Simian etc... and aggregates data from these tools. The aggregated data is then rendered as Tree Maps. It produces two Tree Maps, one for Code Complexity and another for Code Coverage.

I have found another interesting use of Tree Map from my colleague and friend Anurag and they basically use the Tree Maps to radiate the current state of architecture of various components across the entire project. I don't know how they obtain the metrics, but the use of Tree Maps is noteworthy.

Component Scalability Maintainability Security Availability Performance Extensibility Reliability Manageability Usability
Component 1
Component 2
Component 3
Component 4
If you are a products company, you can extend this to your product suites as well...

If you have made use of Tree Maps on your project and would like to share, please use the comments below....or send to me the link and i'll embed it in this blog post. Also, I don't know whether such a tool exists for the .NET world. If you happen to know, drop in a line ;-)

If you feel this article has helped you, leave a comment below and if others can benefit from this article, share it:

Comments [3]

Using GWT I18N

On my current GWT-GXT project, I wanted to enable the application for multiple locales. GWT offers many ways to internationalize your application. To give you an architectural context, services are front-ending client requests and when exceptional situations arise, these services throw exceptions containing Message Key and not messages, along with message parameters as additional information. Using message keys indirection it allows us to translate that message key in to locale-specific message, a standard technique.

It is the responsibility of the page renderer to then pick up the correct locale-specific resource bundle and render the locale-specific message based on the message keys present in the locale-specific properties file. With GWT, this gets very interesting. The way GWT folks have thought about this is really cool. They offer various internationalization techniques Static string internationalization, Dynamic string internationalization and Extending or implementing Localizable. For us, Static String internationalization suited the best.

GWT provides a Messages interface that one needs to extend for their use. So, say for example, I have a GatewayService that throws following message keys wrapped in its custom exception

public final class GatewayMessageKeys {
	private GatewayMessageKeys() {
	}
	public static final String INCORRECT_CREDENTIALS = "incorrectCredentials"; 
	public static final String ACCOUNT_DOES_NOT_EXIST = "accountDoesNotExist";
	public static final String SERVICE_UNAVAILABLE = "serviceUnavailable";
	
	public static final String NOT_LOGGED_IN = "notLoggedIn";
	public static final String LOGOUT_SUCCESSFUL = "logoutSuccessful";
	public static final String LOGOUT_ERROR = "logoutError";
	public static final String SESSION_TIMEOUT = "sessionTimeout";
}
For these message keys, i'll extend GWT provided Messages interface as...
import com.google.gwt.i18n.client.Messages;

public interface GatewayMessages extends Messages {
	String incorrectCredentials();
	String accountDoesNotExist();
	String serviceNotAvailable();
	
	String notLoggedIn();
	String sessionTimeout();
	String logoutSuccessful();
	String logoutError();
}

Once I look at this interface...the aha moment dawns on me! The concept is so clear....any message-key that you throw from services, manifests as method in the GatewayMessages interface. The beauty is that this method always returns a String based message and takes in any type parameters that you would want to substitute in the final localized message. So, the rendering of a localized message happens using a function-based approach and bunch of these functions are grouped together in an interface...so cohesively packed!

To me this is an innovative concept for implementing localization. GWT calls these methods as Message Accessors. These methods have bindings to properties files for localized messages. At runtime, GWT automatically provides an instance of an generated subclass that is implemented using values from a property file selected based on locale...I'm impressed! So to start with, we need make the Application.gwt.xml inherit the internationalization module.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 1.7.0//EN" "http://google-web-toolkit.googlecode.com/svn/tags/1.7.0/distro-source/core/src/gwt-module.dtd">
<module rename-to='applicationName'>
  <!-- Inherit the core Web Toolkit stuff.                        -->
  <inherits name='com.google.gwt.user.User'/>
 
  <!-- Inherit the GXT stuff.                                     -->
  <inherits name='com.extjs.gxt.ui.GXT'/>
 
  <!-- Inherit Internationalization module -->
  <inherits name="com.google.gwt.i18n.I18N"/>
    
  <!-- English language, independent of country -->
  <extend-property name="locale" values="en"/>
  
  <!-- Specify the app entry point class.                         -->
  <entry-point class='com.company.product.client.Application'/>
</module>

Having done that, you will want to put this to use and the place where it would generally end-up is in the response handler's onFailure() method. Below is one such sample call.

AsyncCallback<User> loginActionResponseHandler = new AsyncCallback<User>() {
	public void onFailure(Throwable caught) {
		String messageKey = caught.getMessage();
		String message = null;
		if(GatewayMessageKeys.INCORRECT_CREDENTIALS.equals(messageKey)) {
			gatewayMessages = (GatewayMessages) GWT.create(GatewayMessages.class);
			message = gatewayMessages.incorrectCredentials();
		}
		show(message);
	}

	public void onSuccess(User authenticated) {
		// do something
	}
};
Now, the GatewayMessages interface, has several methods and based on the type of the return Key and I already can see bunch of ugly if-branches when it comes to selecting the correct method to call based on the incoming message key. This job of translating message key to message demands a role of its own....As I BDD, the design this role of a MessageKeyTranslator comes into being...below are the behavior specifications
@RunWith(MockitoJUnit44Runner.class)
public class GatewayMessageKeyTranslatorSpecs {
	
	@Mock
	private GatewayMessages mockGatewayMessages;
	private GatewayMessageKeyTranslator messageKeyTranslator;
	
	@Before
	public void givenThatIHave() {
		messageKeyTranslator = new GatewayMessageKeyTranslator(mockGatewayMessages);
	}

	@Test
	public void itTranslatesIncorrectCredentialsKey() {
		String messageToReturn = "[Incorrect Credentials]";
		when(mockGatewayMessages.incorrectCredentials()).thenReturn(messageToReturn);
		
		assertThat(messageKeyTranslator.translate(GatewayMessageKeys.INCORRECT_CREDENTIALS), is(messageToReturn));
		verify(mockGatewayMessages).incorrectCredentials();
	}
	
	@Test
	public void itTranslatesAccountDoesNotExistKey() {
		String messageToReturn = "[Account Does Not Exist]";
		when(mockGatewayMessages.accountDoesNotExist()).thenReturn(messageToReturn);
		
		assertThat(messageKeyTranslator.translate(GatewayMessageKeys.ACCOUNT_DOES_NOT_EXIST), is(messageToReturn));
		verify(mockGatewayMessages).accountDoesNotExist();
	}

	@Test
	public void itTranslatesServiceUnavailableKey() {
		String messageToReturn = "[Service Not Available]";
		when(mockGatewayMessages.serviceNotAvailable()).thenReturn(messageToReturn);
		
		assertThat(messageKeyTranslator.translate(GatewayMessageKeys.SERVICE_UNAVAILABLE), is(messageToReturn));
		verify(mockGatewayMessages).serviceNotAvailable();
	}
	
	@Test
	public void itTranslatesNotLoggedInKey() {
		String messageToReturn = "[Not Logged In]";
		when(mockGatewayMessages.notLoggedIn()).thenReturn(messageToReturn);
		
		assertThat(messageKeyTranslator.translate(GatewayMessageKeys.NOT_LOGGED_IN), is(messageToReturn));
		verify(mockGatewayMessages).notLoggedIn();
	}

	@Test
	public void itTranslatesSessionTimeoutKey() {
		String messageToReturn = "[Session Timeout]";
		when(mockGatewayMessages.sessionTimeout()).thenReturn(messageToReturn);
		
		assertThat(messageKeyTranslator.translate(GatewayMessageKeys.SESSION_TIMEOUT), is(messageToReturn));
		verify(mockGatewayMessages).sessionTimeout();
	}

	@Test
	public void itTranslatesLogoutSuccessfulKey() {
		String messageToReturn = "[Logout Successful]";
		when(mockGatewayMessages.logoutSuccessful()).thenReturn(messageToReturn);
		
		assertThat(messageKeyTranslator.translate(GatewayMessageKeys.LOGOUT_SUCCESSFUL), is(messageToReturn));
		verify(mockGatewayMessages).logoutSuccessful();
	}
	
	@Test
	public void itTranslatesLogoutErrorKey() {
		String messageToReturn = "[Logout Error]";
		when(mockGatewayMessages.logoutError()).thenReturn(messageToReturn);
		
		assertThat(messageKeyTranslator.translate(GatewayMessageKeys.LOGOUT_ERROR), is(messageToReturn));
		verify(mockGatewayMessages).logoutError();
	}

	@Test
	public void itTranslatesEmptyKey() {
		String messageToReturn = "";
				
		assertThat(messageKeyTranslator.translate(""), is(messageToReturn));
		verify(mockGatewayMessages, never()).incorrectCredentials();
		verify(mockGatewayMessages, never()).accountDoesNotExist();
		verify(mockGatewayMessages, never()).serviceNotAvailable();
		verify(mockGatewayMessages, never()).notLoggedIn();
		verify(mockGatewayMessages, never()).sessionTimeout();
		verify(mockGatewayMessages, never()).logoutError();
		verify(mockGatewayMessages, never()).logoutSuccessful();		
	}

	@Test
	public void itTranslatesNullKey() {
		String messageToReturn = "";
				
		assertThat(messageKeyTranslator.translate(null), is(messageToReturn));
		verify(mockGatewayMessages, never()).incorrectCredentials();
		verify(mockGatewayMessages, never()).accountDoesNotExist();
		verify(mockGatewayMessages, never()).serviceNotAvailable();
		verify(mockGatewayMessages, never()).notLoggedIn();
		verify(mockGatewayMessages, never()).sessionTimeout();
		verify(mockGatewayMessages, never()).logoutError();
		verify(mockGatewayMessages, never()).logoutSuccessful();
	}

}
Here is the GatewayMessageKeyTranslator that got flushed out from the above specs.
public class GatewayMessageKeyTranslator implements MessageKeyTranslator {
	private GatewayMessages gatewayMessages;
	
	public GatewayMessageKeyTranslator() {
		gatewayMessages = (GatewayMessages) GWT.create(GatewayMessages.class);
	}

	public GatewayMessageKeyTranslator(GatewayMessages gatewayMessages) {
		this.gatewayMessages = gatewayMessages;
	}

	public String translate(String messageKey, Object... args) {
		if (GatewayMessageKeys.INCORRECT_CREDENTIALS.equals(messageKey)){
			return gatewayMessages.incorrectCredentials();
		}
		else if (GatewayMessageKeys.ACCOUNT_DOES_NOT_EXIST.equals(messageKey)){
			return gatewayMessages.accountDoesNotExist();
		}
		else if (GatewayMessageKeys.SERVICE_UNAVAILABLE.equals(messageKey)){
			return gatewayMessages.serviceNotAvailable();
		}
		else if (GatewayMessageKeys.NOT_LOGGED_IN.equals(messageKey)){
			return gatewayMessages.notLoggedIn();
		}
		else if (GatewayMessageKeys.SESSION_TIMEOUT.equals(messageKey)){
			return gatewayMessages.sessionTimeout();
		}
		else if (GatewayMessageKeys.LOGOUT_SUCCESSFUL.equals(messageKey)){
			return gatewayMessages.logoutSuccessful();
		}
		else if (GatewayMessageKeys.LOGOUT_ERROR.equals(messageKey)){
			return gatewayMessages.logoutError();
		}
		else {
			return "";
		}
	}
}

The implementation is really ugly with so-many if branches...but my point here is to get the role with responsibility of message key translation flushed out first...basically get it working and then make it clean!

Further...there are many services in the system and a similar approach is required at other places...so, I need to come up with an abstraction using which all the translators in the system can work with...so I extract MessageKeyTranslator interface . Such an interface can reside in a package of its own, and doing so will result in a package with Abstractness value to 1, Instability value close to 0...which is good.

public interface MessageKeyTranslator {
	public String translate(String messageKey, Object ...args);
}

So, the client code, now becomes really clean...

AsyncCallback<User> loginActionResponseHandler = new AsyncCallback<User>() {
	public void onFailure(Throwable caught) {
		String messageKey = caught.getMessage();
		MessageKeyTranslator translator = new GatewayMessageKeyTranslator();
		String message = translator.translate(messageKey);
		show(message);
	}

	public void onSuccess(User authenticated) {
		// do something
	}
};

Now that we have got things right, lets tackle the cleaning bit...Though this is plain Java code, I cannot use Java Reflection to select the method based upon the incoming key, because, GWT java code compiles to JavaScript eventually and hence java reflection will not work. There are other open-source GWT Reflection Apis, but I have not tried'em. By using reflection, I can then come-up with a generic implementation DefaultMessageKeyTranslator which would then be closed for modification. I would have then avoided the concrete translators proliferation. If you have other ideas/comments/suggestions, do send them in....

If you feel this article has helped you, leave a comment below and if others can benefit from this article, share it:

Comments [2]