Configuring Enterprise Applications

Many small web applications could use Tomcat which is a servlet/JSP container, this would be more than adequate. If the application is going to be large then you may want to separate the business logic from your web presentation code by pulling the logic out of your servlets, this means business logic can be used by multiple web applications. In the 90's the EJB (Enterprise Java Bean) specification was created in response to enable server-side application component development, the current release is now EJB3. In the beginning persisting data was a complex task, thus causing people to avoid EJB persistence altogether.

With EJB3 a completely new persistence specification known as the Java Persistence API (JPA) was created, this takes advantage of annotations and is very lightweight compared to the previous one.

EJB 3.0 defines a model for transactional components and objects, the specification defines three types of enterprise beans

Session are typically used to write business code encapsulated in a larger business transactions that may make calls to other transaction components
Entity are objects that represent domain objects mapped to the database, entity persistence is either encapsulated by a database transaction or part of a larger business transaction.
Message-Driven are asynchronous message consumers managed by the container.

Session Beans

Session beans are used to encapsulate business logic, there are two types of session beans

Session beans are pre-created when the server starts and then maintained in a pool. Because SLSBs don't maintain state, each request can grab a pre-created session bean from a pool and return it after the request has completed. SFSBs maintain a session identifier with the client that consecutive requests will use to retrieve the same bean out of the pool. Some applications keep there connections open for awhile thus increasing memory allocation, to alleviate the memory the Java EE specification defines a model of passivation and activation where SFSBs are persisted to secondary storage when they are idle for a period of time and retrieved when accessed again, this is a bit like a process being swapped out to disk in a Unix environment.

Session beans define a business interface, a Java interface used to access the bean. Remote clients use a business interface to make calls to the bean, the interface can be local or remote, the local interface would be accessed via inside the application server (JBoss) the same JVM, a remote interface could be a different process or different server accessing via the network.

Remoting allows clients to download a object, called a dynamic proxy that implements the EJBs business interface. The dynamic proxy does not implement the business logic but does know how to make a call to the server to have the EJB execute the business logic.

When an EJB is deployed to the server, a dynamic proxy is generated and bound into the JNDI server, when the client makes a call to the EJB, it obtains the dynamic proxy by doing a lookup in JNDI, the dynamic proxy shares the same business interface as the session bean, so the client pretends its making a call to the bean. The dynamic proxy takes the call forms it into a message that can be passed over the network to the EJB server, using whatever protocol its configured to use. When the EJB server receives the message, it calls the session bean which executes the business logic and returns the response back to the dynamic proxy and in turns back to the client.

Hibernate and JPA

Entities are used to map objects to a persistence store (normally a database). Hibernate is probably the most popular Object-to-Relational Mapping (ORM) tool in Java. Many of the idea's in Hibernate have been brought into the EJB3 specification, which defines an ORM standard called Java Persistence API (JPA), and Hibernate now implements the JPA specification, which means you can use Hibernate as your persistence framework.

In JPA a persistence context manages entities and their lifecycles, the persistence context manager is managed by the container, developers can access the persistence context through a entity manager. The entity manager isn't remotely accessible to clients, therefore the entity object must be associated with the entity manager before the entity manager can persist it to the database.

Enterprise Packaging

EJBs are packaged in a JAR structure, an enterprise application is comprised of EJBs, POJOs and presentation technologies, they can all be combined in to an EAR file (Enterprise Archive) or a exploded EAR directory, you can think of an EAR file as a archive of archives, it can contain WAR, JAR and SAR files.

An EAR application will contain a META-INF directory which contains a number of standard or proprietary deployment descriptor files

application.xml (standard) is responsible for defining the archives that are part of the EAR and providing any additional information about them, it can provide the context root directory for an example.
jboss-app.xml (proprietary) configures class loading and also used to deploy modules that are jboss specific.

EJB Configuration

There are two types of configuration

Web Application
  • Defining security
  • Defining JNDI names
  • Enabling Clustering
  • Defining which transport protocol a particular bean supports
JBoss EJB Container
  • Protocol Settings
  • Default database used by entities
  • Class Loading

The server/xxx/default/conf directory contains a global proprietary deployment descriptor file called standardjboss.xml, this file applies to all EJB applications deployed to the server. The file is used to configure various EJB containers for the different EJB types and corresponding dynamic proxies that are used to access them.

The EJB server comes in the prepackaged default and all configurations, the EJB deployer is packaged under the deployers/ejb3.deployer directory, it contains configuration files used to configure the EJB3 deployer.

