-
-
Notifications
You must be signed in to change notification settings - Fork 280
/
ClassLoaderOrder.java
185 lines (172 loc) · 7.71 KB
/
ClassLoaderOrder.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/*
* This file is part of ClassGraph.
*
* Author: Luke Hutchison
*
* Hosted at: https://github.com/classgraph/classgraph
*
* --
*
* The MIT License (MIT)
*
* Copyright (c) 2019 Luke Hutchison
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
* LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
* EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/
package nonapi.io.github.classgraph.classpath;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import io.github.classgraph.ClassGraph;
import nonapi.io.github.classgraph.classloaderhandler.ClassLoaderHandler;
import nonapi.io.github.classgraph.classloaderhandler.ClassLoaderHandlerRegistry;
import nonapi.io.github.classgraph.classloaderhandler.ClassLoaderHandlerRegistry.ClassLoaderHandlerRegistryEntry;
import nonapi.io.github.classgraph.utils.LogNode;
/** A class to find all unique classloaders. */
public class ClassLoaderOrder {
/** The {@link ClassLoader} order. */
private final List<Entry<ClassLoader, ClassLoaderHandlerRegistryEntry>> classLoaderOrder = new ArrayList<>();
/**
* The set of all {@link ClassLoader} instances that have been added to the order so far, so that classloaders
* don't get added twice.
*/
// Need to use IdentityHashMap for maps and sets here, because TomEE weirdly makes instances of
// CxfContainerClassLoader equal to (via .equals()) the instance of TomEEWebappClassLoader that it
// delegates to (#515)
private final Set<ClassLoader> added = Collections.newSetFromMap(new IdentityHashMap<ClassLoader, Boolean>());
/**
* The set of all {@link ClassLoader} instances that have been delegated to so far, to prevent an infinite loop
* in delegation.
*/
private final Set<ClassLoader> delegatedTo = Collections
.newSetFromMap(new IdentityHashMap<ClassLoader, Boolean>());
/**
* The set of all parent {@link ClassLoader} instances that have been delegated to so far, to enable
* {@link ClassGraph#ignoreParentClassLoaders()}.
*/
private final Set<ClassLoader> allParentClassLoaders = Collections
.newSetFromMap(new IdentityHashMap<ClassLoader, Boolean>());
/** A map from {@link ClassLoader} to {@link ClassLoaderHandlerRegistryEntry}. */
private final Map<ClassLoader, ClassLoaderHandlerRegistryEntry> classLoaderToClassLoaderHandlerRegistryEntry = //
new IdentityHashMap<ClassLoader, ClassLoaderHandlerRegistryEntry>();
// -------------------------------------------------------------------------------------------------------------
/**
* Get the {@link ClassLoader} order.
*
* @return the {@link ClassLoader} order, as a pair: {@link ClassLoader},
* {@link ClassLoaderHandlerRegistryEntry}.
*/
public List<Entry<ClassLoader, ClassLoaderHandlerRegistryEntry>> getClassLoaderOrder() {
return classLoaderOrder;
}
/**
* Get the all parent classloaders.
*
* @return all parent classloaders
*/
public Set<ClassLoader> getAllParentClassLoaders() {
return allParentClassLoaders;
}
/**
* Find the {@link ClassLoaderHandler} that can handle a given {@link ClassLoader} instance.
*
* @param classLoader
* the {@link ClassLoader}.
* @param log
* the log
* @return the {@link ClassLoaderHandlerRegistryEntry} for the {@link ClassLoader}.
*/
private ClassLoaderHandlerRegistryEntry getRegistryEntry(final ClassLoader classLoader, final LogNode log) {
ClassLoaderHandlerRegistryEntry entry = classLoaderToClassLoaderHandlerRegistryEntry.get(classLoader);
if (entry == null) {
// Try all superclasses of classloader in turn
for (Class<?> currClassLoaderClass = classLoader.getClass(); //
currClassLoaderClass != Object.class && currClassLoaderClass != null; //
currClassLoaderClass = currClassLoaderClass.getSuperclass()) {
// Find a ClassLoaderHandler that can handle the ClassLoader
for (final ClassLoaderHandlerRegistryEntry ent : ClassLoaderHandlerRegistry.CLASS_LOADER_HANDLERS) {
if (ent.canHandle(currClassLoaderClass, log)) {
// This ClassLoaderHandler can handle the ClassLoader class, or one of its superclasses
entry = ent;
break;
}
}
if (entry != null) {
// Don't iterate to next superclass if a matching ClassLoaderHandler was found
break;
}
}
if (entry == null) {
// Use fallback handler
entry = ClassLoaderHandlerRegistry.FALLBACK_HANDLER;
}
classLoaderToClassLoaderHandlerRegistryEntry.put(classLoader, entry);
}
return entry;
}
/**
* Add a {@link ClassLoader} to the ClassLoader order at the current position.
*
* @param classLoader
* the class loader
* @param log
* the log
*/
public void add(final ClassLoader classLoader, final LogNode log) {
if (classLoader == null) {
return;
}
if (added.add(classLoader)) {
final ClassLoaderHandlerRegistryEntry entry = getRegistryEntry(classLoader, log);
if (entry != null) {
classLoaderOrder.add(new SimpleEntry<>(classLoader, entry));
}
}
}
/**
* Recursively delegate to another {@link ClassLoader}.
*
* @param classLoader
* the class loader
* @param isParent
* true if this is a parent of another classloader
* @param log
* the log
*/
public void delegateTo(final ClassLoader classLoader, final boolean isParent, final LogNode log) {
if (classLoader == null) {
return;
}
// Check if this is a parent before checking if the classloader is already in the delegatedTo set,
// so that if the classloader is a context classloader but also a parent, it still gets marked as
// a parent classloader.
if (isParent) {
allParentClassLoaders.add(classLoader);
}
// Don't delegate to a classloader twice
if (delegatedTo.add(classLoader)) {
// Find ClassLoaderHandlerRegistryEntry for this classloader
final ClassLoaderHandlerRegistryEntry entry = getRegistryEntry(classLoader, log);
// Delegate to this classloader, by recursing to that classloader to get its classloader order
entry.findClassLoaderOrder(classLoader, this, log);
}
}
}