All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ocpsoft.pretty.faces.config.annotation.WebClassesFinder Maven / Gradle / Ivy

There is a newer version: 10.0.2.Final
Show newest version
/*
 * Copyright 2010 Lincoln Baxter, III
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.ocpsoft.pretty.faces.config.annotation;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.LinkedHashSet;
import java.util.Set;

import javax.servlet.ServletContext;

/**
 * Implementation of {@link ClassFinder} that searches for classes in the /WEB-INF/classes directory of a
 * web application. Please note that this class is stateful. It should be used only for one class to
 * {@link #findClasses(PrettyAnnotationHandler)}.
 * 
 * @author Christian Kaltepoth
 */
public class WebClassesFinder extends AbstractClassFinder
{

   /**
    * The name of the classes directory
    */
   private final static String CLASSES_FOLDER = "/WEB-INF/classes/";

   /**
    * Manage a set of classes already processed
    */
   private final Set processedClasses = new LinkedHashSet();

   /**
    * Initialization
    */
   public WebClassesFinder(ServletContext servletContext, ClassLoader classLoader, PackageFilter packageFilter)
   {
      super(servletContext, classLoader, packageFilter);
   }

   /*
    * @see
    * com.ocpsoft.pretty.faces.config.annotation.ClassFinder#findClasses(com
    * .ocpsoft.pretty.config.annotation.PrettyAnnotationHandler)
    */
   public void findClasses(PrettyAnnotationHandler handler)
   {
      try
      {
         // we start the recursive scan in the classes folder
         URL classesFolderUrl = servletContext.getResource(CLASSES_FOLDER);

         // abort if classes folder is missing
         if (classesFolderUrl == null)
         {
            log.warn("Cannot find classes folder: " + CLASSES_FOLDER);
            return;
         }

         // call recursive directory processing method
         processDirectory(classesFolderUrl, classesFolderUrl, handler);

      }
      catch (MalformedURLException e)
      {
         throw new IllegalStateException("Invalid URL: " + e.getMessage(), e);
      }
   }

   /**
    * Scan for classes in a single directory. This method will call itself recursively if it finds other directories and
    * call {@link #processClassURL(URL, PrettyAnnotationHandler)} when it finds a file ending with ".class" and that is
    * accepted by the {@link PackageFilter}
    * 
    * @param directoryUrl The URL of the directory to scan
    * @param handler The handler class for classes found
    * @throws MalformedURLException for invalid URLs
    */
   protected void processDirectory(URL classesFolderUrl, URL directoryUrl, PrettyAnnotationHandler handler)
            throws MalformedURLException
   {

      // only the path of the classes folder URL is required in this method
      String classesFolderPath = classesFolderUrl.getPath();

      // log directory name on trace level
      if (log.isTraceEnabled())
      {
         log.trace("Processing directory: " + directoryUrl.toString());
      }

      // get the directory name relative to the '/WEB-INF/classes/' folder
      String relativeDirectoryName = getPathRelativeToClassesFolder(directoryUrl.getPath(), classesFolderPath);

      // call getResourcePaths to get directory entries
      Set paths = servletContext.getResourcePaths(CLASSES_FOLDER + relativeDirectoryName);

      if (paths != null) {

         // loop over all entries of the directory
         for (Object relativePath : paths)
         {

            // get full URL for this entry
            URL entryUrl = servletContext.getResource(relativePath.toString());

            // Seems to happen in some weird situations
            if (entryUrl == null) {
               continue;
            }

            // we are using toString() instead of getPath() because AS7 doesn't handle # characters correctly
            String entryName = entryUrl.toString();

            // if this URL ends with .class it is a Java class
            if (entryName.endsWith(".class"))
            {

               // the name of the entry relative to the '/WEB-INF/classes/' folder
               String entryRelativeName = getPathRelativeToClassesFolder(entryName, classesFolderPath);

               // build class name from relative name
               String className = getClassName(entryRelativeName);

               // check filter
               if (mustProcessClass(className) && !processedClasses.contains(className))
               {

                  // mark this class as processed
                  processedClasses.add(className);

                  // the class file stream
                  InputStream classFileStream = null;

                  // close the stream in finally block
                  try
                  {

                     /*
                      * Try to open the .class file. If an IOException is thrown,
                      * we will scan it anyway.
                      */
                     try
                     {
                        classFileStream = entryUrl.openStream();
                     }
                     catch (IOException e)
                     {
                        if (log.isDebugEnabled())
                        {
                           log.debug("Cound not obtain InputStream for class file: " + entryUrl.toString(), e);
                        }
                     }

                     // analyze the class (with or without classFileStream)
                     processClass(className, classFileStream, handler);

                  }
                  finally
                  {
                     try
                     {
                        if (classFileStream != null)
                        {
                           classFileStream.close();
                        }
                     }
                     catch (IOException e)
                     {
                        if (log.isDebugEnabled())
                        {
                           log.debug("Failed to close input stream: " + e.getMessage());
                        }
                     }
                  }
               }

            }

            // if this URL ends with a slash, its a directory
            if (entryName.endsWith("/"))
            {

               // walk down the directory
               processDirectory(classesFolderUrl, entryUrl, handler);

            }
         }
      }
   }

   /**
    * This method will create a path relative to the '/WEB-INF/classes/' folder for the given path. It will first try to
    * find the '/WEB-INF/classes/' suffix in the path to do so. If this suffix cannot be found (can happen when using
    * the jetty-maven-plugin with 'jetty:run' goal), the method will try to build the relative name by stripping the
    * path of the '/WEB-INF/classes/' folder which must be supplied to the method. The method will throw an
    * {@link IllegalArgumentException} if the relative path could not be build.
    * 
    * @param path The path to build the relative path for
    * @param classesFolderPath the known path of the '/WEB-INF/classes/' folder.
    * @return the relative name of the path
    */
   private String getPathRelativeToClassesFolder(String path, String classesFolderPath)
   {

      // first try to find the '/WEB-INF/classes' suffix
      String result = stripKnownPrefix(path, CLASSES_FOLDER);

      // alternative: try to strip the full path of the '/WEB-INF/classes/' folder
      if (result == null)
      {
         result = stripKnownPrefix(path, classesFolderPath);
      }

      // none of the two methods worked?
      if (result == null)
      {
         throw new IllegalArgumentException("Unable to build path relative to '/WEB-INF/classes/' from: " + path);
      }

      return result;

   }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy