Limitations

The following sections describe limitations of the Migration Tool:

  • Custom JSP Tags Implementation
  • Proprietary API Implementation
  • Build Scripts Generation
  • Application Server Differences
  • Other Migration Limitations
  • OS/Platform Issues

Custom JSP Tags Implementation

The limitations of proprietary custom JSP tags supported in this version are as follows:

Custom JSP Tags for WAS 4.0

The <tsx:getProperty> tag is not supported for bean operations.

Custom JSP Tags for WLS 5.1

The <wl:cache> tag is recognized by the Application Server but is considered a no-op. The caching functionality provided by this tag in WLS 5.1 is not supported. It is implemented as a no-op to prevent the JSP that uses this tag from failing after migration.

Custom JSP Tags for WLS 6.x

The <wl:prefetch> and <wl:beanparam> tags are not supported. The implementation of the <wl:cache> tag does not support "cluster" scope and administration of the cache.

Proprietary API Implementation

Unsupported Proprietary APIs for WAS 4.0

Besides a partial implementation of the com.ibm.websphere.servlet.cache package (see the Capabilities of the tool section), the Migration Tool does not support any package starting with com.ibm except those listed in the Proprietary API Implementation section.

Unsupported Proprietary APIs for WLS 5.1

Besides a partial implementation of the weblogic.common T3 services (see the Capabilities of the tool section), the Migration Tool does not support the following WLS 5.1 packages:

  • All packages starting with bea.jolt. except those listed in the Table 6-9 section.
  • All packages starting with weblogic. except those listed in the Table 6-9 section.

Unsupported Proprietary APIs for WLS 6.0/6.1

Besides a partial implementation of the weblogic.common T3 services (see the Capabilities of the tool section), the Migration Tool does not support the following WLS 6.0/6.1 packages:

  • All packages starting with bea.jolt. except those listed in the Table 6-10 section.
  • All packages starting with weblogic. except those listed in the Table 6-10 section.

Unsupported Proprietary APIs for Sun ONE Application Server 6.5

Sun ONE Application Server 6.5 proprietary APIs are not supported.

Build Scripts Generation

The following limitations apply to the generation of the build scripts:

  • The build scripts generated by the migration tool are not valid if there is more that one application.xml file given in the input. The generated build_ear.xml file(s) are invalid.
  • The build scripts generated by the Migration Tool have a dependency on the directory structure in the output directory. After migration, if you change the name of any directory or move the output directory to another directory, the scripts will not work.

If you want to transfer the code to a different machine before running the build, you have to maintain the same directory structure on that machine as well.
As mentioned in the the Capabilities of the tool section, for the generated build scripts to work properly, the scripts assume the input to the migration tool is in the form of a directory structure that conforms to the JAR file and WAR file structure as required by the Java EE specification. If this is not the case, the build scripts might not execute properly.
To enable the Migration Tool to create a build_jar build script, which, when executed, creates a JAR file containing the enterprise beans, the input to the Migration Tool should adhere to the following structure:

<_app-dir_>/META-INF/*.xml or <_app-dir_>/*.xml
<_app-dir_>/sample/app/*.java

To enable the Migration Tool to create a build_war script, which, when executed, creates a WAR file containing the Web application, the input to the tool should adhere to the following structure:

<_app-dir_>/WEB-INF/*.xml or <_app-dir_>/*.xml
<_app-dir_>/sample/app/*.java 
<_app-dir_>/docroot/[_helper files such as HTML and JSP_]

To enable the Migration Tool to create a build_ear script, which, when executed, creates an EAR file containing the enterprise beans and the Web application, the input to the migration tool should adhere to the following structure:

<_app-dir_>/META-INF/*.xml or <_app-dir_>/*.xml
<_app-dir_>/[_directory structure for creating JAR_] 
<_app-dir_>/[_directory structure for creating WAR_]

In the case of an EAR file, the directory structure just noted is ideal. An input directory structured as follows is also acceptable for the build scripts to be generated and executed with no trouble:

<_app-dir_>/META-INF/application.xml, ejb-jar.xml, *.xml 
<_app-dir_>/WEB-INF/web.xml
<_app-dir_>/sample/app/*.java
<_app-dir_>/docroot/[_helper files such as HTML and JSP_]
  • The Application Server classloader does not allow the same class to be present in both the JAR files and WAR files by default. The build scripts take care of this only to a certain extent. If the class file of a JAR file depends on a file that is inside the directory of a WAR file (the directory in which the web.xml file is present), this file is packaged inside both the JAR file and the WAR file. To avoid this conflict, the file should be placed inside the directory of the JAR file and removed from the WAR file directory. The other option is to delete from inside the compile task of the build_war.xml file the reference to the file that is passed as an argument to the Java compiler, javac.

Application Server Differences

This section lists the known differences in the Java EE implementation between the source and target application servers.

  • Implementation difference of <ejb-ref> between WebLogic 6.x and the Application Server

The session or entity bean description inside the ejb-jar.xml file can contain an optional <ejb-ref> entry. This ejb-ref tag, in turn, might contain an optional <ejb-link> tag. WebLogic 6.x gives preference to the <ejb-link> tag over the mandatory <ejb-ref-name> entry of the ejb-ref tag. This becomes an issue when the ejb-ref-name entries inside the weblogic-ejb-jar.xml and ejb-jar.xml files do not match for a particular bean.
To elaborate, the presence of an ejb-link tag inside the ejb-jar.xml file makes the ejb-ref-name entry inside the weblogic-ejb-jar.xml file irrelevant for WebLogic 6.x. The Migration Tool generates the sun-ejb-jar.xml file from the weblogic-ejb-jar.xml file. Using the generated sun-ejb-jar.xml file leads to the inability to deploy the module on the Application Server.
The example that follows shows a case where the ejb-ref-name entries do not match on WebLogic 6.x. Incidentally, these are valid DD contents for WebLogic 6.x.
The contents of the ejb-jar.xml file are as follows:

<session>
      <description>This is the Cart ejb &lt;/description>
      <display-name>The Cart </display-name>
      <ejb-name>TheCart</ejb-name>
      <home>com.sun.j2ee.blueprints.shoppingcart.cart.ejb.ShoppingCartHome</home>
      <remote>com.sun.j2ee.blueprints.shoppingcart.cart.ejb.ShoppingCart</remote>
      <ejb-class>com.sun.j2ee.blueprints.shoppingcart.cart.ejb.ShoppingCartEJB
      </ejb-class>
      <session-type>Stateful</session-type>
      <transaction-type>Container</transaction-type>
      <ejb-ref>
        <ejb-ref-name>ejb/catalog/Catalog</ejb-ref-name>
        <ejb-ref-type>Session</ejb-ref-type>
        <home>com.sun.j2ee.blueprints.shoppingcart.catalog.ejb.CatalogHome</home>
        <remote>com.sun.j2ee.blueprints.shoppingcart.catalog.ejb.Catalog</remote>
        <ejb-link>TheCatalog</ejb-link>
      </ejb-ref>
</session>

The contents of the weblogic-ejb-jar.xml file are as follows. Note the differences shown in bol;dface.

<weblogic-enterprise-bean>
                <ejb-name>TheCart</ejb-name>
                <stateful-session-descriptor/>
                <reference-descriptor>
                        <ejb-reference-description>
                                <ejb-ref-name>ejb/catalog</ejb-ref-name>
                                <jndi-name>estore/catalog</jndi-name>
                        </ejb-reference-description>
                 </reference-descriptor>
                 <jndi-name>estore/cart</jndi-name>
</weblogic-enterprise-bean>

The workaround for this limitation is to modify either the source-side DDs or the generated sun-ejb-jar.xml file to correct this problem.

  • Migrating applications using Container-Managed Relationships (CMR) from the Java EE Reference Implementation to the Application Server

In the Java EE RI, all CMRs are maintained using the LINK table approach. However, in the Application Server, the LINK table should be used only for many-to-many relationships. For all other cases, a foreign key approach is mandated for maintaining the relationship.
If the source-side application contains a one-to-many relationship and uses the LINK table approach, the Migration Tool migrates the application keeping the LINK table approach intact. As a result, the migrated application does not function as expected on the Application Server.
To get past this limitation, before you migrate the application, manually change the LINK table approach to the foreign key approach. These changes must be reflected in the database schema for the application.

  • Response buffer size variance in migrating Servlets and JSPs

In a Servlet/JSP, the header information should not be set after the response body has been committed to the output stream. This also holds true for cookie/session management, as these also are part of the header information. If the cookie/session object is manipulated/updated after some HTML has been committed to the outputstream, this updated information may be lost and the desired effect may not be seen. Much of this depends upon the default buffer size of the response object in the Application Server. For example, consider the code snippet, which was taken from a Servlet, below. Pay attention to the comments in bold
The original code is as follows.

public void service(HttpServletRequest req, HttpServletResponse res)  
throws IOException  
{
    boolean cookieFound = false;
    Cookie thisCookie = null;

    res.setContentType("text/html");
    PrintWriter out = res.getWriter();

    Cookie[] cookies = req.getCookies();          //Get Cookie information
    for(int i=0; i < cookies.length; i++) {
      thisCookie = cookies[i];
      if (thisCookie.getName().equals("CookieCount")) {
        cookieFound = true;
        break;
      }
    }
    
if (cookieFound == false) {
      thisCookie = new Cookie("CookieCount", "1");
      thisCookie.setMaxAge(60*1);
      res.addCookie(thisCookie);
}    

out.println("<html><head>\n" +              //Writing some html response
      "<title>Cookie Counter</title>\n" +
      "</head>\n" +
      "<body bgcolor=#ffffff> <font face=\"Comic Sans MS\" size+=4 color=red>" +
      "<center><h1>Cookie Counter</h1></center>");    
pageCount++;    
out.println("<p><img src=\"/images/cookie.jpg\" align=left>");    
out.println("<font color=blue>");    
out.println("<p><br><br><br>This page has been visited " + pageCount +
       (pageCount==1?" time":" times") +
       " before.\n");    
if (cookieFound) {                          //Manipulating Cookie again!
      int cookieCount = Integer.parseInt(thisCookie.getValue());
      cookieCount++;
      thisCookie.setValue(String.valueOf(cookieCount));
                                                //Updating Cookie information after
                                                //some response has been written to
                                                //the response buffer! Bad move.
      thisCookie.setMaxAge(10);
          res.addCookie(thisCookie);

      out.println("<p>You have visited this page " +
                  thisCookie.getValue() +
                  (cookieCount==1?" time":" times") +
                  " within the past 10 seconds.\n");    
    } else {
      out.println("<p>Either you haven't visited this page recently, "+
                  "or your browser doesn't like cookies!\n");
    }
    out.println("</body></html>");  
}

This code displays inconsistent behavior when it is run on different application servers. This is due to the following reasons:

  • If the default Response Buffer Size of that particular application server is more than the size of the response written to the Buffer, the Cookie information updated after writing the response reflects in the working of the code. On WebLogic 5.1 and WebSphere Application Server 4.0, the default buffer size is 8 KB and 4 KB, respectively. Although the above code works on these application servers (the response size written to the buffer in this code before updating the Cookie object is less than 4 KB), the code is not effective in other cases when the size of the response written to the buffer is higher than the buffer size.
  • If the default Response Buffer Size of that particular application server is less than the size of the response written to the Buffer, the Cookie information updated after writing the response is lost. This is because the response has already been committed to the client browser, and the headers cannot be set after that. The default buffer size on Sun ONE Application Server 6.5 is 0 KB, so this code does not work in a consistent fashion on that application server.

To get past this limitation, modify the code of the Servlet/JSP to do all header manipulation and updating before writing to the buffer. This is a healthy practice and is advised in the Servlet/JSP specification. The modified code for the previous example follows. Note the modifications, which have been highlighted in boldface.

public void service(HttpServletRequest req, HttpServletResponse res)  
throws IOException  
{
    boolean cookieFound = false;
    Cookie thisCookie = null;

    res.setContentType("text/html");
    PrintWriter out = res.getWriter();

    Cookie[] cookies = req.getCookies();                //Get Cookie information
    for(int i=0; i < cookies.length; i++) {
      thisCookie = cookies[i];
      if (thisCookie.getName().equals("CookieCount")) {
        cookieFound = true;
        break;
      }
    }

    if (cookieFound == false) {                          //Manipulating Cookie
      thisCookie = new Cookie("CookieCount", "1");
      thisCookie.setMaxAge(60*1);
      res.addCookie(thisCookie);
    }
                int cookieCount = 0;
    if (cookieFound) {
      cookieCount = Integer.parseInt(thisCookie.getValue());
      cookieCount++;
      thisCookie.setValue(String.valueOf(cookieCount));
                                                //Update Cookie information before
                                                //some response is written to
                                                //the response buffer.
                                                //Good move! Truly portable code
      thisCookie.setMaxAge(10);
      res.addCookie(thisCookie);
        }

    out.println("<html><head>\n" +       //Now Write your response
         "<title>Cookie Counter</title>\n" +
         "</head>\n" +
         "<body bgcolor=#ffffff> +
                 "<font face=\"Comic Sans MS\" size+=4 color=red>" +
         "<center><h1>Cookie Counter</h1></center>");
    pageCount++;
    out.println("<p><img src=\""+req.getContextPath()+
                "/images/cookie.jpg\" align=left>");
    out.println("<font color=blue>");
    out.println("<p><br><br> +
                 "<br>This page has been visited " + pageCount +
                (pageCount==1?" time":" times") +
                " before.\n");

    if (cookieFound) {
      out.println("<p>You have visited this page " +
                  thisCookie.getValue() +
                  (cookieCount==1?" time":" times") +
                  " within the past 10 seconds.\n");
    } else {
      out.println("<p>Either you haven't visited this page recently, "+
                  "or your browser doesn't like cookies!\n");
    }
    out.println("</body></html>");
    out.close();
  }
  • Difference in the implementation of {{HttpServletRequest}}interface between WLS5.1/6.x/Sun ONE Application Server 6.5 and the Application Server

The getCookies() method of the HttpServletRequest interface is implemented differently by WLS5.1/WLS 6.x/Sun ONE Application Server 6.5 and the Application Server. This may lead to inconsistent behavior by a server-side component that contains a call to this method, similar to the following sample code.
Before looking at the sample code, examine how the Servlet Specification defines this method. As per the documentation of both J2EE 1.2.x, which is the J2EE standard for WLS5.1 and Sun ONE Application Server 6.5, and J2EE 1.3.x, which is the J2EE standard for WLS 6.x, API, the getCookies() method of the HttpServletRequest interface is described as:

getCookies

        public Cookie[] getCookies()

                Returns an array containing all of the Cookie objects the client sent with this
                request. This method returns null if no cookies were sent.

                Returns:
                an array of all the Cookies included with this request, or null if the request
                has no cookies

This implies that the first call to the getCookies() method (when there are no cookies), shown in the code below, results in returning a null. This, in turn, results in a NullPointerException on execution of the lines following the call to the getCookies() method.

Cookie[] cookies = req.getCookies();        <-----> Problem    
for(int i=0; i &lt; cookies.length; i++) {            <-----> NullPointerException here
      thisCookie = cookies[i];
      if (thisCookie.getName().equals("CookieCount")) {
        cookieFound = true;
        break;
      }
    }

Note - However, an aberration exists on the part of WLS 5.1/6.x as well as Sun ONE AS 6.5. The first call to the getCookies() method returns an empty array (an array with zero elements) instead of null (as specified by the documentation), which, in turn, makes the previous sample code work on these application servers.
Since this is not the case in the Application Server, which acts according to the Java EE documentation, this piece of code throws a NullPointerException.
To get beyond this limitation, before deployment you should modify the code manually as follows.

Cookie[] cookies = req.getCookies();            
if(cookies != null)              <-----> Escape NullPointerException here
    {
        for(int i=0; i &lt; cookies.length; i++) {            
                     thisCookie = cookies[i];
                     if (thisCookie.getName().equals("CookieCount")) {
                             cookieFound = true;
                             break;
                     }
        }
    }

Other Migration Limitations

  • Migrating enterprise beans that comply with the EJB 1.0 Specification

WebSphere Application Server 4.0 supports enterprise beans developed as per the EJB 1.0 specification. The Application Server does not support these EJB 1.0 beans. Although the Migration Tool takes a minimal approach to migrating such enterprise beans to make them compliant to the EJB 1.1 specification, this implementation is not fully reliable and may lead to discrepancies, which will surface during deployment of the migrated application.
To get past this limitation, modify the code of the bean so that it is EJB 1.1-compliant before migration.

  • Migrating applications from WebLogic Application Server 6.0/6.1
  • WebLogic 6.1 provides built-in automatic key generation for primary key values of CMP entity beans. When you create a bean using this key-generation approach, the WebLogic EJB container assigns the primary key automatically during the database insert.Note -

This feature is not migrated as part of the application because no equivalent feature is available on the Application Server.
To get past this limitation, modify the code of a CMP entity bean so it does not use this feature. Some useful suggestions are available in EJB Design Patterns by Floyd Marinescu.

  • WebLogic 6.0 allows EJB relationships (CMRs) between two beans only through remote interfaces, which is prohibited by the EJB 2.0 specification. EJB relationships are now based on the local interface. Any enterprise bean that participates in a relationship must have a local interface. Relationships using remote interfaces were removed from the EJB 2.0 specification. Also, the related beans must be deployed within the same EJB JAR file.

Since these restrictions were not in place at the time WebLogic 6.0 was released, an application that uses these now prohibited features must be modified manually to ensure adherence to the EJB 2.0 specification. http://edocs.bea.com/wls/docs61/notes/migrate60to61.html.
To get past this limitation, modify the application manually before or after migration to ensure that all CMRs are between CMP entity beans with local interfaces and that these related beans are located within the same EJB JAR file.

  • WebLogic 6.x standalone applications cannot be migrated to the Application Server
  • WebLogic 6.0 allows WLQL in place of EJB-QL inside the ejb-jar.xml file. This WLQL will not be migrated by the Migration Tool.

To get past this limitation, after migration, manually replace the WLQL expression(s) to the equivalent EJB-QL expression(s) before deploying the application to the Application Server.

  • Migrating applications assumed to be local to the server

The Migration Tool assumes that applications being migrated are local to the server. That is, all method calls/object calls in the applications to be migrated refer to a method/object existing locally on the server. To illustrate this point, the following code shows the modifications done by the Migration Tool to code that provides such connection information.
The original code is as follows.

Properties h = new Properties();
h.put(Context.INITIAL_CONTEXT_FACTORY, m_INITIAL_CONTEXT_FACTORY);        
h.put(Context.PROVIDER_URL, m_PROVIDER_URL);        
h.put(Context.SECURITY_PRINCIPAL, user);        
h.put(Context.SECURITY_CREDENTIALS, password);        
.....        
InitialContext ctx = new InitialContext(h);

This code snippet is replaced by the empty IntialContext constructor, as shown below.

InitialContext ctx = new InitialContext();
.....

Therefore, when migrating an application that is NOT local to the server, keep this issue in mind as the tool assumes the non-existence of remote object calls.
To get past this limitation, before migration, examine the application for all calls to remote objects. Pass the application through the Migration Tool. Then modify the specific changed code snippets so they revert back to the original remote object calls. Specifically, manually add the URL that was originally present and any other connection properties to look up.

  • Migration Tool does not properly handle getter and setter methods of JSP custom tags

The Application Server supports the JSP 1.2 and JSP 2.0 specification. The implementation of the JSP 1.2 specification requires that the getter and setter methods of an attribute inside a custom tag must return and accept the same data type. The migration tool cannot handle this scenario, as the following example illustrates.
The original tag handler class is as follows.

public class Listtag extends TagSupport{
  int numIterms;  public int getNumItems() {
      return numItems;
  }
  
  public void setNumItems(String numItemsStr) 
    numItems = Integer.parseInt(numItemsStr);
  } 
  
}

The tag handler class that the Application Server requires is as follows.

public class Listtag extends TagSupport{
  int numIterms;  public int getNumItems() {
      return numItems;
  }
  
  public void setNumItems(int numItemsStr) 
    numItems = Integer.parseInt(numItemsStr);
  } 
  
}

To get past this limitation, manually make changes inside the tag handler classes so that the migrated application works as expected on the Application Server.

  • Impact of commented method calls in the migrated code

The Application Server restricts the use of some system calls, such as System.setOut(), which, if made, results in a runtime access control exception. Typically, the System.out stream is directed to the server.log file and redirecting it disturbs the server's logging functionality. To avoid this runtime exception, the Migration Tool comments out such calls in the migrated code, as shown in the following example.
The original code is as follows.

public void init(ServletConfig config) throws ServletException{
        super.init(config);
        Logger.initialize("astp.query.log", "Console");
        Logger.log(Logger.LOGTYPEISMESSAGE, "SrvQueryControlloer", "init", "got here!");

        try{
        System.setOut(new PrintStream(new ServletOutputStreamAdapter
                (new FileOutputStream("sys.out"))));
        }catch(IOException eio){throw new ServletException(eio);}
}

After commenting, the migrated code is as follows.

public void init(ServletConfig config) throws ServletException{
        super.init(config);
        Logger.initialize("astp.query.log", "Console");
        Logger.log(Logger.LOGTYPEISMESSAGE, "SrvQueryControlloer", "init", "got here!");

        try{
        /*Removed call to System.setOut()*/
        }catch(IOException eio){throw new ServletException(eio);}
}

