Quantcast
Channel: Nicholas Hagen » Web Application
Viewing all articles
Browse latest Browse all 3

Handling Environments in Java EE Projects

$
0
0

Web applications in Java EE (and even SE) have many components from MDB configuration to JMS configuration to Servlet configuration to JPA/database configuration. Each of these components has their own methodology of configuration. Further, some are easier to manage than others. The reason this is important is when it comes to managing your environments from development to test to production. The most ideal situation is a single build and archive (WAR, EAR, etc) that you can deploy to any environment and change the settings at the container level. This blog article hopes to explain some methods of managing those configurations.

Servlets

The first piece of configuration we will talk about is servlets. Typically, you will not change servlet paths from one environment to another, but there are certain occasions where you will need to. The problem is that there is no way to do substitution parameters in web.xml. One way I found to do this is by using the new servlet-based methods to dynamically add servlets. The Servlet 3.0 specification allows you to add servlets dynamically during startup, typically as part of a Servlet Context Listener.

@WebServletContextListener 
public class MyServletContextListener implements ServletContextListener { 
    public void contextInitialized(ServletContextEvent event) { 
        // create servlet instance
        MyServlet servlet = new MyServlet();
 
        // get current environment
        String env = System.getProperty("env.name");
 
        // configure servlet per environment (dev, test, prod, etc)
 
        // register and configure the servlet
        ServletRegistration.Dynamic reg =
            event.getServletContext().addServlet("MyServlet", servlet);
        reg.setLoadOnStartup(1);
 
        // configure mapping based on environment
        String mapping = null;
        if ("dev".equals(env)) { mapping = "devctx"; }
        if ("test".equals(env)) { mapping = "testctx"; }
        else { mapping = "prodctx"; }
        reg.addMapping(mapping);
    } 
 
    public void contextDestroyed(ServletContextEvent event) { 
        // ...
    } 
}

Servlets must only be added dynamically during startup through a servlet context listener. For more information, see the JavaDocs. Another idea would be to use a custom servlet that acts as a delegate but allows parameter substitution. In this situation, you could use variables such as ${property} within init-param values. The delegating servlet could then load those parameters and substitute system properties for the variables before passing onto the corresponding servlet.

Persistence Units (JPA)

There are two was to use JPA in a Java EE application. The first is using @PersistenceContext to inject an EntityManager into a bean. The second is to directly use Persistence.createEntityManagerFactory. In either scenario, JPA loads a matching META-INF/persistence.xml. Within the persistence unit there are two ways to configure the associated database data source. The first is using JNDI sources. In this case, the container manages the actual configuration which is the best option as you would configure each container differently per environment. However, if that is not a possibility for your scenario (such as using a standard SE application or simple web application), then you can use substitution values to override the persistence unit properties. For example, when using Hibernate as the implementation to JPA, you must configure the hibernate.connection.url which would be different per environment. The Persistence.createEntityManagerFactory method has a form that takes two arguments: the unit name and a set of override properties. The second argument can be used to override or add properties to the persistence unit properties. For example, you could pass the system properties as the second argument and then define the overrides as system properties.

EntityManagerFactory emf = Persistence.createEntityManagerFactory("DataSource", System.getProperties());
EntityManager em = emf.createEntityManager();

On the actual command line, you could define the property such as: -Dhibernate.connection.url=jdbc:..... That will then override the URL setting in the persistence unit. Each environment would pass a different option.

MDB Queues

MDBs and their resource adapter counterparts often times require a configuration for the actual JMS environment (hostname, port, etc). These settings would once again be environment specific. The problem is that the configuration is usually part of an EJB configuration file or using annotations. The nice thing is that some containers allow some of these options to use substitution expressions using system properties. For more information and specific examples for Glassfish, see the blog article on The power of System properties substitution in Glassfish. Other containers such as JBoss, Websphere, etc offer similar support. Consult your individual container for more information.


Viewing all articles
Browse latest Browse all 3

Latest Images

Trending Articles



Latest Images