Monday, December 30, 2013

Apache Shiro Session Clustering

Referred shiro.apache.org

One of the very exciting things about Apache Shiro's session capabilities is that you can cluster Subject sessions natively and never need to worry again about how to cluster sessions based on your container environment. That is, if you use Shiro's native sessions and configure a session cluster, you can, say, deploy to Jetty or Tomcat in development, JBoss or Geronimo in production, or any other environment. Configure session clustering once in Shiro and it works no matter your deployment environment.

So how does it work?

Because of Shiro's POJO-based N-tiered architecture, enabling Session clustering is as simple as enabling a clustering mechanism at the Session persistence level. That is, if you configure a cluster-capable SessionDAO, the DAO can interact with a clustering mechanism and Shiro's SessionManager never needs to know about clustering concerns.
Distributed Caches
Distributed Caches such as Ehcache+TerraCottaGigaSpaces Oracle Coherence, and Memcached (and many others) already solve the distributed-data-at-the-persistence-level problem. Therefore enabling Session clustering in Shiro is as simple as configuring Shiro to use a distributed cache.
This gives you the flexibility of choosing the exact clustering mechanism that is suitable for your environment.
Cache Memory
Note that when enabling a distributed/enterprise cache to be your session clustering data store, one of the following two cases must be true:
  • The distributed cache has enough cluster-wide memory to retain all active/current sessions
  • If the distributed cache does not have enough cluster-wide memory to retain all active sessions, it must support disk overflow so sessions are not lost.
    Failure for the cache to support either of the two cases will result in sessions being randomly lost, which would likely be frustrating to end-users.

EnterpriseCacheSessionDAO

As you might expect, Shiro already provides a SessionDAO implementation that will persist data to an enterprise/distributed Cache. TheEnterpriseCacheSessionDAO expects a Shiro Cache or CacheManager to be configured on it so it can leverage the caching mechanism.
For example, in shiro.ini:
#This implementation would use your preferred distributed caching product's APIs:
activeSessionsCache = my.org.apache.shiro.cache.CacheImplementation

sessionDAO = org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
sessionDAO.activeSessionsCache = $activeSessionsCache

securityManager.sessionManager.sessionDAO = $sessionDAO
Although you could inject a Cache instance directly to the SessionDAO as shown above, it is usually far more common to configure a generalCacheManager to use for all of Shiro's caching needs (sessions as well as authentication and authorization data). In this case, instead of configuring a Cache instance directly, you would tell the EnterpriseCacheSessionDAO the name of the cache in the CacheManager that should be used for storing active sessions.
For example:
# This implementation would use your caching product's APIs:
cacheManager = my.org.apache.shiro.cache.CacheManagerImplementation

# Now configure the EnterpriseCacheSessionDAO and tell it what
# cache in the CacheManager should be used to store active sessions:
sessionDAO = org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
# This is the default value.  Change it if your CacheManager configured a different name:
sessionDAO.activeSessionsCacheName = shiro-activeSessionsCache
# Now have the native SessionManager use that DAO:
securityManager.sessionManager.sessionDAO = $sessionDAO

# Configure the above CacheManager on Shiro's SecurityManager
# to use it for all of Shiro's caching needs:
securityManager.cacheManager = $cacheManager
But there's something a bit strange about the above configuration. Did you notice it?
The interesting thing about this config is that nowhere in the config did we actually tell the sessionDAO instance to use a Cache orCacheManager! So how does the sessionDAO use the distributed cache?
When Shiro initializes the SecurityManager, it will check to see if the SessionDAO implements the CacheManagerAware interface. If it does, it will automatically be supplied with any available globally configured CacheManager.
So when Shiro evaluates the securityManager.cacheManager = $cacheManager line, it will discover that the EnterpriseCacheSessionDAOimplements the CacheManagerAware interface and call the setCacheManager method with your configured CacheManager as the method argument.
Then at runtime, when the EnterpriseCacheSessionDAO needs the activeSessionsCache it will ask the CacheManager instance to return it it, using the activeSessionsCacheName as the lookup key to get a Cache instance. That Cache instance (backed by your distributed/enterprise caching product's API) will be used to store and retrieve sessions for all of the SessionDAO CRUD operations.

Ehcache + Terracotta

One such distributed caching solution that people have had success with while using Shiro is the Ehcache + Terracotta pairing. See the Ehcache-hosted Distributed Caching With Terracotta documentation for full details of how to enable distributed caching with Ehcache.
Once you've got Terracotta clustering working with Ehcache, the Shiro-specific parts are very simple. Read and follow the Ehcache SessionDAO documentation, but we'll need to make a few changes
The Ehcache Session Cache Configuration referenced previously will not work - a Terracotta-specific configuration is needed. Here is an example configuration that has been tested to work correctly. Save its contents in a file and save it in an ehcache.xml file:
TerraCotta Session Clustering

    "localhost:9510"/>
"java.io.tmpdir/shiro-ehcache"/> "10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="false" diskPersistent="false" diskExpiryThreadIntervalSeconds="120"> "shiro-activeSessionCache" maxElementsInMemory="10000" eternal="true" timeToLiveSeconds="0" timeToIdleSeconds="0" diskPersistent="false" overflowToDisk="false" diskExpiryThreadIntervalSeconds="600">
Of course you will want to change your <terracottaConfig url="localhost:9510"/> entry to reference the appropriate host/port of your Terracotta server array. Also notice that, unlike the previous configuration, the ehcache-activeSessionCache element DOES NOT setdiskPersistent or overflowToDisk attributes to true. They should both be false as true values are not supported in clustered configuration.
After you've saved this ehcache.xml file, we'll need to reference it in Shiro's configuration. Assuming you've made the terracotta-specificehcache.xml file accessible at the root of the classpath, here is the final Shiro configuration that enables Terracotta+Ehcache clustering for all of Shiro's needs (including Sessions):
shiro.ini for Session Clustering with Ehcache and Terracotta
sessionDAO = org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
# This name matches a cache name in ehcache.xml:
sessionDAO.activeSessionsCacheName = shiro-activeSessionsCache
securityManager.sessionManager.sessionDAO = $sessionDAO

# Configure The EhCacheManager:
cacheManager = org.apache.shiro.cache.ehcache.EhCacheManager
cacheManager.cacheManagerConfigFile = classpath:ehcache.xml

# Configure the above CacheManager on Shiro's SecurityManager
# to use it for all of Shiro's caching needs:
securityManager.cacheManager = $cacheManager
And remember, ORDER MATTERS. By configuring the cacheManager on the securityManager last, we ensure that the CacheManager can be propagated to all previously-configured CacheManagerAware components (such as the EnterpriseCachingSessionDAO).
Google Java Interview - May 2013

When I was a college senior I applied for a job at Google. During the in-person interview, the interviewer asked me to find the median of an infinite series of numbers and I just stared at the board, having no idea what to do. Every idea I came up with that was reasonable for a finite series fell flat when faced with an infinite series.
After one more excruciating (but less memorable) interview, they politely showed me out.
So, I was a bit nervous this time around. However, I am pleased to report that I never was at a loss for what to do and all of the questions seemed pretty fair and reasonable. Most of the questions were basically variations on things in Cracking the Coding Interview, so I figured I’d share them. I got a few more creative questions which are not listed below (I don’t want to ruin a anyone’s “personal” question) but they weren’t any harder or easier than the others.
Note: if you’re planning to interview somewhere soon, you might want to save this, do your other prep, and then go through these questions as a mock-interview.
Here’s what I was asked:
  • Given this weird tree-like thing:
    semitree
    Find greatest sum on a path from root to leaf (that can only touch one node per level—no going up and down).
    I did a recursive solution that was about six lines long and then she asked me to come up with a way to do it iteratively.
  • Consider a power series:
    a0 + a1x + a2x2 +
    Suppose we have an interface as follows to get the coefficients: a0, a1, a2, etc:
1.class PowerSeries {
2.public:
3.virtual double next();
4.};
You can take the product of two power series:
(a0 + a1x + a2x2 +) * (b0 + b1x + b2x2 +)
Implement next() so it gives you the next coefficient in the product of two power series:
1.class PowerProduct : public PowerSeries {
2.public:
3.PowerProduct(PowerSeries* A, PowerSeries* B);
4.virtual double next();
5.};
  • Reverse bytes in an int.
    This was in my last interview of the day, and mental fatigue had reduced me to such a state that I assumed four bits in a byte. I don’t even know where that came from, but that was really embarrassing when I realized it (well after the interview).
  • Write a function to find if a set A is subset of a set B, B is a subset of A, the two sets are equal, or none of the above (you are allowed to use set operations like union and intersection).
  • Part 2 of the previous question: suppose you are given a list of sets. You wish to filter out any set in the list that are a subset of another set in the list. Use your solution from above to find the smallest possible result list as efficiently as possible.
  • Implement atoi (convert a string to an integer).
  • Given a string, find the logest substring of only two distinct characters. For example, given “aabacccaba”, you would return “accca”.
  • Design a cache.
  • Suppose you are on a Cartesian coordinate system. Find all paths from (0,0) to (m,n) that only go through each point once. For example, if you were given m=2, n=2, you’d have the following:
    paths
    This would be one possible path:
    paths2
    Return the number of possible paths. Then extend for negative coordinates.
  • Given two integers, a and b, find the smallest square integer in the range (or return -1, if there is no such square)

Thursday, December 26, 2013


Question for Sr Java Developer @ Google

Find the nearest common parent of two nodes of a binary tree?


Start with an ordinary depth-first search algorithm:
public void find(Node node, int target) {
    if(node == null || node.value == target) {
        return node;
    }
    if(node.value > target) {
        return find(node.left, target);
    } else {
        return find(node.right, target);
    }
}
Now, adapt this to take two "target" parameters, target1 and target2.
When the search for target1 takes you left, and the search for target2 takes you right, you've found the LCA.
This assumes that both targets actually do exist. If you need to assert that they do, you'll need to continue the search after finding the potential LCA.
public void findLca(Node node, int t1, int t2) {
    if(node == null) {
        return null;
    }
    if(node.value > t2 && node.value > t1) {
        // both targets are left
        return findLca(node.left, t1, t2);
    } else if (node.value < t2 && node.value < t1) {
        // both targets are right
        return findLca(node.right, t1, t2);
    } else {
        // either we are diverging or both targets are equal
        // in both cases so we've found the LCA
        // check for actual existence of targets here, if you like
        return node;
    }
}