With EJB3 you can configure applications almost entirely using annotations and default conventions, you can specify configuration parameters that you want or have to configure by using annotations, and the container assumes default values for most everything that you don't explicitly specify, which can eliminate the need for XML deployment descriptor files. You can still use the XML deployment descriptor files which override the annotations and default configuration.

There are a number of standard and proprietary files that reside in an applications META-INF directory

ejb-jar.xml is the standard deployment descriptor file used to configure session and message-driven beans. Entities are not managed by directly by the container, they are managed by the JPA persistence context.
persistence.xml is the standard deployment descriptor file used to configure a JPA persistence context
jboss.xml

is the proprietary deployment descriptor file used to configure EJBs, the ejb-jar.xml file describes what behavior you are configuring and the jboss.xml file describes how you are configuring the behavior defined in the standard deployment descriptor file.

You can configure

  • Global JNDI Bindings
  • Configure dynamic proxies
  • Configure different EJB containers
  • Defining JBoss service objects
  • Configuring the transport protocol
  • Securing EJBs
Examples
ejb-jar.xml

<ejb-jar>
  <description>Some JBoss Application</description>
  <display-name>Some App</display-name>
  <enterprise-beans>
    <session> ... </session>
    <message-driven> ... </message-driven>
  </enterprise-beans>
  <assembly-descriptor>
    <security-role> ... </security-role>
    <method-permission> ... </method-permission>
    <container-transaction> ... </container-transaction>
    <exclude-list> ... </exclude-list>
  </assembly-descriptor>
</ejb-jar>

Note:
<ejb-jar> root element
<description> and <display-name> are used for logging
<enterprise-bean> defines session and message-driven beans
<assembly-descriptor> provides the definition of method permissions, transaction attributes, interceptor bindings, a list of methods to exclude from being invoked and a list of exception types

persistence.xml <persistence>
  <persistence-unit name="userDatabase">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>java:/DefaultDS</jta-data-source>
    <properties>
      <property name="hibernate.hdm2ddl.auto" value="create-drop"/>
      <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
    </properties>
  </persistence-unit>
<persistence>
jboss-.xml <jboss xmlns="http://www.jboss.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss_5_0.xsd"
       version="3.0">

  <security-domain>datadisk-domain</security-domain>
  <enterprise-bean>
    <session>
      <ejb-name>ShoppingCart</ejb-name>
      <jndi-name>ShoppingCart</jndi-name>
      <clustered>true</clustered>
      <clustered-config>
        <partition-name>DefaultPartition</partition-name>
        <load-balance-policy>org.jboss.ha.framework.interfaces.RnadomRobin</load-balance-policy>
      </clustered-config>
      <security-domain>overriden-domain</security-domain>
    </session>
    <session>
      <ejb-name>StatelessTest</ejb-name>
      <jndi-name>StatelessTest</jndi-name>
    </session>
  </enterprise-bean>
</jboss>

The EJB server is configured in either the EJBs servers configuration files or in the configuration files for the various services that run on top of the EJB server.

File Configuration What it configures
deploy/cluster/jboss-cache-manager.sar/META-INF/jboss-cache-configs.xml All The JBoss cache configuration that defines the caches for SFSB, entities, queries and timestamps
deploy/ejb3-connectors-jboss-beans.xml default, all The EJB connector used for remoting
deploy/ejb3-interceptors-aop.xml default, all All the interceptors used during EJB calls and lifecycles events, both on th client and the server side
deploy/ejb3-timer-service.xml default, all JBoss implementation of the EJB timer
deployers/ejb3.deployer/META-INF/persistence.properties default, all Default properties used when creating a persistence unit
deployers/ejb3.deployer/META-INF/jpa-deployers-jboss-beans.xml default, all The deployer used to recognize and deploy JPA archives
deployers/ejb3.deployer/META-INF/ejb3.deployers/ejb3-jboss-beans.xml default, all The deployer used to recognize and deploy EJB archives

Configuring Session Beans

When session EJBs get deployed to the server, they are automatically bound into JNDI using a default name, however you can change the JNDI binding for a bean. You can also configure the EJB container and dynamic proxy that the client uses to call the server, these configurations will allow you to enable SFSB passivation and configure the pool size for SLSBs.

JNDI is used to provide away for both local and remote application components to look up references to dynamic proxies for the EJB that they need to call. When EJBs are deployed in the server, the server automatically creates the dynamic proxy for the EJB and binds it into the JNDI server.

The best to explain this is by the way of an example, take the below SLSB

SLSB example

// A stateless session bean
@Stateless
public class MessagePrinterBean implements MessagePrinterRemote, MessagePrinterLocal {

  public void printRemoteMessage(String message) { ... }
  public void printLocalMessage(String message) { ... }
}

// A Local Interface
@Local
public interface MessagePrinterLocal {
  public void printLocalMessage(String message);
}

// A Local Interface
@Remote
public interface MessagePrinterRemote {
  public void printRemoteMessage(String message);
}

When the EJB gets deployed it gets bound under the name MessagePrinterBean, which the clients will use to look up the bean, you can change this name by either of the two below methods

Annotation # Use one of the below annotations

@org.jboss.ejb3.annotation.RemoteBinding
@org.jboss.ejb3.annotation.LocalBinding

# So the code would look like

@Stateless
@LocalBinding(jndiBinding="LocalTextMessagerPrinter");
@RemoteBinding(jndiBinding="TextMessagerPrinter");
public class MessagePrinterBean ...

# You can use multiple names too
@RemoteBindings( { @RemoteBinding(jndiBinding="TextMessagerPrinter"),
                   @RemoteBinding(jndiBinding="AnotherName") } );
Configuration
(META-INF/jboss.xml)
<jboss xmlns="http://www.jboss.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss_5_0.xsd"
       version="3.0">
  <enterprise-bean>
    <session>
      <ejb-name>MessagePrinterBean</ejb-name>
      <jndi-name>TextMessagePrinter</jndi-name>
      <local-jndi-name>LocalTextMessagePrinter</local-jndi-name>
    </session>
  </enterprise-bean>
</jboss>

To call the EJB you have to look up a dynamic proxy from a JNDI server and make a call to the proxy.

accessing the remote interface Greeter myGreeter = (Greeter) ctx.lookup("TexanGreeter/remote");
accessing the local interface GreeterLocal myGreeter = (GreeterLocal) ctx.lookup("TexanGreeter/local");
if deployed in an EAR file ctx.lookup("<earfilename>/<BeanName>/remote");

Configuring EJB Containers

IN JBoss there is a container definition for each type of remotely accessible EJB, you can configure feature such as session-bean pool size and SFSB passivation. Both the dynamic proxy and the container for each type of EJB are defined in the server/xxx/conf/standardjboss.xml file, there are two blocks one for the dynamic proxy the other for defining the containers.

Each invoker-proxy-binding block defines a dynamic proxy and how it is associated with an invoker, a component used to configure a transport protocol, the container-configuration blocks configure the server container

To configure the session-bean pool to need to look for the "Standard Stateful SessionBean" and "Standard Stateless SessionBean" <container-name> names.

Stateful bean passivation is configured with two elements

You can disable caching by using the org.jboss.ejb.plugins.NoPassivationCachePolicy which never writes to a second storage.

Entity Persistence

When you deploy an application with an persistence.xml file, the application server automatically scans the class files in the package to see if there are any entities defined, it then creates a persistence context based on the configuration in the persistence.xml file making sure to include all the entity classes that it found.

In JPA, we use the EntityManager class to interact with the persistence context, and we use the EntityManagerFactory class to create EntityManager instances, some code many use the Hibernate Session and SessionFactory objects to interact with the persistence context.

Creating JMX Service Objects

JBoss offers a new component type called a JMX service object, these objects are special type of EJB that are similar to SFSB. Service object can define remote and local interfaces and can be injected into and from other EJBs and maintain there state. The main difference is that they are singletons only a single instance of the service object is available in the server.

The below is an example JMX service object which is an investment calculator

Remote Interface @Remote
public interface Calculator {
  public double getInterestRate();
  public double calculateTotalInterest(double presentValue, int years);
  public double calculateFutureValue(double presentValue, int years);
}
@Management interface @Management
public interface InterestRateManager {
  // Attribute
  public void setInterestRate(double g);
  public double getInterestRate();
  // Life cycle method
  public void create() throws Exceptions;
  public void destroy() throws Exceptions;
}
MBean that manages interest rate @Service(objectName="jbia:service=interestRateManager")
public class InterestRateMBean implements InterestRateManager {
  private double interestRate;
  
  public void setInterestRate(double interestRate) {
    this.interestRate = interestRate;
  }
  
  public double getInterestRate() {
    return interestRate;
  }

  // Lifecycle Method
  public void create() throws Exception {
    interestRate = 5.25;
    System.out.println("Calculator - Creating");
  }

  public void destroy() {
    System.out.println("Calculator - Destroying");
  }
}
SLSB calculator @Stateless
public class StatelessCalculatorBean implements Calculator {
  @EJB(beanName = "InterestRateMBean")
  
  private InterestRateManager interestRateManager;
  
