Tag Archives: spring framework

Spring Declarative Transaction Management With JDK Proxy vs AspectJ

What is this fancy words “Declarative Transaction Management” (DTM) ? Well.. basically it’s the “magic” behind the annotation in Spring.

By default Spring will use JDK Proxy for DTM, but it’s not without a big (yes BIG) gotchas.. Let’s take a look at below cliche example of transferring money from a bank account to another with slight variation — here several transfer requests are processed together by processBatch method:


public class AccountService {

  public void processBatch(List xferReqs) {
    for(TransferReq xferReq : xferReqs) {
      transfer(xferReq.getAmount(), 
               xferReq.getFromAccountNo(),
               xferReq.getToAccountNo());
    }
  }

  
  public void transfer(double amount, long fromAccountNo, long toAccountNo) {
    checkBalanceIsGreaterThan(fromAccountNo, amount);
    withdraw(fromAccountNo, amount);
    deposit(toAccountNo, amount);
  }

  
  public void checkBalanceIsGreaterThan(long accountNo, double amount) {
    ...
  }

  
  public void withdraw(long fromAccountNo, double amount) {
    ...
  }

  
  public void deposit(long toAccountNo, double amount) {
    ...
  }
  
}

When another class invokes processBatch, you’d expect the database transaction to happen like this:

begin
req1 transfer
req1 checkBalanceIsGreaterThan
req1 withdraw
req1 deposit
commit

begin
req2 transfer
req2 checkBalanceIsGreaterThan
req2 withdraw
req2 deposit
commit
...

But it’s NOT! This is a big hidden pitfall that I’ve fallen into (had to learn the hard way right?). Here’s why..

In JDK Proxy Spring did the “magic trick” by automatically creating a subclass with extra DTM functionality (hence the name “proxy”) in place of the original transactional class. The subclass method actually do the transaction management before calling the underlying method.

This has the implication that transaction management will only occur if the method you invoke from a different class is a method.

Since in above example the processBatch method invoked is not a method, transaction management will not be performed!

Here’s a rough example of what the auto-created JDK proxy class might look like:

public class AccountServiceProxy extends AccountService {

  public void processBatch(List xferReqs) {
    super(xferReqs); // <-- Superclass method is invoked here, 
                     //     the below transfer method will NOT execute
  }

  public void transfer(double amount, long fromAccountNo, long toAccountNo) {
    // Code to "check if transaction exist, if not create one" goes here..

    try {
      super(amount, fromAccountNo, toAccountNo);

      // Code to commit goes here..

    } catch(Exception e) {
      // Code to rollback goes here..
    }
    
  }
   
  ... 
}

So yes your database transaction is a mess. Every single statement would be executed in its own transaction (oh no!)..

So How To Fix It?

Well you have several option. First is to keep using JDK Proxy but structure your class such that the first method invokes is a method. In the above example, the processBatch method can be moved into a different class AccountBatchProcessorService, hence when it invokes the proxy class’ transfer method DTM occurs.

Or you leave the code as it is and use the almighty AspectJ..

AspectJ Declarative Transaction Management

With AspectJ, DTM is not done by subclass “proxy”, but there’s a unicorn hiding beneath the cloud that adds DTM code to your method just before it’s compiled (sometimes it’s called “compile-time weaving”).

Here’s how you can enable AspectJ DTM for your project:

On the old-fashioned Spring xml configuration (don’t ask me the new-style annotation config yet, haven’t RTFM), to enable annotation you would have something like this:


  ...
  
  ...

You need to set it into aspectj mode

  

Then in your pom.xml, add dependency to spring-aspects

...

  org.springframework
  spring-aspects
  ${spring-version}

...

And configure aspectj-maven-plugin so that DTM mechanism is weaved when your code is compiled

...

  
    ...
    
      org.codehaus.mojo
      aspectj-maven-plugin
      1.6
      
        
          
            compile
            test-compile
          
          
            
              
                org.springframework
                spring-aspects
              
            
            ${java-version}
            ${java-version}
            ${java-version}
          
        
      
    
    ...
  

