Java Development News:

Adding the Sun One Application Server to TheServerSide Cluster

By Dion Almaer

21 Apr 2003 | TheServerSide.com

Introduction - The Portability Challenge

At the end of September 2002, TheServerSide ported its codebase to be clusterable around BEA WebLogic 7, and Oracle 9iAS - the ultimate display of J2EE portability in action. We then wrote an article which discussed the task. Since that time, we have focused on adding features to TheServerSide, to expand the usefullness of the site to our users.   Recently we worked with Sun and have added the newly re-written Sun ONE Application Server 7 to the cluster. This article discusses the work that was done making TheServerSide.com J2EE application run on the J2EE 1.3 certified Sun ONE Application Server 7.

In this article we will discuss:

  • General Observations on Sun ONE Application Server 7
  • What needed to be done to deploy the application
  • Issues that came up in testing
  • Conclusion


General Observations on Sun ONE Application Server 7

I go back quite a long way, when it comes to the past lives of the Sun ONE Application Server. I remember writing applications using C and NSAPI, back on Netscape Enterprise Server (their old web server). I remember thinking: "This is so much faster than CGI, but it is a bit of a pain". Things have come a long way since then, and I was really interested to see how Sun ONE Application Server was progressing. I had heard that it was significantly re-written, but lets face it, you never know what is marketing and what is real. I have worked on a couple of projects using iPlanet, and although some of its components were OK, I was never hugely impressed. One thing: Sun ONE Application Server is different.

I began to think that maybe nothing of the old servers existed, but I did stumble on the old faithful obj.conf file (from the Netscape Enterprise days), so some of it still survives!


What needed to be done

J2EE is portable right? Well, kinda :) As you may have read in the first clustering article, there were things that definitely cropped up that needed to be fixed, but all in all, it isn't as painful as porting a C application!  A lot of the issues that were found in the first round helped out with this effort, as we knew where to look this time, and the code was generally cleaner and less "well it works on WebLogic"-esque.

Here are the steps that we took to get the server running.


Installation

Download. Click Around. Choose locations for files. Done.
An interesting item was that the installer did different things on varying platforms. On Windows, it put everything under one directory (e.g. c:ServersSunOne). On Linux, it split things apart following more unix-like conventions (/opt, /etc, /usr/java, and so on.). We used the -console mode for our remote box, no need for X.


Domain Setup

Sun ONE Application Server uses a domain model, which is similar to that of WebLogic. We configured a TSSDomain, which housed the Admin Server (admin-server) which needs to be up and running when you want to change configuration info. We also created a TSSServer, which would run the TSS Portal Enterprise Archive.
You can create domains, start/stop servers, and much more from both a Web Interface, or the command line.

E.g.:

Created TSSDomain

  % asadmin create-domain --adminport 4848 --adminuser admin --adminpassword thepassword TSSDomain

Start all servers in TSSDomain

  % asadmin start-domain --domain TSSDomain

When you configure a new server instance, you get to configure everything about it. At this point we tweaked:

  • JVM options (e.g. memory: -ms, -mx) and properties (e.g. -Dtss.property=value).
  • Created Connection Pool
  • Created JDBC DataSource (pointing to the pool)
  • Created Mail Session

Creating the Connection pool was a bit different to the other servers. In both WebLogic and Oracle, you tell the server the database driver (e.g. org.postgresql.Driver), as well as the JDBC URL, username/pass, and other JDBC info. In Sun ONE Application Server 7 you give a JDBC 2 connection pool class. In our case that was org.postgresql.jdbc2.optional.PoolingDataSource. We needed to update our postgresql.jar to one that contained those classes.


Deployment Descriptors

Now we have the server setup. It is time for us to turn to the application (our EAR file). We already have our standard deployment descriptors written (of course) but we need to add those that Sun ONE Application Server 7 requires. There are a couple of choices here. Sun ONE Application Server 7 comes with a migration tool, that will chew up your ear file, look at the other vendor descriptors, and spit out a version that contains the sun-*.xml files. I personally like to understand the choices made in the descriptors, so I spent some time reading both the online documentation, and the DTDs themselves. If you want to migrate an application quickly, then you could use their tool, and be done in a much shorter time.


Build System

Now that the deployment descriptors are created, we could add entries to our build system, that would create an enterprise archive. Sun ONE Application Server 7 supports exploded archives, as well as the traditional zipped-up ones. You have to follow some naming conventions to get the exploded archives to work. For example, an EJB jar file called portal-ejb.jar would exist in its exploded form as portal-ejb_jar, and a portal.war would look like portal_war. Fairly straight forward. On our production systems, we normally end up running exploded apps, to allow us to do quick builds, and for the TSS editors to shove in some new content and get it up and running without having to zip up a large file and redeploy the application. We created the new 'deploy-sunone' build target, which puts things in the right place, and then we were done.


