org.ocpsoft.rewrite.annotation.scan.WebClassesFinder Maven / Gradle / Ivy
/*
* 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 org.ocpsoft.rewrite.annotation.scan;
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;
import org.ocpsoft.rewrite.annotation.api.ClassVisitor;
import org.ocpsoft.rewrite.annotation.spi.ClassFinder;
/**
* 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 call to
* {@link #findClasses(ClassVisitor)}.
*
* @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,
ByteCodeFilter byteCodeFilter)
{
super(servletContext, classLoader, packageFilter, byteCodeFilter);
}
@Override
public void findClasses(ClassVisitor visitor)
{
try
{
// get the absolute URL of 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, CLASSES_FOLDER, visitor);
}
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 #processClass(String, InputStream, ClassVisitor)} when it finds a file ending with ".class" and
* that is accepted by the {@link PackageFilter}
*
* @param absoluteUrl The absolute URL of the WEB-INF node to scan
* @param relativePath The path of the node inside the WEB-INF
* @param visitor The visitor class to call for classes found
* @throws MalformedURLException for invalid URLs
*/
protected void processDirectory(URL absoluteUrl, String relativePath, ClassVisitor visitor)
throws MalformedURLException
{
// log directory name on trace level
if (log.isTraceEnabled())
{
log.trace("Processing directory: " + relativePath);
}
// Convert url to string, this will result in a full path of a node in an exploded war archive
// let it be "file://opt/server/application/abc/expoded/ear/war/WEB-INF/classes/com/"
String urlAsString = absoluteUrl.toString();
Set> paths = servletContext.getResourcePaths(relativePath);
if (paths == null || paths.isEmpty())
{
return;
}
// Process child nodes
for (Object obj : paths)
{
// produces "/WEB-INF/classes/com/mycompany/"
String childNodeName = obj.toString();
// get last part of the node path (folder or class entry)
// for example for childnode "/WEB-INF/classes/com/mycompany/" returns "mycompany/"
String childNodeRelative = getChildNodeName(childNodeName);
// get the folder of the node inside WEB-INF
// for example for childnode "/WEB-INF/classes/com/mycompany/" returns "/WEB-INF/classes/com/"
String webInfFolder = childNodeName.substring(0, childNodeName.length() - childNodeRelative.length());
// Find relative base folder
// produces "file://opt/server/application/abc/expoded/ear/war/"
String urlBase = urlAsString.substring(0, urlAsString.length() - webInfFolder.length());
// Create child node URL
// produces "file://opt/server/application/abc/expoded/ear/war/WEB-INF/classes/com/mycompany/"
URL childNodeUrl = new URL(urlBase + childNodeName);
if (childNodeRelative.endsWith("/"))
{
// Recursive cal
processDirectory(childNodeUrl, childNodeName, visitor);
}
if (childNodeRelative.endsWith(".class"))
{
handleClassEntry(childNodeName, visitor);
}
}
}
/**
* Handles class entry in a WEB-INF.
*/
private void handleClassEntry(String entryName, ClassVisitor visitor)
{
// build class name from relative name
String className = getClassName(entryName.substring(CLASSES_FOLDER.length()));
// 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 this isn't possible, we will scan it anyway.
*/
classFileStream = servletContext.getResourceAsStream(entryName);
if (classFileStream == null)
{
if (log.isDebugEnabled())
{
log.debug("Could not obtain InputStream for class file: " + entryName);
}
}
// analyze the class (with or without classFileStream)
processClass(className, classFileStream, visitor);
}
finally
{
try
{
if (classFileStream != null)
{
classFileStream.close();
}
}
catch (IOException e)
{
if (log.isDebugEnabled())
{
log.debug("Failed to close input stream: " + e.getMessage());
}
}
}
}
}
/**
* @param path The path
* @return last node in a a string representation of URL path. For example for "/a/b/c/d/" returns "d/", for
* "/a/b/c/d.class" returns "d.class"
*/
private String getChildNodeName(String path)
{
String[] elements = path.split("/");
int size = elements.length;
String nodeName = elements[size - 1];
return path.endsWith("/") ? nodeName + "/" : nodeName;
}
@Override
public int priority()
{
return 0;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy