Julian Jewel’s Weblog Welcome to my weblog();
Browsing all posts in: Server-Side Architecture

Spring Integration

July 17

We needed a really light weight ESB and we were evaluating Mule, ServiceMix and finally decided to write our own Spring based service bus. And it ended up working great for us. At that time, the Spring Integration was just being developed. I was looking into the Spring Integration and looks like it is very endpoint / channel based. We wrote a component based service bus, that would just intercept, transform and invoke a service. Spring Integration is neat and flexible, but I’m not sure how the polling channel model would perform. Also we have services that communicate synchronously, but I’m not sure if there is a way to define a request/response type of architecture with Spring Integration. Looks like it is necessary to implement an input and output channel for every messaging pattern like transformer, router, etc.

ORA-06512: at “SYS.SCN_TO_TIMESTAMP”

March 2

We have a cache synchronizer which uses the SCN_TO_TIMESTAMP(ORW_ROWSCN) in one of our queries to check for the recently modified records and updates the cache. The problem with the SCN_TO_TIMESTAMP(ORA_ROWSCN) is that the SCN’s are only valid for 5 days.

So a query like SELECT SCN_TO_TIMESTAMP(MAX(ORA_ROWSCN)) from SOME_TEST_TABLE; will return correctly if the recent ORA_ROWSCN was created in the last 5 days. Or you would get the following error.

java.sql.SQLException: [BEA][Oracle JDBC Driver][Oracle]ORA-08181: specified number is not a valid system change number
ORA-06512: at "SYS.SCN_TO_TIMESTAMP

Luckily we had a MODIFIED_DATE column that our application updates whenever a record is modified. So we ended up using that.

Spring Quartz Vs. JDK Timer

February 27

We ended up using the JDK timer, since

  • it was easy to use
  • calling an EJB
  • instantiated once (quartz instantiates the job everytime)

One nice thing about the JDK timer, even if task is scheduled at a certain time, it would not execute if an existing task is running. Also its thread-safe, since only one task is executing at a time.

More information at -
Task Scheduling – Spring Framework Documentation

JMS Redelivery / Rollback

February 26

We use Weblogic JMS for processing requests asynchronously. We also have an audit log, which writes the request/responses to the database. On a rollback scenario, we would like to audit the exception information. With the container managed transaction scenario, the JMS and JDBC transactions participate in a two phase commit. If the database is down, then the JMS message is rolled back and retried at some later point of time, as configured in the redelivery delay parameters. Now the exception information is logged in the console, but we could not get this into our audit logs because if we catch the exception then the database rollback would not happen. If we catch and re-throw then we could do a non-transactional write of the audit log or our exception handling could be part of a new transaction. But if the exception handling logic writes to the database, and we wish to rollback and retry both transactions, it would not be possible. The getJMSRedelivered() in the JMS message can help figure out if the message was redelivered. If you are using Weblogic, JMS_BEA_RedeliveryLimit and JMS_BEA_DeliveryTime message headers can help determine some information about the redelivery of the message. But it still would not solve the redelivery audit issue.

Distributed Transactional Caching

February 24

We use Ehcache and Hibernate in our product. We also use the custom cache implementations for loading frequently used objects into memory. One problem with the cache implementation is that it does not support transcational caching. We tried using OsCache, but it was quite limiting in its configuration. We decided to extend EhCache to support a transactional distributed cache. Since our application runs within a J2EE server, we decided to use JMS. We faced a problem initially, when a transaction would get rolled back, but the element would be inserted into the cache. We were using the cache.put() api, which updated the local cache even on a rollback. Instead of using cache.put(), we started manually notifying the cache listeners. We also created our own Jms cache peers, peer providers,  peer replicators and peer provider factories.
    public static void notifyCacheListenerRemove(final Cache cache,
           
final Object key) {
       
if (ValidationUtil.isEmpty(cache)) {
           
return;
       
}

        if (ValidationUtil.isNotEmpty(cache.getCacheEventNotificationService())
               
&& ValidationUtil.isNotEmpty(cache
                        .getCacheEventNotificationService
()
                       
.getCacheEventListeners())
               
&& ValidationUtil.isNotEmpty(cache
                        .getCacheEventNotificationService
()
                       
.getCacheEventListeners().size() > 0)) {
           
final Iterator<CacheReplicator> it = cache
                    .getCacheEventNotificationService
()
                   
.getCacheEventListeners().iterator();
           
while (it.hasNext()) {
               
final CacheReplicator replicator = it.next();
               
if (ValidationUtil.isEmpty(replicator)) {
                   
continue;
               
}
               
if (cache.isKeyInCache(key)) {
                   
replicator.notifyElementRemoved(cache, cache.get(key));
               
}
            }
        }
else {
           
cache.remove(key);
       
}
    }

    public static void notifyCacheListenerPut(final Cache cache,
           
final Element element) {
       
if (ValidationUtil.isEmpty(cache) || ValidationUtil.isEmpty(element)) {
           
return;
       
}

        if (ValidationUtil.isNotEmpty(cache.getCacheEventNotificationService())
               
&& ValidationUtil.isNotEmpty(cache
                        .getCacheEventNotificationService
()
                       
.getCacheEventListeners())
               
&& ValidationUtil.isNotEmpty(cache
                        .getCacheEventNotificationService
()
                       
.getCacheEventListeners().size() > 0)) {
           
final Iterator<CacheReplicator> it = cache
                    .getCacheEventNotificationService
()
                   
.getCacheEventListeners().iterator();
           
while (it.hasNext()) {
               
final CacheReplicator replicator = it.next();
               
if (ValidationUtil.isEmpty(replicator)) {
                   
continue;
               
}
               
replicator.notifyElementPut(cache, element);
           
}
        }
else {
           
cache.put(element);
       
}
    }

Julian is one of the country’s foremost experts in software design, process, and construction. He regularly speaks at major technical conferences. Not only is Julian an expert architect and programmer, he excels at passing his knowledge on to others as both a consultant and educator.

Having worked as a CTO, Julian is also in a unique position to assess and improve both your software and your software-development process. If you’re a nontechnical CEO, he can help you bootstrap your startup or analyze (and help you improve) your existing software organization. He regularly does one-on-one CEO and CTO-coaching sessions, and can train individual teams and entire departments on Object-Oriented design/UML, Agile process, and languages.