<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)"/>
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>
<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>
<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=""/>
</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 "/>
</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>
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;
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()));
}
- } 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) {
+ // 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()));
}
}
+ }
+
+ public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain domain, byte[] bytes) {
+ 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) {
+ }
+ }
}
}