Wednesday, October 22, 2014

Neo4j Graph Database Backend for Spring Security Acl 2

Problem

Discussed in previous post

Design

The first challenge was Modelling a set of Tables with Relationships to a Graph. After studying the Tables and Their Relationships I came up with the following Design.

This design can be improved but I stuck with this because the intention was to increase performance not to win a Design competition. Furthermore this design covers the Domain of Spring Security ACL concisely so I stuck with this. Naming of the relationships could be improved but I like these.

In order to successfully provide a Neo4j back-end for Spring Security ACL we must implement three interfaces with Neo4j specific implementation.
  1. LookupStrategy - Used to Read Acls based on Class Name and Instance Id
  2. AclService - Non Mutable Acl related Services
  3. MutableAclService - Mutable Acl related Services

Implementation Decisions

I used Spring-Data-Neo4j project which is an abstraction layer on top of the Neo4j Graph Database which allows annotated classes to be represented as Nodes and Edges, which is convenient for Rapid Development. Furthermore it allows Repositories to do CRUD operations also but in this project I opted not to use them and instead used Neo4jTemplate because I knew I would need to write alot of Dynamic Cypher queries.

Development

The full source of the development is available at https://github.com/shazin/spring-security-acl-neo4j

Testing

The biggest question is "Will it be faster than RDBMS based implementations?". If not the whole project was a failure. Test coverage was done on both Mutable and Non Mutable Acl Services. Testing Non Mutable Acl Service will cover Lookup Strategy as it is used underneath. 

Neo4j In-memory Test Database was used to Test. This is a JVM based, Production Not Ready, Single Database instance. Assuming Production ready Neo4j Embedded or Neo4j Server Databases will increase performance (It ideally should) I decided to test using this. 

The RDBMS I used to Test against was H2, which is also a JVM based, but Production Ready In-memory Database. 