...

At this point your STS/eclipse project might throw error saying Maven configuration is not up to date. If so do right click on the project -> Maven -> Update project. If the setup is good in STS/eclipse you should see a half circle arrow on methods.
tx-arrow

Voila! Your bank transfer should work as expected now

Debugging Database Transaction

Lastly if you’re using Hibernate and log4j, you can get it to spit the SQL statements and ‘begin’ and ‘commit’ log by setting following loggers into DEBUG

log4j.logger.org.hibernate.engine.transaction.spi=DEBUG
log4j.logger.org.hibernate.SQL=DEBUG

Final Note

This article is written against following versions:

  • Spring 4.0.5.RELEASE
  • Hibernate 4.3.5.Final
  • aspectj-maven-plugin 1.6

Enjoy!

Java Spring Web App Silent Self-Update

It’s unimaginable how many apps still force its user to manually update — they’re very annoying! Fortunately if your app is a Java Web App (eg: running in Tomcat) you can set it up to auto-update silently. This is very helpful if you deploy your web-app onsite on clients’ infrastructure.

This article assumes you have a basic understanding of Spring MVC. The article is written against Spring Framework version 4.0.3.RELEASE.

The UpdaterService

The first thing to setup is an UpdaterService that checks periodically if a new version is available. You will need a TaskScheduler to schedule the periodic job. Feel free to either use Java annotation or XML style:

// Java annotation

g
public class AppConfig {
  ...
}



Once setup, you can decorate a method with annotation and it will be invoked by the scheduler
thread every specified period.

In below example my UpdaterService class has a checkAndInstallUpdate() method that get invoked by the scheduler thread every 8 hours.


public class UpdaterService {
  (fixedDelay=8*3600)
  public void checkAndInstallUpdate() {
  }
}

I will not go into much detail on how to check and download the update. There are tons of way of doing it and one popular method is to use Apache HttpClient library.

Typically you would upload your war/jar artifact in your website and have a REST service for apps to check if new version is available. If so then download and install it.

Self Executing Tomcat Container

Here’s another trick I use on my self-updating app: use a self-executing Tomcat. Basically everything required to run tomcat is packaged inside a nested war/jar. If you use spring-boot it already have a support for this, but otherwise you can set it up painlessly using maven plugin.

The other thing you need to make sure is the war/jar file isn’t file-system-locked when the app is running so it can be overwritten by the new version. Self-executing Tomcat does not lock the jar.

Restarting Tomcat

Here comes the tricky bit. First use ProcessBuilder to spawn a new OS process

String myAppPath = System.getenv("MY_APP_PATH");
String command = myAppPath + File.separator + "run.bat";
ProcessBuilder builder = new ProcessBuilder(command);
builder.start();

In the example above it is assumed you have a windows script called run.bat and the value of environment variable MY_APP_PATH is set to the folder that contain the run script.

And directly after that, terminate the JVM using System.exit(0)

System.exit(0);

The termination of the old process will not affect the new ones. And yes, you need to start the new process before you terminate the old one, otherwise it wouldn’t have chance to do so.

See Also

Java EE Default Error Page

The default error page for java webapp can be set via web.xml


  ...
  
    /error
  

Several error pages can be defined with each assigned to specific error code

  
    404
    /notFoundError
  
  
    403
    /forbiddenError
  

If using Spring MVC, the error message and status code can be obtained on the handler using following request attributes:

("/error")
public String error(HttpServletRequest req) {
  Object message = req.getAttribute("javax.servlet.error.message");
  Object statusCode = req.getAttribute("javax.servlet.error.status_code");
  Object requestURI = req.getAttribute("javax.servlet.error.request_uri");
  // ...
}

Running Non-duplicate Task On A Cluster Using Hazelcast

Having a container cluster is great, but one problem is when you need to run something once only (think table cleanup, pulling data to shared db, etc).

