Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,13 @@ public class OpenEJBContextConfig extends ContextConfig {
// since we store all classes in WEB-INF we will do it only once so use this boolean to avoid multiple processing
private Collection<String> webInfClassesAnnotationsProcessed = new ArrayList<>(1);

// isIncluded() resolves the same module roots and the same web resource once
// per candidate class, and every resolution is a filesystem syscall. Both
// mappings are stable for the lifetime of a deploy, and this config instance
// is per context, so they are memoised here rather than recomputed.
private final Map<String, File> canonicalFiles = new HashMap<>();
private final Map<String, File> urlAsFile = new HashMap<>();

public OpenEJBContextConfig(final TomcatWebAppBuilder.StandardContextInfo standardContextInfo) {
logger.debug("OpenEJBContextConfig({0})", standardContextInfo.toString());
info = standardContextInfo;
Expand Down Expand Up @@ -565,7 +572,17 @@ protected void processAnnotationsWebResource(final WebResource webResource,
final Map<String,JavaClassCacheEntry> javaClassCache) {
final WebAppInfo webAppInfo = info.get();
if (webAppInfo != null && FileResource.class.isInstance(webResource)) {
// Tomcat calls this for every web resource, but once every module has been processed
// there is nothing left to match against and resolving the resource is wasted work.
if (allWebAnnotationsProcessed(webAppInfo)) {
return;
}

final File file = new File(FileResource.class.cast(webResource).getCanonicalPath());
// the path already comes from getCanonicalPath(), so record it as its own canonical
// form instead of letting isIncluded() resolve it a second time
canonicalFiles.putIfAbsent(file.getPath(), file);

for (final ClassListInfo info : webAppInfo.webAnnotatedClasses) {
if (webInfClassesAnnotationsProcessed.contains(info.name)) {
continue;
Expand Down Expand Up @@ -724,19 +741,8 @@ protected void processAnnotationWebServlet(final String className, final Annotat
}

private boolean isIncluded(final File root, final File clazz) {
File file;
try { // symb links
file = root.getCanonicalFile();
} catch (final IOException e) {
file = root;
}

File current;
try { // symb links and windows long home names
current = clazz.getCanonicalFile();
} catch (final IOException e) {
current = clazz;
}
final File file = canonical(root); // symb links
File current = canonical(clazz); // symb links and windows long home names
while (current != null && current.exists()) {
if (current.equals(file)) {
final File parent = current.getParentFile();
Expand All @@ -751,7 +757,38 @@ private boolean isIncluded(final File root, final File clazz) {
}

private boolean isIncludedIn(final String filePath, final File classAsFile) throws MalformedURLException {
return isIncluded(URLs.toFile(new URL(filePath)), classAsFile);
File root = urlAsFile.get(filePath);
if (root == null) {
root = URLs.toFile(new URL(filePath));
urlAsFile.put(filePath, root);
}
return isIncluded(root, classAsFile);
}

private boolean allWebAnnotationsProcessed(final WebAppInfo webAppInfo) {
for (final ClassListInfo classes : webAppInfo.webAnnotatedClasses) {
if (!webInfClassesAnnotationsProcessed.contains(classes.name)) {
return false;
}
}
return true;
}

private File canonical(final File file) {
final String key = file.getPath();
final File cached = canonicalFiles.get(key);
if (cached != null) {
return cached;
}

File resolved;
try {
resolved = file.getCanonicalFile();
} catch (final IOException e) {
resolved = file;
}
canonicalFiles.put(key, resolved);
return resolved;
}

}
Loading