šablona/funkce/src/cz/frantovo/xmlWebGenerator/makra/Skriptování.java
author František Kučera <franta-hg@frantovo.cz>
Thu Oct 24 22:06:44 2019 +0200 (2019-10-24)
changeset 136 d5feb9d8ebc3
parent 113 18bf0044f5ab
permissions -rw-r--r--
fix license version: GNU GPLv3
     1 /**
     2  * XML Web generátor – program na generování webových stránek
     3  * Copyright © 2012 František Kučera (frantovo.cz)
     4  *
     5  * This program is free software: you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation, version 3 of the License.
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
    16  */
    17 package cz.frantovo.xmlWebGenerator.makra;
    18 
    19 import static cz.frantovo.xmlWebGenerator.NástrojeCLI.načtiProud;
    20 import static cz.frantovo.xmlWebGenerator.Funkce.spojText;
    21 import static cz.frantovo.xmlWebGenerator.Xmlns.*;
    22 import java.io.ByteArrayInputStream;
    23 import java.io.File;
    24 import java.io.PrintStream;
    25 import java.net.URI;
    26 import java.util.Collections;
    27 import java.util.HashMap;
    28 import java.util.Map;
    29 import javax.xml.parsers.DocumentBuilder;
    30 import javax.xml.parsers.DocumentBuilderFactory;
    31 import javax.xml.transform.Source;
    32 import javax.xml.transform.dom.DOMSource;
    33 import org.w3c.dom.Document;
    34 import org.w3c.dom.Node;
    35 
    36 /**
    37  * Provedeme skript a do stránky vložíme jeho výstup.
    38  *
    39  * @author František Kučera (frantovo.cz)
    40  */
    41 public class Skriptování {
    42 
    43 	private enum FORMÁT {
    44 
    45 		xml,
    46 		xhtml,
    47 		text
    48 	}
    49 	/**
    50 	 * klíč = jazyk – např. bash
    51 	 * hodnota = interpret – např. /bin/bash
    52 	 */
    53 	private static final Map<String, String> interpreti;
    54 
    55 	static {
    56 		Map<String, String> podporovanýJazyk = new HashMap<String, String>();
    57 		podporovanýJazyk.put("bash", "/bin/bash");
    58 		podporovanýJazyk.put("perl", "/usr/bin/perl");
    59 		podporovanýJazyk.put("php", "/usr/bin/php");
    60 		podporovanýJazyk.put("python", "/usr/bin/python");
    61 		interpreti = Collections.unmodifiableMap(podporovanýJazyk);
    62 	}
    63 
    64 	/**
    65 	 * TODO: podporovat i složitější scénáře (např. kompilaci),
    66 	 * než jen vložení do souboru a přidání správného záhlaví.
    67 	 *
    68 	 * @param skriptText skript k vykonání
    69 	 * @param skriptSoubor cesta k souboru se skriptem/programem
    70 	 * @param jazyk programovací jazyk
    71 	 * @param výstupníFormát text (výchozí) | xml (v tom případě kontrolujeme validitu)
    72 	 * @param uriStránky URI aktuálně generované stránky → proměnná prostředí
    73 	 * @param nadpisStránky nadpis stránky → proměnná prostředí
    74 	 * @param perexStránky perex stránky → proměnná prostředí
    75 	 * @return výstup příkazu buď jako textový řetězec nebo jako XML (DOMSource)
    76 	 */
    77 	public static Source interpretuj(String[] skriptText, String skriptSoubor, String jazyk, String výstupníFormát, String uriStránky, String nadpisStránky, String perexStránky) throws Exception {
    78 		String výstupSkriptu = získejVýstupSkriptu(spojText(skriptText), skriptSoubor, jazyk, uriStránky, nadpisStránky, perexStránky);
    79 		return vyrobXml(výstupSkriptu, zjistiFormát(výstupníFormát));
    80 	}
    81 
    82 	private static String získejVýstupSkriptu(String skriptText, String skriptSoubor, String jazyk, String uriStránky, String nadpisStránky, String perexStránky) throws Exception {
    83 
    84 		try {
    85 			if (isNeprázdný(skriptSoubor)) {
    86 				System.err.println("\tInterpretuji skript ze souboru: " + skriptSoubor);
    87 			} else {
    88 				System.err.println("\tInterpretuji skript v jazyce:   " + jazyk);
    89 			}
    90 
    91 			File souborStránky = new File(new URI(uriStránky));
    92 			File f;
    93 
    94 			if (isNeprázdný(skriptText)) {
    95 				/** Skript je zadán uvnitř elementu přímo ve stránce */
    96 				String interpret = interpreti.get(jazyk);
    97 				if (interpret == null) {
    98 					throw new Exception("Neznámý skriptovací jazyk: " + jazyk);
    99 				}
   100 
   101 				f = File.createTempFile("xml-web-generátor-", ".skript");
   102 				f.deleteOnExit();
   103 				f.setExecutable(true);
   104 
   105 				PrintStream ps = new PrintStream(f);
   106 				ps.print("#!");
   107 				ps.println(interpret);
   108 				ps.println();
   109 				ps.print(skriptText);
   110 				ps.close();
   111 			} else if (isNeprázdný(skriptSoubor)) {
   112 				/** Skript/program je uložen v externím souboru */
   113 				if (skriptSoubor.startsWith(File.separator)) {
   114 					/** absolutní cesta */
   115 					f = new File(skriptSoubor);
   116 				} else {
   117 					/** relativní cesta */
   118 					f = new File(souborStránky.getParent(), File.separatorChar + skriptSoubor);
   119 				}
   120 
   121 				if (!f.canExecute()) {
   122 					throw new Exception("Soubor se skriptem není spustitelný → nastavte: chmod +x " + f);
   123 				}
   124 			} else {
   125 				throw new Exception("Musí být vyplněn text skriptu, nebo cesta k souboru.");
   126 			}
   127 
   128 
   129 			String[] prostředí = new String[]{
   130 				"LANG=" + System.getenv("LANG"),
   131 				"USER=" + System.getenv("USER"),
   132 				"XWG_SKRIPTOVANI_JAVA=" + "šablona" + File.separator + "funkce" + File.separator + "src" + File.separator + Skriptování.class.getName().replaceAll("\\.", File.separator) + ".java",
   133 				"XWG_STRANKA_URI=" + uriStránky, // env:URI aktuálně zpracovávané stránky
   134 				"XWG_STRANKA_SOUBOR=" + souborStránky.getAbsolutePath(), // env:absolutní cesta k souboru
   135 				"XWG_STRANKA_NADPIS=" + nadpisStránky, // env:nadpis stránky
   136 				"XWG_STRANKA_PEREX=" + perexStránky // env:perex stránky
   137 			};
   138 
   139 			Runtime r = Runtime.getRuntime();
   140 			Process p = r.exec(new String[]{f.getAbsolutePath()}, prostředí);
   141 
   142 			String výsledek = načtiProud(p.getInputStream());
   143 			String chyby = načtiProud(p.getErrorStream());
   144 
   145 			p.waitFor();
   146 
   147 			if (p.exitValue() == 0) {
   148 				if (chyby.length() > 0) {
   149 					System.err.println("--- Chybový výstup skriptu -----");
   150 					System.err.println(chyby);
   151 					System.err.println("--------------------------------");
   152 					System.err.println("Nicméně skript skončil úspěšně, takže pokračujeme dál.");
   153 				}
   154 
   155 				return výsledek.trim();
   156 			} else {
   157 				System.err.println("--- Standardní výstup skriptu: -----");
   158 				System.err.println(výsledek);
   159 				System.err.println("--- Cyhbový výstup skriptu: ---------");
   160 				System.err.println(chyby);
   161 				System.err.println("--------------------------------------");
   162 				throw new Exception("Návratová hodnota: " + p.exitValue());
   163 			}
   164 		} catch (Exception e) {
   165 			System.err.println("Došlo k chybě při vykonávání skriptu.");
   166 			System.err.println("--------");
   167 			System.err.println(skriptText);
   168 			System.err.println("--------");
   169 			e.printStackTrace(System.err);
   170 			throw e;
   171 		}
   172 	}
   173 
   174 	private static boolean isNeprázdný(String s) {
   175 		return !(s == null || s.trim().isEmpty());
   176 	}
   177 
   178 	private static FORMÁT zjistiFormát(String výstupníFormát) {
   179 		try {
   180 			return FORMÁT.valueOf(výstupníFormát);
   181 		} catch (NullPointerException e) {
   182 			return FORMÁT.text;
   183 		} catch (IllegalArgumentException e) {
   184 			return FORMÁT.text;
   185 		}
   186 	}
   187 
   188 	/**
   189 	 * @param zadání výstup vygenerovaný skriptem
   190 	 * @param xmlFormát formát zadání: true = xml fragment | false = prostý text
   191 	 * @return xml fragment nebo prostý text zabalený do html/body
   192 	 * @throws Exception
   193 	 */
   194 	private static Source vyrobXml(String zadání, FORMÁT formát) throws Exception {
   195 		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
   196 		DocumentBuilder db = dbf.newDocumentBuilder();
   197 		Document d;
   198 
   199 
   200 		if (formát == FORMÁT.text) {
   201 			d = db.newDocument();
   202 			Node html = d.createElementNS(XHTML, "html");
   203 			Node body = d.createElementNS(XHTML, "body");
   204 			Node text = d.createTextNode(zadání);
   205 			body.appendChild(text);
   206 			html.appendChild(body);
   207 			d.appendChild(html);
   208 		} else {
   209 			if (formát == FORMÁT.xhtml) {
   210 				zadání = "<html xmlns='" + XHTML + "' xmlns:m='" + MAKRO + "'><body>" + zadání + "</body></html>";
   211 			}
   212 			try {
   213 				d = db.parse(new ByteArrayInputStream(zadání.getBytes()));
   214 			} catch (Exception e) {
   215 				System.err.println("Chyba: Skript vrátil neplatné XML.");
   216 				throw e;
   217 			}
   218 		}
   219 
   220 		return new DOMSource(d);
   221 	}
   222 }