[Debate] – And what about configuration in Java EE 7 ?
Join the DZone community and get the full member experience.
Join For FreeHow do you configure your enterprise application ? Or to be more precise “what is configuration, what can you configure in Java EE and how can you configure it ?“
What is configuration ?
Sometimes your application needs to change parts of its behavior at deployment time. You then need to provide some external configuration for some components. For example, in your development environment you don’t want to use a datasource and instead hit the database with a user & password, in your test environment you lookup for the datasource and use it. If you deploy your application in Europe you need to use the Euro as the current currency and if you deploy it in the US you need dollars. You’ve deployed your 2.3 version of your application and you want this “2.3” to appear at the bottom of your webpage as well as in your Swing Help->About menu. In a test environment everybody can access all the methods, in production security roles add certain restrictions. And so on and so forth…
In the Java EE specification there are several roles that deal with configuration (chapter 2.11) :
- Deployer : “During Configuration, external dependencies declared by the Application Component Provider are resolved and application assembly instructions defined by the Application Assembler are followed.”
- System Administrator : “The System Administrator is responsible for the configuration and administration of the enterprise’s computing and networking infrastructure.”
If you want to read more about configuration of the EE platform I suggest you read chapter 5 of the Java EE 6 spec.
How do we configure today ?
I first need to say that, thanks to Configuration by exception (or Convention over Configuration), you don’t need to add default configuration to your EE 6 application. Default behavior and default configuration allows most applications to get the behavior they want most of the time, without the use of either annotations or deployment descriptors. But when we need to configure our application, how do we do it today ? The EE platform has some (optional) deployment descriptors you can use such as :
- web.xml : you can configure parameters in your servlets with <context-param> or filters with <init-param>
- ejb-jar.xml : with the <env-entry> you can configure your EJBs
- application.xml : here you can configure some application specific information such as the context-root of the web application
- persistence.xml : it’s typically where you will configure the datasource or database access parameters
- application-client.xml, ra.xml, webservices.xml…
Usually these files are located under your WEB-INF or META-INF directory. You can then also use JNDI to access this configuration or create your own environment entries in the JNDI tree. Your methods can then access the environment using the JNDI interfaces and lookup methods on component-specific context objects (or with the @Resource annotation and the new lookup attribute @Resource(lookup="java:app/env/TheOrderQueue")). Since Java EE 6 there are several environment namespaces (java:comp, java:module, java:app, java:global). So the EE prefered approach are environement entries such as this ejb-jar.xml file :
<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee" version="3.2">
<enterprise-beans>
<session>
<ejb-name>MyEJB</ejb-name>
<ejb-class>org.agoncal.MyEJB</ejb-class>
<remote>org.agoncal.MyEJBRemote</remote>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
<resource-ref>
<res-ref-name>jdbc/employee</res-ref-name>
<jndi-name>jdbc/__default</jndi-name>
</resource-ref>
<env-entry>
<env-entry-name>aMessage</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>Hello World</env-entry-value>
</env-entry>
</session>
</enterprise-beans>
</ejb-jar>
Environment entries are seen as resources (you can inject them with @Resource) and they can be of any type : String, Object, JMS factories & destinations, datasources… In the code below I inject the datasource called jdbc/employee as well as a String called aMessage :
@Stateless
public class MyEJB {
@Resource(name="jdbc/employee")
private DataSource employeeDataSource;
@Resource(name="aMessage")
private String welcomeMessage;
...
}
With CDI, Qualifiers and Producers you could have the following code which makes use of the CDI typesafety :
@Stateless
public class MyEJB {
@Inject @EmployeeDS
private DataSource employeeDataSource;
@Inject @AHelloWorldMsg
private String welcomeMessage;
...
}
With CDI and Alternatives you can then inject an alternative value for welcomeMessage or a different datasource for the employeeDataSource. Alternatives can then be used to configure your application.
What’s missing ?
JNDI is cool… but can be of a drag when you use servlet containers such as Tomcat or when you do simple batch processing (you don’t want to access a remote JNDI tree) or simple Java class. And EE relies a lot on JNDI. If we look at EJBs, the world is changing : it went from a complex component model to a POJO that can run in an embedded container. So let’s treat it as a POJO.
In the code above, why do I have to treat the welcomeMessage as an environment entry I should lookup ? Why can’t I just treat it as a simple String in a POJO which value changes at deployment time? Datasources, JMS factories… are container resources, but not a welcome message. Going futher, if an EJB is a POJO as well as a Servlet a RESTful Web Service or a Managed Bean, why not just configure these component using the same configuration model ?
CDI brings alternatives and the possibility to inject alternative values. But again, why do I have to use @Produces (to produce a String for the welcome message), @Inject, @Alternative and a seperate class that gives me the value of the alternative welcome message, when I just want to configure externally the value of the String ?
What’s missing in Java EE is a simple way to configure your beans (and by bean I mean EJBs and so on).
What do we do next ?
Java EE 7 has started and we have 18 months to talk about it and make it happen. So why not having a more flexible configuration model in the platform. And because we don’t want to reinvent the wheel, let’s get some inspiration from Spring Config, or even better Seam Config (which makes even XML a bit more type-safe ;o) Taking my previous code example, I would not inject the welcomeMessage but just treat it as a simple String :
@Stateless
public class MyEJB {
@Inject @EmployeeDS
private DataSource employeeDataSource;
private String welcomeMessage;
...
@Stateless
public class MyEJB {
@Inject @EmployeeDS
private DataSource employeeDataSource;
private String welcomeMessage;
...
}
}
Then, if I want to configure the welcome message the Seam Config way I’ll have an external XML file (let’s reuse the ejb-jar.xml) and use new namespaces : here the namespace r refers to the package org.agoncal. So r:MyEJB referes to the class org.agoncal.MyEJB. So, as you can see r:welcomeMessage refers to the property org.agoncal.MyEJB.welcomeMessage in which we set the String Hello World :
<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:s="urn:java:ee:ejb"
xmlns:r="urn:java:org.agoncal" version="3.2">
<s:enterprise-beans>
<s:session>
<r:MyEJB>
<s:ejb-name>MyEJB</s:ejb-name>
<s:ejb-class>
<r:MyEJB/>
</s:ejb-class>
<s:remote>
<r:MyEJBRemote/>
</s:remote>
<s:session-type-stateless/>
<s:transaction-type-container/>
<r:employeeDataSource>
<r:ADifferentEmployeeDSQualifier/>
</r:employeeDataSource>
<r:welcomeMessage>Hello World</r:welcomeMessage>
</r:MyEJB>
</s:session>
</s:enterprise-beans>
</ejb-jar>
The namespace urn:java:ee:ejb is EJB Config’s root namespace (inspired from Seam Config). This is where the built-in elements live. Here I just give a simple (mayby non accurate) example of what configuration could look like, but if you look at Seam Config, you can configure nearly everything (lists, maps, references…).
And going further ?
Well, if an EJB is a POJO with specific services (transactional, thread safe, secure…) let’s consider it like a bean : a Managed Bean with sepecific services. So let’s declare it in the beans.xml (CDI file). Same for all the managed beans. At the moment there are several deployment descriptors. What about having the possibility to have a single one (as well as multiple like today) to configure the entire plaform ? Something like application.xml could be extended, or beans.xml.
Java EE 7 is going cloud, so why not use the same way to configure your nodes, instances, platform… ?
Let’s continue this debate
I’ve written this blog because I started a thread on the Java EE 7 mailing list on configuration. I’m not an expert on configuration but I can see the benefit of having something similar to Seam Config in the EE platform. Changing (or upgrading) the way we’ve been doing configuration throught environment entries is a huge work (look at all the deployment descriptors that we should have to extend). Is it worth it ? Do you care ?
Use this blog to post your comments or the Java EE 7 mailing list.
References
- Seam Config
- Former Spring Java Config
- Applicaction configuration in Java EE 6 using CDI – a simple example
- Configuring an Environment Reference to an Environment Variable
- Configure your EJB 3 with envirnoment entries using ENC
From http://agoncal.wordpress.com/2011/06/10/debate-and-what-about-configuration-in-java-ee-7/
Opinions expressed by DZone contributors are their own.
Comments