miércoles, 18 de abril de 2007

Managing JPA: Spring vs EJB3

With the arrival of the first commercial Java EE 5 application server (Weblogic 10) a production quality EE option to manage JPA is available. As a matter of fact, day by day I'm more comfortable with Glassfish but unfortunately it lacks the sales punch of Bea or IBM. As an architect it's a good question to determine what are the differences between a EJB3 approach versus a pure (lightweight) Spring approach and how and where to use one or the other.

As a side note, if the deployment target will be Weblogic 10+ then reading the Pitchfork Project documentation is advisable as some nice tricks can be performed.

First of all let's describe how a SLSB EJB3 likes to manage persistence. As you can imagine the entity classes stay the same and the bean will serve as a facade. Everything is then packed in an EAR file that usually contains a WAR file (for the screens), a JAR file for the EJBs and another JAR file inside the lib directory (for common libraries) with the entities. A simple code example of the implementation class:

public abstract class AbstractCRUD implements CRUD {

   protected abstract EntityManager getEntityManager();

   public void create(Object entity) {
      getEntityManager.persist(entity);
   }

   ...
}

@Stateless
@Local(GenericCRUD.class)
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class GenericCRUDImpl extends AbstractCRUD implements Serializable {

   @PersistenceContext private EntityManager em;

   public EntityManager getEntityManager() {
      return em;
   }
}

The code above is simple. All the implementation logic has been moved to an abstract class (reusable later). The EJB just indicates how it should be deployed, how to obtain the EntityManager from the context or how to mange security and transactions. It's easy to see how much EJB3 has improved the developing experience. As Spring the EJB3 specification uses annotations and dependency injection. Here's a little list with pros/cons of this EJB3 approach:

ProsCons
Extremely easy to codeForces an EAR deployment
Extensive use of annotationsDI just for container managed classes
Declarative transactions and securitySeveral business layers
Optional deployment descriptorsLooses lazy loading when accessed remotely
Local or remote deployments 
Standards based 

Spring approach is different. As always they enforce a lightweight, POJO based, solution (EJBs now are as similar to a POJO as possible). They offer three distinct possibilities (and the best of all is that they're easily intechangeable by configuration):
  • The JPATemplate: Specialy useful when upgrading from other templates (ie Hibernate). Here's an use explanation by Inteface 21 themselves. It has two downsides IMHO, it's Spring dependent (invasive) and it uses inline functions (which I tend to dislike)
  • The LocalContainerEntiyManagerFactoryBean: Or converting the Spring context in a JPA container (!). As in the first case it allows declarative transactions and it adds the capability to parse @PersistenceContext for EntityManager injection. Here's another explanation
  • Leveraging the JTA (container) EntityManager. Spring will integrate with the AS and use the containers facilities.
I will go in a little more detail with the last one as it really shines in a JEE5 environment. The first thing to achieve is making Spring aware of the JTA environment so it can fetch and inject the PersistenceContext and EntityManager. This is done at the end of the web.xml file (see the schema):

<persistence-unit-ref>
   <persistence-unit-ref-name>persistenceUnit</persistence-unit-ref-name>
   <persistence-unit-name>persistenceEJBPU</persistence-unit-name>
</persistence-unit-ref>

The EntityManager should be published in the registry by now so Spring can get a hook. Add the following to the XML configuration:

<jee:jndi-lookup id="entityManagerFactory" jndi-name="java:comp/env/persistenceUnit"/>

<bean class="org...jpa.support.PersistenceAnnotationBeanPostProcessor"/>

<bean id="transactionManager" class="org...jta.JtaTransactionManager">

<tx:annotation-driven/>

That's all the configuration that is need. Two steps are still missing, the first one making your controllers (or beans in general) transactional and the second inject the EM into the DAO/s. To solve the first issue the easiest way is to annotate the bean with @Transactional, Spring's magic will do the rest and the bean will join/create a JTA transaction. The second is solved by using the @PersistenceContext annotation.

public class SpringCRUDImpl extends AbstractCRUD {

   private EntityManager em;

   @PersistenceContext
   public void setEntityManager(EntityManager em) {
      this.em = em;
   }

   protected EntityManager getEntityManager() {
      return em;
   }

}

As you see it's again very easy as the actual code is the same as the EJB3, just the way to get the EntityManager varies.

Now we are in disposition to answer the initial question. Which technology fits better? And I'm going to give a response. Both! Just use both! Leverage the fact that the same implementation works for both cases and create two facades, use the EJB3 facade for container managed classes (like filters or servlets) and Spring for your beans. Both parts work well together and Spring can join a transaction created by an EJB3 and viceversa. Nice, isn't it?

martes, 10 de abril de 2007

Thread safe controllers in Spring MVC

Reading the Javadoc for the Controller interface of the Spring MVC framework, at the very beginning it is written:

Any implementation of the Controller interface should be a reusable, thread-safe class, capable of handling multiple HTTP requests throughout the lifecycle of an application.

I'll bypass the reusable part as is obvious (it's a controller!). But, by now, nobody should be unaware about the need of writing thread safe controllers. Of course, it can be asked why? In fact not just the MVC but all the context should be able to handle concurrent accesses adequately. It's explicitly stated for controllers because they work in an environment where collisions are not possible but usual. And thread-safety is just that, enabling the objects to work correctly in multi-threaded environments.

