diff --git a/Makefile b/Makefile index bd1784b0..a6e91811 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ SHELL ?= /bin/bash endif #JAR_VERSION := $(shell mvn -q -Dexec.executable="echo" -Dexec.args='$${project.version}' --non-recursive exec:exec -DforceStdout) -JAR_VERSION := 1.54 +JAR_VERSION := 1.55 JAR_FILE := mn2pdf-$(JAR_VERSION).jar all: target/$(JAR_FILE) diff --git a/README.adoc b/README.adoc index 33028c5e..2dea0cc7 100644 --- a/README.adoc +++ b/README.adoc @@ -17,14 +17,14 @@ You will need the Java Development Kit (JDK) version 8, Update 241 (8u241) or hi [source,sh] ---- -java -Xss5m -Xmx2048m -jar target/mn2pdf-1.54.jar --xml-file --xsl-file --pdf-file [--syntax-highlight] +java -Xss5m -Xmx2048m -jar target/mn2pdf-1.55.jar --xml-file --xsl-file --pdf-file [--syntax-highlight] ---- e.g. [source,sh] ---- -java -Xss5m -Xmx2048m -jar target/mn2pdf-1.54.jar --xml-file tests/G.191.xml --xsl-file tests/itu.recommendation.xsl --pdf-file tests/G.191.pdf +java -Xss5m -Xmx2048m -jar target/mn2pdf-1.55.jar --xml-file tests/G.191.xml --xsl-file tests/itu.recommendation.xsl --pdf-file tests/G.191.pdf ---- === PDF encryption features @@ -100,7 +100,7 @@ Update version in `pom.xml`, e.g.: ---- org.metanorma.fop mn2pdf -1.54 +1.55 Metanorma XML to PDF converter ---- @@ -111,8 +111,8 @@ Tag the same version in Git: [source,xml] ---- -git tag v1.54 -git push origin v1.54 +git tag v1.55 +git push origin v1.55 ---- Then the corresponding GitHub release will be automatically created at: diff --git a/pom.xml b/pom.xml index 431eef3b..4d3e2463 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.metanorma.fop mn2pdf - 1.54 + 1.55 Metanorma XML to PDF converter jar https://www.metanorma.org diff --git a/src/main/java/org/metanorma/fop/PDFGenerator.java b/src/main/java/org/metanorma/fop/PDFGenerator.java index 788c479b..f99e13ba 100644 --- a/src/main/java/org/metanorma/fop/PDFGenerator.java +++ b/src/main/java/org/metanorma/fop/PDFGenerator.java @@ -208,8 +208,12 @@ public PDFGenerator (String inputXMLFilePath, String inputXSLFilePath, String ou public boolean process() { + + String methodName = getClass().getSimpleName() + "." + (new Object(){}.getClass().getEnclosingMethod().getName()); + Profiler.addMethodCall(methodName); + try { - + logger.info("Preparing..."); File fXML = new File(inputXMLFilePath); @@ -346,6 +350,7 @@ public boolean process() { e.printStackTrace(System.err); return false; } + Profiler.removeMethodCall(); return true; } @@ -360,13 +365,16 @@ public boolean process() { * @throws FOPException, SAXException In case of a FOP problem */ private void convertmn2pdf(fontConfig fontcfg, XSLTconverter xsltConverter, File pdf) throws IOException, FOPException, SAXException, TransformerException, ParserConfigurationException { - + + String methodName = getClass().getSimpleName() + "." + (new Object(){}.getClass().getEnclosingMethod().getName()); + Profiler.addMethodCall(methodName); + String imagesxml = sourceXMLDocument.getImageFilePath(); String indexxml = sourceXMLDocument.getIndexFilePath(); try { - + //Setup XSLT Properties additionalXSLTparams = new Properties(); @@ -393,7 +401,12 @@ private void convertmn2pdf(fontConfig fontcfg, XSLTconverter xsltConverter, File logger.info("[INFO] XSL-FO file preparation..."); // transform XML to XSL-FO (XML .fo file) - xsltConverter.transform(sourceXMLDocument); + if (shouldCreateIFFile(indexxml)) { + // IF file will be created later in runSecondPass, so no need to set "final_transform" = true (i.e. attach embedded files) + xsltConverter.transform(sourceXMLDocument, false); + } else { + xsltConverter.transform(sourceXMLDocument); + } String xmlFO = sourceXMLDocument.getXMLFO(); debugXSLFO = xmlFO; @@ -431,12 +444,16 @@ private void convertmn2pdf(fontConfig fontcfg, XSLTconverter xsltConverter, File e.printStackTrace(System.err); System.exit(ERROR_EXIT_CODE); } - - + + Profiler.removeMethodCall(); } private void runFOP (fontConfig fontcfg, Source src, File pdf) throws IOException, FOPException, SAXException, TransformerException { + + String methodName = getClass().getSimpleName() + "." + (new Object(){}.getClass().getEnclosingMethod().getName()); + Profiler.addMethodCall(methodName); + OutputStream out = null; String xmlIF = null; long startMethodTime = System.currentTimeMillis(); @@ -600,17 +617,22 @@ private void runFOP (fontConfig fontcfg, Source src, File pdf) throws IOExceptio } } - printProcessingTime(new Object(){}.getClass().getEnclosingMethod(), startMethodTime); + Profiler.printProcessingTime(methodName, startMethodTime); + Profiler.removeMethodCall(); } private Source runSecondPass (String indexxml, Source sourceFO, fontConfig fontcfg, Properties xslparams, XSLTconverter xsltConverter, File pdf) throws Exception, IOException, FOPException, SAXException, TransformerException, ParserConfigurationException { + + String methodName = getClass().getSimpleName() + "." + (new Object(){}.getClass().getEnclosingMethod().getName()); + Profiler.addMethodCall(methodName); + Source src = sourceFO; File fileXmlIF = new File(indexxml); long startMethodTime = System.currentTimeMillis(); - if (!indexxml.isEmpty() && !fileXmlIF.exists()) { //there is index + if (shouldCreateIFFile(indexxml)) { //there is index // if file exist - it means that now document by language is processing // and don't need to create intermediate file again @@ -637,16 +659,23 @@ private Source runSecondPass (String indexxml, Source sourceFO, fontConfig fontc src = new StreamSource(new StringReader(xmlFO)); } - printProcessingTime(new Object(){}.getClass().getEnclosingMethod(), startMethodTime); + Profiler.printProcessingTime(methodName, startMethodTime); + Profiler.removeMethodCall(); return src; } - + + private boolean shouldCreateIFFile(String indexxml) { + return !indexxml.isEmpty() && !(new File(indexxml)).exists(); + } private String generateFOPIntermediateFormat(Source src, File fontConfig, File pdf, boolean isSecondPass, String sfx) throws SAXException, IOException, TransformerConfigurationException, TransformerException { - String xmlIF = ""; - + long startMethodTime = System.currentTimeMillis(); - + String methodName = getClass().getSimpleName() + "." + (new Object(){}.getClass().getEnclosingMethod().getName()); + Profiler.addMethodCall(methodName); + + String xmlIF = ""; + // run 1st pass to produce FOP Intermediate Format FopFactory fopFactory = FopFactory.newInstance(fontConfig); //Create a user agent @@ -700,14 +729,18 @@ private String generateFOPIntermediateFormat(Source src, File fontConfig, File p } finally { out.close(); } - - printProcessingTime(new Object(){}.getClass().getEnclosingMethod(), startMethodTime); - + + Profiler.printProcessingTime(methodName, startMethodTime); + Profiler.removeMethodCall(); + return xmlIF; } private void createIndexFile(String indexxmlFilePath, String intermediateXML, File pdf) { - + + String methodName = getClass().getSimpleName() + "." + (new Object(){}.getClass().getEnclosingMethod().getName()); + Profiler.addMethodCall(methodName); + long startMethodTime = System.currentTimeMillis(); try { @@ -734,10 +767,15 @@ private void createIndexFile(String indexxmlFilePath, String intermediateXML, Fi logger.severe("Can't save index.xml into temporary folder"); ex.printStackTrace(); } - printProcessingTime(new Object(){}.getClass().getEnclosingMethod(), startMethodTime); + Profiler.printProcessingTime(methodName, startMethodTime); + Profiler.removeMethodCall(); } private String addHiddenMath(String sourceXML) { + + String methodName = getClass().getSimpleName() + "." + (new Object(){}.getClass().getEnclosingMethod().getName()); + Profiler.addMethodCall(methodName); + long startMethodTime = System.currentTimeMillis(); try { SAXParserFactory factory = SAXParserFactory.newInstance(); @@ -746,17 +784,23 @@ private String addHiddenMath(String sourceXML) { InputSource inputSource = new InputSource( new StringReader(sourceXML)); saxParser.parse(inputSource, fopIFHiddenMathHandler); String result = fopIFHiddenMathHandler.getResultedXML(); - printProcessingTime(new Object(){}.getClass().getEnclosingMethod(), startMethodTime); + Profiler.printProcessingTime(methodName, startMethodTime); + Profiler.removeMethodCall(); return result; } catch (Exception ex) { logger.severe("Can't update IF for hidden math."); ex.printStackTrace(); } + Profiler.removeMethodCall(); return sourceXML; } private String flatIFforXFDF(String sourceXML) { + + String methodName = getClass().getSimpleName() + "." + (new Object(){}.getClass().getEnclosingMethod().getName()); + Profiler.addMethodCall(methodName); + long startMethodTime = System.currentTimeMillis(); try { SAXParserFactory factory = SAXParserFactory.newInstance(); @@ -765,17 +809,23 @@ private String flatIFforXFDF(String sourceXML) { InputSource inputSource = new InputSource( new StringReader(sourceXML)); saxParser.parse(inputSource, fopIFFlatHandler); String result = fopIFFlatHandler.getResultedXML(); - printProcessingTime(new Object(){}.getClass().getEnclosingMethod(), startMethodTime); + Profiler.printProcessingTime(methodName, startMethodTime); + Profiler.removeMethodCall(); return result; } catch (Exception ex) { logger.severe("Can't flat IF."); ex.printStackTrace(); } + Profiler.removeMethodCall(); return sourceXML; } private String createTableIF(String intermediateXML) { + + String methodName = getClass().getSimpleName() + "." + (new Object(){}.getClass().getEnclosingMethod().getName()); + Profiler.addMethodCall(methodName); + String xmlTableIF = ""; long startMethodTime = System.currentTimeMillis(); try { @@ -784,7 +834,8 @@ private String createTableIF(String intermediateXML) { logger.severe("Can't generate information about tables from Intermediate Format."); ex.printStackTrace(); } - printProcessingTime(new Object(){}.getClass().getEnclosingMethod(), startMethodTime); + Profiler.printProcessingTime(methodName, startMethodTime); + Profiler.removeMethodCall(); return xmlTableIF; } @@ -813,6 +864,9 @@ private String createTableIF(String intermediateXML) { // Apply XSL tranformation (file xsltfile) for XML String or StreamSource private String applyXSLT(String xsltfile, Object sourceXML, boolean fixSurrogatePairs) throws Exception { + + String methodName = getClass().getSimpleName() + "." + (new Object(){}.getClass().getEnclosingMethod().getName()); + Profiler.addMethodCall(methodName); long startMethodTime = System.currentTimeMillis(); Source srcXSL = new StreamSource(getStreamFromResources(getClass().getClassLoader(), xsltfile)); @@ -828,9 +882,10 @@ private String applyXSLT(String xsltfile, Object sourceXML, boolean fixSurrogate StreamResult sr = new StreamResult(resultWriter); transformer.transform(src, sr); String xmlResult = resultWriter.toString(); - - printProcessingTime(new Object(){}.getClass().getEnclosingMethod(), startMethodTime, xsltfile); - + + Profiler.printProcessingTime(methodName, startMethodTime, xsltfile); + Profiler.removeMethodCall(); + return xmlResult; } @@ -873,6 +928,10 @@ private String applyXSLT(String xsltfile, Object sourceXML, boolean fixSurrogate // Apply XSL tranformation (file xsltfile) for the source xml and IF string (parameter 'if_xml') private String applyXSLTExtended(String xsltfile, StreamSource sourceXML, String xmlIFStr, boolean fixSurrogatePairs) throws Exception { + + String methodName = getClass().getSimpleName() + "." + (new Object(){}.getClass().getEnclosingMethod().getName()); + Profiler.addMethodCall(methodName); + long startMethodTime = System.currentTimeMillis(); Source srcXSL = new StreamSource(getStreamFromResources(getClass().getClassLoader(), xsltfile)); @@ -895,9 +954,10 @@ private String applyXSLTExtended(String xsltfile, StreamSource sourceXML, String StreamResult sr = new StreamResult(resultWriter); transformer.transform(sourceXML, sr); String xmlResult = resultWriter.toString(); - - printProcessingTime(new Object(){}.getClass().getEnclosingMethod(), startMethodTime, xsltfile); - + + Profiler.printProcessingTime(methodName, startMethodTime, xsltfile); + Profiler.removeMethodCall(); + return xmlResult; } @@ -1054,7 +1114,11 @@ private void readEncryptionParameters(File fEncryptionParameters) { } private void setTablesWidths(fontConfig fontcfg, XSLTconverter xsltConverter, File pdf) { + + String methodName = getClass().getSimpleName() + "." + (new Object(){}.getClass().getEnclosingMethod().getName()); + Profiler.addMethodCall(methodName); long startMethodTime = System.currentTimeMillis(); + try { if (isTableExists && xmlTableIF.isEmpty()) { // generate IF with table width data @@ -1068,33 +1132,36 @@ private void setTablesWidths(fontConfig fontcfg, XSLTconverter xsltConverter, Fi logger.severe("Can't generate information about tables from Intermediate Format."); ex.printStackTrace(); } - + debugSaveXML(xmlTablesOnly, pdf.getAbsolutePath() + ".tablesonly.xml"); - + SourceXMLDocument sourceXMLDocumentTablesOnly = new SourceXMLDocument(xmlTablesOnly); + // transform XML to XSL-FO (XML .fo file) - xsltConverter.transform(sourceXMLDocumentTablesOnly); - + xsltConverter.transform(sourceXMLDocumentTablesOnly, false); + String xmlFO = sourceXMLDocumentTablesOnly.getXMLFO(); - - debugSaveXML(xmlFO, pdf.getAbsolutePath() + ".fo.tables.xml"); - + //debug + debugSaveXML(xmlFO, pdf.getAbsolutePath() + ".fo.tables.xml"); + fontcfg.outputFontManifestLog(Paths.get(pdf.getAbsolutePath() + ".tables.fontmanifest.log.txt")); - + fontcfg.setSourceDocumentFontList(sourceXMLDocumentTablesOnly.getDocumentFonts()); Source sourceFO = new StreamSource(new StringReader(xmlFO)); + logger.info("[INFO] Generation of Intermediate Format with information about the table's widths ..."); String xmlIF = generateFOPIntermediateFormat(sourceFO, fontcfg.getConfig(), pdf, true, ".tables"); xmlTableIF = createTableIF(xmlIF); - + debugSaveXML(xmlTableIF, pdf.getAbsolutePath() + ".tables.xml"); - + xsltConverter.setParam("table_if", "false"); logger.info("[INFO] Generated successfully!"); } + if (!xmlTableIF.isEmpty()) { // pass Table widths XML via parameter 'if_xml' logger.info("[INFO] Generation XML with table's widths ..."); @@ -1110,18 +1177,21 @@ private void setTablesWidths(fontConfig fontcfg, XSLTconverter xsltConverter, Fi } catch (Exception e) { logger.log(Level.SEVERE, "Can''t obtain table's widths information: {0}", e.toString()); } - printProcessingTime(new Object(){}.getClass().getEnclosingMethod(), startMethodTime); + Profiler.printProcessingTime(methodName, startMethodTime); + Profiler.removeMethodCall(); } private void debugSaveXML(String xmlString, String pathTo) { try { if (DEBUG) { + //DEBUG: write table width information to file String xmlString_UTF8 = xmlString.replace("", ""); try ( BufferedWriter writer = Files.newBufferedWriter(Paths.get(pathTo))) { writer.write(xmlString_UTF8); } + //Setup output //OutputStream outstream = new java.io.FileOutputStream(pdf.getAbsolutePath() + ".fo.xml"); //Resulting SAX events (the generated FO) must be piped through to FOP @@ -1142,11 +1212,4 @@ private int getIFPageCount(String xmlIF) { return pagecount; } - private void printProcessingTime(Method method, long startTime, String ... params) { - if (DEBUG) { - long endTime = System.currentTimeMillis(); - String addon = Arrays.toString(params); - logger.log(Level.INFO, "Method '" + method.getName() + "(" + addon + ")' processing time: {0} milliseconds", endTime - startTime); - } - } } diff --git a/src/main/java/org/metanorma/fop/Profiler.java b/src/main/java/org/metanorma/fop/Profiler.java new file mode 100644 index 00000000..bdc36780 --- /dev/null +++ b/src/main/java/org/metanorma/fop/Profiler.java @@ -0,0 +1,62 @@ +package org.metanorma.fop; + +import org.metanorma.utils.LoggerHelper; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Stack; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static org.metanorma.Constants.DEBUG; + +public class Profiler { + + protected static final Logger logger = Logger.getLogger(LoggerHelper.LOGGER_NAME); + + + static ArrayList arraysMethodCalls = new ArrayList<>(); + + static Stack stackMethods = new Stack<>(); + + public static void addMethodCall(String methodName) { + stackMethods.push(methodName); + String msg = String.join("", Collections.nCopies(stackMethods.size() * 2, " ")) + methodName; + arraysMethodCalls.add(msg); + } + + public static void removeMethodCall() { + try { + stackMethods.pop(); + } catch (Exception ex) {}; + } + + public static void printProcessingTime(String methodName, long startTime, String ... params) { + if (DEBUG) { + long endTime = System.currentTimeMillis(); + String addon = Arrays.toString(params); + if (addon.isEmpty()) { + addon = "(" + addon + ")"; + } + String msg = String.format(methodName + addon + " processing time: %d milliseconds", endTime - startTime); + logger.log(Level.INFO, msg); + arraysMethodCalls.add(String.join("", Collections.nCopies(stackMethods.size() * 2, " ")) + msg); + } + } + + public static void printFullProcessingTime() { + if (DEBUG) { + logger.log(Level.INFO, "============================"); + logger.log(Level.INFO, "============================"); + logger.log(Level.INFO, "============================"); + for (String msg: arraysMethodCalls) { + logger.log(Level.INFO, msg); + } + logger.log(Level.INFO, "============================"); + logger.log(Level.INFO, "============================"); + logger.log(Level.INFO, "============================"); + } + } + +} diff --git a/src/main/java/org/metanorma/fop/SourceXMLDocument.java b/src/main/java/org/metanorma/fop/SourceXMLDocument.java index 4879e4c4..a4eeb036 100644 --- a/src/main/java/org/metanorma/fop/SourceXMLDocument.java +++ b/src/main/java/org/metanorma/fop/SourceXMLDocument.java @@ -63,6 +63,7 @@ public class SourceXMLDocument { String xmlFO = ""; public SourceXMLDocument(File fXML) { + this.fXML = fXML; this.documentFilePath = this.fXML.getParent(); if (this.documentFilePath == null) { @@ -80,6 +81,7 @@ public SourceXMLDocument(File fXML) { } public SourceXMLDocument(String strXML) { + try { this.sourceXMLstr = strXML; DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); @@ -113,7 +115,8 @@ public void setXMLFO(String xmlFO) { this.xmlFO = xmlFO; } - public List getDocumentFonts() { + public List getDocumentFonts() { + List documentFontList = new ArrayList<>(); if(!xmlFO.isEmpty()) { @@ -149,7 +152,7 @@ public List getDocumentFonts() { logger.info(e.toString()); } } - + return documentFontList; } @@ -248,6 +251,7 @@ public String getIndexFilePath() { } public ArrayList getLanguagesList () { + ArrayList languagesList = new ArrayList<>(); try { // open XML and find all tags @@ -273,7 +277,7 @@ public ArrayList getLanguagesList () { logger.severe("Can't read language list from source XML."); ex.printStackTrace(); } - + return languagesList; } diff --git a/src/main/java/org/metanorma/fop/Util.java b/src/main/java/org/metanorma/fop/Util.java index b2ead521..205a79bc 100644 --- a/src/main/java/org/metanorma/fop/Util.java +++ b/src/main/java/org/metanorma/fop/Util.java @@ -86,7 +86,7 @@ public class Util { protected static final Logger logger = Logger.getLogger(LoggerHelper.LOGGER_NAME); - + public static int getFileSize(URL url) { URLConnection conn = null; try { @@ -691,15 +691,21 @@ public static String floatArrayToString(float[] a) { } public static String innerXml(Node node) { - DOMImplementationLS lsImpl = (DOMImplementationLS)node.getOwnerDocument().getImplementation().getFeature("LS", "3.0"); + DOMImplementationLS lsImpl = (DOMImplementationLS) node.getOwnerDocument().getImplementation().getFeature("LS", "3.0"); LSSerializer lsSerializer = lsImpl.createLSSerializer(); lsSerializer.getDomConfig().setParameter("xml-declaration", false); NodeList childNodes = node.getChildNodes(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < childNodes.getLength(); i++) { - sb.append(lsSerializer.writeToString(childNodes.item(i))); + sb.append(lsSerializer.writeToString(childNodes.item(i))); } - return sb.toString(); + return sb.toString(); } + public static String encodeBase64(String input) { + if (input == null || input.isEmpty()) { + return ""; + } + return Base64.getEncoder().encodeToString(input.getBytes()); + } } diff --git a/src/main/java/org/metanorma/fop/XSLTconverter.java b/src/main/java/org/metanorma/fop/XSLTconverter.java index e75f218b..d76534bd 100644 --- a/src/main/java/org/metanorma/fop/XSLTconverter.java +++ b/src/main/java/org/metanorma/fop/XSLTconverter.java @@ -72,13 +72,17 @@ public void setParam(String name, Object value) { public Object getParam(String name) { return transformerFO.getParameter(name); } - + public void transform(SourceXMLDocument sourceXMLDocument) throws TransformerException { - + transform(sourceXMLDocument, true); + } + + public void transform(SourceXMLDocument sourceXMLDocument, boolean isFinalTransform) throws TransformerException { + + String methodName = getClass().getSimpleName() + "." + (new Object(){}.getClass().getEnclosingMethod().getName()); + Profiler.addMethodCall(methodName); startTime = System.currentTimeMillis(); - - String methodName = new Object(){}.getClass().getEnclosingMethod().getName(); - + //Setup input for XSLT transformation Source src = sourceXMLDocument.getStreamSource(); @@ -87,23 +91,16 @@ public void transform(SourceXMLDocument sourceXMLDocument) throws TransformerExc // Step 0. Convert XML to FO file with XSL StringWriter resultWriter = new StringWriter(); StreamResult sr = new StreamResult(resultWriter); - + + transformerFO.setParameter("final_transform", String.valueOf(isFinalTransform)); //Start XSLT transformation and FO generating transformerFO.transform(src, sr); String xmlFO = resultWriter.toString(); sourceXMLDocument.setXMLFO(xmlFO); - - printProcessingTime(methodName); - - } - - - private void printProcessingTime(String methodName) { - if (DEBUG) { - long endTime = System.currentTimeMillis(); - logger.log(Level.INFO, methodName + " processing time: {0} milliseconds", endTime - startTime); - } + + Profiler.printProcessingTime(methodName, startTime); + Profiler.removeMethodCall(); } } diff --git a/src/main/java/org/metanorma/fop/fontConfig.java b/src/main/java/org/metanorma/fop/fontConfig.java index 24c9732b..ba9e4bf3 100644 --- a/src/main/java/org/metanorma/fop/fontConfig.java +++ b/src/main/java/org/metanorma/fop/fontConfig.java @@ -88,7 +88,9 @@ class fontConfig { static List fopFonts = new ArrayList<>(); private File fFontManifest; - + + private static List registeredFonts = new ArrayList<>(); + private boolean isReady = false; //private final List defaultFontList = new DefaultFonts().getDefaultFonts(); @@ -100,7 +102,7 @@ public fontConfig() { setFontPath(DEFAULT_FONT_PATH); - FOPconfigXML = getSourceFOPConfigFile(); + FOPconfigXML = getSourceFOPConfigFile(); if (fopFonts.isEmpty()) { fopFonts = getFOPfonts(); @@ -128,6 +130,7 @@ public void setFontPath(String fontPath) { } public void setFontManifest(File fFontManifest) { + this.fFontManifest = fFontManifest; /* Example expected format: Cambria: @@ -404,6 +407,7 @@ public FOPFontTriplet getFontDefaultProperties(String font) { } public void setSourceDocumentFontList(List sourceDocumentFontList) { + this.sourceDocumentFontList = sourceDocumentFontList; isReady = false; @@ -421,11 +425,11 @@ public void setSourceDocumentFontList(List sourceDocumentFontList) { } }*/ } - } private void updateConfig() throws IOException, Exception { + if(!isReady) { // set file paths for fonts @@ -471,11 +475,13 @@ public void outputAvailableAWTFonts(Path logPath) { } private Document getSourceFOPConfigFile() { + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); try { DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); InputStream config = Util.getStreamFromResources(getClass().getClassLoader(), CONFIG_NAME); Document sourceFOPConfig = dBuilder.parse(config); + return sourceFOPConfig; } catch (Exception ex) { logger.severe(ex.toString()); @@ -483,7 +489,7 @@ private Document getSourceFOPConfigFile() { } } - private List getFOPfonts() { + private List getFOPfonts() { List fonts = new ArrayList<>(); NodeList fontNodes = FOPconfigXML.getElementsByTagName("font"); @@ -492,17 +498,18 @@ private List getFOPfonts() { for (int i = 0; i < fontNodes.getLength(); i++) { Node fontNode = fontNodes.item(i); XmlMapper xmlMapper = new XmlMapper(); - + try { // DEBUG String xml = xmlMapper.writeValueAsString(new FOPFont()); - + FOPFont fopfont = xmlMapper.readValue(innerXml(fontNode), FOPFont.class); fonts.add(fopfont); } catch (JsonProcessingException ex) { logger.log(Level.SEVERE, "Error in reading font information: {0}", ex.toString()); logger.log(Level.SEVERE, "XML fragment: {0}", innerXml(fontNode)); } - } + } + return fonts; } @@ -519,7 +526,7 @@ public List getUsedFonts () // set file paths for fonts private void setFontsPaths() throws IOException, URISyntaxException { - + List machineFontList = getMachineFonts(); fopFonts.stream() @@ -626,6 +633,7 @@ private void setFontsPaths() throws IOException, URISyntaxException { } private List getMachineFonts() throws IOException{ + List systemFontListURL = new ArrayList<>(); List userFontListURL = new ArrayList<>(); @@ -643,10 +651,12 @@ private List getMachineFonts() throws IOException{ for(URL url: userFontListURL){ machineFontList.add(URLDecoder.decode(url.toString(), StandardCharsets.UTF_8.name())); } + return machineFontList; } private void updateFontsInFOPConfig(Document xmlDocument) { + XPath xPath = XPathFactory.newInstance().newXPath(); String expression = "/fop/renderers/renderer/fonts"; try { @@ -702,7 +712,7 @@ private void updateFontsInFOPConfig(Document xmlDocument) { } } catch (XPathExpressionException ex) { logger.severe(ex.toString()); - } + } } public void outputFOPFontsLog(Path logPath) { @@ -770,6 +780,7 @@ public void setPDFUAmode(String mode) throws SAXException, IOException, ParserCo private void updateFontsForGraphicsEnvironment(){ + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); try (Stream walk = Files.walk(Paths.get(this.fontPath))) { @@ -790,35 +801,40 @@ private void updateFontsForGraphicsEnvironment(){ } public static void registerFont(GraphicsEnvironment ge, String fontFile){ - if (ge == null) { - ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); - } - try { - // try to obtain font to check an exception: - // java.lang.NullPointerException: Cannot load from short array because "sun.awt.FontConfiguration.head" is null - String[] names = ge.getAvailableFontFamilyNames(); - int count = names.length; - } catch (Exception e) { - logger.severe("[ERROR] " + e.toString()); - logger.severe("[ERROR] fontconfig not found or no one system font not installed."); - System.exit(ERROR_EXIT_CODE); - } - try { - Font ttfFont = Font.createFont(Font.TRUETYPE_FONT, new File(fontFile)); - //register the font - ge.registerFont(ttfFont); - } catch(FontFormatException e) { + if (!registeredFonts.contains(fontFile)) { + + if (ge == null) { + ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + } try { - Font type1Font = Font.createFont(Font.TYPE1_FONT, new File(fontFile)); + // try to obtain font to check an exception: + // java.lang.NullPointerException: Cannot load from short array because "sun.awt.FontConfiguration.head" is null + String[] names = ge.getAvailableFontFamilyNames(); + int count = names.length; + } catch (Exception e) { + logger.severe("[ERROR] " + e.toString()); + logger.severe("[ERROR] fontconfig not found or no one system font not installed."); + System.exit(ERROR_EXIT_CODE); + } + try { + Font ttfFont = Font.createFont(Font.TRUETYPE_FONT, new File(fontFile)); //register the font - ge.registerFont(type1Font); - } catch(FontFormatException e1) { - e1.printStackTrace(); - } catch (IOException e2) { - e2.printStackTrace(); + ge.registerFont(ttfFont); + registeredFonts.add(fontFile); + } catch(FontFormatException e) { + try { + Font type1Font = Font.createFont(Font.TYPE1_FONT, new File(fontFile)); + //register the font + ge.registerFont(type1Font); + registeredFonts.add(fontFile); + } catch(FontFormatException e1) { + e1.printStackTrace(); + } catch (IOException e2) { + e2.printStackTrace(); + } + } catch (IOException e) { + e.printStackTrace(); } - } catch (IOException e) { - e.printStackTrace(); } } @@ -860,8 +876,8 @@ private String innerXml(Node node) { Result target = new StreamResult(out); transformer.transform(source, target); } catch (TransformerException ex) {} + return out.toString(); - } } diff --git a/src/main/java/org/metanorma/fop/mn2pdf.java b/src/main/java/org/metanorma/fop/mn2pdf.java index 8b2b4f9c..95b113a2 100644 --- a/src/main/java/org/metanorma/fop/mn2pdf.java +++ b/src/main/java/org/metanorma/fop/mn2pdf.java @@ -1,7 +1,6 @@ package org.metanorma.fop; -import java.io.PrintWriter; -import java.io.StringWriter; +import java.io.*; import java.util.logging.Logger; import org.apache.commons.cli.CommandLine; @@ -14,7 +13,6 @@ import static org.metanorma.Constants.APP_NAME; import static org.metanorma.Constants.ERROR_EXIT_CODE; import static org.metanorma.Constants.DEBUG; -import static org.metanorma.fop.PDFGenerator.logger; import org.metanorma.utils.LoggerHelper; @@ -25,6 +23,8 @@ public class mn2pdf { protected static final Logger logger = Logger.getLogger(LoggerHelper.LOGGER_NAME); + private static long startTime; + static final String CMD = "java -Xss5m -Xmx2048m -jar " + APP_NAME + ".jar"; static final Options optionsInfo = new Options() { @@ -221,9 +221,12 @@ public class mn2pdf { * @param args command-line arguments */ public static void main(String[] args) throws ParseException { - + Profiler.addMethodCall(new Object(){}.getClass().getEnclosingMethod().getName()); + LoggerHelper.setupLogger(); + startTime = System.currentTimeMillis(); + CommandLineParser parser = new DefaultParser(); String ver = Util.getAppVersion(); @@ -347,6 +350,11 @@ public static void main(String[] args) throws ParseException { } LoggerHelper.closeFileHandler(); + Profiler.printProcessingTime("Total mn2pdf", startTime); + + Profiler.removeMethodCall(); + + Profiler.printFullProcessingTime(); } private static String getUsage() { @@ -357,5 +365,4 @@ private static String getUsage() { pw.flush(); return stringWriter.toString(); } - }