package org.argeo.app.servlet.publish;
+import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.commons.io.IOUtils;
+import org.apache.fop.apps.Fop;
+import org.apache.fop.apps.FopFactory;
import org.apache.xalan.processor.TransformerFactoryImpl;
-import org.argeo.api.cms.CmsTheme;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.ux.CmsTheme;
import org.argeo.app.docbook.DbkType;
import org.argeo.app.docbook.DbkUtils;
import org.argeo.cms.auth.RemoteAuthUtils;
public class DbkServlet extends HttpServlet {
private static final long serialVersionUID = 6906020513498289335L;
+ private CmsLog log = CmsLog.getLog(DbkServlet.class);
+
private Repository repository;
private DocumentBuilderFactory documentBuilderFactory;
private TransformerFactory transformerFactory;
- private Templates docBoookTemplates;
+ private Templates docBoookHtmlTemplates;
+
+ // FOP
+ private Templates docBoookFoTemplates;
private Map<String, CmsTheme> themes = Collections.synchronizedMap(new HashMap<>());
+ private String xslBase;
+
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
path = path.substring(0, path.length() - "/index.html".length());
}
+ boolean pdf = false;
+ if (path.toLowerCase().endsWith(".pdf")) {
+ pdf = true;
+ if (path.toLowerCase().endsWith("/index.pdf")) {
+ path = path.substring(0, path.length() - "/index.pdf".length());
+ }
+ }
+
Session session = null;
try {
session = RemoteAuthUtils.doAs(() -> Jcr.login(repository, null), new ServletHttpRequest(req));
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
session.exportDocumentView(dbkNode.getPath(), out, true, false);
arr = out.toByteArray();
-// System.out.println(new String(arr, StandardCharsets.UTF_8));
} catch (RepositoryException e) {
throw new JcrException(e);
}
- try (InputStream in = new ByteArrayInputStream(arr);
-// ByteArrayOutputStream out = new ByteArrayOutputStream();
- ) {
-
- Result xmlOutput = new StreamResult(resp.getOutputStream());
+ try (InputStream in = new ByteArrayInputStream(arr);) {
DocumentBuilder docBuilder = documentBuilderFactory.newDocumentBuilder();
-// Document doc = docBuilder.parse(new File(
-// System.getProperty("user.home") + "/dev/git/gpl/argeo-qa/doc/platform/argeo-platform.dbk.xml"));
Document doc = docBuilder.parse(in);
Source xmlInput = new DOMSource(doc);
- Transformer transformer = docBoookTemplates.newTransformer();
+ if (pdf) {
+ // String baseUri = req.getRequestURI();
+ FopFactory fopFactory = FopFactory.newInstance(URI.create(req.getRequestURL().toString()));
+ resp.setContentType("application/pdf");
+
+// // DocBook to FO
+// byte[] foBytes;
+// try (ByteArrayOutputStream out = new ByteArrayOutputStream();) {
+// Result xmlOutput = new StreamResult(out);
+// Transformer docBookTransformer = docBoookFoTemplates.newTransformer();
+// docBookTransformer.transform(xmlInput, xmlOutput);
+// foBytes = out.toByteArray();
+// }
+//
+// // FO to PDF
+// try (InputStream foIn = new ByteArrayInputStream(foBytes)) {
+// Fop fop = fopFactory.newFop("application/pdf", resp.getOutputStream());
+// Transformer fopTransformer = transformerFactory.newTransformer(); // identity
+// Source src = new StreamSource(foIn);
+// Result fopResult = new SAXResult(fop.getDefaultHandler());
+// fopTransformer.transform(src, fopResult);
+// }
+//
- // gather CSS
- if (cmsTheme != null) {
- StringBuilder sb = new StringBuilder();
- for (String cssPath : cmsTheme.getWebCssPaths()) {
- sb.append(req.getContextPath()).append(req.getServletPath()).append('/');
- sb.append(themeId).append('/').append(cssPath).append(' ');
+ Fop fop = fopFactory.newFop("application/pdf", resp.getOutputStream());
+ Transformer docBookTransformer = getDocBoookFoTemplates().newTransformer();
+ Result fopResult = new SAXResult(fop.getDefaultHandler());
+ docBookTransformer.transform(xmlInput, fopResult);
+
+ } else {
+ Result xmlOutput = new StreamResult(resp.getOutputStream());
+ resp.setContentType("text/html");
+ Transformer docBookTransformer = getDocBoookHtmlTemplates().newTransformer();
+
+ // gather CSS
+ if (cmsTheme != null) {
+ StringBuilder sb = new StringBuilder();
+ for (String cssPath : cmsTheme.getWebCssPaths()) {
+ sb.append(req.getContextPath()).append(req.getServletPath()).append('/');
+ sb.append(themeId).append('/').append(cssPath).append(' ');
+ }
+ // FIXME make it more generic
+ sb.append("https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap")
+ .append(' ');
+ sb.append(
+ "https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,300;0,400;0,600;1,400&display=swap")
+ .append(' ');
+ if (sb.length() > 0)
+ docBookTransformer.setParameter("html.stylesheet", sb.toString());
}
- // FIXME make it more generic
- sb.append("https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap")
- .append(' ');
- sb.append(
- "https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,300;0,400;0,600;1,400&display=swap")
- .append(' ');
- if (sb.length() > 0)
- transformer.setParameter("html.stylesheet", sb.toString());
+ docBookTransformer.transform(xmlInput, xmlOutput);
}
- transformer.transform(xmlInput, xmlOutput);
// resp.getOutputStream().write(out.toByteArray());
} catch (Exception e) {
throw new ServletException("Cannot transform " + path, e);
public void init() throws ServletException {
// TODO improve configuration and provisioning of DocBook XSL
- String xslBase = System.getProperty("argeo.docbook.xsl");
+ xslBase = System.getProperty("argeo.docbook.xsl");
if (xslBase == null) {
// We need namespace aware XSL!
// Fedora (sudo dnf install docbook5-style-xsl)
if (!Files.exists(Paths.get(defaultXslBase))) {
defaultXslBase = "/opt/docbook-xsl";
if (!Files.exists(Paths.get(defaultXslBase))) {
- throw new ServletException("System property argeo.docbook.xsl is not set and default location "
- + defaultXslBase + " does not exist.");
+ log.error("System property argeo.docbook.xsl is not set and default location " + defaultXslBase
+ + " does not exist.");
}
}
xslBase = defaultXslBase;
}
- String xsl = xslBase + "/html/docbook.xsl";
documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setXIncludeAware(true);
documentBuilderFactory.setNamespaceAware(true);
- // We must explicitly use the non-XSLTC transformer, as XSLTC is not working
- // with DocBook stylesheets
- transformerFactory = new TransformerFactoryImpl();
+ }
- Source xslSource = new StreamSource(xsl);
+ protected Templates createDocBookTemplates(String xsl) {
try {
- docBoookTemplates = transformerFactory.newTemplates(xslSource);
- if (docBoookTemplates == null)
- throw new ServletException("Could not instantiate XSL " + xsl);
+ if (transformerFactory == null) {
+ // We must explicitly use the non-XSLTC transformer, as XSLTC is not working
+ // with DocBook stylesheets
+ transformerFactory = new TransformerFactoryImpl();
+ }
+ Source xslSource = new StreamSource(xsl);
+ Templates templates = transformerFactory.newTemplates(xslSource);
+ if (templates == null)
+ throw new IllegalStateException("Could not instantiate XSL " + xsl);
+ return templates;
} catch (TransformerConfigurationException e) {
- throw new ServletException("Cannot instantiate XSL " + xsl, e);
+ throw new IllegalStateException("Cannot instantiate XSL " + xsl, e);
+ }
+
+ }
+
+ protected Templates getDocBoookHtmlTemplates() {
+ if (docBoookHtmlTemplates == null) {
+ String htmlXsl = xslBase + "/html/docbook.xsl";
+ docBoookHtmlTemplates = createDocBookTemplates(htmlXsl);
+ }
+ return docBoookHtmlTemplates;
+ }
+
+ protected Templates getDocBoookFoTemplates() {
+ if (docBoookFoTemplates == null) {
+ String foXsl = xslBase + "/fo/docbook.xsl";
+ docBoookFoTemplates = createDocBookTemplates(foXsl);
}
+ return docBoookFoTemplates;
}
public void setRepository(Repository repository) {
themes.remove(theme.getThemeId());
}
+ public static void main(String[] args) throws Exception {
+ // Step 1: Construct a FopFactory by specifying a reference to the configuration
+ // file
+ // (reuse if you plan to render multiple documents!)
+ FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());
+
+ // Step 2: Set up output stream.
+ // Note: Using BufferedOutputStream for performance reasons (helpful with
+ // FileOutputStreams).
+ OutputStream out = new BufferedOutputStream(new FileOutputStream(new File(
+ System.getProperty("user.home") + "/dev/git/unstable/argeo-qa/doc/platform/argeo-platform-test.pdf")));
+
+ try {
+ // Step 3: Construct fop with desired output format
+ Fop fop = fopFactory.newFop("application/pdf", out);
+
+ // Step 4: Setup JAXP using identity transformer
+ TransformerFactory fopTransformerFactory = TransformerFactory.newInstance();
+ Transformer fopTransformer = fopTransformerFactory.newTransformer(); // identity transformer
+
+ // Step 5: Setup input and output for XSLT transformation
+ // Setup input stream
+ Source src = new StreamSource(new File(
+ System.getProperty("user.home") + "/dev/git/unstable/argeo-qa/doc/platform/argeo-platform.fo"));
+
+ // Resulting SAX events (the generated FO) must be piped through to FOP
+ Result res = new SAXResult(fop.getDefaultHandler());
+
+ // Step 6: Start XSLT transformation and FOP processing
+ fopTransformer.transform(src, res);
+
+ } finally {
+ // Clean-up
+ out.close();
+ }
+ }
}