/* WebBox - Dein Server. Copyright (C) 2020 Ulrich Hilger, http://uhilger.de This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ package de.uhilger.wbx.web; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.util.HashMap; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Map; import javax.servlet.ServletOutputStream; import static org.asciidoctor.Asciidoctor.Factory.create; import org.asciidoctor.Asciidoctor; import static org.asciidoctor.AttributesBuilder.attributes; import static org.asciidoctor.OptionsBuilder.options; import org.asciidoctor.SafeMode; /** * Das AdocServlet wandelt AsciiDoc-Inhalte (*.adoc) * zu HTML-Seiten und PDF-Dokumenten * * Mit Angabe des Parameters ?pdf=true im URL wird PDF erzeugt, andernfalls HTML */ public class AdocServlet extends HttpServlet { private static final String DOT = "."; private static final String HTML = "html"; private static final String PDF = "pdf"; private static final String SERVLET_NAME = "AdocServlet"; /** * Die Methode processRequest verarbeitet HTTP-Anfragen des Typs * GET und POST. * * @param request die Servlet-Anfrage * @param response die Servlet-Antwort * @throws ServletException wenn ein Servlet-spezifischer Fehler passiert * @throws IOException wenn ein Eingabe- oder Ausgabe-Fehler passiert */ protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Asciidoc-Quelldatei aus HTTP-Request ermitteln String vPath = request.getServletPath(); String absname = getServletContext().getRealPath(vPath); File adocfile = new File(absname); // HTML-Datei ermitteln String nameext = adocfile.getName(); String fname = nameext.substring(0, nameext.lastIndexOf(DOT)); File htmlfile = new File(adocfile.getParentFile(), fname + DOT + HTML); File outfile = htmlfile; // Standardmaessig wird HTML zurueckgegeben response.setCharacterEncoding("UTF-8"); /* nach HTML transformieren, wenn die Quelle sich geandert hat oder die HTML-Datei noch nicht existiert */ if(!htmlfile.exists() || adocfile.lastModified() > htmlfile.lastModified()) { transform(absname); } /* nach PDF transformieren, wenn der Parameter pdf=true existiert und wenn die Quelle sich geandert hat oder die PDF-Datei noch nicht existiert */ String pdf = request.getParameter(PDF); if(null != pdf && pdf.equalsIgnoreCase(Boolean.TRUE.toString())) { File pdffile = new File(adocfile.getParentFile(), fname + DOT + PDF); outfile = pdffile; // PDF soll zurueckgegeben werden if(!pdffile.exists() || adocfile.lastModified() > pdffile.lastModified()) { response.setContentType("application/pdf"); transform(absname, PDF); } ServletOutputStream os = response.getOutputStream(); InputStream bytes = new FileInputStream(outfile); int b = bytes.read(); while(b > -1 ) { os.write(b); b = bytes.read(); } } else { PrintWriter out = response.getWriter(); InputStreamReader in = new InputStreamReader(new FileInputStream(outfile), "UTF-8"); in.transferTo(out); } } /** * Nach HTML transformieren * @param fileName der Dateiname der Quelldatei samt absoluter Pfadangabe */ private void transform(String fileName) { transform(fileName, null); } /** * In ein Format transformieren, das von einem 'Backend' von Asciidoctor * unterstuetzt wird * @param fileName der Dateiname der Quelldatei samt absoluter Pfadangabe * @param backend das Kuerzel des Backends, z.B. der String 'pdf', wenn * nach PDF transformiert werden soll */ private void transform(String fileName, String backend) { Map attributes; File outFile = new File(fileName); String thisDirName = outFile.getParent(); File pdfStyles = new File(outFile.getParentFile(), "custom-theme.yml"); if(pdfStyles.exists()) { attributes = attributes() .attribute("pdf-themesdir", thisDirName) .attribute("pdf-theme","custom") .attribute("pdf-fontsdir", thisDirName + "/fonts") .attribute("allow-uri-read") .sourceHighlighter("highlightjs") .asMap(); } else { attributes = attributes() .sourceHighlighter("highlightjs") .asMap(); } Map options; if(null != backend) { options = options().inPlace(false) .safe(SafeMode.SERVER) .backend(backend).attributes(attributes).asMap(); } else { options = options().inPlace(false) .safe(SafeMode.SERVER) .attributes(attributes).asMap(); } Asciidoctor asciidoctor = create(); asciidoctor.requireLibrary("asciidoctor-diagram"); asciidoctor.convertFile(new File(fileName), options); } /** * Die HTTP-GET-Methode verarbeiten. * * @param request die Servlet-Anfrage * @param response die Servlet-Antwort * @throws ServletException wenn ein Servlet-spezifischer Fehler passiert * @throws IOException wenn ein Eingabe- oder Ausgabe-Fehler passiert */ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Die HTTP-POST-Methode verarbeiten. * * @param request die Servlet-Anfrage * @param response die Servlet-Antwort * @throws ServletException wenn ein Servlet-spezifischer Fehler passiert * @throws IOException wenn ein Eingabe- oder Ausgabe-Fehler passiert */ @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Eine Kurzbeschreibung des Servlets ausgeben. * * @return einen String mit der Kurzbeschreibung des Servlets */ @Override public String getServletInfo() { return SERVLET_NAME; } }