Since you have multiple VM running off the same source code, it will normally run duplicate instance of the task — one per VM. You can avoid that from happening using distributed lock.

 private HazelcatInstance hz;

ILock lock = hz.getLock(MyTask.class.getName());

Every node in the cluster has access to distributed lock. Only one node can obtain the lock. If a node successfully obtained the lock its thread will continue executing, otherwise it will block until it manages to obtain one (or times out).

logger.info("Trying to run task on this node...");
lock.lock(); // thread execution will only pass this line if no other node has the lock

logger.info("Running task on this node..");
// do something here

Since calling lock.lock() might block the thread, you typically want to run it on a separate thread.

If a node that has the lock crashes / dies, the lock will be released, and other nodes can pick it up and become the ‘task owner’.

See Also

Obtaining Maven Version Programatically On Runtime

This is my favorite way of reading Maven project version from runtime.

First on your pom, declare that all files on src/main/resources will be filtered — meaning any placeholder (eg: ${project.version}) will be substituted by Maven.


  ...
  
    
      src/main/resources
      true
    
  

Then create a properties file (eg: myapp.properties) with key-value pair containing the Maven project version

myapp.version=${project.version}

Ensure the file above is configured on your Spring container either using xml:


Or Java annotation:


("classpath:/myapp.properties")
public class TheConfig {
  ...
}

The key-value entry can then be injected on any Java beans living in the container:


public class MyClass {
  ("${myapp.version}") private String version;
  ...
}

Or even spring xml config:


  

Beware that if you have more than 1 Spring container (eg: root and servlet), you need to declare on both, otherwise the injection will fail.

Using Custom Role Populator On Spring Security LDAP

Here’s how you can use Spring Security LDAP just for password authentication, but use your own database for assigning role / authorities.

First on your context xml define an LDAP server context bean as per normal:


Then define LDAPAuthenticationProvider bean:


  
    
      
      
        
          
          
          
        
      
    
  
  

If you noticed at the bottom we set authoritiesPopulator into myLDAPAuthPopulator bean which we’ll define next. This is where you can lookup your database using jdbc or other method to populate the roles given an authenticated username:

("myLDAPAuthPopulator")
public class MyLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator {

  
  public Collection extends GrantedAuthority> getGrantedAuthorities(DirContextOperations userData, String username) {
    List authorities = new ArrayList();
    User user = userDAO.findByUsername(username);
    for(String role : user.getRoles()) {
      authorities.add(new SimpleGrantedAuthority(role));
    }
    return authorities;
  }

}

And finally register this authentication provider in the authentication manager:


  

Showing Spring Security Principal and Conditional Logic on JSP

If your app is setup with Spring Security, you can show currently logged in user in JSP by using:

${pageContext.request.userPrincipal.name}