Both being in-memory implementations and being JVM based somewhat testifies that the underlying Storage hardware has no input in performance (SATA, SSD, doesn't matter) and no latency due to Network congestion.

And I was using the Ubuntu 14.04 LTS 64-bit Operating system with Intel Core i7 Processor, 4 Gb RAM and Sun JDK 8.

Test Data comprised of 200 ACL Entries (2 for each Object Identity), 3 Sids (Including logged in User Sid), 100 Classes and 100 Object Identities.

Testing was mainly focused on Retrieval and for to retrieve 50 non following Object Identities with ACL Entries (2 for each Object Identity) while running four random times with an Empty Cache, following were the results. 


The results are in Nanoseconds and Neo4j based Spring Security Acl implementation is a clear winner!

Conclusion

Neo4j clearly stands up for its claims and with this implementation Spring Security ACL could also reach its fullest potential. Can clearly say that this is one of the fastest backend implementations for Spring Security ACL. Even though the difference is in Nanoseconds, the performance will matter with higher volume of Users, Object Identities, Sids and ACL Entries. 

The code base could be improved, specially in Cypher queries thus increasing performance even more. Anyone who likes to contribute is welcome.

This doesn't mean that RDBMS are now obsolete. I personally think that RDBMS will be here for at least another 20 years if not more!

And constructive criticism is always welcome.

References
  1. http://neo4j.com/docs/stable/introduction.html - Cypher Language
  2. http://www.h2database.com/html/main.html - H2 Database


Neo4j Graph Database Backend for Spring Security Acl 1

As part of work here at Mimos, I have been working a lot with Spring Security. Some of my previous posts are testament for this. I even got the chance to work with Spring Security ACL which is a project which also comes under Spring Security eco-system and covers the "Authorization" part of Security. I feel Spring Security ACL project is seriously under-rated and one factor which stops it from reaching its fullest potential is in my opinion its Data store end. 

Predominantly design to work with a Relational Database, Spring Security ACL Team have done a great job to reduce the round trips to fetch data from Database by using Caching extensively which decreases data read time heavily.  Yet in a production system where ACL data also tend to change rapidly and with higher volume of users, ACLs and Objects to Protect, Bottleneck at Data end is inevitable. 

Furthermore Spring Security ACL Data is distributed in 4 tables named acl_sid, acl_class, acl_object_identity and acl_entry. So to query and retrieve ACL entries for a Principal or Role for a Particular class instance, Joining of these 4 tables is required. 

Also I got the exposure to do a Research and Development on Neo4j Graph Database which is a NoSQL, Schema-less, Graph Database which stores Data in the form of Property Nodes and Edges.

Neo4j is widely used in the Industry from Courier Route Decision Making to Finding a Date Match. Neo4j is said to be really good to represent Highly Connected Data because it stores all the Data in a Graph and said to be able to Model the real world as close as possible.

While reading through Neo4j Use Cases, I found that a Telecommunication company has used Neo4j for its Identity and Access Management system to improve performance. With Neo4j they have managed to reduce load time from Minutes to Milliseconds. 

This got me thinking and lit a light bulb over my head. What if I can write a Data backend for Spring Security ACL using Neo4j? Easier said than done. Neo4j being a Graph Database is a completely different paradigm with its own query language to named Cypher. 

References
  1. http://docs.spring.io/spring-security/site/docs/3.0.x/reference/domain-acls.html - Spring Security Acl
  2. http://neo4j.com/ - Neo4j
  3. http://neo4j.com/users/telenor/ - Telecom Use Case

Tuesday, September 30, 2014

Spring Security Filter Chain Registration Using WebApplicationInitializer for Servlet 3.x

Starting from Servlet 3.x Specification some code saving features have been introduced such as XML less annotation based Servlet and Filter registration. In conjunction with this Spring has introduced WebApplicationInitializer interface which allows the registration of Servlet and Filters using Java instead of using web.xml file.

This is neat feature because this will eliminate the need for the XML files required in the Spring MVC based web applications. Since most of the Spring Application Context configurations are also directing towards Java Config, Moving to would be ideal;

I read the documentation of the Spring WebApplicationInitializer and was able to register both DispatcherServlet and DelegatingFilterProxy in using it. So the following web.xml tags;

<context-param>
    <param-name>contextClass</param-name>
    <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
  </context-param>
  <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>com.lkbotics.visualizer.config.AppConfig</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <filter>
      <filter-name>springSecurityFilterChain</filter-name>
      <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
      <async-supported>true</async-supported>
  </filter>
  <filter-mapping>
      <filter-name>springSecurityFilterChain</filter-name>
      <url-pattern>/*</url-pattern>
  </filter-mapping>
  <filter>
      <filter-name>eTagFilter</filter-name>
      <filter-class>org.springframework.web.filter.ShallowEtagHeaderFilter</filter-class>
      <async-supported>true</async-supported>
  </filter>
  <filter-mapping>
      <filter-name>eTagFilter</filter-name>
      <url-pattern>/*</url-pattern>
  </filter-mapping>
  <servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextClass</param-name>
        <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </init-param>
    <init-param>
        <param-name>contextConfigLocation</param-name>
          <param-value>com.lkbotics.visualizer.web.config.MvcConfig</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    <async-supported>true</async-supported>
  </servlet>
  <servlet-mapping>
    <servlet-name>appServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

Can effectively be replaced by the following implementation of WebApplicationInitializer

import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.filter.ShallowEtagHeaderFilter;
import org.springframework.web.servlet.DispatcherServlet;

import com.lkbotics.visualizer.config.AppConfig;
import com.lkbotics.visualizer.web.config.MvcConfig;

public class CustomWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext container) throws ServletException {
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
        rootContext.register(AppConfig.class);
        
        container.addListener(new ContextLoaderListener(rootContext));
        
        AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
        dispatcherContext.register(MvcConfig.class);
        
        FilterRegistration.Dynamic springSecurityFilterChain = container.addFilter("springSecurityFilterChain", new DelegatingFilterProxy());
        springSecurityFilterChain.addMappingForUrlPatterns(null, false, "/*");
        springSecurityFilterChain.setAsyncSupported(true);
        
        FilterRegistration.Dynamic shallowETagFilter = container.addFilter("shallowETagFilter", new ShallowEtagHeaderFilter());
        shallowETagFilter.addMappingForUrlPatterns(null, true, "/*");
        shallowETagFilter.setAsyncSupported(true);
        
        ServletRegistration.Dynamic dispatcher = container.addServlet("servletDispatcher", new DispatcherServlet(dispatcherContext));
        dispatcher.setLoadOnStartup(1);
        dispatcher.setAsyncSupported(true);
        dispatcher.addMapping("/");        
    }

}

As usual Spring Security requirements apply, There must be FilterChainProxy bean registered with the name springSecurityFilterChain or custom bean name must be passed in while instantiating the DelegatingFilterProxy inside WebApplicationInitializer.

Caveats [1]

web.xml versioning

WEB-INF/web.xml and WebApplicationInitializer use are not mutually exclusive; for example, web.xml can register one servlet, and a WebApplicationInitializer can register another. An initializer can even modify registrations performed in web.xml through methods such as ServletContext#getServletRegistration(String). However, if WEB-INF/web.xml is present in the application, its version attribute must be set to "3.0" or greater, otherwise ServletContainerInitializer bootstrapping will be ignored by the servlet container.


References
  1. WebApplicationInitializer
  2. FilterRegistration.Dynamic

Wednesday, July 23, 2014

Spring Security Custom FilterChainProxy using Java Configuration

In a previous post I wrote how to custom configure FilterChainProxy using Java Bean XML configuration file. I got some feedback and of the things I was pointed out was that it could also be done using Java configuration instead of XML configuration. But at that time I couldn't do it because we were using XML configuration files for beans. But now as part of my work I needed to work with Spring using Java configuration. So I thought this is the right time to go back and write the whole custom FilterChainProxy configuration in Java configuration.

After some documentation reading, trial and error, stackoverflow I managed to get the following Java configuration to work as exactly as same as my previous post's XML configuration.


import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;

import javax.inject.Inject;
import javax.servlet.ServletException;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.intercept.RunAsManager;
import org.springframework.security.access.intercept.RunAsManagerImpl;
import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.access.vote.RoleVoter;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.authentication.dao.ReflectionSaltSource;
import org.springframework.security.authentication.dao.SaltSource;
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
import org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.expression.WebExpressionVoter;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.CookieClearingLogoutHandler;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.web.filter.RequestContextFilter;

import com.lkbotics.visualizer.util.CustomUsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Inject
    UserDetailsService userService;

    @Bean
    public AuthenticationManager authenticationManager() throws Exception {
        AuthenticationManager authenticationManager = new ProviderManager(
                Arrays.asList(authenticationProvider()));
        return authenticationManager;
    }

    @Bean
    public AuthenticationProvider authenticationProvider() throws Exception {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(userService);
        authenticationProvider.setSaltSource(saltSource());
        authenticationProvider.setPasswordEncoder(passwordEncoder());
        authenticationProvider.afterPropertiesSet();
        return authenticationProvider;
    }

    @Bean
    public SaltSource saltSource() throws Exception {
        ReflectionSaltSource saltSource = new ReflectionSaltSource();
        saltSource.setUserPropertyToUse("salt");
        saltSource.afterPropertiesSet();
        return saltSource;
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new Md5PasswordEncoder();
    }

    @Bean
    public FilterChainProxy springSecurityFilterChain()
            throws ServletException, Exception {
        List<SecurityFilterChain> securityFilterChains = new ArrayList<SecurityFilterChain>();
        securityFilterChains.add(new DefaultSecurityFilterChain(
                new AntPathRequestMatcher("/login**")));
        securityFilterChains.add(new DefaultSecurityFilterChain(
                new AntPathRequestMatcher("/resources/**")));
        securityFilterChains.add(new DefaultSecurityFilterChain(
                new AntPathRequestMatcher("/**"),
                securityContextPersistenceFilter(), 
                logoutFilter(),
                usernamePasswordAuthenticationFilter(),
                exceptionTranslationFilter(),
                filterSecurityInterceptor()));
        return new FilterChainProxy(securityFilterChains);
    }

    @Bean
    public SecurityContextPersistenceFilter securityContextPersistenceFilter() {
        return new SecurityContextPersistenceFilter(
                new HttpSessionSecurityContextRepository());
    }

    @Bean
    public ExceptionTranslationFilter exceptionTranslationFilter() {
        ExceptionTranslationFilter exceptionTranslationFilter = new ExceptionTranslationFilter(
                new LoginUrlAuthenticationEntryPoint("/login"));
        AccessDeniedHandlerImpl accessDeniedHandlerImpl = new AccessDeniedHandlerImpl();
        accessDeniedHandlerImpl.setErrorPage("/exception");
        exceptionTranslationFilter
                .setAccessDeniedHandler(accessDeniedHandlerImpl);
        exceptionTranslationFilter.afterPropertiesSet();
        return exceptionTranslationFilter;
    }

    @Bean
    public UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter()
            throws Exception {
        UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter = new UsernamePasswordAuthenticationFilter();
        usernamePasswordAuthenticationFilter
                .setAuthenticationManager(authenticationManager());
        usernamePasswordAuthenticationFilter.setAllowSessionCreation(true);
        SimpleUrlAuthenticationSuccessHandler successHandler = new SimpleUrlAuthenticationSuccessHandler(
                "/");
        successHandler.setAlwaysUseDefaultTargetUrl(true);
        usernamePasswordAuthenticationFilter
                .setAuthenticationSuccessHandler(successHandler);
        usernamePasswordAuthenticationFilter
                .setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler(
                        "/login?error=true"));
        usernamePasswordAuthenticationFilter.afterPropertiesSet();

        return usernamePasswordAuthenticationFilter;

    }

    @Bean
    public FilterSecurityInterceptor filterSecurityInterceptor()
            throws Exception {
        FilterSecurityInterceptor filterSecurityInterceptor = new FilterSecurityInterceptor();
        filterSecurityInterceptor
                .setAuthenticationManager(authenticationManager());
        filterSecurityInterceptor
                .setAccessDecisionManager(accessDecisionManager());
        filterSecurityInterceptor.setRunAsManager(runAsManager());
        LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>();
        List<ConfigAttribute> configs = new ArrayList<ConfigAttribute>();
        configs.add(new org.springframework.security.access.SecurityConfig(
                "isAuthenticated()"));
        requestMap.put(new AntPathRequestMatcher("/**"), configs);
        FilterInvocationSecurityMetadataSource filterInvocationSecurityMetadataSource = new ExpressionBasedFilterInvocationSecurityMetadataSource(
                requestMap, new DefaultWebSecurityExpressionHandler());
        filterSecurityInterceptor
                .setSecurityMetadataSource(filterInvocationSecurityMetadataSource);
        filterSecurityInterceptor.afterPropertiesSet();

        return filterSecurityInterceptor;
    }

    public AffirmativeBased accessDecisionManager() throws Exception {
        List<AccessDecisionVoter> voters = new ArrayList<AccessDecisionVoter>();
        voters.add(new WebExpressionVoter());
        voters.add(new RoleVoter());
        AffirmativeBased affirmativeBased = new AffirmativeBased(voters);
        affirmativeBased.setAllowIfAllAbstainDecisions(false);
        affirmativeBased.afterPropertiesSet();

        return affirmativeBased;
    }

    @Bean
    public RunAsManager runAsManager() throws Exception {
        RunAsManagerImpl runAsManager = new RunAsManagerImpl();
        runAsManager.setKey("V_RUN_AS");
        runAsManager.afterPropertiesSet();
        return runAsManager;
    }

    @Bean
    public LogoutFilter logoutFilter() throws ServletException {
        List<LogoutHandler> handlers = new ArrayList<LogoutHandler>();
        handlers.add(new CookieClearingLogoutHandler("JSESSIONID"));
        handlers.add(new SecurityContextLogoutHandler());
        LogoutFilter logoutFilter = new LogoutFilter("/login",
                handlers.toArray(new LogoutHandler[] {}));
        logoutFilter.afterPropertiesSet();
        return logoutFilter;
    }
    
    
}

Furthermore you will need the following configuration in web.xml to support the Java configuration.

<context-param>
    <param-name>contextClass</param-name>
    <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
  </context-param>
  <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value><PACKAGE>.SecurityConfig</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <filter>
      <filter-name>springSecurityFilterChain</filter-name>
      <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  </filter>
  <filter-mapping>
      <filter-name>springSecurityFilterChain</filter-name>
      <url-pattern>/*</url-pattern>
  </filter-mapping>
  <servlet>

The same rules applies where DelegatingFilterProxy in web.xml must be named springSecurityFilterChain because our custom FilterChainProxy in SecurityConfig is named springSecurityFilterChain.

Trackbacks/Pings

  1. Spring Blog - http://spring.io/blog/2014/07/29/this-week-in-spring-spring-xd-edition-july-29th-2014

Tuesday, June 24, 2014

Simple Redis Master/Slave Replication

Redis is an in memory key value store developed to be scale-able from ground up. Redis enables this through client side sharding as well as server side master/slave replication. In this post I am going to explain a Simple 1 Master 2 Slave Server Replication Setup for Redis in a Single Host. This can be easily moved to multiple Hosts if and when the need arises with very minor changes. For this you must have downloaded redis and compiled it. If you haven't done that please follow my previous post.
The setup I am going to create looks like the above figure, where there is a Redis master listening on port 6379 and 2 Redis slaves connecting to the Master and will be listening on ports 6380 and 6381 respectively.

You need to follow the below steps to create 2 different configuration files for the slaves. 
  1. Open a Shell Terminal
  2. Navigate to redis home directory
  3. Issue "cp redis.conf redis-slave1.conf"
  4. Issue "cp redis.conf redis-slave2.conf"
  5. Open the "redis-slave1.conf" file using a Text Editor and find the line which has the port configuration and change it so that it looks like the following;  
          port 6380

     6.  And then find the line which has the slaveof configuration and change it so that it looks like the following; 

          slaveof 127.0.0.1 6379

       7.   And then find dbfilename configuration and change to "slave1-dump.rdb" as following;

          dbfilename slave1-dump.rdb

      8.  Repeat the steps 5 - 7 with "redis-slave2.conf" but this time the port must be 6381, dbfilename becomes "slave2-dump.rdb" and slaveof configuration remains the same.
       9.  Now you can start the Master followed by the 2 Slave by issuing the following commands;          

          nohup ./src/redis-server ./redis.conf > master.log 2>&1&

          nohup ./src/redis-server ./redis-slave1.conf > slave1.log 2>&1&

          nohup ./src/redis-server ./redis-slave2.conf > slave2.log 2>&1&

     10.  Now you can issue a "./src/redis-cli" and can connect to the master or any slave by providing the "./src/redis-cli -p <Slave Port>"

The recommended setup is that All writes are done to Master and All reads are performed on Slaves.
As you can see you just need to change the "127.0.0.1" host ip in your Slaves' slaveof command if you want to move this replication setup to multiple hosts. 

Sunday, June 22, 2014

Getting Started with Redis on Ubuntu

Redis, an in-memory key value data store. It comes under the category of NoSQL or Non Relational Database where storing, manipulating and retrieving of data in Redis doesn't require and use any SQL or Relations (Tables).

Relational Databases look at solving real world domain representation inside computers using a Relation/Table. A Relation/Table is a Set where the following properties are guaranteed.
  1. Every Cell contains one atomic value.
  2. Every Row is uniquely identifiable.
  3. Order of the columns has no significance.
  4. Order of the rows has no significance.
Furthermore relational databases allow to define constraints within and among relations. These constraints can be;
  1. Entity Integrity Constraints - Primary Key/Unique Columns 
  2. Referential Integrity Constraints - Foreign Key
On top of this there is a language called Structured Query Language which is a standardized way of Retrieving, Manipulating of data in those Relation/Table.

With the growth of high volume websites such as Twitter, Facebook and the emergence of IAAS (Infrastructure As A Service) solutions such as Amazon AWS, which uses distributed data centers around the globe, the need for NoSQL databases are ever so high! This is because issuing of a single SQL which covers data in across multiple data centers in different countries is not possible. Furthermore relational databases depends a lot on JOINs and distributed data centers pose a problem to this also. 

Redis, on the other hand doesn't use SQL or Relation/Table. Redis has built-in data structures and algorithms to solve frequently faced design issues.

Redis has Key/Value, Lists, Hashes (Maps), Set and Sorted Set data structures.

To get started with Redis in Ubuntu;
  1. You just need to download Redis.
  2. Unzip the File
  3. Open a Shell Terminal
  4. Navigate into the extracted directory
  5. Issue "make" command
  6. Optionally Issue "make test" to verify everything is working fine.
  7. Navigate into "src" folder
  8. Issue "chmod +x redis-server" and "chmod +x redis-cli"
  9. Issue "./redis-server"
  10. Now the Redis server will be up and listening in port 6379
  11. You can issue "./redis-cli" to start a Client where you can issue commands to Redis server

Friday, June 13, 2014

Custom Dozer Mapper Factory Bean

As part of my work I had to learn and make use of Dozer mapper. A Java Bean to Java Bean Mapper which enables Converting from one type of Java Bean (Ex:- Spring hateoas Resource) to another Java Bean (Ex:- Entity) easy and less error prone. You can learn more about this library from Dozer page.

The tricky part doing the job was that the requirement was that every JPA Entity had a corresponding Mutable and Non Mutable interface. Mutable interface extends from the Non Mutable interface. So the mapping needed to be done by using the Mutable interface to Spring hateoas Resource.

<?xml version="1.0" encoding="utf-8"?>
<mappings xmlns="http://dozer.sourceforge.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://dozer.sourceforge.net
          http://dozer.sourceforge.net/schema/beanmapping.xsd">

    <mapping>
        <class-a>com.shazin.example.domain.MutableItem</class-a>
        <class-b>com.shazin.example.web.resource.ItemEditResource</class-b>
        <field>
            <a>..</a>
            <b>..</b>
        </field>
        ..
    </mapping>
</mappings>

Furthermore when mapping the two back using the DozerBeanMapper API inside of the Service, the following needed to be done, completely avoiding the Entity class because at the service level only interfaces must be used not entities.

mapper.map(sourceItemResource, MutableItem.class);

This posed an issue because map method expected a second argument of implementation class of the destination bean.

The solution was writing an Custom implementation of org.dozer.BeanFactory which will provide the correct Implementation class based on the interface. So wrote the following AbstractMapperBeanFactory class.

import java.util.HashMap;
import java.util.Map;

import org.dozer.BeanFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class AbstractMapperBeanFactory implements BeanFactory {
    private static final Logger logger = LoggerFactory
            .getLogger(AbstractMapperBeanFactory.class);

    protected AbstractMapperBeanFactory() {
        register(sourceToDestinationMap);
    }

    private final Map<String, Class<?>> sourceToDestinationMap = new HashMap<>();

    protected abstract void register(
            Map<String, Class<?>> sourceToDestinationMap);

    @Override
    public final Object createBean(Object source, Class<?> sourceClass,
            String targetBeanId) {
        Class<?> destinationClass = null;
        Object result = null;
        try {
            Class<?> targetBeanClass = Thread.currentThread()
                    .getContextClassLoader().loadClass(targetBeanId);
            if (targetBeanClass.isInterface()) {
                destinationClass = sourceToDestinationMap.get(targetBeanId);
            } else {
                destinationClass = targetBeanClass;
            }

            if (logger.isDebugEnabled()) {
                logger.debug("Source Object : " + source);
                logger.debug("Source Class : " + sourceClass);
                logger.debug("Target Bean Id : " + targetBeanId);
                logger.debug("Destination Class : " + destinationClass);
                logger.debug("Target Bean Class : " + targetBeanClass);
            }

            if (destinationClass == null) {
                logger.warn(String.format(
                        "No matching destination class found for class %s",
                        targetBeanId));
            } else {
                result = destinationClass.newInstance();
            }

        } catch (ClassNotFoundException | InstantiationException
                | IllegalAccessException e) {
            logger.error(String.format(
                    "Error while creating target bean for class %s",
                    targetBeanId), e);
        }
        return result;
    }
}


And for each Module we could register Interfaces and corresponding implementations by Sub classing the above abstract class and implementing the register method as following.

public class CustomMappingBeanFactory extends AbstractMapperBeanFactory {

    protected void register(Map<String, Class<?>> sourceToDestinationMap) {
        sourceToDestinationMap.put(MutableItem.class.getName(), ItemEntity.class);
        ..
    }

}

And finally making use of the CustomMappingBeanFactory in the mapping configuration file as below.

<?xml version="1.0" encoding="utf-8"?>
<mappings xmlns="http://dozer.sourceforge.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://dozer.sourceforge.net
          http://dozer.sourceforge.net/schema/beanmapping.xsd">

    <mapping bean-factory="CustomMappingBeanFactory">
        <class-a>com.shazin.example.domain.MutableItem</class-a>
        <class-b>com.shazin.example.web.resource.ItemEditResource</class-b>
        <field>
            <a>..</a>
            <b>..</b>
        </field>
        ..
    </mapping>
</mappings>