All posts by gerrytan

Java Web Session Cluster Replication With Hazelcast

Source: http://www.hazelcast.com/use-cases/web-session-clustering/

This is a great way to ensure that session information is maintained when you are clustering web servers. You can also use a similar pattern for managing user identities. Learn how easy it is to maintain session state across a set of servers here!

Say you have more than one web servers (A, B, C) with a load balancer in front of them. If server A goes down then your users on that server will be directed to one of the live servers (B or C) but their sessions will be lost! So we have to have all these sessions backed up somewhere if we don’t want to lose the sessions upon server crashes. Hazelcast WM allows you to cluster user http sessions automatically. Followings are required for enabling Hazelcast Session Clustering:

  • Target application or web server should support Java 1.5+
  • Target application or web server should support Servlet 2.4+ spec
  • Session objects that needs to be clustered have to be Serializable

Here are the steps to setup Hazelcast Session Clustering:

Put the hazelcast and hazelcast-wm jars in your WEB-INF/lib directory.

Put the following xml into web.xml file. Make sure Hazelcast filter is placed before all the other filters if any; put it at the top for example.


    hazelcast-filter
    com.hazelcast.web.WebFilter
    
    
        map-name
        my-sessions
    
    
    
        sticky-session
        true
    
    
    
        debug
        true
    


    hazelcast-filter
    /*
    FORWARD
    INCLUDE
    REQUEST


    com.hazelcast.web.SessionListener

Package and deploy your war file as you would normally do.

It is that easy! All http requests will go through Hazelcast WebFilter and it will put the session objects into Hazelcast distributed map if needed.

Clustering Tomcat Using Static Membership

Source: http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=2009794

Purpose

This article gives an example of cluster configuration using static cluster membership (instead of determining it dynamically over multicast), and points out some important aspects of membership configuration. While multicast membership is simpler to set up, static membership is necessary on networks with multicast disabled.

Resolution

Example: This is an example element in server.xml from a node that is part of a 2-node static cluster. In this example, all nodes are on the same host. You can copy this example and modify hosts and ports as necessary for your own cluster.


  

  

    

    
      
    
    
    
    

    
          
          
          
    

  
  
  

  
  

This example differs from the default multicast configuration as discussed in the Apache Tomcat 6 Clustering how-to. These differences are important when creating your own non-multicast configuration:

  • The McastService element is removed.
  • The channelStartOptions=”3″ switch has been added to the Cluster element, to disable the multicast service. Even when not explicitly configured, the multicast service is enabled by default. If the multicast service is not disabled this way, and multicast is enabled on the network, your nodes could cluster with unexpected members. For more information about the Cluster element, see its entry in the Apache documentation.
  • The TcpPingInterceptor class is added. This interceptor pings other nodes so that all nodes can recognize when other nodes have left the cluster. Without this class, the cluster may appear to work fine, but session replication can break down when nodes are removed and re-introduced. For more information about the TcpPingInterceptor element, see its entry in the Apache API documentation.
  • The StaticMembershipInterceptor element is added at the end of the list of interceptors, specifying the other static members of the cluster. For more information about the StaticMembershipInterceptor element, see its entry in the Apache documentation.

Remember these points when modifying the configuration:

  • As with the default configuration, you can use either the DeltaManager or BackupManager by changing the element.
    The order of the interceptors is very important. Preserve the order presented here.

    Caution: Reversing the first two interceptors can results in a log full of messages similar to:

    WARNING: Unable to send ping from TCP ping thread.
    java.lang.NullPointerException
            at org.apache.catalina.tribes.group.interceptors.TcpPingInterceptor.sendPing(TcpPingInterceptor.java:121)
            at org.apache.catalina.tribes.group.interceptors.TcpPingInterceptor$PingThread.run(TcpPingInterceptor.java:166)
    
  • One member in the static list is commented out: the member that corresponds to the node on which this configuration file is located. Be sure not to include a node in its own cluster membership. If this were done, the node would sync to itself as if it were a different node in the cluster. With DeltaManager, that could lead to errors at startup like:
    org.apache.catalina.ha.session.DeltaManager waitForSendAllSessions
    SEVERE: Manager [localhost#/petcare]: No session state send at [time] received, timing out after 60,087 ms.
    org.apache.catalina.ha.session.DeltaManager getAllClusterSessions
    WARNING: Manager [localhost#/petcare]: Drop message SESSION-GET-ALL inside GET_ALL_SESSIONS sync phase start date [times]
    

    With the BackupManager this configuration is silently accepted, but the node would consider itself its own backup. Restarting the node would result in the loss of sessions not synced to other nodes.

Additional Information

This configuration is known to work with Tomcat 6.0.33. It does not work with Tomcat 7.0.22/23. For more information, see the Apache bug report.

Transferring File Using FTPS in Java

Here’s a sample code on setting up FTPS file transfer in Java. Make sure you have setup SSLContext trusting the FTPS server’s certificate.

SSLContext sslContext = /* setup SSLContext */
FTPSClient ftps = new FTPSClient(true, sslContext);
ftps.connect(hostname, port);

