gather necessary .xsb for ooxml-lite jar via intercepting the calls to SchemaTypeSystemImpl.XsbReader

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1884850 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2020-12-28 00:47:23 +00:00
parent b0830f9d94
commit 07ba96f023
4 changed files with 99 additions and 74 deletions

View File

@ -157,7 +157,7 @@ under the License.
<property name="ooxml.testokfile" location="build/ooxml-testokfile.txt"/>
<property name="ooxml.lite.agent" location="lib/ooxml-tests/ooxml-lite-agent.jar"/>
<property name="ooxml.lite.report" location="build/ooxml-lite-report.txt"/>
<property name="ooxml.lite.report" location="build/ooxml-lite-report"/>
<property name="ooxml.lite.jar" location="build/dist/maven/poi-ooxml-lite/poi-ooxml-lite-${version.id}.jar"/>
<property name="ooxml.lite.includes" value="^(com/microsoft/schemas|org/(etsi|openxmlformats|w3/)|org/apache/poi/schemas)"/>
@ -1157,6 +1157,7 @@ under the License.
destdir="${basedir}/src/multimodule/ooxml-lite-agent/java9"
includeantruntime="false"
fork="true"
modulepath="${basedir}/lib/main-tests"
unless:true="${isJava8}">
<compilerarg line="--patch-module org.apache.poi.ooxml_lite=${ooxml.output.test.dir}"/>
</javac>
@ -1168,6 +1169,7 @@ under the License.
<attribute name="Multi-Release" value="true"/>
<attribute name="Automatic-Module-Name" value="org.apache.poi.ooxml_lite"/>
<attribute name="Premain-Class" value="org.apache.poi.ooxml.lite.OOXMLLiteAgent"/>
<!-- attribute name="Can-Retransform-Classes" value="true"/ -->
</manifest>
</jar>
</target>
@ -1711,7 +1713,7 @@ under the License.
<echo message="Create ooxml-lite schemas"/>
<local name="lite.exports"/>
<loadresource property="lite.exports">
<file file="${ooxml.lite.report}"/>
<file file="${ooxml.lite.report}.clazz"/>
<filterchain>
<tokenfilter>
<replaceregex pattern="[/\\][^/\\]+$" replace=""/>
@ -1750,7 +1752,7 @@ under the License.
</modulepath>
</javac>
<copy file="${ooxml.lite.report}" tofile="build/ooxml-lite-classes.txt" overwrite="true">
<copy file="${ooxml.lite.report}.clazz" tofile="${ooxml.lite.report}.clazz2" overwrite="true">
<filterchain>
<tokenfilter>
<replaceregex pattern="(.*)" replace="\1.class${line.separator}\1$*.class "/>
@ -1758,62 +1760,22 @@ under the License.
</filterchain>
</copy>
<local name="ooxml.lite.xsbs"/>
<loadresource property="ooxml.lite.xsbs">
<file file="${ooxml.lite.report}"/>
<copy file="${ooxml.lite.report}.xsb" tofile="${ooxml.lite.report}.xsb2" overwrite="true">
<filterchain>
<linecontains negate="true" matchany="true">
<contains value="$"/>
<contains value="TypeSystemHolder"/>
</linecontains>
<suffixlines suffix=".java"/>
<prefixlines prefix="org/apache/poi/schemas/ooxml/system/ooxml/"/>
<suffixlines suffix=".xsb"/>
</filterchain>
</loadresource>
<concat dest="build/ooxml-lite-classes.txt" append="true">
<filelist dir="build/xmlbean-sources" files="${ooxml.lite.xsbs}"/>
<filterchain>
<linecontains>
<contains value="resolveHandle"/>
</linecontains>
<replaceregex pattern='.*"([^"]+)".*' replace="org/apache/poi/schemas/ooxml/system/ooxml/\1.xsb"/>
</filterchain>
</concat>
<!-- the following xsb files aren't detected, i.e. not directly loaded by XmlBeans interface classes -->
<echo file="build/ooxml-lite-classes.txt" append="true">
org/apache/poi/schemas/ooxml/system/ooxml/index.xsb
org/apache/poi/schemas/ooxml/system/ooxml/picelement.xsb
org/apache/poi/schemas/ooxml/system/ooxml/groupelement.xsb
org/apache/poi/schemas/ooxml/system/ooxml/group7d3fdoctype.xsb
org/apache/poi/schemas/ooxml/system/ooxml/shapelayoutelement.xsb
org/apache/poi/schemas/ooxml/system/ooxml/shapetypeelement.xsb
org/apache/poi/schemas/ooxml/system/ooxml/shapetypeb89bdoctype.xsb
org/apache/poi/schemas/ooxml/system/ooxml/shapeelement.xsb
org/apache/poi/schemas/ooxml/system/ooxml/shapeaee1doctype.xsb
org/apache/poi/schemas/ooxml/system/ooxml/tblelement.xsb
org/apache/poi/schemas/ooxml/system/ooxml/tbleb1bdoctype.xsb
org/apache/poi/schemas/ooxml/system/ooxml/relationshipreferenceelement.xsb
org/apache/poi/schemas/ooxml/system/ooxml/qualifyingpropertieselement.xsb
org/apache/poi/schemas/ooxml/system/ooxml/oleobjelement.xsb
org/apache/poi/schemas/ooxml/system/ooxml/oleobj8482doctype.xsb
org/apache/poi/schemas/ooxml/system/ooxml/stcellspans60f6type.xsb
org/apache/poi/schemas/ooxml/system/ooxml/stcellspanf3a5type.xsb
org/apache/poi/schemas/ooxml/system/ooxml/alternatecontentelement.xsb
org/apache/poi/schemas/ooxml/system/ooxml/chartelement.xsb
org/apache/poi/schemas/ooxml/system/ooxml/chartf85cdoctype.xsb
org/apache/poi/schemas/ooxml/system/ooxml/rectelement.xsb
org/apache/poi/schemas/ooxml/system/ooxml/rectaf36doctype.xsb
</echo>
</copy>
<mkdir dir="build/dist/maven/poi-ooxml-lite"/>
<jar destfile="${ooxml.lite.jar}" duplicate="preserve">
<zipfileset dir="${basedir}/src/multimodule/ooxml-lite/java9" prefix="META-INF/versions/9" excludes="*.java"/>
<zipfileset src="${ooxml.xsds.jar}">
<patternset includesfile="build/ooxml-lite-classes.txt">
<patternset includesfile="${ooxml.lite.report}.clazz2">
<include name="org/apache/poi/schemas/ooxml/element/**/*.xsb"/>
</patternset>
<patternset includesfile="${ooxml.lite.report}.xsb2"/>
</zipfileset>
<zipfileset dir="src/multimodule/ooxml-full/java9" prefix="META-INF/versions/9" excludes="*.java"/>
<manifest>