  public double calculateTotalValue(double presentValue, int years) {
    return calculateFutureValue(presentValue, years) - presentValue;
  }

  public double calculateFutureValue(double presentValue, int years) {
    double interestRate = interestRateManager.getInterestRate() / 100;
    return presentValue * Math.pow((1.0 + interestRate), years);
  }

  public double getInterestRate() {
    return interestRateManager.getInterestRate();
  }
}

The class-level variable interestRateManager field is injected into the SLSB using the @EJB annotation, it injects a bean called InterestRateMBean which is the service object that implements the InterestrRateManager interface and manages the interest rate for the investment calculator.

The interface for the MBean uses the @Management annotation, this tells JBoss that the interface is a management interface for a service object, any set and get methods becomes a JMX attribute on the MBean. MBeans have a lifecycle thus you need the create() and destroy() methods defined on the interface.

The MBean class has the @Service annotation, this tells JBoss that an instance of this class is a service object, and the container will maintain it as a singleton. The objectName defines the JMX name that the service gets bound to in the JMX server.

To change the rate you do the following:

  1. Go to the JMX console http://127.0.0.1:8080/jmx-console/
  2. Navigate to the jbia:service=interestRateManagaer MBean
  3. Modify the InterestRate Attribute

To access the remote interface you can use the following code:

Access the remote interface Calculator calc = (Calculator) ctx.lookup("StatelessCalculatorBean/remote");
System.out.println(calc.calculator(1,10,100));

Note: should get 15947.906.....

You can access the MBean without injection, such as a servlet or JSP

Accessing MBean without injection MBeanServer server = MBeanServerLocator.locate();
calcManager = (InterestRateManager) MBeanProxyExt.create(InterestRateManager.class, "jbia:service=interestRateManager", server);

Transport Protocol

Some applications may require some form of remote access to EJBs, most cases you can use a standard socket-based protocol, but sometimes you may have a network security restriction that limits you to tunneling EJB calls over HTTP. JBoss supports many different transport protocols including RMI (Remote Method Invocation), JBoss has a remoting document discussing all the different possible transport protocols that can be used.

JBoss uses the new JBoss remoting framework to enable EJB remoting, as previously discussed an EJB client makes calls to a dynamic proxy that has been downloaded from a JNDI server,

  1. The dynamic proxy uses the JBoss remoting framework to call a server invoker, and its job is to read requests on a particular transport and forward them to one or more invocation handlers that handle the request.
  2. The server invoker is created by a connector, a component configured in server/xxx/deploy/remoting-jboss-beans.xml file (used to be remoting-service.xml).
  3. When the connector component is created it creates the server invoker and binds it (or connects it) to its invocation handlers.
  4. The application server defines an invocation handler known as the Unified Invoker, it configuration is found in server/xxx/deploy/remoting-jboss-beans, remember this is a invocation handler not a invoker
  5. The invocation handler can be configured to call various EJB containers used for different types of EJBs, the request will specify which invocation handler it wants the request directed to. This information is provided when it is created by its proxy factory, the component that creates new dynamic proxies. The proxy factory is bound to an invocation handler, when the proxy factory is asked to create a new dynamic proxy it confirms that the dynamic proxy knows how to generate requests that wind up at the correct invocation handler.
  6. The binding between the invocation handler and the proxy factory can be done in one of two places. The default configuration for proxy factories is in the server/xxx/standardjboss.xml file, the invoker-proxy-binding elements define the proxy factories.
  7. This binds them to their invocation handlers
  8. This same definition and bind can also be done in an applications META-INF/jboss.xml file.

Changing the transport only requires a change to the connector configuration in the server/xxx/deploy/remote-jboss-beans.xml file.

Connector Config <!-- The Connector is the core component of the remoting server service. -->
<!-- It binds the remoting invoker (transport protocol, callback configuration, -->
<!-- data marshalling, etc.) with the invocation handlers. -->
<bean name="UnifiedInvokerConnector" class="org.jboss.remoting.transport.Connector">
  <annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(
        name="jboss.remoting:service=Connector,transport=socket",
        exposedInterface=org.jboss.remoting.transport.ConnectorMBean.class,
        registerDirectly=true)
  </annotation>
  <property name="serverConfiguration"><inject bean="UnifiedInvokerConfiguration"/></property>
</bean>


<!-- Remoting server configuration -->
<bean name="UnifiedInvokerConfiguration" class="org.jboss.remoting.ServerConfiguration">
  <constructor>
    <!-- transport: Others include sslsocket, bisocket, sslbisocket, http, https, rmi, sslrmi, servlet, sslservlet.     -->
    <parameter>socket</parameter>
  </constructor>