// Timeout exception will be raised if no response received after 20s
ftps.setDataTimeout(20000);

// Authenticate
ftps.user("ftp_user")
ret = ftps.pass("ftp_pass");

// Define protection buffer size and protocol. Following are the default for implicit FTP (FTPS)
ftps.parsePBSZ(0);
ftps.execPROT("P");

// Set passive mode and file transfer type
ftps.type(FTP.BINARY_FILE_TYPE);
ftps.enterLocalPassiveMode();

// Remote path where file will be downloaded from
ftps.changeWorkingDirectory("/remote/path");

// Retrieve a file called "file.txt" from remote server
FileOutputStream local = new FileOutputStream("file.txt");
ftps.retrieveFile("file.txt", local);

This code uses commons-net package, make sure it is included in maven dependencies:


  commons-net
  commons-net
  3.3

The actual FTPS code will vary greatly depending on your FTPS server setup. The above assumes FTPS server is running in passive mode with normal username / password authentication.

Trusting X509 Base64 PEM SSL Certificate in Java

If you ever find yourself having to establish SSL connection with untrusted server (eg: because the server’s cert is not chained to 3rd party CA (internal / testing servers)), you’ll probably use -Djavax.net.ssl.trustStore and -Djavax.net.ssl.trustStorePassword.

While this method works great for jvm-wide configuration, it’s a bit tricky if you want to apply it to specific class / method only. Also if you ever had to dynamically update the trust certificate, it might be harder to get this method working

Trusting Certificate Using SSLContext

Supposed you have a X.509 SSL certificate in Base 64 encoded PEM format like below:

-----BEGIN CERTIFICATE-----
MIIDBzCCAe+gAwIBAgIJAI1DCiDwQMQ0MA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNV
BAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xNDA0MzAyMjU1NTZaFw0yNDA0MjcyMjU1
NTZaMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBAOjZRpPtBBrOE32MV2X1HlTmLFE3977o4k97CYZetgxZ
guLy+dPBaJ6fA3pjhkqXbICtsaBewAjnlvUgUilc0quwklepw9Sd9L6M9NgyCFGf
G1AFA8wEJwmtxA7TnDNjuqATqbLUOe2douuQ9Krttd5zbGB2vDO1Chc4GYb1pUxV
wTAdk+bXrpoeP/82LEYjcYq2UTXs/cUnzDAOzOCXcCugx2Rh2EdS/S6oXgOYv/BD
q1jVj3AojcJuJixW/BGWwvw/hkBof0RzrnJNqHnO3PWfc0LhOeqKwOhMZ9dV2p0m
v5X221nrBMwOZRDJBWybE5YuWmAt6ci2BtHgn3l4ClcCAwEAAaNQME4wHQYDVR0O
BBYEFBFwLKrHXhSyapQbXp/2E/R1VT0XMB8GA1UdIwQYMBaAFBFwLKrHXhSyapQb
Xp/2E/R1VT0XMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAMRaPuv
lFTZpAn8lCqom0Af8+3OGEPUEYPOReE0xG7Ph+OSPhlI860C0QwiZn0PR3L+QK2F
d1g9GndfJATgyjqbhebKXO1b0OAQfGIPsEHsCtT+4myFNHnYmHKqnX1NrUXpjzcP
4uHpVU7Nomz+f4WjH+cACL4PrlldPtXXOsn7vFdZrYunitHTvslWe3RoQCkHRc93
3OKx4Xh2Vy1wCrfkZYd8Q1y55jysxwitYhQAYwv9GyL/pj5jzB5PxLAZbDRznK5E
CbqiKbfbcAEpbxceXG0YmVYY/kEzXKPxUw99GH/hkUTFhCT03unx7LWtYI5BG5o+
QCVuzU8kMeiOFkQ=
-----END CERTIFICATE-----

