Sunday, 26 June 2011

Integrating: Jetty, Spring, AspectJ, Wicket, Hibernate, MySQL, ActiveMQ and Atomikos (web archive scope)

Overview


The Spring framework has long provided an attractive alternative to J2EE application servers (especially prior to the arrival of JavaEE 6). Development teams often opted to go for a setup that uses Spring to manage the application context, coupled with a plain Servlet/JSP container and a good ORM solution.

Indeed, the "Jetty/Tomcat + Spring + Hibernate" stack has served many projects. As growth and complexity kicks in, things like JMS and (not long after that) XA transactions, start becoming a necessity.

It is at that point that teams start discussing the use of an application server, in order to gain a "certified" stack that combines all of the above (and more) facilities. However, some teams want to keep on using the "roll your own" path, by adding these aspects into the mix.

In this entry I will describe a setup that combines the most common JEE APIs using a custom assembly of components. The setup comprises of:

  • Jetty 7.3.1 (Servlet/JSP)
  • Spring 3.0.5 (CDI)
  • AspectJ 1.6.10 (because it is cool)
  • Atomikos 3.7.0 (JTA with XA support)
  • Hibernate 3.6.0 (JPA)
  • ActiveMQ 5.5.0 (JMS)
  • MySQL (JDBC, using driver 5.1.15)

Note that all of the above are integrated at the Web Archive level (i.e. the libraries are all included in WEB-INF/lib with nothing placed in the JVM classpath). This is because I often choose to "embed" Jetty when working in this mode, using my own custom launcher.

The basics: a Spring-enabled WAR, with Wicket managing the presentation