...

Securing EJBs

Session beans can be accessed locally or remotely, if accessed locally then the web application does not have to explicitly pass the security credentials to the EJB server, the security credentials are automatically propagated from the web container to the EJB container. If an EJB is accessed from a standalone application or web container running in a different JVM process, then the security details must be passed to the EJB server from the client. EJBs are secured on an individual method basis, security can be added to the EJB methods (public methods declared in the EJBs interface) using either standard Java EE annotations or XML descriptor files.

There are four Java annotations used to specify security for EJB methods

@javax.annotation.security.RolesAllowed used to define which roles have access to a given method
@javax.annotation.security.PermitAll used to signify that any authenticated user can access the method
@javax.annotation.security.DenyAll used to signify that no user can access the method
@org.jboss.ejb3.annotations.SecurityDomain A JBoss-specific annotation used to define the security domain that calls to this bean will be routed to.

So an example using annotation is below, which I am not going to explain as it is pretty much self-explaining

EJB security @SecurityDomain("simple-security-domain")
@RolesAllowed( {"bank-manager", "teller"} )
@Stateless
public class StatelessCalculatorBean implements Calculator, CalculatorRemote {
  
  // defined by the @RolesAllowed above  
  public double calculateTotalInterest(double presentValue, int years) {
    return calculateFutureValue(presentValue, years) - presentValue;
  }

  @RolesAllowed("teller")
  public double calculateFutureValue(double presentValue, int years) {
    double interestRate = 5.25 / 100;
    return presentValue * Math.pow((1.0 + interestRate), years);
  }

  @RolesAllowed("bank-manager")
  public double getInterestRate() {
    return 5.25;
  }

  @DenyAll
  public String getTheAnswertoLifeItself() {
    return "room 1401";
  }

  @PermitAll
  public String freeForAll() {
    return "room 237";
  }
}

If can also define security in the EJB deployment descriptors META-INF/ejb-jar.xml and META-INF/jboss.xml. The files will override any security settings made in annotations, you can define the security domain for the entire application by using the following in the META-INF/jboss.xml.

define security in the EJB deployment descriptors <ejb-jar xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejbjar_3_0.xsd"
         version=3.0">
  <assembly-descriptor>
    <security-role>
      <role-name>teller</role-name>
    </security_role>

    <method-permission>
      <role-name>teller</role-name>
      <method>
        <ejb-name>StatelessCalculatorBean</ejb-name>
        <method-name>getInterestRate</method-name>
    </method-permission>

    <method-permission>
      <unchecked/>
      <method>
        <ejb-name>StatelessCalculatorBean</ejb-name>
        <method-name>freeForAll</method-name>
    </method-permission>

    <exclude-list>
      <method>
        <ejb-name>StatelessCalculatorBean</ejb-name>
        <method-name>excludeMethod</method-name>
    </exclude-list>

  </assembly-descriptor>
</ejb-jar>

The <unchecked/> attribute is the same as @PermitAll annotation and the <exclude-list> attribute is the same as @DenyAll.

Securing EJB Communication

The following are steps to secure EJB communications over SSL, you need to do the following

  1. Create a server certificate inside of a keystore
  2. Export the server certificate
  3. Import the server certificate into a client truststore
  4. Configure a connector to support SSL
  5. Point the server to the server keystore
  6. Point the client to the client truststore
Creating the connector <?xml version="1.0" encoding="UTF-8"?>
<server>
  <mbean code="org.jboss.remoting.transport.Connector"
         name="jboss.remoting:type=Connector,transport=sslsocket3843,handler=ejb3">

    <attribute name="InvokerLocator">sslsocket://${jboss.bind.address}:3843</attribute>
    <attribute name="Configuration"
      <config>
        <handlers>
          <handler subsystem="AOP">
            org.jboss.aspects.remoting.AOPRemotingInvocationHandler
          </handler>
        </handlers>
      </config>
    </attribute>
  </mbean>
Binding EJB to invoker using annotations

import javax.ejb.Stateless;
import org.jboss.ejb3.annotation.RemoteBinding;
import org.jboss.ejb3.annotation.RemoteBindings;

@RemoteBindings({
  @RemoteBinding(clientBindUrl = "sslsocket://127.0.0.1:3843", jndiBinding="StatelessSSL")
  })
@Stateless
public class ...... {
 ...
}

Point to the keystore ./run.sh -Djavax.net.ssl.keyStore=/path/to/keystore.pfv
         -Djavax.net.ssl.keyStorePassword=password -c enterprise