package de.tudresden.gis.manage.xml; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.StringReader; import java.io.StringWriter; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** * This class contains static methods for xml related operation, reading, saving changing (dynamic change of platform, container and keywwords) * * @author Bernd Grafe */ public class XmlHelpMethods { public static String[] str; /** * Method to read a file. * * @param path of file * @param threaded if true thread reading is enabled * @return file content as string * @throws IOException */ public static String readFile (String path, Boolean threaded) throws IOException { if (threaded) return readFileThreaded(path, 4); else return readFileNormal(path); } /** * Method to read a file based on path with buffered reader * * @param path of file * @return file content as string */ private static String readFileNormal(String path) { String sCurrentLine; String fileString = ""; BufferedReader bReader = null; try { FileReader fReader = new FileReader(path); bReader = new BufferedReader(fReader, 16000); while ((sCurrentLine = bReader.readLine()) != null) { fileString += sCurrentLine; } } catch (IOException e) { e.printStackTrace(); } finally { try { if (bReader != null) bReader.close(); } catch (IOException ex) { ex.printStackTrace(); } } return fileString; } /** * This method implements faster file reading with threads and nio.files * * @param file path to file * @param threads number of threads * @return content of file * @throws IOException */ private static String readFileThreaded(String file, int threads) throws IOException { String fileString = ""; Path path = Paths.get(file); List<String> text = Files.readAllLines(path, StandardCharsets.UTF_8); //number of threads int threadNumber = threads; Thread[] array= new Thread[threadNumber]; int size = text.size(); str = new String [threadNumber]; int d = size/threadNumber; for (int i = 0; i < threadNumber; i++) { int min = d * i; int max = d * (i + 1); if (i == threadNumber - 1) max = size; Thread a = new Thread(new threadReader(i,text,min,max)); a.start(); array[i] = a; } for (Thread is:array) { try { is.join(); } catch (InterruptedException e) { is.interrupt(); } } for (String jsonPart : str) { fileString += jsonPart; } return fileString; } /** * This method writes a file based on xml string * @param path * @param content (xml) * @return true if successfully written * @throws IOException */ public static Boolean writeFile(String path, String content) throws IOException { //read file OutputStream out = null; InputStream filecontent = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8)); try { //initiate output stream out = new FileOutputStream(new File(path)); int read = 0; final byte[] bytes = new byte[1024]; while ((read = filecontent.read(bytes)) != -1) { out.write(bytes, 0, read); } } catch(Exception e) { return false; } finally { if (out != null) out.close(); if (filecontent != null) filecontent.close(); } return true; } /** * Method to create a document based on xml string. * * @param content (xml) * @return Document file for given xml content * @throws SAXException * @throws IOException * @throws ParserConfigurationException */ public static Document createDocumentString (String content) throws SAXException, IOException, ParserConfigurationException{ DocumentBuilderFactory fac = DocumentBuilderFactory.newInstance(); fac.setNamespaceAware(true); Document doc = fac.newDocumentBuilder().parse(new InputSource(new StringReader(content))); return doc; } /** * Method to create a document based on file path. * * @param path xml file path * @return Document for given xml file * @throws ParserConfigurationException * @throws SAXException * @throws IOException */ public static Document createDocumentPath (String path) throws ParserConfigurationException, SAXException, IOException{ File fXmlFile = new File(path); DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); Document doc = dBuilder.parse(fXmlFile); return doc; } /** * Method to correct a path. Splits last slash. * * @param path * @return corrected path */ private static String checkPath (String path){ if(path.startsWith("/")){ path= path.substring(1, path.length()); } return path; } /** * Method to get absolute path based on relative path from src folder. * * @param resource - relative path * @return absolute path */ public static String getPath (String resource) { String path = Thread.currentThread().getContextClassLoader().getResource(resource).getPath(); //relative path based on src folder, example resource= gpt/search/browse/browse-catalog.xml return checkPath(path); } /** * Method to delete an element based on tag name . * @param doc * @param tagName * @return */ private static Document deleteElement(Document doc, String tagName) { //only 2 of 3 were deleted ? NodeList nodes = doc.getElementsByTagName(tagName); for (int i = 0; i < nodes.getLength(); i++) { Element e = (Element)nodes.item(i); e.getParentNode().removeChild(e); } return doc; } /** * Method to remove all children of g:options - element * * @param doc document with children g:options * @return document without children g:options */ public static Document removeAllOptions(Document doc) { NodeList nodes = doc.getElementsByTagName("g:options"); Node node = nodes.item(0); while (node.hasChildNodes()) node.removeChild(node.getFirstChild()); return doc; } /** * Method to delete old elements and add new elements in target file based on tag name of source file. * * @param source * @param target * @param sourceTagName * @param targetTagNameParent * @param targetTagNameChild * @return document * @throws ParseException */ public static Document addNewElements(Document source, Document target, String sourceTagName, String targetTagNameParent, String targetTagNameChild, List<String> ignoreList) throws ParseException{ //list for attributes to be more dynamic if reuse //remove old entries target = removeAllOptions(target); // add new entries NodeList nameList = source.getElementsByTagName(sourceTagName); NodeList parents = target.getElementsByTagName(targetTagNameParent); Element parent = (Element) parents.item(0); // g:options - only 1 // element //add space placeholder as first entry Element o = target.createElement(targetTagNameChild); o.setAttribute("g:value", ""); o.setAttribute("g:label", ""); parent.appendChild(o); for (int i = 0; i < nameList.getLength(); i++) { String value = nameList.item(i).getTextContent(); if (value != null && !value.equals("") && !ignoreList.contains(value)) { Element p = target.createElement(targetTagNameChild); p.setAttribute("g:value", value); p.setAttribute("g:label", value); parent.appendChild(p); } } return changeDate(target); } /** * Method to convert document to string. * * @param doc * @return document content as string */ public static String doc2String(Document doc) { try { StringWriter sw = new StringWriter(); TransformerFactory tf = TransformerFactory.newInstance(); Transformer transformer = tf.newTransformer(); transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); transformer.setOutputProperty(OutputKeys.METHOD, "xml"); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); transformer.transform(new DOMSource(doc), new StreamResult(sw)); return sw.toString(); } catch (Exception ex) { throw new RuntimeException("Error converting to String", ex); } } /** * Method to check difference between actual time and saved time in xml file. * * @param target document * @return time difference as integer * @throws ParseException */ public static int checkDateDifference (Document target) throws ParseException{ int diff = 0; NodeList parents = target.getElementsByTagName("g:options"); Element parent = (Element) parents.item(0); //g:options - only 1 element DateFormat format = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.ENGLISH); //date xml String time = parent.getAttribute("time"); Date oldT = format.parse(time); //date now Date newT = new Date(); //compare diff = (int) ((newT.getTime() - oldT.getTime()) / 1000); return diff; } /** * Method to change update date in xml files - used for reloadable issue and auto change on start up. * * @param target document * @return updated document * @throws ParseException */ private static Document changeDate (Document target) throws ParseException { NodeList parents = target.getElementsByTagName("g:options"); Element parent = (Element) parents.item(0); //g:options - only 1 element DateFormat format = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.ENGLISH); Date newT = new Date(); String time = format.format(newT); parent.setAttribute("time", time); return target; } }