1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.xml.secure;
19
20 import static org.junit.jupiter.api.Assertions.assertEquals;
21
22 import java.io.IOException;
23 import java.io.UncheckedIOException;
24 import java.nio.file.Files;
25 import java.nio.file.Path;
26 import java.nio.file.Paths;
27 import java.util.Arrays;
28 import java.util.Locale;
29 import java.util.Set;
30 import java.util.TreeSet;
31
32 import javax.xml.transform.Source;
33
34 import org.junit.jupiter.api.AfterAll;
35 import org.junit.jupiter.api.BeforeAll;
36 import org.junit.jupiter.api.Test;
37 import org.junit.jupiter.api.condition.DisabledInNativeImage;
38 import org.vafer.jdependency.Clazz;
39 import org.vafer.jdependency.Clazzpath;
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 @DisabledInNativeImage
58 class ShadingFootprintTest {
59
60 private static final String PKG = "org.apache.commons.xml.secure.";
61
62
63 private static final Set<String> DOCUMENT_BUILDER_FACTORY = set(
64 "FallbackIgnoreEntityResolver2",
65 "SecureDocumentBuilder",
66 "SecureDocumentBuilderFactory",
67 "SecureDocumentBuilderFactory$1",
68 "SecureDocumentBuilderFactory$Wrapper",
69 "SecureException",
70 "MethodHandleFactory",
71 "MethodHandleFactory$ThrowableCallable");
72
73
74
75 private static final Set<String> SAX_PARSER_FACTORY = set(
76 "FallbackIgnoreEntityResolver2",
77 "SecureException",
78 "SecureSAXParser",
79 "SecureSAXParserFactory",
80 "SecureSAXParserFactory$1",
81 "SecureSAXParserFactory$SecureExpatXMLReader",
82 "SecureSAXParserFactory$Wrapper",
83 "SecureXMLReader",
84 "MethodHandleFactory",
85 "MethodHandleFactory$ThrowableCallable");
86
87
88
89 private static final Set<String> XML_INPUT_FACTORY = set(
90 "FallbackIgnoreXMLResolver",
91 "SecureException",
92 "SecureXMLInputFactory",
93 "SecureXMLInputFactory$1",
94 "SecureXMLInputFactory$Wrapper",
95 "MethodHandleFactory",
96 "MethodHandleFactory$ThrowableCallable");
97
98
99
100
101
102
103
104
105 private static final Set<String> TRANSFORMER_FACTORY = saxParserFactoryPlus(
106 "FallbackIgnoreEntityResolver2",
107 "FallbackIgnoreURIResolver",
108 "SecureDocumentBuilder",
109 "SecureDocumentBuilderFactory",
110 "SecureDocumentBuilderFactory$1",
111 "SecureDocumentBuilderFactory$Wrapper",
112 "SecureException",
113 "SecureSAXParser",
114 "SecureSAXParserFactory",
115 "SecureSAXParserFactory$1",
116 "SecureSAXParserFactory$SecureExpatXMLReader",
117 "SecureSAXParserFactory$Wrapper",
118 "SecureTemplates",
119 "SecureTemplatesHandler",
120 "SecureTransformer",
121 "SecureTransformerFactory",
122 "SecureTransformerFactory$1",
123 "SecureTransformerFactory$Wrapper",
124 "SecureTransformerHandler",
125 "SecureXMLFilter",
126 "SecureXMLReader",
127 "SaxonProvider",
128 "SaxonProvider$1",
129 "SaxonProvider$SecureConfiguration",
130 "SaxonProvider$SaxonProviderConfigurer");
131
132
133
134 private static final Set<String> XPATH_FACTORY = saxParserFactoryPlus(
135 "FallbackIgnoreEntityResolver2",
136 "FallbackIgnoreURIResolver",
137 "SecureDocumentBuilder",
138 "SecureDocumentBuilderFactory",
139 "SecureDocumentBuilderFactory$1",
140 "SecureDocumentBuilderFactory$Wrapper",
141 "MethodHandleFactory",
142 "MethodHandleFactory$ThrowableCallable",
143 "SecureException",
144 "SecureSAXParser",
145 "SecureSAXParserFactory",
146 "SecureSAXParserFactory$1",
147 "SecureSAXParserFactory$SecureExpatXMLReader",
148 "SecureSAXParserFactory$Wrapper",
149 "SecureXMLReader",
150 "SecureXPath",
151 "SecureXPathExpression",
152 "SecureXPathFactory",
153 "SecureXPathFactory$1",
154 "SecureXPathFactory$Wrapper",
155 "SaxonProvider",
156 "SaxonProvider$1",
157 "SaxonProvider$SecureConfiguration",
158 "SaxonProvider$SaxonProviderConfigurer");
159
160
161
162 private static final Set<String> SCHEMA_FACTORY = saxParserFactoryPlus(
163 "FallbackIgnoreEntityResolver2",
164 "FallbackIgnoreLSResourceResolver",
165 "SecureException",
166 "SecureSAXParser",
167 "SecureSAXParserFactory",
168 "SecureSAXParserFactory$1",
169 "SecureSAXParserFactory$SecureExpatXMLReader",
170 "SecureSAXParserFactory$Wrapper",
171 "SecureSchema",
172 "SecureSchemaFactory",
173 "SecureSchemaFactory$1",
174 "SecureSchemaFactory$Wrapper",
175 "SecureValidator",
176 "SecureValidatorHandler",
177 "SecureXMLReader");
178
179
180
181
182
183 private static final int LIBRARY_CLASS_COUNT = 8;
184
185
186
187
188 private static final String[] REPORTED = {"SecureDocumentBuilderFactory", "SecureSAXParserFactory", "SecureXMLInputFactory",
189 "SecureTransformerFactory", "SecureXPathFactory", "SecureSchemaFactory"};
190
191 private static Clazzpath clazzpath;
192 private static Path classesDir;
193
194
195
196
197 private static long bytesOf(final Set<String> simpleNames) {
198 long total = 0;
199 for (final String name : simpleNames) {
200 try {
201 total += Files.size(classesDir.resolve("org/apache/commons/xml/secure/" + name + ".class"));
202 } catch (final IOException e) {
203 throw new UncheckedIOException(e);
204 }
205 }
206 return total;
207 }
208
209
210
211
212 private static Set<String> closureOf(final String simpleName) {
213 final Clazz entry = clazzpath.getClazz(PKG + simpleName);
214 if (entry == null) {
215 throw new IllegalStateException("Not on the compiled classpath: " + PKG + simpleName);
216 }
217 final Set<String> names = new TreeSet<>();
218 names.add(strip(entry.getName()));
219 for (final Clazz dependency : entry.getTransitiveDependencies()) {
220 if (dependency.getName().startsWith(PKG)) {
221 names.add(strip(dependency.getName()));
222 }
223 }
224 return names;
225 }
226
227 @BeforeAll
228 static void indexCompiledClasses() throws Exception {
229 classesDir = Paths.get(SecureException.class.getProtectionDomain().getCodeSource().getLocation().toURI());
230 clazzpath = new Clazzpath();
231 clazzpath.addClazzpathUnit(classesDir);
232 }
233
234
235
236
237
238 @AfterAll
239 static void reportFootprint() {
240 final Set<String> libraryClosure = new TreeSet<>();
241 for (final String entry : REPORTED) {
242 libraryClosure.addAll(closureOf(entry));
243 }
244 final long library = bytesOf(libraryClosure);
245 final StringBuilder report = new StringBuilder("\nShade footprint (uncompressed .class bytes, % of full library):\n");
246 for (final String entry : REPORTED) {
247 final Set<String> closure = closureOf(entry);
248 final long bytes = bytesOf(closure);
249 report.append(String.format(Locale.ROOT, " %-24s %2d classes %7d bytes %5.1f%%%n", entry, closure.size(), bytes, 100.0 * bytes / library));
250 }
251 if (Boolean.getBoolean(ShadingFootprintTest.class.getName() + ".reportFootprint")) {
252 System.out.print(report);
253 }
254 }
255
256 private static Set<String> rootClosure() {
257 return closureOf("SecureDocumentBuilderFactory");
258 }
259
260
261
262
263 private static Set<String> saxParserFactoryPlus(final String... more) {
264 final Set<String> union = new TreeSet<>(SAX_PARSER_FACTORY);
265 union.addAll(Arrays.asList(more));
266 return union;
267 }
268
269 private static Set<String> set(final String... names) {
270 return new TreeSet<>(Arrays.asList(names));
271 }
272
273 private static String strip(final String qualifiedName) {
274 return qualifiedName.substring(PKG.length());
275 }
276
277 @Test
278 void documentBuilderFactoryFootprint() {
279 assertEquals(DOCUMENT_BUILDER_FACTORY, closureOf("SecureDocumentBuilderFactory"));
280 }
281
282 @Test
283 void rootClosureMatchesDocumentBuilderFootprint() {
284 assertEquals(LIBRARY_CLASS_COUNT, rootClosure().size(), "SecureDocumentBuilderFactory closure size drifted");
285 }
286
287 @Test
288 void saxParserFactoryFootprint() {
289 assertEquals(SAX_PARSER_FACTORY, closureOf("SecureSAXParserFactory"));
290 }
291
292 @Test
293 void schemaFactoryFootprint() {
294 assertEquals(SCHEMA_FACTORY, closureOf("SecureSchemaFactory"));
295 }
296
297 @Test
298 void transformerFactoryFootprint() {
299 assertEquals(TRANSFORMER_FACTORY, closureOf("SecureTransformerFactory"));
300 }
301
302 @Test
303 void xmlInputFactoryFootprint() {
304 assertEquals(XML_INPUT_FACTORY, closureOf("SecureXMLInputFactory"));
305 }
306
307 @Test
308 void xPathFactoryFootprint() {
309 assertEquals(XPATH_FACTORY, closureOf("SecureXPathFactory"));
310 }
311 }