Managing dependencies in migrations and new applications for WebSphere Application Server V8

This article describes the steps for effectively managing enterprise applications using IBM® Rational® Application Developer V8.0 for IBM WebSphere® Application Server V8.0. It will also provide some insight into investigating the class loading behaviour of WebSphere Application Server through the class loader viewer. This content is part of the IBM WebSphere Developer Technical Journal.

Sharad Chandra (schandr1@in.ibm.com), Senior WebSphere Consultant, IBM

Author photoSharad Chandra is working as Senior WebSphere Consultant in IBM Software Group. He has 8 years of experience on BPM and SOA technologies and a versatile background in handling complex customer solutions related to BPM and middleware technologies.



09 May 2012

Also available in Russian

Introduction

IBM WebSphere Application Server can help businesses offer richer user experiences through the rapid delivery of innovative applications. Developers can jump start their development efforts and leverage their skills by selecting from the comprehensive set of open standards-based programming models supported, enabling them to better align project requirements with programming model capabilities and developer skills. WebSphere Application Server also speeds application delivery by encouraging reuse and extending the life of existing application assets.

IBM Rational Application Developer provides a single, comprehensive development environment designed to meet a variety of needs, from Web interfaces to server-side applications, individual development to advanced team environments, and Java™ development to application integration. Rational Application Developer is part of the IBM Rational Software Development Platform, a series of products all built on the Eclipse open source platform for creating application development tools. Each product in the Rational desktop family offers the same integrated development environment (IDE). The differences among these products reflect the plug-in tools that are available in each configuration.

Dependency management plays an important role in post migration scenarios or during the development of applications with a huge number of dependent JARs for WebSphere Application Server. There could be situations where, for example, application code is being migrated from competitive platforms conforming to Java 1.4 specifications to WebSphere Application Server V8, which is built on the latest Java specs. If dependencies in such cases are not arranged properly, you could end up with class-related exceptions. While each application server has its own way of keeping application JAR files, it is best to rearrange these JARs using the best options provided by Rational Application Developer and WebSphere Application Server.

This article looks at dependency management through Rational Application Developer V8.0 and WebSphere Application Server V8.0. The focus here is specifically on post migration scenarios, however most information presented here is applicable in other situations as well.


Analysis of application architecture

The EAR generated out of the Rational tooling (Figure 1) contains an EJB module and a web module, with an optional application client, connector module, and so on, with the following deployment descriptors identifying each module:

  • application.xml
  • ejb-jar.xml
  • web.xml
  • ra.xml.
Figure 1. Application EAR structure
Figure 1. Application EAR structure

Keeping in mind that an EAR can have more than one EJB and Web modules, it is possible to encounter situations where:

  • Some application classes are duplicated in both EJB and Web modules because they are used in both.
  • Some JARs are referenced in both EJB and Web modules and so copies of the JAR is kept in multiple places.

Few examples of such dependencies involve loggers, XML parsers, and so on. The next section explains how these can be managed effectively.

During application development or post migration when the EAR has been brought into the Rational Application Developer workspace, one important step is to analyze the application architecture to identify the libraries it uses. An application might consist of open source frameworks, such as Struts, Spring, Hibernate, and so no, apart from the usual JSPs, servlets, and EJBs. In many cases, these framework dependencies reside in the Web module only. Few dependencies such as a logger (for example, log4j) will be used by both EJB and Web modules. As mentioned above, there could be duplicate classes in both EJB and Web modules because they are used in both. Apart from that, an application can have many JAR dependencies to support framework JARs. These dependencies have internal references to each other and could be important for application execution.

Few open source application servers bundle their JARs in EARs, adding to unnecessary dependencies. One example of this is j2ee.jar, which resolves J2EE-specific classes. The presence of these JAR files can be reduced by building the application code using the WebSphere Application Server V8.0 runtime available with the Rational tooling. You can do this by setting application server runtime in project facets.

One option is to use {APPSERVER_ROOT}/plugins JARs prefixed as javax.j2ee.* and org.apache.* to resolve application dependencies. This will require a one-time effort of code rebuilding. (Be aware that javax.j2ee.servlet.jar and com.ibm.ws.runtime.jar are loaded during server startup.)

