Tapestry 5 deployed on Tomcat - possibly a solution

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

Tapestry 5 deployed on Tomcat - possibly a solution

Peter Skala
Tapestry 5 documentation states, that component classes stored under WEB-INF/classes on Tomcat will not be found during the initialization.

I did not experience this problem, neither with Tomcat 5.5.15, nor with 6.0.16.  The problem is something else: components packaged in a jar file (custom component library module) are not found on Tomcat.

What HLS writes about this topic on his site ( see “Fighting with Tomcat” from February 20th, 2007) might support my experience.

There is a solution to this problem. It is not very elegant, but it is working, as far as I can judge. Please try it, if it works generally.

The only class to be changed is ClassNameLocatorImpl.java. If the method getResources called in findClassesWithinPath does not deliver any entry, the other possibility will be tried, which is contained in the new method testForJarComponents below. It scans all the URLs available to the class loader for the searched packagePath. If found, all .class files saved on this path are returned.

private Collection<String> findClassesWithinPath(String packagePath) throws IOException
    {
        Collection<String> result = CollectionFactory.newList();

        Enumeration<URL> urls = contextClassLoader.getResources(packagePath);

      boolean urlsFound = false;            // new

        while (urls.hasMoreElements())
        {
        urlsFound = true;                 // new

            URL url = urls.nextElement();

            URL converted = converter.convert(url);

            scanURL(packagePath, result, converted);
        }

        if( urlsFound == false)              // new
        {  
            try  
            {
            testForJarComponents( packagePath, result);
            }
            catch (IOException ex)
            {
            }
        }

        return result;
    }

And now the new method:

    /**
     * Scan all the URLs available to the class loader. In case when a URL is a jar file,
     * check if a searched packagePaht is contained in it. If yes, return all classes
     * contained on the path
     *
     * @param packagePath
     * @param result - Collection reference
     * @throws java.io.IOException
     */
 private void scanJarsForComponents( String packagePath, Collection<String> result)
                                                      throws IOException
 {
       
        String packageName = packagePath.replace('/', '.');
        if( URLClassLoader.class.isInstance( contextClassLoader) && packagePath != null)  
       {
            URL[] searchUrls =  ((URLClassLoader) contextClassLoader).getURLs();
           
            for( int i = 0; i < searchUrls.length; i++ )  {                
                                                                       
               if( searchUrls[ i].getFile().indexOf( ".jar") > 1)  
               {
                  JarFile jarFile = new JarFile( searchUrls[ i].getFile());
                  Enumeration<JarEntry> jarEntries = jarFile.entries();
                 
                  while( jarEntries.hasMoreElements())
                  {
                     String potentialComponentPathName = jarEntries.nextElement().getName();
                     if( potentialComponentPathName.indexOf( packagePath) == 0 )
                     {          
                        String potentialComponentName =
                                        potentialComponentPathName.substring( packagePath.length());
                        int classIdx = potentialComponentName.lastIndexOf( CLASS_SUFFIX);
                       
                             // if a class is allowed to be in a subpackage, the second test should be removed
                        if( classIdx > 0 && potentialComponentName.indexOf( '/') == -1 )  
                       {            
                            String classNameFound =
                                               packageName + potentialComponentName.substring(0, classIdx);
                            result.add( classNameFound);
                        }
                     }
                  }
               }
           }
      }
 }