In practice, building a thread safe controller is easily achieved (unless the bean starts doing weird things) if:
  • The bean subclasses a framework class (ie. SimpleFormController or MultiActionController)
  • The beans and their dependencies are stateless
Take into account that these requirements can be very simple to fulfill as Spring beans always work better as stateless services.

But even if that's not possible Spring 2.0 offers a new solution with the new scopes. Defining a Controller as request scoped will execute the Controller in a thread safe way. Of course, probably some of the dependencies will have to be declared with the same scope as nothing will be achieved if the state is saved across different beans. In addition, the old Java way of using the synchronized keyword would also work. Unfortunately, both seem like "last resort" solutions and come with a performance penalty (and it can be a pretty big hit).

So the problems can come (most easily) when:
  • A direct implementation of controller is made
  • It's a singleton bean
  • No specific concurrency control is applied
  • The bean or its dependencies access and modify global resources (a class variable for example) or save state information
Otherwise everything, at least at first sight, looks to be in good shape. But if it fits the requirements a special treatment is in order. First of all, the bad news, ensuring a method is thread safe can be quite complex. So much so, that probably the average programmer won't qualify. In fact concurrency/threads/locks is probably the most complex area in development today and Java helps...but doesn't solve the problem. This are some useful code tips:
  • Declare the method parameters as final if possible
  • Local variables are always thread-safe
  • Understand the volatile keyword
  • Setters and getters are points to check
  • Avoid modifying global variables during method execution
  • Check subroutines as well
  • Be careful with synchronized. It's a solution but can cause multiple side effects (and nasty ones like deadlocks)
  • Use AOP proxies for dependencies that hold state info
  • Remember that Java collections (and others) are not thread safe by default!
  • Dependency Injection works better if the objects are wired at initialization and are treated like immutables onwards (final again)
  • Understand the ThreadLocal class and its uses. A Filter that saves a ThreadLocal variable is a good start.
  • Abstractions offered by Spring (ie. transaction management) are thread safe
  • static has nothing to do with thread safety. Each static invocation should be analyzed

martes, 3 de abril de 2007

Create users programmatically in Weblogic 10

So I had to spent yesterday the whole morning trying to programmatically add a user to a Weblogic 10 security realm. The biggest problem I had to solve was the poor documentation available. It seems it was cut and pasted from the previous version and some things have changed. Not that much really but enough to create me some headaches.