View File

@ -17,6 +17,7 @@
module org.apache.poi.ooxml_lite {
requires java.instrument;
requires static net.bytebuddy.agent;
exports org.apache.poi.ooxml.lite;
}

View File

@ -17,6 +17,8 @@
package org.apache.poi.ooxml.lite;
import static net.bytebuddy.matcher.ElementMatchers.named;
import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
@ -31,48 +33,108 @@ import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.SuperMethodCall;
import net.bytebuddy.matcher.ElementMatchers;
import org.apache.xmlbeans.impl.schema.SchemaTypeSystemImpl;
/**
* OOXMLLiteAgent is the replacement for the former OOXMLLite, because in Java 12
* it isn't possible to access the privates :) of the ClassLoader
*/
public class OOXMLLiteAgent {
static class LoggingTransformer implements ClassFileTransformer {
final Path path;
final Pattern includes;
final Set<Integer> fileHashes = new HashSet<>();
public static void premain(String agentArgs, Instrumentation inst) throws IOException {
String[] args = (agentArgs == null ? "" : agentArgs).split("\\|", 2);
String logBase = args.length >= 1 ? args[0] : "ooxml-lite-report";
public LoggingTransformer(String agentArgs) {
String[] args = (agentArgs == null ? "" : agentArgs).split("\\|", 2);
path = Paths.get(args.length >= 1 ? args[0] : "ooxml-lite.out");
includes = Pattern.compile(args.length >= 2 ? args[1] : ".*/schemas/.*");
XsbLogger.load(logBase+".xsb");
try {
if (Files.exists(path)) {
try (Stream<String> stream = Files.lines(path)) {
stream.forEach((s) -> fileHashes.add(s.hashCode()));
}
} else {
Files.createFile(path);
ClazzLogger log = new ClazzLogger();
log.load(logBase+".clazz");
log.setPattern(args.length >= 2 ? args[1] : ".*/schemas/.*");
inst.addTransformer(log);
new AgentBuilder.Default()
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut())
.type(named("org.apache.xmlbeans.impl.schema.SchemaTypeSystemImpl$XsbReader"))
.transform((builder, type, cl, m) ->
builder
.constructor(ElementMatchers.any())
.intercept(MethodDelegation.to(XsbLogger.class).andThen(SuperMethodCall.INSTANCE))
)
.installOn(inst);
}
/**
* This logger intercepts the loading of XmlBeans .xsb
*
* when ran in the ant junitlauncher, it's not possible to have the interceptor methods as
* instance method of ClazzLogger. the junit test will fail ... though it works ok in IntelliJ
* probably because of classpath vs. modulepath instantiation
*/
public static class XsbLogger {
private static Path logPath;
private static final Set<Integer> hashes = new HashSet<>();
static void load(String path) throws IOException {
logPath = Paths.get(path);
if (Files.exists(logPath)) {
try (Stream<String> stream = Files.lines(logPath)) {
stream.forEach((s) -> hashes.add(s.hashCode()));
}
}
}
// SchemaTypeSystemImpl.XsbReader::new is delegated to here - method name doesn't matter
public static void loadXsb(SchemaTypeSystemImpl parent, String handle) {
write(logPath, handle, hashes);
}
public static void loadXsb(SchemaTypeSystemImpl parent, String handle, int filetype) {
loadXsb(parent, handle);
}
}
/**
* This logger is used to log the used XmlBeans classes
*/
public static class ClazzLogger implements ClassFileTransformer {
Path logPath;
Pattern includes;
final Set<Integer> hashes = new HashSet<>();
public void setPattern(String regex) {
includes = Pattern.compile(regex);
}
public void load(String path) throws IOException {
this.logPath = Paths.get(path);
if (Files.exists(this.logPath)) {
try (Stream<String> stream = Files.lines(this.logPath)) {
stream.forEach((s) -> hashes.add(s.hashCode()));
}
} catch (IOException ignored) {
}
}
public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain domain, byte[] bytes) {
if (path != null && className != null && !fileHashes.contains(className.hashCode()) && includes.matcher(className).find()) {
try {
// TODO: check if this is atomic ... as transform() is probably called synchronized, it doesn't matter anyway
Files.write(path, (className+"\n").getBytes(StandardCharsets.ISO_8859_1), StandardOpenOption.APPEND);
fileHashes.add(className.hashCode());
} catch (IOException ignroed) {
}
if (logPath != null && className != null && includes.matcher(className).find()) {
write(logPath, className, hashes);
}
return bytes;
}
}
public static void premain(String agentArgs, Instrumentation inst) {
inst.addTransformer(new LoggingTransformer(agentArgs));
static void write(Path path, String item, Set<Integer> hashes) {
if (!hashes.contains(item.hashCode())) {
try {
// TODO: check if this is atomic ... as transform() is probably called synchronized, it doesn't matter anyway
Files.write(path, (item+"\n").getBytes(StandardCharsets.ISO_8859_1), StandardOpenOption.CREATE, StandardOpenOption.APPEND);
hashes.add(item.hashCode());
} catch (IOException ignroed) {
}
}
}
}