However, note in this case that, since the only method call inside the try/catch block is commented out, the IOException is never thrown from inside the try/catch block and a compile time error results. The Migration Tool is currently limited since it does not have the ability to detect the following:

  • The commented out method call is the one that originally raised the exception that the try/catch block is handling.
  • The commented out method call is the only call in the try/catch block.

To get past this limitation, look in the migration report, which informs you of this condition, and take the necessary action, by commenting out the specific exception-causing lines, if required.

  • Impact of directory structure inside the EAR file to be migrated

The Migration Tool expects the JAR files to be directly under the EAR file. The tool does not support the migration of nested JAR files. All of the JAR files must be directly under the EAR file for the migration to be successful.
The following example shows the original unsupported EAR file structure.

EAR
 |
 |
 |---Lib/lib.jar
 |
 |
 |---EJBs
 |    |---EJB1.jar
 |    |---EJB2.jar
 |
 |---WEB
 |    |---WEB1.war
 |    |---WEB2.war

The EAR file structure needs to be modified to a supported configuratiuon, as shown in the following example, for the migration to be successful.

EAR
 |
 |
 |---lib.jar
 |
 |---EJB1.jar
 |
 |---EJB2.jar
 |
 |---WEB1.war
 |
 |---WEB2.war
  • Unsupported encoding type "Cp1252" on Solaris

