In this article by Christopher Ritchie, the author of R WildFly Configuration, Deployment, and Administration, Second Edition, you will learn to configure enterprise services and components, such as transactions, connection pools, and Enterprise JavaBeans.
(For more resources related to this topic, see here.)
To allow your application to connect to a database, you will need to configure your server by adding a datasource. Upon server startup, each datasource is prepopulated with a pool of database connections. Applications acquire a database connection from the pool by doing a JNDI lookup and then calling getConnection(). Take a look at the following code:
Connection result = null; try { Context initialContext = new InitialContext(); DataSource datasource = (DataSource)initialContext.lookup("java:/MySqlDS"); result = datasource.getConnection(); } catch (Exception ex) { log("Cannot get connection: " + ex);}
After the connection has been used, you should always call connection.close() as soon as possible. This frees the connection and allows it to be returned to the connection pool—ready for other applications or processes to use.
Releases prior to JBoss AS 7 required a datasource configuration file (ds.xml) to be deployed with the application. Ever since the release of JBoss AS 7, this approach has no longer been mandatory due to the modular nature of the application server.
Out of the box, the application server ships with the H2 open source database engine (http://www.h2database.com), which, because of its small footprint and browser-based console, is ideal for testing purposes.
However, a real-world application requires an industry-standard database, such as the Oracle database or MySQL. In the following section, we will show you how to configure a datasource for the MySQL database.
Any database configuration requires a two step procedure, which is as follows:
Let's look at each section in detail.
In WildFly's modular server architecture, you have a couple of ways to install your JDBC driver. You can install it either as a module or as a deployment unit.
The first and recommended approach is to install the driver as a module. We will now look at a faster approach to installing the driver. However, it does have various limitations, which we will cover shortly.
The first step to install a new module is to create the directory structure under the modules folder. The actual path for the module is JBOSS_HOME/modules/<module>/main.
The main folder is where all the key module components are installed, namely, the driver and the module.xml file. So, next we need to add the following units:
The MySQL JDBC driver used in this example, also known as Connector/J, can be downloaded for free from the MySQL site (http://dev.mysql.com/downloads/connector/j/). At the time of writing, the latest version is 5.1.30.
The last thing to do is to create the module.xml file. This file contains the actual module definition. It is important to make sure that the module name (com.mysql) corresponds to the module attribute defined in the your datasource.
You must also state the path to the JDBC driver resource and finally add the module dependencies, as shown in the following code:
<module name="com.mysql"> <resources> <resource-root path="mysql-connector-java-5.1.30-bin.jar"/> </resources> <dependencies> <module name="javax.api"/> <module name="javax.transaction.api"/> </dependencies> </module>
Here is a diagram showing the final directory structure of this new module:
You will notice that there is a directory structure already within the modules folder. All the system libraries are housed inside the system/layers/base directory. Your custom modules should be placed directly inside the modules folder and not with the system modules.
Once the JDBC driver is installed, you need to configure the datasource within the application server's configuration file. In WildFly, you can configure two kinds of datasources, local datasources and xa-datasources, which are distinguishable by the element name in the configuration file.
A local datasource does not support two-phase commits using a java.sql.Driver. On the other hand, an xa-datasource supports two-phase commits using a javax.sql.XADataSource.
Adding a datasource definition can be completed by adding the datasource definition within the server configuration file or by using the management interfaces. The management interfaces are the recommended way, as they will accurately update the configuration for you, which means that you do not need to worry about getting the correct syntax.
In this article, we are going to add the datasource by modifying the server configuration file directly. Although this is not the recommended approach, it will allow you to get used to the syntax and layout of the file. In this article, we will show you how to add a datasource using the management tools.
Here is a sample MySQL datasource configuration that you can copy into your datasources subsystem section within the standalone.xml configuration file:
<datasources> <datasource jndi-name="java:/MySqlDS" pool-name="MySqlDS_Pool" enabled="true" jta="true" use-java-context="true" use-ccm="true"> <connection-url> jdbc:mysql://localhost:3306/MyDB </connection-url> <driver>mysql</driver> <pool /> <security> <user-name>jboss</user-name> <password>jboss</password> </security> <statement/> <timeout> <idle-timeout-minutes>0</idle-timeout-minutes> <query-timeout>600</query-timeout> </timeout> </datasource> <drivers> <driver name="mysql" module="com.mysql"/> </drivers> </datasources>
As you can see, the configuration file uses the same XML schema definition from the earlier -*.ds.xml file, so it will not be difficult to migrate to WildFly from previous releases.
In WildFly, it's mandatory that the datasource is bound into the java:/ or java:jboss/ JNDI namespace.
Let's take a look at the various elements of this file:
One key aspect of the datasource configuration is the pool element. You can use connection pooling without modifying any of the existing WildFly configurations, as, without modification, WildFly will choose to use default settings. If you want to customize the pooling configuration, for example, change the pool size or change the types of connections that are pooled, you will need to learn how to modify the configuration file.
Here's an example of pool configuration, which can be added to your datasource configuration:
<pool> <min-pool-size>5</min-pool-size> <max-pool-size>10</max-pool-size> <prefill>true</prefill> <use-strict-min>true</use-strict-min> <flush-strategy>FailingConnectionOnly</flush-strategy> </pool>
The attributes included in the pool configuration are actually borrowed from earlier releases, so we include them here for your reference:
Attribute | Meaning |
initial-pool-size | This means the initial number of connections a pool should hold (default is 0 (zero)). |
min-pool-size | This is the minimum number of connections in the pool (default is 0 (zero)). |
max-pool-size | This is the maximum number of connections in the pool (default is 20). |
prefill | This attempts to prefill the connection pool to the minimum number of connections. |
use-strict-min | This determines whether idle connections below min-pool-size should be closed. |
allow-multiple-users | This determines whether multiple users can access the datasource through the getConnection method. This has been changed slightly in WildFly. In WildFly, the line <allow-multiple-users>true</allow-multiple-users> is required. In JBoss AS 7, the empty element <allow-multiple-users/> was used. |
capacity | This specifies the capacity policies for the pool—either incrementer or decrementer. |
connection-listener | Here, you can specify org.jboss.jca.adapters.jdbc.spi.listener.ConnectionListener that allows you to listen for connection callbacks, such as activation and passivation. |
flush-strategy | This specifies how the pool should be flushed in the event of an error (default is FailingConnectionsOnly). |
For each connection within a connection pool, the WildFly server is able to create a statement cache. When a prepared statement or callable statement is used, WildFly will cache the statement so that it can be reused. In order to activate the statement cache, you have to specify a value greater than 0 within the prepared-statement-cache-size element. Take a look at the following code:
<statement> <track-statements>true</track-statements> <prepared-statement-cache-size>10</prepared-statement-cache-size> <share-prepared-statements/> </statement>
Notice that we have also set track-statements to true. This will enable automatic closing of statements and ResultSets. This is important if you want to use prepared statement caching and/or don't want to prevent cursor leaks.
The last element, share-prepared-statements, can only be used when the prepared statement cache is enabled. This property determines whether two requests in the same transaction should return the same statement (default is false).
Adding an xa-datasource requires some modification to the datasource configuration. The xa-datasource is configured within its own element, that is, within the datasource. You will also need to specify the xa-datasource class within the driver element.
In the following code, we will add a configuration for our MySQL JDBC driver, which will be used to set up an xa-datasource:
<datasources> <xa-datasource jndi-name="java:/XAMySqlDS" pool-name="MySqlDS_Pool" enabled="true" use-java-context="true" use-ccm="true"> <xa-datasource-property name="URL"> jdbc:mysql://localhost:3306/MyDB </xa-datasource-property> <xa-datasource-property name="User">jboss </xa-datasource-property> <xa-datasource-property name="Password">jboss </xa-datasource-property> <driver>mysql-xa</driver> </xa-datasource> <drivers> <driver name="mysql-xa" module="com.mysql"> <xa-datasource-class> com.mysql.jdbc.jdbc2.optional.MysqlXADataSource </xa-datasource-class> </driver> </drivers> </datasources>
Datasource versus xa-datasource
You should use an xa-datasource in cases where a single transaction spans multiple datasources, for example, if a method consumes a Java Message Service (JMS) and updates a Java Persistence API (JPA) entity.
In the WildFly application server, every library is a module. Thus, simply deploying the JDBC driver to the application server will trigger its installation.
If the JDBC driver consists of more than a single JAR file, you will not be able to install the driver as a deployment unit. In this case, you will have to install the driver as a core module.
So, to install the database driver as a deployment unit, simply copy the mysql-connector-java-5.1.30-bin.jar driver into the JBOSS_HOME/standalone/deployments folder of your installation, as shown in the following image:
Once you have deployed your JDBC driver, you still need to add the datasource to your server configuration file. The simplest way to do this is to paste the following datasource definition into the configuration file, as follows:
<datasource jndi-name="java:/MySqlDS" pool-name="MySqlDS_Pool" enabled="true" jta="true" use-java-context="true" use-ccm="true"> <connection-url> jdbc:mysql://localhost:3306/MyDB </connection-url> <driver>mysql-connector-java-5.1.130-bin.jar</driver> <pool /> <security> <user-name>jboss</user-name> <password>jboss</password> </security> </datasource>
Alternatively, you can use the command-line interface (CLI) or the web administration console to achieve the same result.
What about domain deployment?
In this article, we are discussing the configuration of standalone servers. The services can also be configured in the domain servers. Domain servers, however, don't have a specified folder scanned for deployment. Rather, the management interfaces are used to inject resources into the domain.
At this point, you might wonder about a best practice for deploying the JDBC driver. Installing the driver as a deployment unit is a handy shortcut; however, it can limit its usage. Firstly, it requires a JDBC 4-compliant driver.
Deploying a non-JDBC-4-compliant driver is possible, but it requires a simple patching procedure. To do this, create a META-INF/services structure containing the java.sql.Driver file. The content of the file will be the driver name. For example, let's suppose you have to patch a MySQL driver—the content will be com.mysql.jdbc.Driver.
Once you have created your structure, you can package your JDBC driver with any zipping utility or the .jar command, jar -uf <your -jdbc-driver.jar> META-INF/services/java.sql.Driver.
The most current JDBC drivers are compliant with JDBC 4 although, curiously, not all are recognized as such by the application server. The following table describes some of the most used drivers and their JDBC compliance:
Database | Driver | JDBC 4 compliant | Contains java.sql.Driver |
MySQL | mysql-connector-java-5.1.30-bin.jar | Yes, though not recognized as compliant by WildFly | Yes |
PostgreSQL | postgresql-9.3-1101.jdbc4.jar | Yes, though not recognized as compliant by WildFly | Yes |
Oracle | ojdbc6.jar/ojdbc5.jar | Yes | Yes |
Oracle | ojdbc4.jar | No | No |
As you can see, the most notable exception to the list of drivers is the older Oracle ojdbc4.jar, which is not compliant with JDBC 4 and does not contain the driver information in META-INF/services/java.sql.Driver.
The second issue with driver deployment is related to the specific case of xa-datasources. Installing the driver as deployment means that the application server by itself cannot deduce the information about the xa-datasource class used in the driver. Since this information is not contained inside META-INF/services, you are forced to specify information about the xa-datasource class for each xa-datasource you are going to create.
When you install a driver as a module, the xa-datasource class information can be shared for all the installed datasources.
<driver name="mysql-xa" module="com.mysql"> <xa-datasource-class> com.mysql.jdbc.jdbc2.optional.MysqlXADataSource </xa-datasource-class> </driver>
So, if you are not too limited by these issues, installing the driver as a deployment is a handy shortcut that can be used in your development environment. For a production environment, it is recommended that you install the driver as a static module.
After installing your driver, you may want to limit the amount of application configuration in the server file. This can be done by configuring your datasource programmatically This option requires zero modification to your configuration file, which means greater application portability. The support to configure a datasource programmatically is one of the cool features of Java EE that can be achieved by using the @DataSourceDefinition annotation, as follows:
@DataSourceDefinition(name = "java:/OracleDS", className = " oracle.jdbc.OracleDriver", portNumber = 1521, serverName = "192.168.1.1", databaseName = "OracleSID", user = "scott", password = "tiger", properties = {"createDatabase=create"}) @Singleton public class DataSourceEJB { @Resource(lookup = "java:/OracleDS") private DataSource ds; }
In this example, we defined a datasource for an Oracle database. It's important to note that, when configuring a datasource programmatically, you will actually bypass JCA, which proxies requests between the client and the connection pool.
The obvious advantage of this approach is that you can move your application from one application server to another without the need for reconfiguring its datasources. On the other hand, by modifying the datasource within the configuration file, you will be able to utilize the full benefits of the application server, many of which are required for enterprise applications.
The Enterprise JavaBeans (EJB) container is a fundamental part of the Java Enterprise architecture. The EJB container provides the environment used to host and manage the EJB components deployed in the container. The container is responsible for providing a standard set of services, including caching, concurrency, persistence, security, transaction management, and locking services.
The container also provides distributed access and lookup functions for hosted components, and it intercepts all method invocations on hosted components to enforce declarative security and transaction contexts. Take a look at the following figure:
As depicted in this image, you will be able to deploy the full set of EJB components within WildFly:
EJB components that don't keep conversational states (SLSB and MDB) can be optionally configured to emit timed notifications.
Now that we have briefly outlined the basic types of EJB, we will look at the specific details of the application server configuration. This comprises the following components:
Let's see them all in detail.
EJBs are configured within the ejb3.2.0 subsystem. By default, no stateless session bean instances exist in WildFly at startup time. As individual beans are invoked, the EJB container initializes new SLSB instances.
These instances are then kept in a pool that will be used to service future EJB method calls. The EJB remains active for the duration of the client's method call. After the method call is complete, the EJB instance is returned to the pool. Because the EJB container unbinds stateless session beans from clients after each method call, the actual bean class instance that a client uses can be different from invocation to invocation. Have a look at the following diagram:
If all instances of an EJB class are active and the pool's maximum pool size has been reached, new clients requesting the EJB class will be blocked until an active EJB completes a method call. Depending on how you have configured your stateless pool, an acquisition timeout can be triggered if you are not able to acquire an instance from the pool within a maximum time.
You can either configure your session pool through your main configuration file or programmatically. Let's look at both approaches, starting with the main configuration file.
In order to configure your pool, you can operate on two parameters: the maximum size of the pool (max-pool-size) and the instance acquisition timeout (instance-acquisition-timeout). Let's see an example:
<subsystem > <session-bean> <stateless> <bean-instance-pool-ref pool-name="slsb-strict-max-pool"/> </stateless> ... </session-bean> ... <pools> <bean-instance-pools> <strict-max-pool name="slsb-strict-max-pool" max-pool-size= "25" instance-acquisition-timeout="5" instance-acquisition- timeout-unit="MINUTES"/> </bean-instance-pools> </pools> ... </subsystem>
In this example, we have configured the SLSB pool with a strict upper limit of 25 elements. The strict maximum pool is the only available pool instance implementation; it allows a fixed number of concurrent requests to run at one time. If there are more requests running than the pool's strict maximum size, those requests will get blocked until an instance becomes available. Within the pool configuration, we have also set an instance-acquisition-timeout value of 5 minutes, which will come into play if your requests are larger than the pool size.
You can configure as many pools as you like. The pool used by the EJB container is indicated by the attribute pool-name on the bean-instance-pool-ref element. For example, here we have added one more pool configuration, largepool, and set it as the EJB container's pool implementation. Have a look at the following code:
<subsystem > <session-bean> <stateless> <bean-instance-pool-ref pool-name="large-pool"/> </stateless> </session-bean> <pools> <bean-instance-pools> <strict-max-pool name="large-pool" max-pool-size="100" instance-acquisition-timeout="5" instance-acquisition-timeout-unit="MINUTES"/> <strict-max-pool name="slsb-strict-max-pool" max-pool-size="25" instance-acquisition-timeout="5" instance-acquisition-timeout-unit="MINUTES"/> </bean-instance-pools> </pools> </subsystem>
We have detailed the steps necessary to configure the SLSB pool size through the main configuration file. However, the suggested best practice is to use CLI to alter the server model.
Here's how you can add a new pool named large-pool to your EJB 3 subsystem:
/subsystem=ejb3/strict-max-bean-instance-pool=large-pool:
add(max-pool-size=100)
Now, you can set this pool as the default to be used by the EJB container, as follows:
/subsystem=ejb3:write-attribute(name=default-slsb-instance-pool,
value=large-pool)
Finally, you can, at any time, change the pool size property by operating on the max-pool-size attribute, as follows:
/subsystem=ejb3/strict-max-bean-instance-pool=large-pool:write-
attribute(name="max-pool-size",value=50)
In this article, we continued the analysis of the application server configuration by looking at Java's enterprise services.
We first learned how to configure datasources, which can be used to add database connectivity to your applications. Installing a datasource in WildFly 8 requires two simple steps: installing the JDBC driver and adding the datasource into the server configuration.
We then looked at the enterprise JavaBeans subsystem, which allows you to configure and tune your EJB container. We looked at the basic EJB component configuration of SLSB.