/*******************************************************************************
* Copyright (c) 2014 MEDEVIT.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* T. Huster - initial API and implementation
*******************************************************************************/
package at.medevit.elexis.ehc.ui.util;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.eclipse.core.runtime.FileLocator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.ProcessingInstruction;
import org.xml.sax.SAXException;
public class CDALoader {
private static Logger log = LoggerFactory.getLogger(CDALoader.class);
private static DocumentBuilderFactory factory = null;
private static String defaultXsl = null;
private static String cdaReportsBase = "cdareports";
private static String tmpCDAFile = cdaReportsBase + File.separator + "tmp_cdafile.xml";
private static String tmpXslFile = cdaReportsBase + File.separator + "tmp_stylesheet.xsl";
public CDALoader(){
File eHealthCDA = new File(cdaReportsBase);
if (!eHealthCDA.exists() || !eHealthCDA.isDirectory()) {
eHealthCDA.mkdir();
}
defaultXsl = "type=\"text/xsl\" href=\"" + initDefaultXsl() + "\"";
factory = DocumentBuilderFactory.newInstance();
}
public File buildXmlDocument(InputStream inStream){
return buildXmlDocument(inStream, "");
}
public File buildXmlDocument(InputStream inStream, String path){
File cdaFile = createTempCDAFile();
try {
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(inStream);
// modify stylesheet if necessary
XPath xpath = XPathFactory.newInstance().newXPath();
String expression = "/processing-instruction('xml-stylesheet')";
ProcessingInstruction pi =
(ProcessingInstruction) xpath.evaluate(expression, doc, XPathConstants.NODE);
if (pi == null) {
pi = doc.createProcessingInstruction("xml-stylesheet", defaultXsl);
doc.insertBefore(pi, doc.getDocumentElement());
} else if (!isValidStylesheet(pi.getNodeValue(), path)) {
pi.setData(defaultXsl);
}
// write the content into xml file
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(cdaFile.getAbsolutePath()));
transformer.transform(source, result);
log.debug("Done parsing XML");
} catch (SAXException sax) {
log.error("XML file causes troubles - either no proper XML or InputStream corrupt", sax);
} catch (ParserConfigurationException | XPathExpressionException | IOException e) {
log.error("Error while trying to parse inpustream", e);
} catch (TransformerException te) {
log.error(
"Could not transform content from InputStream into file [" + cdaFile.getName()
+ "]", te);
}
return cdaFile;
}
private File createTempCDAFile(){
File cdaFile = new File(tmpCDAFile);
try {
if (cdaFile.exists()) {
cdaFile.delete();
}
cdaFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
return cdaFile;
}
private boolean isValidStylesheet(String value, String cdaFilePath){
if (value.startsWith("type=\"text/xsl")) {
String hrefAttribute = "href=\"";
int hrefStart = value.indexOf(hrefAttribute) + 6;
int hrefEnd = value.indexOf("\"", hrefStart + 1);
String xslPath = value.substring(hrefStart, hrefEnd);
if (!validHttpLink(xslPath)) {
if (!validLocalXsl(xslPath, cdaFilePath)) {
return false;
}
log.debug("Use XSL given in the stylesheet line entry");
return true;
}
}
return false;
}
/**
* check if the XSL path is a http link
*
* @param link
* location given on the stylesheet line of the xml
* @return true if resovlable, false otherwise
*/
private boolean validHttpLink(String link){
URL url = null;
try {
url = new URL(link);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
return connection.getResponseCode() == HttpURLConnection.HTTP_OK;
} catch (IOException e) {
return false;
}
}
/**
* check if the XSL can be found on the filesystem
*
* @param xslPath
* path given in the stylesheet ref
* @param basePath
* of the actual xml file
* @return true if resolvable, false if not found
*/
private boolean validLocalXsl(String xslPath, String basePath){
File tmp = new File(xslPath);
if (tmp.exists()) {
return true;
} else {
int baseLocationEnd = basePath.lastIndexOf(File.separator);
String path = basePath.substring(0, baseLocationEnd) + File.separator + xslPath;
tmp = new File(path);
// if it exist copy file to appropriate directory
if (tmp.exists()) {
try {
File xslCopy = new File(cdaReportsBase + File.separator + xslPath);
if (xslCopy.exists()) {
xslCopy.delete();
}
Files.copy(tmp.toPath(), xslCopy.toPath());
} catch (IOException e) {
return false;
}
return true;
}
return false;
}
}
private static String initDefaultXsl(){
String path = "";
try {
File tmpXsl = new File(tmpXslFile);
// copy of xsl only needed if not there yet
if (!tmpXsl.exists()) {
URL xslUrl =
FileLocator.resolve(CDALoader.class.getResource("/rsc/vhitg-cda-v3.xsl"));
Files.copy(xslUrl.openStream(), tmpXsl.toPath());
}
path = tmpXsl.getAbsolutePath();
} catch (IOException e) {
e.printStackTrace();
}
return path;
}
}