franta-hg@6: package cz.frantovo.xmlWebGenerator; franta-hg@6: franta-hg@27: import java.io.BufferedReader; franta-hg@6: import java.io.File; franta-hg@27: import java.io.IOException; franta-hg@27: import java.io.InputStream; franta-hg@27: import java.io.InputStreamReader; franta-hg@27: import java.io.PrintStream; franta-hg@6: import java.util.Date; franta-hg@6: import java.net.URI; franta-hg@6: import java.net.URISyntaxException; franta-hg@6: franta-hg@28: /** franta-hg@28: * Knihovna funkcí volaných z XSLT. franta-hg@28: * franta-hg@36: * TODO: franta-hg@32: * - rozdělit na více modulů (jmenných prostorů). franta-hg@32: * - CLI konektor franta-hg@28: * franta-hg@28: * @author fiki franta-hg@28: */ franta-hg@6: public class Funkce { franta-hg@27: franta-hg@30: private static final String PŘÍKAZ_PYGMENTIZE = "pygmentize"; franta-hg@32: private static final String PŘÍKAZ_DOT = "dot"; franta-hg@30: private static final String PŘÍKAZ_WHICH = "which"; franta-hg@32: private static final String ADRESÁŘ_VÝSTUPNÍ = "výstup"; franta-hg@32: private static int počítadloDiagramů = 0; franta-hg@30: franta-hg@28: /** franta-hg@28: * Zjištuje, kdy byl naposledy daný soubor změněn. franta-hg@28: * @param soubor cesta k souboru franta-hg@28: * @return datum poslední změny franta-hg@28: * @throws URISyntaxException franta-hg@28: */ franta-hg@21: public static Date posledníZměna(String soubor) throws URISyntaxException { franta-hg@28: URI uri = new URI(soubor); franta-hg@28: File f = new File(uri); franta-hg@28: return new Date(f.lastModified()); franta-hg@21: } franta-hg@27: franta-hg@27: /** franta-hg@27: * Zvýrazňuje syntaxi zdrojového kódu. Používá k tomu externí program/knihovnu pygmentize. franta-hg@27: * @param zdroják zdrojový kód, který předáme příkazu pygmentize na standardním vstupu franta-hg@27: * @param jazyk předáme příkazu pygmentize jako parametr -l <lexer> franta-hg@28: * @return zvýrazněný text nebo null, pokud došlo k chybě. franta-hg@31: * TODO: franta-hg@36: * - vracet místo textu instanci com.icl.saxon.om.NodeInfo http://saxon.sourceforge.net/saxon6.5.3/extensibility.html franta-hg@31: * - nebo kontrolovat validitu vygenerovaného kódu (v současnosti se spoléháme na bezchybnost pygmentize) franta-hg@27: */ franta-hg@27: public static String zvýrazniSyntaxi(String zdroják, String jazyk) throws IOException, InterruptedException { franta-hg@28: if (jazyk == null || jazyk.length() == 0) { franta-hg@28: System.err.println("Není vyplněn atribut „jazyk“ → není jasné, jak se má zvýrazňovat."); franta-hg@28: return null; franta-hg@36: } else if (isPříkazDostupný(PŘÍKAZ_PYGMENTIZE)) { franta-hg@27: Runtime r = Runtime.getRuntime(); franta-hg@30: Process p = r.exec(new String[]{PŘÍKAZ_PYGMENTIZE, "-f", "html", "-l", jazyk}); franta-hg@27: franta-hg@27: PrintStream vstupProcesu = new PrintStream(p.getOutputStream()); franta-hg@27: vstupProcesu.print(zdroják); franta-hg@27: vstupProcesu.close(); franta-hg@27: franta-hg@27: String výsledek = načtiProud(p.getInputStream()); franta-hg@27: String chyby = načtiProud(p.getErrorStream()); franta-hg@27: franta-hg@27: p.waitFor(); franta-hg@27: franta-hg@27: if (chyby.length() == 0) { franta-hg@28: // Pozor: pygmentize má i při chybě návratový kód 0 → je potřeba kontrolovat chybový výstup. franta-hg@27: return výsledek; franta-hg@27: } else { franta-hg@28: System.err.print("Při zvýrazňování syntaxe došlo k chybě: " + chyby); franta-hg@28: return null; franta-hg@27: } franta-hg@27: } else { franta-hg@30: System.err.println("Příkaz " + PŘÍKAZ_PYGMENTIZE + " není na vašem systému dostupný → zvýrazňování syntaxe nebude fungovat."); franta-hg@28: System.err.println("Můžete ho nainstalovat pomocí:"); franta-hg@28: System.err.println("\t$ aptitude install python-pygments # (Debian/Ubuntu)"); franta-hg@28: System.err.println("\t$ yum install python-pygments # (Fedora/RedHat)"); franta-hg@28: return null; franta-hg@27: } franta-hg@27: } franta-hg@27: franta-hg@28: /** franta-hg@31: * Vygeneruje CSS styl pro zvýrazňování syntaxe. franta-hg@31: * @return obsah CSS souboru nebo null, pokud generování nebylo možné franta-hg@31: */ franta-hg@31: public static String generujCssSyntaxe() throws IOException, InterruptedException { franta-hg@36: if (isPříkazDostupný(PŘÍKAZ_PYGMENTIZE)) { franta-hg@31: Runtime r = Runtime.getRuntime(); franta-hg@31: Process p = r.exec(new String[]{PŘÍKAZ_PYGMENTIZE, "-S", "default", "-f", "html"}); franta-hg@31: return načtiProud(p.getInputStream()); franta-hg@31: } else { franta-hg@31: return null; franta-hg@31: } franta-hg@31: } franta-hg@31: franta-hg@31: /** franta-hg@32: * Vytvoří obrázek s diagramem. franta-hg@32: * @param zadání definice diagramu ve formátu dot franta-hg@32: * @param vodorovně zda má být graf orientovaný vodorovně franta-hg@32: * @return název souboru bez přípony, který byl vytvořen, nebo null, pokud došlo k chybě. franta-hg@32: */ franta-hg@32: public static String vytvořDiagram(String zadání, boolean vodorovně) throws IOException, InterruptedException { franta-hg@36: if (isPříkazDostupný(PŘÍKAZ_DOT)) { franta-hg@32: počítadloDiagramů++; franta-hg@32: String soubor = "diagram-" + počítadloDiagramů; franta-hg@32: String souborSložka = ADRESÁŘ_VÝSTUPNÍ + File.separator + soubor; franta-hg@32: franta-hg@32: StringBuilder zdroják = new StringBuilder(zadání.length() + 200); franta-hg@32: franta-hg@32: zdroják.append("digraph d {\n"); franta-hg@32: zdroják.append("\tbgcolor=\"transparent\";\n"); franta-hg@32: if (vodorovně) { franta-hg@32: zdroják.append("\trankdir=LR;"); franta-hg@32: } franta-hg@32: zdroják.append(zadání); franta-hg@32: zdroják.append("}\n"); franta-hg@32: franta-hg@32: Runtime r = Runtime.getRuntime(); franta-hg@32: Process p = r.exec(new String[]{PŘÍKAZ_DOT, "-T", "svg", "-o", souborSložka + ".svg"}); franta-hg@32: franta-hg@32: /** franta-hg@32: * TODO: generovat i PNG bitmapu franta-hg@32: */ franta-hg@32: PrintStream vstupProcesu = new PrintStream(p.getOutputStream()); franta-hg@32: vstupProcesu.print(zdroják.toString()); franta-hg@32: vstupProcesu.close(); franta-hg@32: franta-hg@32: String chyby = načtiProud(p.getErrorStream()); franta-hg@32: franta-hg@32: p.waitFor(); franta-hg@32: franta-hg@32: if (chyby.length() == 0) { franta-hg@32: return soubor; franta-hg@32: } else { franta-hg@32: System.err.print("Při vytváření diagramu došlo k chybě: " + chyby); franta-hg@32: return null; franta-hg@32: } franta-hg@32: } else { franta-hg@32: System.err.println("Příkaz " + PŘÍKAZ_DOT + " není na vašem systému dostupný → diagramy nelze vygreslit."); franta-hg@32: System.err.println("Můžete ho nainstalovat pomocí:"); franta-hg@32: System.err.println("\t$ aptitude install graphviz # (Debian/Ubuntu)"); franta-hg@32: System.err.println("\t$ yum install graphviz # (Fedora/RedHat)"); franta-hg@32: return null; franta-hg@32: } franta-hg@32: } franta-hg@32: franta-hg@32: /** franta-hg@28: * Čte proud dat dokud to jde a výsledek pak vrátí jako text. franta-hg@28: * @param proud vstupní proud franta-hg@28: * @return obsah proudu jako text franta-hg@28: * @throws IOException franta-hg@28: */ franta-hg@27: private static String načtiProud(InputStream proud) throws IOException { franta-hg@27: StringBuilder výsledek = new StringBuilder(); franta-hg@27: BufferedReader buf = new BufferedReader(new InputStreamReader(proud)); franta-hg@27: while (true) { franta-hg@27: String radek = buf.readLine(); franta-hg@27: if (radek == null) { franta-hg@27: break; franta-hg@27: } else { franta-hg@27: výsledek.append(radek); franta-hg@27: výsledek.append("\n"); franta-hg@27: } franta-hg@27: } franta-hg@27: return výsledek.toString(); franta-hg@27: } franta-hg@27: franta-hg@28: /** franta-hg@28: * Pomocí programu which zjistí, jestli je daný příkaz v systému přítomný. franta-hg@28: * @param příkaz jehož přítomnost zjišťujeme franta-hg@28: * @return true pokud příkaz v systému existuje franta-hg@28: */ franta-hg@36: private static boolean isPříkazDostupný(String příkaz) { franta-hg@27: try { franta-hg@27: Runtime r = Runtime.getRuntime(); franta-hg@30: Process p = r.exec(new String[]{PŘÍKAZ_WHICH, příkaz}); franta-hg@27: p.waitFor(); franta-hg@27: return p.exitValue() == 0; franta-hg@27: } catch (Exception e) { franta-hg@30: System.err.printf("Při zjišťování dostupnosti příkazu „%s“ došlo k chybě: %s", příkaz, e.getLocalizedMessage()); franta-hg@27: return false; franta-hg@27: } franta-hg@27: } franta-hg@6: }