You can trust this by setting up a SSLContext:

CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream certFile = new FileInputStream("mycert.crt");
Certificate ca = cf.generateCertificate(certFile); // this is java.security.cert.Certificate;

KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);

TrustManager trustManager = TrustManagerUtils.getDefaultTrustManager(keyStore);
SSLContext sslContext = SSLContextUtils.createSSLContext("TLS", null /*keyManager*/, trustManager);

Here the certificate above is placed on mycert.crt file on java work directory. On SSLContextUtils.createSSLContext the keyManager param is set to null because we don’t need present any private keys. The TrustManagerUtils and SSLContextUtils came from commons-net package so you’ll need to add that dependency to your pom.xml:


  commons-net
  commons-net
  3.3

SSLContext has a getSocketFactory() method which you can use to setup a SSLSocket which will verify against mycert.crt

SSLSocketFactory socketFactory = sslContext.getSocketFactory();
Socket socket = socketFactory.createSocket("dev.mycompany.com", 1234);

You can also pass SSLContext directly to some other libraries for it to trust your cert, below is ftps example using commons-net

FTPSCLient ftps = new FTPSClient(true, sslContext);

Setup IMAP on Exchange Server 2013

Turn On IMAP Services

On the windows server where exchange runs, ensure Microsoft Exchange IMAP4 and Microsoft Exchange IMAP4 Backend started and set the mode to automatic.

imap-svc

Setup Firewall / NAT Port Forwarding On The Router

By default IMAP listens to port 143 and 993 (SSL), the idea here is by setting up port forwarding, packets that hits your office IP will be translated and forwarded into the exchange server. There are no generic instruction on how to do this as each router type is different, however conceptually you want to setup a rule to this effect:

When a packet arrives to to port 143 and/or 993, translate it into and forward it to port 143 and/or 993

Keep in mind the Windows server has its own firewall so you might need to open the ports there too

Setup DNS Alias

Typically you would want imap.mycompany.com to point to the Windows server that hosts Exchange. This can be achieved by adding a DNS A Record on your internet domain manager (provided by your domain hosting).

Observe IMAP Settings on Exchange Admin Center (EAC)

Make sure you have it enabled, selected login method to your liking etc:

exchange-eac

And Finally Setup IMAP on Your Phone / Email Client

Depending on your setting, the IMAP details might look like this:

  • IMAP server: imap.mycompany.com
  • Port: 143
  • Enable TLS: true
  • Username:
  • Password:

Javascript Engine in Java

Yes you can create your own javascript engine in Java. This is a cool feature I never knew existed. I don’t know how long it’s been around, I’m guessing Java 6.

Basically, you can do something like this:

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class JavaJS {

  public static void main(String[] args) throws ScriptException {
    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine engine = manager.getEngineByName("JavaScript");
    String script = 
        "function sayHello(name) {"
      + "  print('Hello ' + name);"
      + "}"
      + "sayHello('tom');";
    engine.eval(script);
  }

}

And it will print Hello tom.

You can even mix and match Java and Javascript, here’s how to have Java calling the Javascript function above:

