Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

OOXMLLite.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /* ====================================================================
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.ooxml.util;
  16. import java.io.File;
  17. import java.io.IOException;
  18. import java.lang.reflect.Field;
  19. import java.lang.reflect.Method;
  20. import java.net.URL;
  21. import java.security.AccessController;
  22. import java.security.CodeSource;
  23. import java.security.PrivilegedAction;
  24. import java.security.ProtectionDomain;
  25. import java.util.ArrayList;
  26. import java.util.Enumeration;
  27. import java.util.HashSet;
  28. import java.util.List;
  29. import java.util.Set;
  30. import java.util.Vector;
  31. import java.util.jar.JarEntry;
  32. import java.util.jar.JarFile;
  33. import java.util.regex.Pattern;
  34. import org.apache.poi.util.IOUtils;
  35. import org.apache.poi.util.StringUtil;
  36. import org.apache.poi.util.SuppressForbidden;
  37. import org.apache.xmlbeans.StringEnumAbstractBase;
  38. import org.junit.Test;
  39. import org.junit.internal.TextListener;
  40. import org.junit.runner.Description;
  41. import org.junit.runner.JUnitCore;
  42. import org.junit.runner.Result;
  43. import org.reflections.Reflections;
  44. import junit.framework.TestCase;
  45. /**
  46. * Build a 'lite' version of the ooxml-schemas.jar
  47. *
  48. * @author Yegor Kozlov
  49. */
  50. public final class OOXMLLite {
  51. private static final Pattern SCHEMA_PATTERN = Pattern.compile("schemaorg_apache_xmlbeans/(system|element)/.*\\.xsb");
  52. /**
  53. * Destination directory to copy filtered classes
  54. */
  55. private File _destDest;
  56. /**
  57. * Directory with the compiled ooxml tests
  58. */
  59. private File _testDir;
  60. /**
  61. * Reference to the ooxml-schemas.jar
  62. */
  63. private File _ooxmlJar;
  64. OOXMLLite(String dest, String test, String ooxmlJar) {
  65. _destDest = new File(dest);
  66. _testDir = new File(test);
  67. _ooxmlJar = new File(ooxmlJar);
  68. }
  69. public static void main(String[] args) throws IOException {
  70. System.out.println("Free memory (bytes): " +
  71. Runtime.getRuntime().freeMemory());
  72. long maxMemory = Runtime.getRuntime().maxMemory();
  73. System.out.println("Maximum memory (bytes): " +
  74. (maxMemory == Long.MAX_VALUE ? "no limit" : maxMemory));
  75. System.out.println("Total memory (bytes): " +
  76. Runtime.getRuntime().totalMemory());
  77. String dest = null, test = null, ooxml = null;
  78. for (int i = 0; i < args.length; i++) {
  79. switch (args[i]) {
  80. case "-dest":
  81. dest = args[++i]; // lgtm[java/index-out-of-bounds]
  82. break;
  83. case "-test":
  84. test = args[++i]; // lgtm[java/index-out-of-bounds]
  85. break;
  86. case "-ooxml":
  87. ooxml = args[++i]; // lgtm[java/index-out-of-bounds]
  88. break;
  89. }
  90. }
  91. OOXMLLite builder = new OOXMLLite(dest, test, ooxml);
  92. builder.build();
  93. }
  94. void build() throws IOException {
  95. List<Class<?>> lst = new ArrayList<>();
  96. //collect unit tests
  97. String exclude = StringUtil.join("|",
  98. "BaseTestXWorkbook",
  99. "BaseTestXSheet",
  100. "BaseTestXRow",
  101. "BaseTestXCell",
  102. "BaseTestXSSFPivotTable",
  103. "TestSXSSFWorkbook\\$\\d",
  104. "TestUnfixedBugs",
  105. "MemoryUsage",
  106. "TestDataProvider",
  107. "TestDataSamples",
  108. "All.+Tests",
  109. "ZipFileAssert",
  110. "AesZipFileZipEntrySource",
  111. "TempFileRecordingSXSSFWorkbookWithCustomZipEntrySource",
  112. "PkiTestUtils",
  113. "TestCellFormatPart\\$\\d",
  114. "TestSignatureInfo\\$\\d",
  115. "TestCertificateEncryption\\$CertData",
  116. "TestPOIXMLDocument\\$OPCParser",
  117. "TestPOIXMLDocument\\$TestFactory",
  118. "TestXSLFTextParagraph\\$DrawTextParagraphProxy",
  119. "TestXSSFExportToXML\\$\\d",
  120. "TestXSSFExportToXML\\$DummyEntityResolver",
  121. "TestFormulaEvaluatorOnXSSF\\$Result",
  122. "TestFormulaEvaluatorOnXSSF\\$SS",
  123. "TestMultiSheetFormulaEvaluatorOnXSSF\\$Result",
  124. "TestMultiSheetFormulaEvaluatorOnXSSF\\$SS",
  125. "TestXSSFBugs\\$\\d",
  126. "AddImageBench",
  127. "AddImageBench_jmhType_B\\d",
  128. "AddImageBench_benchCreatePicture_jmhTest",
  129. "TestEvilUnclosedBRFixingInputStream\\$EvilUnclosedBRFixingInputStream",
  130. "TempFileRecordingSXSSFWorkbookWithCustomZipEntrySource\\$TempFileRecordingSheetDataWriterWithDecorator",
  131. "TestXSSFBReader\\$1",
  132. "TestXSSFBReader\\$TestSheetHandler",
  133. "TestFormulaEvaluatorOnXSSF\\$1",
  134. "TestMultiSheetFormulaEvaluatorOnXSSF\\$1",
  135. "TestZipPackagePropertiesMarshaller\\$1",
  136. "SLCommonUtils",
  137. "TestPPTX2PNG\\$1",
  138. "TestMatrixFormulasFromXMLSpreadsheet\\$1",
  139. "TestMatrixFormulasFromXMLSpreadsheet\\$Navigator",
  140. "TestPOIXMLDocument\\$UncaughtHandler",
  141. "TestOleShape\\$Api",
  142. "TestOleShape\\$1",
  143. "TestPOIXMLDocument\\$1",
  144. "TestXMLSlideShow\\$1",
  145. "TestXMLSlideShow\\$BufAccessBAOS",
  146. "TestXDDFChart\\$1",
  147. "TestOOXMLLister\\$1",
  148. "TestOOXMLPrettyPrint\\$1"
  149. );
  150. System.out.println("Collecting unit tests from " + _testDir);
  151. collectTests(_testDir, _testDir, lst, ".+.class$", ".+(" + exclude + ").class");
  152. System.out.println("Found " + lst.size() + " classes");
  153. //run tests
  154. JUnitCore jUnitCore = new JUnitCore();
  155. jUnitCore.addListener(new TextListener(System.out) {
  156. private final Set<String> classes = new HashSet<>();
  157. private int count;
  158. @Override
  159. public void testStarted(Description description) {
  160. // count how many test-classes we already saw
  161. classes.add(description.getClassName());
  162. count++;
  163. if(count % 100 == 0) {
  164. System.out.println();
  165. System.out.println(classes.size() + "/" + lst.size() + ": " + description.getDisplayName());
  166. }
  167. super.testStarted(description);
  168. }
  169. });
  170. Result result = jUnitCore.run(lst.toArray(new Class<?>[0]));
  171. if (!result.wasSuccessful()) {
  172. throw new RuntimeException("Tests did not succeed, cannot build ooxml-lite jar");
  173. }
  174. //see what classes from the ooxml-schemas.jar are loaded
  175. System.out.println("Copying classes to " + _destDest);
  176. Set<Class<?>> classes = getLoadedClasses(_ooxmlJar.getName());
  177. Set<String> packages = new HashSet<>();
  178. for (Class<?> cls : classes) {
  179. copyFile(cls);
  180. packages.add(cls.getPackage().getName());
  181. if (cls.isInterface()) {
  182. /// Copy classes and interfaces declared as members of this class
  183. for (Class<?> fc : cls.getDeclaredClasses()) {
  184. copyFile(fc);
  185. }
  186. }
  187. }
  188. for (String pkg : packages) {
  189. Reflections reflections = new Reflections(pkg);
  190. Set<Class<? extends List>> listClasses = reflections.getSubTypesOf(List.class);
  191. listClasses.removeAll(classes);
  192. for (Class listClass : listClasses) {
  193. for (Class<?> compare : classes) {
  194. if (listClass.getName().startsWith(compare.getName())) {
  195. copyFile(listClass);
  196. }
  197. }
  198. }
  199. Set<Class<? extends StringEnumAbstractBase>> enumClasses = reflections.getSubTypesOf(StringEnumAbstractBase.class);
  200. listClasses.removeAll(classes);
  201. for (Class enumClass : enumClasses) {
  202. for (Class<?> compare : classes) {
  203. if (enumClass.getName().startsWith(compare.getName())) {
  204. copyFile(enumClass);
  205. }
  206. }
  207. }
  208. }
  209. //finally copy the compiled .xsb files
  210. System.out.println("Copying .xsb resources");
  211. try (JarFile jar = new JarFile(_ooxmlJar)) {
  212. for (Enumeration<JarEntry> e = jar.entries(); e.hasMoreElements(); ) {
  213. JarEntry je = e.nextElement();
  214. if (SCHEMA_PATTERN.matcher(je.getName()).matches()) {
  215. File destFile = new File(_destDest, je.getName());
  216. IOUtils.copy(jar.getInputStream(je), destFile);
  217. }
  218. }
  219. }
  220. }
  221. private void copyFile(Class<?> cls) throws IOException {
  222. String className = cls.getName();
  223. String classRef = className.replace('.', '/') + ".class";
  224. File destFile = new File(_destDest, classRef);
  225. IOUtils.copy(cls.getResourceAsStream('/' + classRef), destFile);
  226. }
  227. private static boolean checkForTestAnnotation(Class<?> testclass) {
  228. for (Method m : testclass.getDeclaredMethods()) {
  229. if(m.isAnnotationPresent(Test.class)) {
  230. return true;
  231. }
  232. }
  233. // also check super classes
  234. if(testclass.getSuperclass() != null) {
  235. for (Method m : testclass.getSuperclass().getDeclaredMethods()) {
  236. if(m.isAnnotationPresent(Test.class)) {
  237. return true;
  238. }
  239. }
  240. }
  241. System.out.println("Class " + testclass.getName() + " does not derive from TestCase and does not have a @Test annotation");
  242. // Should we also look at superclasses to find cases
  243. // where we have abstract base classes with derived tests?
  244. // if(checkForTestAnnotation(testclass.getSuperclass())) return true;
  245. return false;
  246. }
  247. /**
  248. * Recursively collect classes from the supplied directory
  249. *
  250. * @param arg the directory to search in
  251. * @param out output
  252. * @param ptrn the pattern (regexp) to filter found files
  253. */
  254. private static void collectTests(File root, File arg, List<Class<?>> out, String ptrn, String exclude) {
  255. if (arg.isDirectory()) {
  256. File files[] = arg.listFiles();
  257. if (files != null) {
  258. for (File f : files) {
  259. collectTests(root, f, out, ptrn, exclude);
  260. }
  261. }
  262. } else {
  263. String path = arg.getAbsolutePath();
  264. String prefix = root.getAbsolutePath();
  265. String cls = path.substring(prefix.length() + 1).replace(File.separator, ".");
  266. if(!cls.matches(ptrn)) {
  267. return;
  268. }
  269. if (cls.matches(exclude)) {
  270. return;
  271. }
  272. //ignore inner classes defined in tests
  273. if (cls.indexOf('$') != -1) {
  274. System.out.println("Inner class " + cls + " not included");
  275. return;
  276. }
  277. cls = cls.replace(".class", "");
  278. try {
  279. Class<?> testclass = Class.forName(cls);
  280. if (TestCase.class.isAssignableFrom(testclass)
  281. || checkForTestAnnotation(testclass)) {
  282. out.add(testclass);
  283. }
  284. } catch (Throwable e) { // NOSONAR
  285. System.out.println("Class " + cls + " is not in classpath");
  286. }
  287. }
  288. }
  289. /**
  290. *
  291. * @param ptrn the pattern to filter output
  292. * @return the classes loaded by the system class loader
  293. */
  294. @SuppressWarnings("unchecked")
  295. private static Set<Class<?>> getLoadedClasses(String ptrn) {
  296. // make the field accessible, we defer this from static initialization to here to
  297. // allow JDKs which do not have this field (e.g. IBM JDK) to at least load the class
  298. // without failing, see https://issues.apache.org/bugzilla/show_bug.cgi?id=56550
  299. final Field _classes = AccessController.doPrivileged(new PrivilegedAction<Field>() {
  300. @Override
  301. @SuppressForbidden("TODO: Reflection works until Java 8 on Oracle/Sun JDKs, but breaks afterwards (different classloader types, access checks)")
  302. public Field run() {
  303. try {
  304. Field fld = ClassLoader.class.getDeclaredField("classes");
  305. fld.setAccessible(true);
  306. return fld;
  307. } catch (Exception e) {
  308. throw new RuntimeException(e);
  309. }
  310. }
  311. });
  312. ClassLoader appLoader = ClassLoader.getSystemClassLoader();
  313. try {
  314. Vector<Class<?>> classes = (Vector<Class<?>>) _classes.get(appLoader);
  315. Set<Class<?>> set = new HashSet<>();
  316. for (Class<?> cls : classes) {
  317. // e.g. proxy-classes, ...
  318. ProtectionDomain pd = cls.getProtectionDomain();
  319. if (pd == null) {
  320. continue;
  321. }
  322. CodeSource cs = pd.getCodeSource();
  323. if (cs == null) {
  324. continue;
  325. }
  326. URL loc = cs.getLocation();
  327. if (loc == null) {
  328. continue;
  329. }
  330. String jar = loc.toString();
  331. if (jar.contains(ptrn)) {
  332. set.add(cls);
  333. }
  334. }
  335. return set;
  336. } catch (IllegalAccessException e) {
  337. throw new RuntimeException(e);
  338. }
  339. }
  340. }