How to migrate from GlassFish to WildFly

The Imixs Workflow Project was started in the early beginning of the JEE5 Specification. Since than all workflow components where tested on GlassFish V2 and V3. GlassFish is a great application server and still the Reference Implementation for JEE. So we recommend the usage of GlassFish for development and in production for our customers.

But since Oracle announced stopping commercial support for GlassFish and recommend there customers to use WebLogic in productive environments its time for open source projects (like the Imixs project) also look for alternatives. And the brand new JEE Server WildFly from RedHead is such an alternative. WildFly is based on the well known JBoss Application server and a promising platform for JEE Open Source Projects. In the following sections I will explain what is necessary to migrate a JEE Project form GlassFish to WildFly.

General

First I want to point out that one advantage of the Java Enterprise platform is its standardization. This means a JEE Application should be platform independent and can be run on any JEE implementation. This is true for simple components and web applications. It becomes more complex as the application becomes more complex. So you will need to use in some cases platform specific deployment descriptors and use after all different server setups for your application. The suprising thing here is that Wilfly need less custom deployment descriptors as GlassFish.
In the following section I will focus on:

  • The DataSource configuration (JPA)
  • The Security Configurateion (JAAS)
  • The REST Service Configuration (JAX-RS)

 

JPA – EclipseLink

If you have developed JEE on GlassFish you typically use EclipseLink as the JPA implementation. JBoss and Wildfly use in default Hibernate. Both implementation shuld do the same thing but it is a good idea to stay with EclipseLink, if you started with it. You can add EclipseLink very easy by adding EclipseLink.jar into the folder

modules/system/layers/base/org/eclipse/persistence/main

and update the configuration in

modules/system/layers/base/org/eclipse/persistence/main/module.xml

This is described here. It is important to add the org.jipijapa.eclipselink.JBossArchiveFactoryImpl afterwards with the following command:

jboss-cli.sh --connect '/system-property=eclipselink.archive.factory:add(value=org.jipijapa.eclipselink.JBossArchiveFactoryImpl)'

 

Datasource Configuration (MySQL)

The Datasource management is one of the things which is really much easier to use as in GlassFish Server. For example to use the MySQL JDBC driver you can simply deploy the driver jar into Wildfly. In the web inferface from WildFly choose: Runtime->Server->Manage Deployments and add your mysql Driver jar (e.g mysql-connector-java-5.1.7-bin.jar) as a new deployment. That’s it.

If you now go to add a new Datasource:

Profile->Subsystem->Connector->Datasources 

you can choose the mysql driver directly. If you need to configure a XADataSorce which I recommend you need to know the MySQL XADatasource class name:

com.mysql.jdbc.jdbc2.optional.MysqlXADataSource

Also you need to add the JDBC connect string (URL) manually. This can be done in the section ‘Properties’ where you cann add a new key ‘URL’ with the corresponding value. E.g. : jdbc:mysql://localhost:3306/my-first-db

See also details about datasource configuration here.

RestEasy Configuration

Using RestServices makes it necessary to change things in the web.xml file because Jersey (used by GlassFish) and RestEasy (used by Wildfly) have  different configurations.
In GlassFish V3 a RestService configuration for Jersey looks typically like this:

<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
 <servlet>
 <servlet-name>ImixsRestService</servlet-name>
 <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
 <init-param>
 <param-name>com.sun.jersey.config.property.packages</param-name>
 <param-value>org.imixs.workflow.jaxrs</param-value>
 </init-param>
 <load-on-startup>1</load-on-startup>
 </servlet>

In WildFly you need to chage the configuration like this:

<context-param>
 <param-name>resteasy.scan</param-name>
 <param-value>true</param-value>
 </context-param>
 <context-param>
 <param-name>resteasy.servlet.mapping.prefix</param-name>
 <param-value>/rest</param-value>
 </context-param>
 <listener>
 <listener-class>
 org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
 </listener-class>
 </listener>
 <servlet>
 <servlet-name>ImixsRestService</servlet-name>
 <servlet-class>
 org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
 </servlet-class>
 </servlet>

An useful short example about resteasy you can find here
http://www.mkyong.com/webservices/jax-rs/resteasy-hello-world-example/

Security Realm

The Security Realm configuration is quite simple in WildFly. You can add for example a JDBC Security Realm similar to a GlassFish JDBCRealm from the WildFly Web Console:

Profile->Subsystems->Security->Security Domains

This is an example for a Database Security configuration:

Attributes:

  • Name: imixsrealm
  • CacheType: Default

Authentication code:

  • Database = required

Module Options for Authentication code ‘Database’:

  • dsJndiName=java:/jdbc/imixs_office
  • hashAlgorithm=SHA-256
  • hashEncoding=hex
  • principalsQuery=select PASSWORD from USERID where ID=?
  • rolesQuery=select GROUP_ID,’Roles’ from USERID_USERGROUP where ID=?
  • unauthenticatedIdentity=anonymous

The security domain configuration in the standalone.xml configuraiton file than looks like this:

<security-domain name="imixsrealm">
 <authentication>
 <login-module code="Database" flag="required">
 <module-option name="dsJndiName" value="java:/jdbc/imixs_office"/>
 <module-option name="hashAlgorithm" value="SHA-256"/>
 <module-option name="hashEncoding" value="hex"/>
 <module-option name="principalsQuery" value="select PASSWORD from USERID where ID=?"/>
 <module-option name="rolesQuery" value="select GROUP_ID,'Roles' from USERID_USERGROUP where ID=?"/>
 <module-option name="unauthenticatedIdentity" value="anonymous"/>
 </login-module>
 </authentication>
 </security-domain>