Once these dependencies are identified, you can address the distribution of these JAR files.


Managing JARs for web module

The web module consists of JSP and servlets, which can be further enhanced using standard template libraries (JSTL, and so on), MVC and ORM frameworks (Struts, Hibernate, and so on), XML frameworks, web services, and so on. Depending on how these libraries are used, JARs can grow exponentially and therefore need to be managed. These JARs are usually kept in the WEB-INF/lib directory (Figure 2) and are loaded by WAR classloader by default. You can drop JARs into this folder through Rational Application Developer. We’ll discuss how many JARs can be managed as exceptions later.

Figure 2. WEB-INF/lib directory
Figure 2. WEB-INF/lib directory

Managing dependencies for EJB modules

Java archives that are referenced by classes in EJB modules can be kept at an EAR level shared library that you can create through Rational Application Developer. To import external JARs as an EAR level shared library, you need to import them as Java EE utility jars. To do this:

  1. Right-click on the EAR in Rational Application Developer and select Import > Java EE Utility Jar (Figure 3).
    Figure 3. JavaEE Utility Jar option
    Figure 3. JavaEE Utility Jar option
  2. Select the Copy utility jar into existing EAR from external location radio button (Figure 4) and click Next.
    Figure 4. Copy utility jar into existing EAR from external location
    Figure 4. Copy utility jar into existing EAR from external location
  3. Browse for the JAR file (Figure 5), select the file and click Finish. You should see a lib folder created in the EAR when the import is complete (Figure 6).
    Figure 5. Selecting the external jars
    Figure 5. Selecting the external jars
    Figure 6. lib folder created after import
    Figure 6. lib folder created after import

Dependencies at the EAR level are visible to both web and EJB modules. Therefore, custom application JARs that need to be shared across modules can also be placed at this location, along with third party JARs, following the above steps.


Sharing application classes across multiple modules

There could be scenarios where an application EAR can have duplicate Java classes in both the EJB and web modules. These duplicate classes can be kept in a separate common module, referred to as the Java utility module. In Rational Application Developer, you can create a Java utility module within an EAR by navigating to File > New > Other... > Java EE > Utility Project (Figure 7).

Figure 7. Utility Project option
Figure 7. Utility Project option

Name the Utility project and associate it to the existing EAR (Figure 8). This will create a lib folder in the EAR. If the lib folder already exists, for example from importing the JARs as described earlier, the utility module will be copied as a JAR inside this folder after the EAR is exported.

Figure 8. Naming utility project
Figure 8. Naming utility project

To share classes across multiple modules, copy all the Java classes, along with the fully qualified package hierarchy, into the src folder of this Utility project (Figure 9).

Figure 9. Classes in shared utility project
Figure 9. Classes in shared utility project
Figure 10. lib folder inside EAR
Figure 10. lib folder inside EAR
Figure 11. Contents of lib folder
Figure 11. Contents of lib folder
Figure 12. Classes inside SharedClassesUtility jar
Figure 12. Classes inside SharedClassesUtility jar

To build the code in other modules (Web and EJB) referring to this shared utility, you can add a project reference to the utility in each module from which you want to access classes in it (Figure 13).

Figure 13. Reference shared utility in other modules
Figure 13. Reference shared utility in other modules

Figures14 and 15 show the order in which classes are loaded by WebSphere Application Server for this particular EAR.

Figure 14. Classes as seen by the web module
Figure 14. Classes as seen by the web module
Figure 15. Classes as seen by EJB module
Figure 15. Classes as seen by EJB module

Managing additional dependencies outside the EAR

If the applications inside the EAR are supported by multiple JAR dependencies enough to drastically increase the size of the EAR, it is better to keep these JARs in an external folder and associate it with application as shared libraries.

To create a shared library, create a folder anywhere on the file system (preferably on {APPSERVER_ROOT}) and set its location in the Classpath field of Environment > Shared libraries (Figure 16).

Figure 16. Configuring shared library
Figure 16. Configuring shared library

Once the shared library is configured, you can associate it with the application by navigating to Applications > Enterprise Applications > {Application Name} > Shared library references, and associate it with either the EAR or web module (Figure 17).