The encoding type "Cp1252" in deployment descriptors is not supported on Solaris.
To get beyond this limitation, either perform the migration on a Windows platform, such as Windows 2000/NT/XP only, or change the encoding type to "UTF-8", which is supported on Solaris as well as Windows platforms.

OS/Platform Issues

This section lists the known limitations/bugs of the underlying operating system or J2SE SDK.

Java Development Kit (JDK) 1.5.x

There are some incompatibilities when using different versions of J2SE SDK.

  • J2SE SDK is required for running the migration tool; the JRE alone is not sufficient.
  • The Migration Tool requires J2SE SDK Version 1.5.x.

Windows 2000 Service Pack 2

The Migration Tool requires Service Pack 2 or higher for Windows 2000. If a Service Pack lower than SP2 is used, the Migration Tool might exhibit erratic behavior when it displays files in the input panel.

File Chooser's Features

The File Chooser, which pops up for selecting the output directory, lacks some functionality, due to a feature deficiency in J2SE SDK. The "Create New Folder" button creates a new folder, but does not highlight the newly created folder. To some, this may be confusing.

Problem with selecting the floppy drive (A

While choosing an input or output directory on Windows, if you click floppy drive (A:), a popup window titled "java.exe - No Disk" with three buttons, Abort, Retry, Ignore appears (in case it is empty). This popup comes up twice, even if you click the Ignore button.

Problem with JAR, WAR, RAR, or an EAR Filenames as Input

The Migration Tool does not accept, as input, archives that have whitespace in their file name(s).

Previous