To finish the configuration, add the file jboss-web.xml in the folder WEB-INF of your web module with the following content. his file is used to define the security domain used by the application:

<?xml version="1.0" encoding="UTF-8"?>
 <jboss-web>
     <security-domain>imixsrealm</security-domain>
</jboss-web>

Role Mapping

In different to GlassFish for WildFly there is no explicit role-group mapping necessary. So you need no special deployment descriptor like the /WEB-INF/glassfish-application.xml. The Roles defined by a application can be directly used in the security configuration for a user.

See also: http://wildfly.org/news/2014/02/06/GlassFish-to-WildFly-migration/

In case you have existing group mappings (e.g. in a database group table or in a LDAP directory) you can add the mapping by defining a file app.properties, where app is the name of the security domain, as defined above. Save this file in the folder WILDFLY_HOME/standalone/configuration or WILDFLY_HOME/domain/configuration to be taken into account.

This is an example of my file imixsrealm.properties which mapps the group names to roles defined in my application:

IMIXS-WORKFLOW-Reader=org.imixs.ACCESSLEVEL.READERACCESS
IMIXS-WORKFLOW-Author=org.imixs.ACCESSLEVEL.AUTHORACCESS
IMIXS-WORKFLOW-Editor=org.imixs.ACCESSLEVEL.EDITORACCESS
IMIXS-WORKFLOW-Manager=org.imixs.ACCESSLEVEL.MANAGERACCESS

Groups are listed on the left of the equal operator and roles are listed on the right. In the example above, users in the group ‘IMIXS-WORKFLOW-Reader’ fulfill the role ‘org.imixs.ACCESSLEVEL.READACCESS’.

Note: To activate this role mapping the security domain need a login-module section for the RoleMapping:

Authentication code:

  • RoleMapping = required

Module Options for Authentication code ‘RoleMapping’:

  • rolesProperties=file:${jboss.server.config.dir}/imixsrealm.properties
  • replaceRole=false

The section in the standalone.xml file looks like this:

 <security-domain name="imixsrealm">
 <authentication>
 <login-module code="Database" flag="required">
 <module-option name="dsJndiName" value="java:/jdbc/imixs_office"/>
 <module-option name="hashAlgorithm" value="SHA-256"/>
 <module-option name="hashEncoding" value="hex"/>
 <module-option name="principalsQuery" value="select PASSWORD from USERID where ID=?"/>
 <module-option name="rolesQuery" value="select GROUP_ID,'Roles' from USERID_USERGROUP where ID=?"/>
 <module-option name="unauthenticatedIdentity" value="anonymous"/>
 </login-module>
 <login-module code="RoleMapping" flag="required">
 <module-option name="rolesProperties" value="file:${jboss.server.config.dir}/imixsrealm.properties"/>
 <module-option name="replaceRole" value="false"/>
 </login-module>
 </authentication>
 </security-domain>

Mail

Using mail sessions makes it necessary to know some details about JNDI Resource names. In GlassFish you can configure a jndi resource with any name you choosse. For example: mail/org.imixs.workflow.mail

The configuration in your ejb-jar.xml or web.xml file looks than like this:

<!-- Mail Configuration -->
<env-entry>
<description> Mail Plugin Session name</description>
<env-entry-name>IMIXS_MAIL_SESSION</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>mail/org.imixs.workflow.mail</env-entry-value>
</env-entry>
<resource-ref>
<res-ref-name>mail/org.imixs.workflow.mail</res-ref-name>
<res-type>javax.mail.Session</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

In wildfly the name ‘mail/org.imixs.workflow.mail’ is not allowed to be used as a JNDI resource name. You allways have to start
with the prafix ‘java:/’ or ‘java:jboss:/’. This means your jndi mail resource name would be ‘java:/mail/org.imixs.workflow.mail’
And so you also need to change the res-ref-name tag in your ejb-jar.xml or web.xml like this:

<!-- Mail Configuration -->
<env-entry>
<description> Mail Plugin Session name</description>
<env-entry-name>IMIXS_MAIL_SESSION</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>mail/org.imixs.workflow.mail</env-entry-value>
</env-entry>
<resource-ref>
<res-ref-name>java:/mail/org.imixs.workflow.mail</res-ref-name>
<res-type>javax.mail.Session</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

In general Wildfly use always the java:/ prefix in jndi names. Se be careful about this small change in the naming.

Configuration of mail-session in standalone.xml

To add a mail resource to WildFly you can modify the standalone.xml file. Add the new mail resource into the tag entry ‘<subsystem xmlns=”urn:jboss:domain:mail:2.0″>’

<subsystem xmlns="urn:jboss:domain:mail:2.0">
 <mail-session name="default" jndi-name="java:jboss/mail/Default">
 <smtp-server outbound-socket-binding-ref="mail-smtp"/>
 </mail-session>

<mail-session name="java:/mail/org.imixs.workflow.mail" jndi-name="java:/mail/org.imixs.workflow.mail" debug="true">
     <smtp-server outbound-socket-binding-ref="mail-smtp"/>
 </mail-session>
</subsystem>

It’s important to define the smtp-server outbound-socket-binding-ref which is defined in the section ‘socket-binding-group’. If this is missing mails will always be forwarded to localhost independent from the default outbound-socket-binding for mail-smtp!

See the following example:

 <outbound-socket-binding name="mail-smtp">
 <remote-destination host="localhost" port="25"/>
 </outbound-socket-binding>

Note: You can also define additional outbound-socket-bindings for different smtp mail servers/smarthosts if needed.