Figure 17. Associating shared library to EAR
Figure 17. Associating shared library to EAR

Class loading behavior

Next, let’s look at how you can use the class loader viewer available in the WebSphere Application Server administrative console to observe class loading behavior at run time. This information is helpful when investigating class loader related issues. There are two kind of class loaders that play an important role in WebSphere Application Server. An application class loader groups Enterprise JavaBean™ (EJB) modules, shared libraries, resource adapter archives (RAR files), and dependency Java archive (JAR) files associated to an application. Dependency JAR files are JAR files that contain code that can be used by both enterprise beans and servlets. An application class loader is the parent of a web application archive (WAR) class loader. By default, a web module has its own WAR class loader to load the contents of the web module. The WAR class loader policy value of an application class loader determines whether the WAR class loader or the application class loader is used to load the contents of the Web module.

Figure 18. Class loader hierarchy diagram
Figure 18. Class loader hierarchy diagram

The default server level class loader policy associated with WebSphere Application Server V8.0 is Multiple with parent class loader first. This signifies that each EAR will get its own class loader, and in each application, EAR level libraries are loaded first followed by web libraries.

To understand class loader behavior through class loader viewer, we'll use the log4j library and observe its loading behaviors when kept in an EJB module, web module, or both, for class loading policies. Class Loader Viewer can be accessed through the administrative console by navigating to Troubleshooting > Class loader viewer > server1 > {YOUR APPLICATION}.

Class loading behavior with PARENT_FIRST

Application libraries are loaded first, followed by web libraries. The JAR dependencies can be kept in WEB-INF/lib if it is to be used only by classes of web module, whereas developer-created compiled Java classes go into WEB-INF/classes. Let’s look at two cases:

  • Case 1: log4j jar copied in WEB-INF/lib directory

    When the log4j JAR is kept only in the WEB-INF/lib directory, it is loaded by the web class loader, and the classes inside the JAR will be visible to only Web module Java classes (Figure 19).

    Figure 19. log4j jar loaded by web class loader
    Figure 19. log4j jar loaded by web class loader
  • Case 2: log4j jar copied at application level library

    When the log4j.jar file is kept in an EAR level library, it is visible to classes in both the modules. In Figure 20, log4j is not removed from WEB-INF/lib, just to showcase how an additional JAR at an EAR level library is loaded and seen in the class loader viewer.

    Figure 20. log4j jar loaded by both application and WEB class loader
    Figure 20. log4j jar loaded by both application and WEB class loader

Detecting duplicate and versioned JARs

Two versions of the same library placed in different locations or the same locations in the EAR could result in class conflicts, such as version-related issues. For example, suppose at the EAR level you have version 1 of a JAR file containing method f(), and at the web level you have version 3 of the same JAR file, which contains method f(String), with f() removed due to deprecation. If the application class tries to access f(String) it will get java.lang.NoSuchMethodError, since classes in the web module can see only the JAR loaded by the application class loader which does not have the f(String) method. To test this, two versions of log4j are kept at the EAR and web module levels and verified through the class loader viewer, shown in Figure 21.

Figure 21. Duplicate jar detection
Figure 21. Duplicate jar detection

Class loading behavior with PARENT_LAST

When class loading settings are changed to PARENT_LAST, the web class loader is given a priority over the application class loaders to load the classes. In such cases, web applications will not be able to see classes available at the EAR level. You can see in Figure 22 that ../WEB-INF/lib/log4j.jar is loaded prior to ../TestApp.ear/lib/log4j-1.2.16.jar, as compared to Figure 21, above.

Figure 22. Parent Last class loader policy
Figure 22. Parent Last class loader policy

Testing the application scenarios

Dependency visibility test

The test case provided with the included download material shows the configuration of the log4j library and shared utility so that it can be called from both EJB and web module-based application classes. Two log4j property files are created to write separate logs from the EJB and web modules. These property files are kept in custom folder {PROFILE_ROOT}/log4jProperty (Figures 23 and 24). The log4j jar is kept at an EAR level library to make it visible to classes in all the modules of EAR.

Figure 23. log4j property files folder
Figure 23. log4j property files folder
Figure 24. log4j property files
Figure 24. log4j property files