You can also check if the user has enough right to access a resource. This example ensures user has enough rights to access /admin or else the link won’t be rendered:


  
  • Admin Home
  • Make sure you have spring-security-taglibs on your classpath:

    
      org.springframework.security
      spring-security-taglibs
      ${org.springframework.security-version}
    
    

    And the tag prefix declared on top of the JSP page:

    <%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
    

    Spring Security Auto Login After Successful Registration

    Asking your user to login immediately after he/she registers might be tedious. Here’s how you can log them in immediately using Spring Security (thanks to this SO thread).

    Typically you will have some sort of registration form with a backing controller like this:

    
    ("/register")
    public class RegisterController {
      ...
      (method = POST)
      public String register( User user) {
        // perform registration logic..
        // redirect back to login page
        return "redirect:/login";
      }
      ...
    }
    

    But a server-side login can be done by autowiring UserDetailService and AuthenticationManager:

    
    ("/register")
    public class RegisterController {
      ...
       ("authMgr") private AuthenticationManager authMgr;
       private UserDetailsService userDetailsSvc;
    
      (method = POST)
      public String register( User user) {
        // perform registration logic..
    
        // perform login authentication
        try {
          UserDetails userDetails = userDetailsSvc.loadUserByUsername(username);
          UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
          authMgr.authenticate(auth);
    
          // redirect into secured main page if authentication successful
          if(auth.isAuthenticated()) {
            SecurityContextHolder.getContext().setAuthentication(auth);
            return "redirect:/";
          }
        } catch (Exception e) {
          logger.debug("Problem authenticating user" + username, e);
        }
    
        return "redirect:/error";
      }
      ...
    }
    

    Note that in above code the AuthenticationManager injection is qualified by ("authMgr"). This is to avoid multiple beans ambiguity. In effect in the xml context configuration (if you use one) an id attribute has to be set:

      ...
      
        ...
      
    
      
        ...
      
      ...
    

    Also in order for this setup to work, the registration page has to be filtered by spring security

      ...
      
      
    
      
        
      
      ...
    

    See Also

    Installing Spring Security On Spring MVC Project

    Using HandlerInterceptor or ControllerAdvice to Make Spring MVC Model Attribute Available Everywhere

    Often you’ll want a particular model attribute to be available everywhere (eg: application version, name, etc). Doing model.addAttribute() everytime is a really bad idea, if you have to refactor it down the track you could end up with hundreds of line modification scattered everywhere.

    Using ControllerAdvice

    One simple way to achieve this as outlined by Spring documentation is by using Spring 3.1’s e annotation.

    Create a new class like this:

    e
    public class PopulateGlobalAttribute {
      ("appversion")
      public String getAppVersion() {
        return "1.0";
      }
    }
    

    And the getAppVersion() will be used to help each handler method in all controllers to add additional stuff to Model object.

    However this method poses one problem. If the handler method is returning a redirect view, the model attributes will be exposed as a query string on the browser URL.

    Using HandlerInterceptor

    Fortunately Josh Kalderimis proposes a nice solution on his blog post using HandlerInterceptor.

    This is my own version of HandlerInterceptor which is based from Josh’s:

    public class PopulateGlobalAttrInterceptor implements HandlerInterceptor {
      private Map properties = new HashMap();
    
      /**
       * This method ensures the global attributes are added only for non-redirection view / view name
       */
      
      public void postHandle(HttpServletRequest req, HttpServletResponse res, Object handler,
          ModelAndView mav) throws Exception {
        if(mav == null) return;
    
        boolean isRedirectView = mav.getView() instanceof RedirectView;
        boolean isViewObject = mav.getView() != null;
        boolean viewNameStartsWithRedirect = (mav.getViewName() == null ? true : 
          mav.getViewName().startsWith(UrlBasedViewResolver.REDIRECT_URL_PREFIX));
        
        if(mav.hasView() && (
          ( isViewObject && !isRedirectView) ||
          (!isViewObject && !viewNameStartsWithRedirect))){
            addCommonModelData(mav);
        }
      }
    
      private void addCommonModelData(ModelAndView mav) {
        mav.getModel().putAll(properties);
      }
    
      
      public void afterCompletion(HttpServletRequest req, HttpServletResponse res, Object handler,
          Exception ex) throws Exception {
      }
    
      
      public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler)
          throws Exception {
        return true;
      }
    
      /* getters & setters */
    }
    

    In SpringMVC HandlerInterceptors are similar like servlet filters, it will be used to filter (intercept) through every requests. Similar like ControllerAdvice, the postHandle method will be invoked by all handlers to help populate the model.

    Once you have this you need to register this interceptors. If you use xml based configuration you can do something like this:

    
    
      ...
    
      
    
      
        
          
            
          
        
      
    
      
        
      
      ...
    
    

    Now without any additional code, you’re guaranteed ${appversion} is available everywhere on your jsp view.

    Stock Ticker Demo Webapp Using Spring 4 Websocket

    In case you haven’t heard what Websocket is, long story short it’s a brand new cool technique of asynchronous client-server communication for web application. Instead of periodic / long ajax polling, newer browsers allow you to have a persistent socket (almost like TCP) where both client and server can send messages anytime.

    Yes the all-new Spring 4 came with shiny Websocket support! Here’s a stock ticker app to get you started (thanks to raymondhlee’s article for the inspiration). This app will let you add/remove a stock code and update its price every second (by randomly adding / subtracting some percentage)

    stockticker

    Environment / Tools

    • Java 7
    • Tomcat 7.0.47
    • Servlet API 3
    • Spring Framework 4.0.2.RELEASE

    Maven Dependencies

    Most dependencies are similar to Spring MVC but there’s few addition required to support websocket. You also need to use Servlet 3.

    
      org.springframework
      spring-context
      ${org.springframework-version}
    
    
    
      org.springframework
      spring-webmvc
      ${org.springframework-version}
    
    
    
      org.springframework
      spring-messaging
      ${org.springframework-version}
    
    
    
      org.springframework
      spring-websocket
      ${org.springframework-version}
    
    
    
      javax.servlet
      javax.servlet-api
      3.1.0
      provided
    
    
    
      com.fasterxml.jackson.core
      jackson-databind
      2.3.2
    
    

    web.xml

    You need to use version 3 of the web.xml schema, and on DispatcherServlet config, set true. Here’s src/main/webapp/WEB-INF/web.xml

    
    
    
      
      
        appServlet
        org.springframework.web.servlet.DispatcherServlet
        
          contextConfigLocation
          /WEB-INF/servlet-context.xml
        
        1
        true
      
    
      
        appServlet
        /
      
    
    
    

    Setup Websocket Message Broker On Servlet Context XML

    Apart from the standard Spring MVC config, one new stuff we’re introducing is the Websocket Message Broker. The message broker will help us listening, mapping and sending messages. Note that as suggested by Spring docs we’re using STOMP message protocol and SockJS to support non-websocket browser.

    Also note following configs:

    • Stomp endpoint: /ws
    • Message broker app prefix: /app
    • Message queue prefix: /topic

    Here’s src/main/webapp/WEB-INF/servlet-context.xml:

    
    
    
      
    
      
    
      
        
        
      
    
      
    
      
        
          
        
        
      
    
    
    

    The Domain Object

    Stock class is a simple POJO with code, price and time fields. I’ve also added getTimeStr() to format the time as string and additional constructor.

    package com.gerrydevstory.stockticker;
    
    import java.io.Serializable;
    import java.text.DateFormat;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class Stock implements Serializable {
    
      private static final long serialVersionUID = 1L;
      private String code = "";
      private double price = 0.0;
      private Date time = new Date();
      
      public Stock() {
        
      }
      
      public Stock(String code, double price) {
        this.code = code;
        this.price = price;
      }
      
      private DateFormat df = new SimpleDateFormat("dd MMM yyyy, HH:mm:ss");
      
      public String getTimeStr() {
        return df.format(time);
      }
      
      /* standard getters & setters */
      
    }
    

    Broadcast Prices And Add / Remove Stock

    At the core of this app is the HomeController class. There’s a updatePriceAndBroadcast() method which is scheduler to run every 1 second using TaskScheduler. This controller also has websocket handler method to add new stock and remove all. Note the usage of annotation, it will make more sense once we go through the javascript part below.

    package com.gerrydevstory.stockticker;
    
    
    public class HomeController {
    
       private SimpMessagingTemplate template;  
      private TaskScheduler scheduler = new ConcurrentTaskScheduler();
      private List stockPrices = new ArrayList();
      private Random rand = new Random(System.currentTimeMillis());
      
      /**
       * Iterates stock list, update the price by randomly choosing a positive
       * or negative percentage, then broadcast it to all subscribing clients
       */
      private void updatePriceAndBroadcast() {
        for(Stock stock : stockPrices) {
          double chgPct = rand.nextDouble() * 5.0;
          if(rand.nextInt(2) == 1) chgPct = -chgPct;
          stock.setPrice(stock.getPrice() + (chgPct / 100.0 * stock.getPrice()));
          stock.setTime(new Date());
        }
        template.convertAndSend("/topic/price", stockPrices);
      }
      
      /**
       * Invoked after bean creation is complete, this method will schedule 
       * updatePriceAndBroacast every 1 second
       */
      
      private void broadcastTimePeriodically() {
        scheduler.scheduleAtFixedRate(new Runnable() {
           public void run() {
            updatePriceAndBroadcast();
          }
        }, 1000);
      }
      
      /**
       * Handler to add one stock
       */
      ("/addStock")
      public void addStock(Stock stock) throws Exception {
        stockPrices.add(stock);
        updatePriceAndBroadcast();
      }
      
      /**
       * Handler to remove all stocks
       */
      ("/removeAllStocks")
      public void removeAllStocks() {
        stockPrices.clear();
        updatePriceAndBroadcast();
      }
      
      /**
       * Serve the main page, view will resolve to /WEB-INF/home.jsp
       */
      (value = "/", method = RequestMethod.GET)
      public String home() {
        return "home";
      }
    
    }
    

    Client Side Stuff

    To render the stock prices, I created an empty HTML table. The idea is we will empty the table and fill it in with new prices per update

    
    
    Code Price Time

    Underneath that, I’ll also add few form input so you can add a new stock and remove everything

    Code: Price:

    The javascript stuff is a bit complicated. Apart from JQuery, there are 2 libraries used here: StompJS and SockJS. As opposed of using direct API, SockJS provides fallback for older browser not supporting websocket. StompJS provides higher level abstraction of sending and receiving messages in STOMP protocol.

    StompJS did not come with CDN, so I had to manually download it and place it on src/main/webapp/resources/stomp.js

    
    
    
    

    Next is the inline script block. Here I used SockJS to connect to the Spring websocket STOMP endpoint /ws (recall servlet-context.xml above). My webapp context path is /stockticker.

    //Create stomp client over sockJS protocol
    var socket = new SockJS("/stockticker/ws");
    var stompClient = Stomp.over(socket);
    
    // Callback function to be called when stomp client is connected to server
    var connectCallback = function() {
      stompClient.subscribe('/topic/price', renderPrice);
    }; 
    
    // Callback function to be called when stomp client could not connect to server
    var errorCallback = function(error) {
      alert(error.headers.message);
    };
    
    // Connect to server via websocket
    stompClient.connect("guest", "guest", connectCallback, errorCallback);
    

    The connectCallback function above registers renderPrice callback when a message is sent to /topic/price. This function empties the result HTML table and re-add the cells with new stock price

    // Render price data from server into HTML, registered as callback
    // when subscribing to price topic
    function renderPrice(frame) {
      var prices = JSON.parse(frame.body);
      $('#price').empty();
      for(var i in prices) {
        var price = prices[i];
        $('#price').append(
          $('').append(
            $('').html(price.code),
            $('
    ').html(price.price.toFixed(2)),
            $('
    ').html(price.timeStr)
          )
        );
      }
    }
    
                  

    And lastly, utilising JQuery let’s create handlers for adding and removig stocks

    // Register handler for add button
    $(document).ready(function() {
      $('.add').click(function(e){
        e.preventDefault();
        var code = $('.new .code').val();
        var price = Number($('.new .price').val());
        var jsonstr = JSON.stringify({ 'code': code, 'price': price });
        stompClient.send("/app/addStock", {}, jsonstr);
        return false;
      });
    });
    
    // Register handler for remove all button
    $(document).ready(function() {
      $('.remove-all').click(function(e) {
        e.preventDefault();
        stompClient.send("/app/removeAllStocks");
        return false;
      });
    });
    

    Download And Try The Source Code

    The source code of this demo app . Clone it using git:

    git clone .git

    Import it as Existing Maven Project in STS (File > Import > Existing Maven Project) and run on in-memory Tomcat 7.0.47 using following Run Configuration (Run > Run Configurations…):

    tomcat-22-maven-sts

    And this Tomcat container has to run on Java 7 to enable Websocket support.

    tomcat-22-maven-sts-jdk