The available code in 9.2 looked like this. The first step is dedicated to retrieve the DomainRuntimeService. Of course, the Weblogic 10 documentation on the topic says more or less the same. Unfortunately, that MBean isn't visible any more (or so it seems). In addition, Weblogic's documentation is clear requiring authentication before accessing the server management beans but the examples provided never show how to do it (it's done via JNDI authentication). Here's some working code for the 10th version:

public void init() throws Exception {
   env.put(Context.INITIAL_CONTEXT_FACTORY,
      "weblogic.jndi.WLInitialContextFactory");
   env.put(Context.SECURITY_PRINCIPAL, userName);
   env.put(Context.SECURITY_CREDENTIALS, password);
   env.put(Context.PROVIDER_URL, "t3://" + host + ":" + port);
   InitialContext ctx = new InitialContext(env);
   wls = (MBeanServer) ctx.lookup("java:comp/env/jmx/runtime");
   ObjectName MBTservice = new ObjectName( "com.bea:Name=MBeanTypeService," +
      "Type=weblogic.management.mbeanservers.MBeanTypeService");
   ObjectName rs = new ObjectName("com.bea:Name=RuntimeService," +
      "Type=weblogic.management.mbeanservers.runtime.RuntimeServiceMBean");
   ObjectName domainMBean = (ObjectName) wls.getAttribute(rs,
      "DomainConfiguration");
   ObjectName securityConfig = (ObjectName) wls.getAttribute(domainMBean,
      "SecurityConfiguration");
   ObjectName defaultRealm = (ObjectName) wls.getAttribute(securityConfig,
      "DefaultRealm");
   ObjectName[] atnProviders = (ObjectName[]) wls.getAttribute(defaultRealm,
      "AuthenticationProviders");
   for (ObjectName providerName : atnProviders) {
      if (userEditor == null) {
         ModelMBeanInfo info = (ModelMBeanInfo) wls.getMBeanInfo(providerName);
         String className = (String)
            info.getMBeanDescriptor().getFieldValue("interfaceClassName");
            if (className != null) {
               String[] mba = (String[]) wls.invoke( MBTservice, "getSubtypes",
                  new Object[] {
                    "weblogic.management.security.authentication.UserEditorMBean" },
                  new String[] { "java.lang.String" });
               for (String mb : mba)
                  if (className.equals(mb)) userEditor = providerName;
            }
         }
      }
   if (userEditor == null)
      throw new RuntimeException("Could not retrieve user editor");
   ctx.close();
}

An then users can be added with:

public final boolean createUser(final User user) {
   boolean retVal = false;
   try {
      ctx = new InitialContext(env);
      wls = (MBeanServer) ctx.lookup("java:comp/env/jmx/runtime");
      wls.invoke(userEditor,
         "createUser",
         new Object[] {
            user.getUserName(),
            user.getPassword(),
            user.getDescription()},
         new String[] {
            "java.lang.String",
            "java.lang.String",
            "java.lang.String"});
      ctx.close();
      retVal = true;
   } catch (Exception ex) {
      log.warn("Cannot create user (" + user + ")", ex);
   }
   return retVal;
}

So just one petition to Bea people...please update the documentation! :-)

domingo, 1 de abril de 2007

Setting up an Agile development environment

During the last week I had the opportunity to build a development environment from scratch, something that is rarely possible, as a lot of the clients tend to have infrastructures (and procedures) of their own. It was an amusing task as I could decide all the needed tools and how and when they would be used. I think this has been the first time really where I've started a project that includes everything that will be useful later!

So let's start talking about what I do consider an Agile environment. It is important as Agile is composed of several methods and not all of them can be applied to a project always. As a matter of fact only saying Agile can make a manage shudder! For example, Agile software development specifies that risk can be reduced if iterations (planning, requirements analysis, design, coding, testing and documentation) are used. That wasn't an option this time as all the design work was already done. A system based on (code) milestones was considered enough. So what are absolute necessities then?
  • Linux!
  • A powerful Source Code Management (SCM) tool like Subversion: A fantastic code repository where several developers can work at the same time (no locks), supports truly atomic commits, branching and merging, binary files, tags and different network protocols
  • A Continuous Integration Build tool (I like CruiseControl): This is fundamental! It allows to have a reliable repository at any time and it's the basement for other tasks. It ensures developers are always working with the latest artifacts
  • Test Development Environment (JUnit and Cobertura): It's like Test Driven Development without been a purist (tests first!). In my experience, no project can be under control after it reaches some critical mass unless the testing is somehow automatic.
  • Project Management tools (wiki, issue tracker, blogs, timelines...): I've worked with Jira, Trac and Scarab. All are good. Jira is outstanding tracking issues (but is commercial). Trac is a suite of tools and integrates nicely with Subversion.
  • Coding style: A lot of tools in the Java world can test the code. PMD, Checkstyle and Simian can be all recommended (and will help squashing bugs)
  • Netbeans and Glassfish: Have Eclipse & JBoss been outclassed by Sun?
  • Open Source Frameworks: At least Spring, Hibernate and DWR!
  • QALAB! To get nice reports on how everything has been going
  • And the usual crop of Weblogic (10!), Oracle and such...

Trying to build this kind of environment from scratch is difficult, belive me. But it is worth the effort. Fortunately, Buildix exists! Buildix is a Linux distro that installs and configures Apache, Tomcat, Subversion, Trac and Cruisecontrol for you. Add in the scripts (to manage users or to create projects) and the amount of time it can save is just awesome. Just install (from the FAQ: Log in as root and run knoppix-installer). Take in account that it comes with a price as doing it by yourself will let you select the suite of tools and get the latest available version of each tool (for example, Trac adds blogging in their current builds). But really, if it is the first time or your Linux skills are not that sharp, you are better off choosing Buildix.

Just one advice to conclude. Agile development enviroments are hard to install and to maintain, so use them! There's no point in having a wiki and not writing or not adding bugs to the database. This kind of installation offers a lot of possibilities to project managers, developers and, even, the client because they are valuable knowledge repositories. Use them as much as possible and keep track of how everything evolves.