Invocable invocable = (Invocable) engine;
invocable.invokeFunction("sayHello", "Jim");

Cool eh? Read more about this on the Oracle’s Java Scripting Programmer Guide or google JSR-223.

Unit Testing Using In-Memory MySQL Database On Spring

Well the title lied, there’s no such thing as in-memory MySQL database (or at least I won’t be using it for this article). Instead I will use H2 in-memory database setup to run in “MySQL mode”


  
  

(thanks to joensson for sharing this technique on SO)

If your app just uses plain jdbc then adding above datasource to your test context would be sufficient, but if you use JPA/Hibernate the cost of table setup, scanning etc could be quite significant.

To overcome this you can split the test context using y annotation.

In the example below I have unit tests for two DAOs: AccountDAOTest and CustomerDAOTest:

y({
  ation("/test-root-context.xml"),
  ation("AccountDAOTest-context.xml")
})
(SpringJUnit4ClassRunner.class)
public class AccountDAOTest {
}
y({
  ation("/test-root-context.xml"),
  ation("CustomerDAOTest-context.xml")
})
(SpringJUnit4ClassRunner.class)
public class CustomerDAOTest {
}

By doing this Spring test-root-context.xml will be setup once and reused accross all unit tests. Only put components common to all tests in test-root-context.xml. In my case I put the following:

  • DataSource
  • EntityManagerFactory
  • TransactionManager


  
  





  
  




  

All test specific components go into their respective context.

Don’t forget to add if your DAO uses it. This can’t be placed on test-root-context.xml because I don’t scan all my DAOs there.

And lastly — ofcourse — you need to make sure your pom.xml has dependency to spring-test, junit and h2



  com.h2database
  h2
  1.3.176
  test



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



  junit
  junit
  4.7
  test

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 Geographical Location On Google Map (Geocoding)

Translating a geographical location such as “London, UK” into a lat/long coordinate (lat: 51.5085150, long: -0.1254870) is called geocoding. This coordinate can then be used to display the location on google map.

Try putting a location in the box below and hit go:

Register for Google Map API Key

In order to implement the above widget first obtain an API key from Google:

  1. Go to
  2. Select Services on the left menu, ensure Geocoding API, Google Maps Embed API and Google Maps JavaScript API v3 are turned on

    geocoding1

    geocoding2
  3. Go to API Access, select Create new Browser key

    geocoding3
  4. The list of accepted HTTP referers will be asked, if you’re testing on local machine this would probably be localhost/*, otherwise you need to put your website domain name here. Hit Create once you’re done

    geocoding4
  5. Take a note of your API key, this will be used in the later part of this tutorial

    geocoding5

The HTML Code

This widget only contains 3 elements:

  • A text input box to provide the geographical location
  • A button to submit the address and show it on the map
  • A div container for the map
Enter location (eg: London, UK): 


Javascript

2 javascript libraries are used: jQuery and Google Map JS. The key parameter on the Google Map JS URL should be the key created above.


Firstly let’s initialize the div container so it doesn’t come up with blank map, here I set it into coordinate of San Francisco, CA:

$(document).ready(function() {
        var map = new google.maps.Map($('#map')[0], {
                center: new google.maps.LatLng(37.7749295, -122.4194155),
                zoom: 8
        });
        ...
}

And create a click handler for the ‘Go’ button which sends ajax post into Google Map JS API. The API will return a JSON response with the location if successful.

$(document).ready(function() {
        ...
        $('#go').click(function(e) {
                e.preventDefault();
                var loc = $('#loc').val();
                $.ajax({
                        url: '//maps.googleapis.com/maps/api/geocode/json?sensor=false&address='+loc
                }).done(function(data) {
                        if(data.status != "OK") {
                                alert("Unable to find location");
                                return;
                        }
                        var loc_result = data.results[0].geometry.location;
                        map.setCenter(new google.maps.LatLng(loc_result.lat, loc_result.lng));
                });
        });
});

See the widget in action in full screen.

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" %>