J2EE Verifier

Now that the deployment descriptors are created, we could build an EAR file that Sun ONE Application Server 7 would like. However, instead of throwing the EAR file at the server, we used the Sun J2EE Verifier (which comes with Sun ONE Application Server 7) to make sure that the application is J2EE compliant, and Sun ONE Application Server 7 is happy with it.

% verifier.bat -v -ra -d verification_output_dir portal.ear

The J2EE verifier came up with a few parts of the app that were not playing to the letter of the spec, so we were able to fix those problems (mainly issues with EJB exception handling, and migration of the code from EJB 1.0). This tools is very nice to have. Whenever we add/modify the code, the verifier will be run to catch out any naughty things that we may have done. This is especially important for us, as we run the same code in so many different application servers. If we had the luxury of running in one, then even if the code wasn't J2EE compliant, if it worked in that particular server, you could say "oh well. it works".


Deploying TSS Portal App

When the application passed the J2EE verification tests, we felt ready to deploy to the server. As before, this task can be done from the Web interface, or via command-line:

Deploy by Directory

  % asadmin deploydir --user admin --password adminpassword --type application
 --instance TSSServer /tss/software/sunone/domains/TSSDomain/TSSServer/applications/j2ee-apps/portal

Deploy archive

  % asadmin deploy --user admin --password adminpassword --type application --instance TSSServer portal.ear

Undeploy

  % asadmin undeploy --user admin --password adminpassword --type application --instance TSSServer portal

The application deployed cleanly first time (thanks to the J2EE verifier!).


Issues that came up in testing

Getting an application deployed is one thing. Then it has to actually work :) When we first hit the TSS portal application, nothing showed up but errors. We needed to go through debugging to clean up the issues.


Java Security

As soon as we hit the application we saw a lot of POA exceptions. This led us down the path of trying to work out what was going on at the CORBA layer (POA is part of CORBA; Portable Object Adapter). As it happened, these exceptions led us down the WRONG path. After a bit of debugging, we found out that some of the code wasn't able to load due to the security settings. These areas were:

  • Tangosol Cache: this code needs to be able to play with sockets
  • OSCache: this code needs to be able to write the HTML cached files to disk
  • Sun JCE (Cryptography): this code needs to install a security provider
In the Sun ONE Application Server 7 server.xml file (or view via web interface) you can see which security policy is being used by finding:
-Djava.security.policy=/tss/software/sunone/domains/TSSDomain/TSSServer/config/server.policy
We added security settings for the above code to be able to do its thing. Items like:
Allow a new JCE provider

 grant codeBase "file:/path/to/codebase" {
  permission java.security.SecurityPermission "putProviderProperty.SunJCE";
  permission java.security.SecurityPermission "insertProvider.SunJCE";
 };

Allow OSCache to write files

 grant codeBase "file:/path/to/codebase" {
  permission java.io.FilePermission "<<ALL FILES>>", "read,write,delete";
 };
We also could have taken out the java.security.policy system property, which would disable ANY security checks. This helps with performance, but can be dangerous, especially if there is any chance that you app will run untrusted code!


Problems with <jsp:include>'s

We had the app running, and some pages worked absolutely fine. However for some reason some of them were giving us weird exceptions, and the page half showing up:

SEVERE: ApplicationDispatcher[] Servlet.service() for servlet default threw exception
java.lang.IllegalStateException
        at org.apache.jasper.runtime.ServletResponseWrapperInclude.getOutputStream(ServletResponseWrapperInclude.java:109)
        at org.apache.catalina.servlets.DefaultServlet.serveResource(DefaultServlet.java:1162)
        at org.apache.catalina.servlets.DefaultServlet.doGet(DefaultServlet.java:520)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:740)
        ...
Soon it became obvious that this was happening with some <jsp:include>s. Sun ONE Application Server 7 (or Apache Jasper in this case) didn't seem to like:
<jsp:include page="/usercount.include" />
This is used on the pages that show how many users are subscribed on TSS. A cronjob created that file from time to time, so the amount is psuedo-real time. Jasper didn't like the name of the file. When we changed it to usercount.html all was happy again. As long as the filename was .html or .jsp, it seemed to be fine, so we just made sure that any <jsp:include> included a file with that extension.


Error in internal Sun ONE Application Server 7 EJB Cache

