[[Migrate_Order_Application_from_EAP5]]
= Porting the Order Application from EAP 5.1 to WildFly {wildflyVersion}

Andy Miller ported an example Order application that was used for
performance testing from EAP 5.1 to WildFly {wildflyVersion}. These are the notes he
made during the migration process.

[[overview-of-the-application]]
== Overview of the application

The application is relatively simple. it contains three servlets, some
stateless session beans, a stateful session bean, and some entities.

In addition to application code changes, modifications were made to the
way the EAR was packaged. This is because WildFly removed support of
some proprietary features that were available in EAP 5.1.

[[summary-of-changes]]
== Summary of changes

[[code-changes]]
=== Code Changes

[[modify-jndi-lookup-code]]
==== Modify JNDI lookup code

Since this application was first written for EAP 4.2/4.3, which did not
support EJB reference injection, the servlets were using pre-EE 5
methods for looking up stateless and stateful session bean interfaces.
While migrating to WildFly, it seemed a good time to change the code to
use the @EJB annotation, although this was not a required change.

The real difference is in the lookup name. WildFly only supports the new
EE 6 portable JNDI names rather than the old EAR structure based names.
The JNDI lookup code changed as follows:

Example of code in the EAP 5.1 version:

[source, java]
----
try {
    context = new InitialContext();
    distributionCenterManager = (DistributionCenterManager) context.lookup("OrderManagerApp/DistributionCenterManagerBean/local");
} catch(Exception lookupError) {
    throw new ServletException("Couldn't find DistributionCenterManager bean", lookupError);
}
try {
    customerManager = (CustomerManager) context.lookup("OrderManagerApp/CustomerManagerBean/local");
} catch(Exception lookupError) {
    throw new ServletException("Couldn't find CustomerManager bean", lookupError);
}
 
try {
    productManager = (ProductManager) context.lookup("OrderManagerApp/ProductManagerBean/local");
} catch(Exception lookupError) {
    throw new ServletException("Couldn't find the ProductManager bean", lookupError);
}
----

Example of how this is now coded in WildFly:

[source, java]
----
@EJB(lookup="java:app/OrderManagerEJB/DistributionCenterManagerBean!services.ejb.DistributionCenterManager")
private DistributionCenterManager distributionCenterManager;
 
@EJB(lookup="java:app/OrderManagerEJB/CustomerManagerBean!services.ejb.CustomerManager")
private CustomerManager customerManager;
 
@EJB(lookup="java:app/OrderManagerEJB/ProductManagerBean!services.ejb.ProductManager")
private ProductManager productManager;
----

In addition to the change to injection, which was supported in EAP
5.1.0, the lookup name changed from:

[source, java]
----
OrderManagerApp/DistributionCenterManagerBean/local
----

to:

[source, java]
----
java:app/OrderManagerEJB/DistributionCenterManagerBean!services.ejb.DistributionCenterManager
----

All the other beans were changed in a similar manner. They are now based
on the portable JNDI names described in EE 6.

[[modify-logging-code]]
=== Modify logging code

The next major change was to logging within the application. The old
version was using the commons logging infrastructure and Log4J that is
bundled in the application server. Rather than bundling third-party
logging, the application was modified to use the new WildFly Logging
infrastructure.

The code changes themselves are rather trivial, as this example
illustrates:

Old JBoss Commons Logging/Log4J:

[source, java]
----
private static Log log = LogFactory.getLog(CustomerManagerBean.class);
----

New WildFly Logging

[source, java]
----
private static Logger logger = Logger.getLogger(CustomerManagerBean.class.toString());
----

Old JBoss Commons Logging/Log4J:

[source, java]
----
if(log.isTraceEnabled()) {
    log.trace("Just flushed " + batchSize + " rows to the database.");
    log.trace("Total rows flushed is " + (i+1));
}
----

New WildFly Logging:

[source, java]
----
if(logger.isLoggable(Level.TRACE)) {
    logger.log(Level.TRACE, "Just flushed " + batchSize + " rows to the database.");
    logger.log(Level.TRACE, "Total rows flushed is " + (i+1));
}
----

In addition to the code changes made to use the new AS7 JBoss log
manager module, you must add this dependency to the `MANIFEST.MF` file
as follows:

[source, java]
----
Manifest-Version: 1.0
Dependencies: org.jboss.logmanager
----

[[modify-the-code-to-use-infinispan-for-2nd-level-cache]]
=== Modify the code to use Infinispan for 2nd level cache

Jboss Cache has been replaced by Infinispan for 2nd level cache. This
requires modification of the `persistence.xml` file.

This is what the file looked like in EAP 5.1:

[source, java]
----
<properties>
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.jbc2.JndiMultiplexedJBossCacheRegionFactory"/>
<property name="hibernate.cache.region.jbc2.cachefactory" value="java:CacheManager"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.use_query_cache" value="false"/>
<property name="hibernate.cache.use_minimal_puts" value="true"/>
<property name="hibernate.cache.region.jbc2.cfg.entity" value="mvcc-entity"/>
<property name="hibernate.cache.region_prefix" value="services"/>
</properties>
----

This is how it was modified to use Infinispan for the same
configuration:

[source, java]
----
<properties>
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.use_minimal_puts" value="true"/>
</properties>
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
----

Most of the properties are removed since they will default to the
correct values for the second level cache. See
https://docs.jboss.org/author/display/AS71/JPA+Reference+Guide#JPAReferenceGuide-UsingtheInfinispansecondlevelcache["Using
the Infinispan second level cache"] for more details.

That was the extent of the code changes required to migrate the
application to AS7.

[[ear-packaging-changes]]
=== EAR Packaging Changes

Due to modular class loading changes, the structure of the existing EAR
failed to deploy successfully in WildFly.

The old structure of the EAR was as follows:

[source, java]
----
$ jar tf OrderManagerApp.ear
META-INF/MANIFEST.MF
META-INF/application.xml
OrderManagerWeb.war
OrderManagerEntities.jar
OrderManagerEJB.jar
META-INF/
----

In this structure, the entities and the `persistence.xml` were in one
jar file, `OrderManagerEntities.jar`, and the stateless and stateful
session beans were in another jar file, `OrderManagerEJB.jar`. This did
not work due to modular class loading changes in WildFly. There are a
couple of ways to resolve this issue:

1.  Modify the class path in the `MANIFEST.MF`
2.  Flatten the code and put all the beans in one JAR file.

The second approach was selected because it simplified the EAR
structure:

[source, java]
----
$ jar tf OrderManagerApp.ear
META-INF/application.xml
OrderManagerWeb.war
OrderManagerEJB.jar
META-INF/
----

Since there is no longer an `OrderManagerEntities.jar` file, the
`applcation.xml` file was modified to remove the entry.

An entry was added to the `MANIFEST.MF` file in the
`OrderManagerWeb.war` to resolve another class loading issue resulting
from the modification to use EJB reference injection in the servlets.

[source, java]
----
Manifest-Version: 1.0
Dependencies: org.jboss.logmanager
Class-Path: OrderManagerEJB.jar
----

The `Class-Path` entry tells the application to look in the
`OrderManagerEJB.jar` file for the injected beans.

[[summary]]
=== Summary

Although the existing EAR structure could have worked with additional
modifications to the `MANIFEST.MF` file, this approach seemed more
appealing because it simplified the structure while maintaining the web
tier in its own WAR.

The source files for both versions is attached so you can view the
changes that were made to the application.