The respective property files are loaded in relative modules as shown in Figures 25 and 26.

Figure 25. Loading property file in EJB
Figure 25. Loading property file in EJB
Figure 26. Loading property file in servlet
Figure 26. Loading property file in servlet

Because log4j libraries are referenced in both the EJB and web modules, the dependency should be kept such that it is visible to both modules (Figure 27).

Figure 27. Generated logs
Figure 27. Generated logs

Shared utility test

This test shows how to share common application classes across multiple modules. To test the shared utility, we developed a TestSharedUtility class that is called successfully from both EJB and Web modules and response is logged (Figures 28 through 30).

Figure 28. Shared Utility class
Figure 28. Shared Utility class
Figure 29. Class call from EJB module
Figure 29. Class call from EJB module
Figure 30. Class call from web module
Figure 30. Class call from web module

Class conflict test

To test class conflicts, two JAR dependencies are created with two methods with the same name but with different parameters. It is assumed that the method of dependency 1 has been deprecated and removed from dependency 2. Although there could be several permutations to keep these dependencies, dependency 1 is kept here as a utility JAR at the EAR level and dependency 2 is kept in the WEB-INF/lib directory. Knowing that dependency 1 is loaded by the application class loader and dependency 2 is loaded by the web class loader, observe the behavior in a call from a servlet (Figures 31 and 32).

Figure 31. Version1 class method signature
Figure 31. Version1 class method signature
Figure 32. Version2 class method signature
Figure 32. Version2 class method signature

In the Version 2 case, the method f() has been removed due to deprecation. The older JAR, version1test.jar, is kept at EAR level whereas the newer JAR, version2test.jar, is kept in WEB-INF/lib (Figure 33).

Figure 33. Location of copied JARs
Figure 33. Location of copied JARs

Assuming that the test servlet wants to call the method of the newer JAR and that the previous JAR was kept at EAR level by mistake, the new result is shown in Figure 34.

Figure 34. Invocation of new method version
Figure 34. Invocation of new method version

When the test is run, the classes of version1test.jar file will be visible to the servlet and hence will throw the exception shown in Listing 1.

Exception trace
[4/13/12 6:25:10:247 EDT] 00000021 servlet
E com.ibm.ws.webcontainer.servlet.ServletWrapper service Uncaught service() exception 
thrown by servlet com.ibm.test.VersionTestServlet: java.lang.NoSuchMethodError: 
com/ibm/test/TestClass.f(Ljava/lang/String;)Ljava/lang/String;
   at com.ibm.test.VersionTestServlet.doPost(VersionTestServlet.java:41)
   at javax.servlet.http.HttpServlet.service(HttpServlet.java:595)
   at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
   at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1147)
   at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:
	722)
   at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:
	449)
   at com.ibm.ws.webcontainer.servlet.ServletWrapperImpl.handleRequest
	(ServletWrapperImpl.java:178)
   at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters
	(WebAppFilterManager.java:1020)
   at com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:3703)
   at com.ibm.ws.webcontainer.webapp.WebGroup.handleRequest(WebGroup.java:304)
   at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:953)
   at com.ibm.ws.webcontainer.WSWebContainer.handleRequest(WSWebContainer.java:1655)
   at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:195)
   at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination
	(Http	InboundLink.java:452)
   at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewRequest
	(HttpInboundLink.java:511)

You can remove the exception by either removing version1test.jar from the EAR while keeping the other in WEB-INF/lib, or by replacing version1test.jar with version2test.jar and removing the latter from WEB-INF/lib, if its classes needs to be called from the EJB as well.


Conclusion

It is always a best practice to plan dependencies when designing a fresh application or performing a migration. Not only does it help with better application management, but it reduces the complexities associated with troubleshooting class-related issues.


Acknowledgements

The author thanks Deepak Gupta for his review of this article.


Download

DescriptionNameSize
Code sample1205_chandra_attachment.zip525 KB

Resources

Learn

Get products and technologies

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into WebSphere on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere, Rational, DevOps
ArticleID=813226
ArticleTitle=Managing dependencies in migrations and new applications for WebSphere Application Server V8
publish-date=05092012