We noticed that exceptions were being throw in some situations, and content was being displayed for parts of the site. The log file showed us:

Mar 17 12:45:09 PM ERROR EJB - An error occured searching for a fullMessageView
javax.ejb.EJBException: nested exception is: java.lang.NullPointerException
java.lang.NullPointerException
 at com.sun.appserv.util.cache.LruCache.trimLru(LruCache.java:102)
 at com.sun.appserv.util.cache.LruCache.itemAdded(LruCache.java:147)
 at com.sun.appserv.util.cache.BaseCache._put(BaseCache.java:511)
 at com.sun.appserv.util.cache.BaseCache.add(BaseCache.java:454)
 at com.sun.ejb.containers.EntityContainer.addReadyEJB(EntityContainer.java:2069)
 at com.sun.ejb.containers.EntityContainer.releaseContext(EntityContainer.java:766)
 at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:523)
 at portal.services.ejb.beans.CategoryBean_EJBObjectImpl.getCategoryDetails(CategoryBean_EJBObjectImpl.java:155)
 ...
So, something wasn't going right when the container went to trim its cache, for certain EJBs. We only have a few categories in TSS (home, discussions, events, etc). Due to this, I configure the Category Entity EJB to have a small pool and cache size. It turned out that the Sun ONE Application Server 7 default resize-quantity is 16. In some situation, the container tried to resize the cache by more than the maximum, and it blew up. The simple fix involved setting a lower resize-quantity in the sun-ejb-jar.xml:
  <ejb>
   <ejb-name>portal.Category</ejb-name>
   <jndi-name>portal.CategoryHome</jndi-name>
   <resource-ref>
    <res-ref-name>jdbc/ejbPool</res-ref-name>
    <jndi-name>jdbc.tssPool</jndi-name>
   </resource-ref>
   <pass-by-reference>true</pass-by-reference>
   <bean-pool>
    <steady-pool-size>5</steady-pool-size>
    <max-pool-size>15</max-pool-size>
   </bean-pool>
   <bean-cache>
    <max-cache-size>20</max-cache-size>
    <resize-quantity>5</resize-quantity>
    <cache-idle-timeout-in-seconds>600</cache-idle-timeout-in-seconds>
   </bean-cache>
  </ejb>


Difference in opinion when choosing a web application

The site was now looking good. I could click around and all looked normal. Then I decided to POST some information from some form. I kept being sent back to the home page, and nothing was updated. We were very confused. After scratching our heads, we realized that Sun ONE Application Server 7 chooses which web application to run differently to the others. Let me explain the conditions. We have:

  • A web application named 'portal'
  • A servlet controller (as in MVC) pined to '/portal' in the web.xml
  • The server has the default web application as 'portal'
What should a request for http://server/portal?x=1&y=2 do?

WebLogic and Oracle: Both of these servers decide to use the default web application and THEN pass /portal in. This resolves as the equivilent: http://server/portal/portal?x=1&y=2
Sun ONE Application Server 7: Application Server 7 reasons that /portal means to hit THAT web application, and hence not pass in /portal again. This eventually resolves to http://server/portal/index.jsp?x=1&y=2

Interesting huh? There was of course a simple solution for us. We changed the web application to be called portal-web instead of the overused portal.
To make this change the following edits needed to be made:

  • build system: changed web application name
  • ear/application.xml: Point to portal-web
  • appserver specific: Edit files to use the default web app of 'portal-web'
    . weblogic: config.xml: <WebServer DefaultWebApp="portal-web" ...
    . oracle: default-web-site.xml: <default-web-app application="portal" name="portal-web" root="/" />
    . sunone: server.xml: <virtual-server id="TSSServer" ... default-web-module="portal:portal-web.war">


Conclusion

J2EE Portability

There are always issues when porting from one system to another. We ran into a couple in the port to Sun ONE Application Server 7, and I am sure we would run into more if we ported to another server. However, it is still great that with a couple days of work, a real-world application can be up and running on a totally new application server. J2EE portability is not perfect. The spec doesn't account for everything, and each vendor will have its quirks. It is pretty darn good though! Of course, we have tried to make sure that our application is coded to the standards, and definitely doesn't use any of the vendors extension classes.


Sun ONE Application Server 7

I was very pleased with the ease of use of Sun ONE Application Server 7. It is great to see Sun with a quality, performant, and viable solution. I would like to thank Homer Yau from Sun for his help.


About the Author

Dion Almaer (dion@theserverside.com) is Chief Architect of TheServerSide.com, a service of The Middleware Company (www.middleware-company.com), one of the nation's leading training companies in EJB/J2EE and B2B technology training.