Since we will use Spring to inject all of the resources (JTA, JDBC connections, JPA Persistence Units, JMS, ...), the first step is to create a Spring-enabled WAR. In this step, we will also integrate Apache Wicket to take over page generation (sorry, but I have long hated JSF and JSP with a passion, so these are the first thing I want to get rid of.

So, we start by updating our web.xml as follows:




 My own near-JEE stack

 
  Wicket mode (development/deployment)
  wicket.configuration
  
  
  development
 

 
  my.app.filter.wicket
  org.apache.wicket.protocol.http.WicketFilter
  
   applicationClassName   my.Application  
 
 
  
  my.app.filter.wicket
  /*
 

 
  Main Spring context configuration file
  contextConfigLocation  
  /WEB-INF/applicationContext.xml
 

 
  
  org.springframework.web.context.ContextLoaderListener
 

 
  BASIC
 


This is all that is needed for web.xml. The rest of the magic lies totally within Spring's configuration file (/WEB-INF/applicationContext.xml).




 
 

 
 

 
 

 
 



Note that the references to META-INF/spring/... are presented in the following sections.

Adding the Atomikos JTA implementation


The next step is to create the META-INF/spring/tx-services.xml where we instantiate the Atomikos transaction manager and bind it as our JTA implementation. Note that this is where we need to explaing to Spring that we are using AspectJ and therefore the @Transactional annotation must be handled via @Configurable at the class implementation level.




 
 
  
  
 
 
 
  
 

 
 
  
  
 

    
        
    

    
    


Integrating ActiveMQ as a JMS provider that uses Atomikos for transaction management


The next step is to create the META-INF/spring/jms-services.xml where we define the ActiveMQ broker and tell it to interact with Atomikos for participating in transactions...




 
 
  
  
         
    
   
  
  
   
    
    
    
    
    
    
   
  
 

 
 
  
  
  
 

 
  
   
  
  
   
  
 

 

 
  
  
 

 

 
  
 


Integrating Hibernate as a JPA provider that uses Atomikos for transaction management


Last but not least, the META-INF/spring/db-services.xml will add Hibernate to the mix, telling it to interact with Atomikos for participating in transactions.

Important Note 1: that I have a lot of ${database.variable} that I usually load from a property file; you should replace this with whatever values are suitable for your case.

Important Note 2: The hibernate.transaction.factory_class is explicitly shown as commented out, as I have seen quite a few people using it (due to picking up old Atomikos documentation) when it is NO LONGER NEEDED for things to work properly (see the Atomikos forum thread referenced in the comment).




 
  XADBMS
  
   com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
  
  
   
    ${database.url}
    ${database.username}
    ${database.password}
   
  
  
  
  

 

 
 
  
   
  
 

 
    
        
        
        
            
                
                
                
            
        
        
            
                
                 org.hibernate.cfg.ImprovedNamingStrategy
                
                
                 ${database.hibernate.hbm2ddl}
                
                
                
                    com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup 
                 
            
        
    


Important Note 3:Remember to use JTA mode for transactions in your persistence.xml, as in:


...

Friday, 24 June 2011

Spring exception translation with AspectJ: bug workaround

One of the nice features of Spring is the database access exception translation that simplifies error-handling. Most of us enabled it by adding the PersistenceExceptionTranslationPostProcessor (see the Exception translation in the Spring reference).

Unfortunately, when using a "pure-AspectJ" approach, you will find that the out-of-the-box JpaExceptionTranslatorAspect does not recognize the various JPA dialects out there. I was pretty dissappointed when I found that JPA access from @Configurable object instances does NOT undergo "proper exception translation".

Thanks to Martin Deinum's feedback I quickly "restored" this limitation by creating a custom aspect to invoke the "proper" exception translator (which in my case is the HibernateJpaDialect).

So, until this bug is resolved, the following aspect will take care of things:

import org.springframework.dao.DataAccessException;
import org.springframework.orm.jpa.vendor.HibernateJpaDialect;

public aspect HibernateJpaDialectExceptionTranslationAspect {
    pointcut entityManagerCall(): call(* javax.persistence.EntityManager.*(..)) || call(* javax.persistence..EntityManagerFactory.*(..)) || call(* javax.persistence.EntityTransaction.*(..)) || call(* javax.persistence.Query.*(..));
    
    after() throwing(RuntimeException re): entityManagerCall() {
     HibernateJpaDialect hibernateDialect = new HibernateJpaDialect();
     DataAccessException dex = hibernateDialect.translateExceptionIfPossible(re);

     if (dex != null) {
      throw dex;
     } else {
      throw re;
     }        
    } 
}

Sunday, 12 June 2011

JDeveloper 11g 11.1.2 is out with Maven support (among others)

Oracle have released Oracle JDeveloper 11g, version 11.1.2.0.0. Among other new features, such as JSF 2, my favorite is the Maven 2 integration!

Check it out! Download is available (as usual) from the technet site!

IMPORTANT NOTE: SOA & WebCenter are NOT yet available for this release, so you must stick 11.1.1.5 for such projects.

Friday, 27 May 2011

Using Beehive code (BEA WebLogic <=10.3.1) with recent versions of Oracle WebLogic

Recent versions of the WebLogic Server no longer ship with Beehive libraries. As a result, old code that was based on Beehive must ne re-written so as to remove this dependency.

If you simply must deploy a Beehive project on a newer WebLogic Server, there is way to achieve that. Oracle will NOT support it of course, but if you decide to take the risk and go ahead with this anyway, here is how to do it:

  1. Locate the library "wlw-system.jar" in your old WebLogic installation. Copy it to the library folder of your target domain (the one that is based on a newer WebLogic version that does not have Beehive). The folder is ${DOMAIN_HOME}/lib
  2. Restart your domain's servers (in order to pick up the wlw-system.jar in their classpath)
  3. Using workshop, look up the WebLogic shared libraries that your project uses. These are listed in the project properties at "Java Build Path --> Libraries"
  4. For each shared library go to your Workshop preferences under "WebLogic-->Shared Libraries" and click "Edit.." to see the location of the library. Copy all of the EAR/WAR archives for these libraries into some "staging" folder (e.g. /home/yourusername/app-libs)
  5. Deploy all of the archives (EAR/WAR) that you located in the steps above as shared libraries in your new domain

You may now deploy your application on servers where the shared libraries were targeted.

Wednesday, 25 May 2011

Using a different HTTP proxy per each JAX-WS client stub

JAX-WS is about to standardize a web service feature, for specifying the use of a different HTTP proxy per each JAX-WS client instance. This can be extremely useful in complex enterprise IT environments, where network security teams are often paranoid and have different proxies for accessing different parts of the network. No longer do you need to host applications modules on different VMs just because they require different proxy settings. Instead of using the global http.proxyHost and http.proxyPort, you can specify a different proxy per JAX-WS client stub.

Since OFM 11gR1 Patchset 2, one can already exploit this upcoming JAX-WS feature, using WebLogic's ClientProxyFeature API. The approach is described in WebLogic's API Reference.

Although the documentation is pretty straight-forward, it fails to address the fact that the JAX-WS stack will try to retrieve the WSDL during the service instantiation, which leads to the following problem: since the ClientProxyFeature only applies at the web service port level, the following will fail:

// The service location is a runtime configuration value...
    URL wsdlURL = new URL(System.getProperty("serviceLocationAtRuntime"));

    // The below will try to fetch the WSDL from the wsdlURL location
    // The proxy is NOT in effect at this point and will cause a network error
    Service myService = new Service(wsdlURL, ...);

    // The code will never reach this point; so much for ClientProxyFeature
    ClientProxyFeature cpf = new ClientProxyFeature();
    cpf.setType(Proxy.Type.HTTP);
    cpf.setProxyHost(CONFIG.getProxyHost());
    cpf.setProxyPort(CONFIG.getProxyPort());
    servicePort = myService.getServiceSoap(cpf);

The solution is to bundle the WSDL as a resource in your application and instantiate the service using the local copy of the WSDL. Then, after enabling the proxy, you can set the runtime service address via the BindingProvider API.

// Don't go over the network to fetch the WSDL; use it from the classpath
    URL wsdlURL = Service.class.getResource("Service.wsdl");

    // The below will work, but will assume the service address is whatever
    // was defined in your application-bundled WSDL, so we still need to
    // somehow define a run-time location; keep reading to see how we do this
    // after getting the service port
    Service myService = new Service(wsdlURL, ...);

    // Enable the use of an HTTP proxy for this specific port instance
    ClientProxyFeature cpf = new ClientProxyFeature();
    cpf.setType(Proxy.Type.HTTP);
    cpf.setProxyHost(CONFIG.getProxyHost());
    cpf.setProxyPort(CONFIG.getProxyPort());
    servicePort = myService.getServiceSoap(cpf);

    // Now that we have the port, configure the service address using
    // a run-time value:
    URL wsdlURL = new URL(System.getProperty("serviceLocationAtRuntime"));
    BindingProvider bp = (BindingProvider)servicePort;
    bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
        wsdlURL.toString());

    // You can now call the web service via the HTTP proxy
    servicePort.invokeSomeOperation(...);

Wednesday, 18 May 2011

Mental note to myself # 8734874243

Oracle SOA Suite 11g -- Repository notes


...because I always forget, let me put these down for my future reference!

Status values for composite instances



The following values are used for the CUBE_INSTANCE.STATE column of SOA Suite's "SOAINFRA" schema.

OPEN states CLOSED states
INITIATED PENDING_CANCEL
RUNNING COMPLETED
SUSPENDED FAULTED
FAULTED CANCELED
ABORTED
STALE

Some SQL to quickly review statistics regarding the state of composite instances within some time window:

SELECT
  CASE state
    WHEN 0 THEN 'initiated'
    WHEN 1 THEN 'open.running'
    WHEN 2 THEN 'open.suspended'
    WHEN 3 THEN 'open.faulted'
    WHEN 4 THEN 'closed.pending_cancel'
    WHEN 5 THEN 'closed.completed'
    WHEN 6 THEN 'closed.faulted'
    WHEN 7 THEN 'closed.cancelled'
    WHEN 8 THEN 'closed.aborted'
    WHEN 9 THEN 'closed.stale'
    ELSE 'huh?'
  END state_text,
  COUNT (*)
FROM cube_instance ci
WHERE ci.creation_date >= (:startdate) AND ci.creation_date < (:enddate)
group by ci.state;

Status of “recently created” composite instances


What's going on with recently created instances?
SELECT
  CIKEY, STATE, CREATION_DATE, MODIFY_DATE, STATUS, 
  COMPOSITE_NAME, COMPONENT_NAME, COMPOSITE_REVISION, DOMAIN_NAME
FROM cube_instance 
WHERE creation_date >= SYSDATE-1 AND STATE < 5 AND ROWNUM < 20
ORDER BY creation_date DESC;

Status of “recently updated” composite instances


What's going on with recently updated instances?
SELECT
  CIKEY, STATE, CREATION_DATE, MODIFY_DATE, STATUS,
  COMPOSITE_NAME, COMPONENT_NAME, COMPOSITE_REVISION, DOMAIN_NAME
FROM cube_instance 
WHERE creation_date >= SYSDATE-1 AND STATE < 5 AND ROWNUM < 20 
ORDER BY modify_date DESC;

Tuesday, 26 April 2011

BoneCP: a promising new connection pooling library

For a long time, we've been stuck with C3P0 and DBCP in the Java connection pooling arena. These tools, each with its own problems, have served us rather well. Competition from "newcomers" such as Proxool does not seem to have made much difference. At least this is what Google Trends comparison indicates.

BoneCP is a new contender in this area which has caught my attention. It is "Apache v2"-licensed, well-documented and (as far as I can tell from my limited use so far) stable and fast.

If you're looking for a C3P0/DBCP alternative it's worth giving a try. The only thing I am rather "nervous" about is the size of its community. It seems to be maintained by few individuals, but so are most new OSS projects prior to gaining wider acceptance.

So go ahead and have a look.