implement backend endpoints and file creating logic for processing multiple XMLs with XSLT
This commit is contained in:
		@@ -42,6 +42,7 @@ public class SparkApplication {
 | 
			
		||||
        registry.registerController(new ProcessorInfoController(logger, saxon, xalan));
 | 
			
		||||
 | 
			
		||||
        registry.registerController(new XmlController(gson, logger, saxon, xalan));
 | 
			
		||||
        registry.registerController(new MultipleXMLController(gson,logger, (Saxon) saxon));
 | 
			
		||||
        registry.registerController(new JsonController(gson, jsongson, logger));
 | 
			
		||||
 | 
			
		||||
        registry.register();
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,101 @@
 | 
			
		||||
package com.r11.tools.controller;
 | 
			
		||||
 | 
			
		||||
import com.google.gson.Gson;
 | 
			
		||||
import com.r11.tools.controller.internal.*;
 | 
			
		||||
import com.r11.tools.model.XMLMultipleFilesBody;
 | 
			
		||||
import com.r11.tools.model.XMLResponseBody;
 | 
			
		||||
import com.r11.tools.xml.Saxon;
 | 
			
		||||
import com.r11.tools.xml.XmlEngine;
 | 
			
		||||
import net.sf.saxon.s9api.SaxonApiException;
 | 
			
		||||
import org.apache.logging.log4j.Logger;
 | 
			
		||||
import spark.Request;
 | 
			
		||||
import spark.Response;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
 | 
			
		||||
@GlobalControllerManifest
 | 
			
		||||
public class MultipleXMLController implements RestController {
 | 
			
		||||
 | 
			
		||||
    private final Gson gson;
 | 
			
		||||
    private final Logger logger;
 | 
			
		||||
 | 
			
		||||
    private final Saxon saxon;
 | 
			
		||||
 | 
			
		||||
    public MultipleXMLController(Gson gson, Logger logger, Saxon saxon) {
 | 
			
		||||
        this.gson = gson;
 | 
			
		||||
        this.logger = logger;
 | 
			
		||||
        this.saxon = saxon;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ScopedControllerManifest(method = HandlerType.POST, path = "/multiple/xslt")
 | 
			
		||||
    public void acceptRequestXslt(Request request, Response response) {
 | 
			
		||||
        acceptRequest(request, response, XmlJobType.XSLT);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void acceptRequest(Request request, Response response, XmlJobType xmlJobType) {
 | 
			
		||||
        XMLMultipleFilesBody requestBody;
 | 
			
		||||
        try {
 | 
			
		||||
            requestBody = this.gson.fromJson(request.body(), XMLMultipleFilesBody.class);
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            requestErrorResponse(response, e);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        processRequest(new MultipleXmlJob(response, requestBody, saxon, xmlJobType));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void processRequest(MultipleXmlJob xmlJob) {
 | 
			
		||||
        logger.info(xmlJob);
 | 
			
		||||
        XMLResponseBody responseBody = null;
 | 
			
		||||
        long timeStart = System.currentTimeMillis();
 | 
			
		||||
        long duration;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            responseBody = processData(xmlJob);
 | 
			
		||||
 | 
			
		||||
            duration = System.currentTimeMillis() - timeStart;
 | 
			
		||||
            responseBody.setDuration(duration);
 | 
			
		||||
 | 
			
		||||
            xmlJob.getResponse().status(200);
 | 
			
		||||
 | 
			
		||||
            this.logger.info("Request (" + xmlJob.getXmlJobType() + ", " +
 | 
			
		||||
                    xmlJob.getEngine().getVersion() +
 | 
			
		||||
                    ") processed in " + duration + " ms.");
 | 
			
		||||
 | 
			
		||||
        } catch (Exception ex) {
 | 
			
		||||
            responseBody = processingErrorResponse(ex, xmlJob);
 | 
			
		||||
 | 
			
		||||
        } finally {
 | 
			
		||||
            xmlJob.getResponse().body(this.gson.toJson(responseBody));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private XMLResponseBody processData(MultipleXmlJob xmlJob) throws IOException, SaxonApiException, InterruptedException {
 | 
			
		||||
        Saxon engine = xmlJob.getEngine();
 | 
			
		||||
        XMLMultipleFilesBody requestBody = xmlJob.getRequestBody();
 | 
			
		||||
        String result = engine.processXSLT(requestBody.getData(), requestBody.getProcessorData());
 | 
			
		||||
        return new XMLResponseBody(result, "OK", requestBody.getVersion());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    private XMLResponseBody processingErrorResponse(Exception ex, MultipleXmlJob xmlJob) {
 | 
			
		||||
        XmlEngine engine = xmlJob.getEngine();
 | 
			
		||||
        XmlJobType xmlJobType = xmlJob.getXmlJobType();
 | 
			
		||||
        Response response = xmlJob.getResponse();
 | 
			
		||||
 | 
			
		||||
        XMLResponseBody responseBody =
 | 
			
		||||
                new XMLResponseBody(ex.getMessage(), "ERR", engine.getVersion(), -1);
 | 
			
		||||
 | 
			
		||||
        response.status(400);
 | 
			
		||||
        this.logger.error("Error on processing " + xmlJobType + " using " + engine.getVersion() + ". " + ex);
 | 
			
		||||
 | 
			
		||||
        return responseBody;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void requestErrorResponse(Response response, Exception ex) {
 | 
			
		||||
        XMLResponseBody responseBody = new XMLResponseBody(ex.getMessage(), "ERR", "N/A", -1);
 | 
			
		||||
        response.status(400);
 | 
			
		||||
        response.body(this.gson.toJson(responseBody));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -2,6 +2,7 @@ package com.r11.tools.controller;
 | 
			
		||||
 | 
			
		||||
import com.google.gson.Gson;
 | 
			
		||||
import com.r11.tools.controller.internal.*;
 | 
			
		||||
import com.r11.tools.model.XMLMultipleFilesBody;
 | 
			
		||||
import com.r11.tools.model.XMLRequestBody;
 | 
			
		||||
import com.r11.tools.model.XMLResponseBody;
 | 
			
		||||
import com.r11.tools.model.XPathQueryResult;
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,38 @@
 | 
			
		||||
package com.r11.tools.controller.internal;
 | 
			
		||||
 | 
			
		||||
import com.r11.tools.model.XMLMultipleFilesBody;
 | 
			
		||||
import com.r11.tools.model.XMLRequestBody;
 | 
			
		||||
import com.r11.tools.xml.Saxon;
 | 
			
		||||
import com.r11.tools.xml.XmlEngine;
 | 
			
		||||
import spark.Response;
 | 
			
		||||
 | 
			
		||||
public class MultipleXmlJob {
 | 
			
		||||
 | 
			
		||||
    private final Response response;
 | 
			
		||||
    private final XMLMultipleFilesBody requestBody;
 | 
			
		||||
    private final Saxon engine;
 | 
			
		||||
    private final XmlJobType xmlJobType;
 | 
			
		||||
 | 
			
		||||
    public MultipleXmlJob(Response response, XMLMultipleFilesBody requestBody, Saxon engine, XmlJobType xmlJobType) {
 | 
			
		||||
        this.response = response;
 | 
			
		||||
        this.requestBody = requestBody;
 | 
			
		||||
        this.engine = engine;
 | 
			
		||||
        this.xmlJobType = xmlJobType;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Response getResponse() {
 | 
			
		||||
        return response;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public XMLMultipleFilesBody getRequestBody() {
 | 
			
		||||
        return requestBody;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Saxon getEngine() {
 | 
			
		||||
        return engine;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public XmlJobType getXmlJobType() {
 | 
			
		||||
        return xmlJobType;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,32 @@
 | 
			
		||||
package com.r11.tools.model;
 | 
			
		||||
 | 
			
		||||
import com.google.gson.annotations.SerializedName;
 | 
			
		||||
 | 
			
		||||
public class XMLMultipleFilesBody {
 | 
			
		||||
 | 
			
		||||
    @SerializedName("data")
 | 
			
		||||
    private XMLMultipleFilesData[] data;
 | 
			
		||||
    @SerializedName("processorData")
 | 
			
		||||
    private String processorData;
 | 
			
		||||
    @SerializedName("processor")
 | 
			
		||||
    private String processor;
 | 
			
		||||
    @SerializedName("version")
 | 
			
		||||
    private String version;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public String getProcessorData() {
 | 
			
		||||
        return processorData;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getProcessor() {
 | 
			
		||||
        return processor;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getVersion() {
 | 
			
		||||
        return version;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public XMLMultipleFilesData[] getData() {
 | 
			
		||||
        return data;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,18 @@
 | 
			
		||||
package com.r11.tools.model;
 | 
			
		||||
 | 
			
		||||
import com.google.gson.annotations.SerializedName;
 | 
			
		||||
 | 
			
		||||
public class XMLMultipleFilesData {
 | 
			
		||||
    @SerializedName("fileName")
 | 
			
		||||
    private String filename;
 | 
			
		||||
    @SerializedName("fileData")
 | 
			
		||||
    private String data;
 | 
			
		||||
 | 
			
		||||
    public String getFilename() {
 | 
			
		||||
        return filename;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getData() {
 | 
			
		||||
        return data;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,11 +1,18 @@
 | 
			
		||||
package com.r11.tools.xml;
 | 
			
		||||
 | 
			
		||||
import com.r11.tools.model.XMLMultipleFilesData;
 | 
			
		||||
import com.r11.tools.model.XPathQueryResult;
 | 
			
		||||
import net.sf.saxon.Configuration;
 | 
			
		||||
import net.sf.saxon.lib.CatalogResourceResolver;
 | 
			
		||||
import net.sf.saxon.s9api.*;
 | 
			
		||||
 | 
			
		||||
import javax.xml.transform.stream.StreamSource;
 | 
			
		||||
import java.io.StringReader;
 | 
			
		||||
import java.io.StringWriter;
 | 
			
		||||
import java.io.*;
 | 
			
		||||
import java.nio.file.*;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Comparator;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler for Saxon engine
 | 
			
		||||
@@ -13,6 +20,54 @@ import java.io.StringWriter;
 | 
			
		||||
 */
 | 
			
		||||
public class Saxon implements XmlEngine{
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *  Transforms many XML documents via XSLT.
 | 
			
		||||
     * @param data XML Files to be transformed.
 | 
			
		||||
     * @param transform XSLT
 | 
			
		||||
     * @return transformed xml
 | 
			
		||||
     * @throws SaxonApiException thrown on stylesheet or transformation error
 | 
			
		||||
     */
 | 
			
		||||
    public String processXSLT(XMLMultipleFilesData[] data, String transform) throws SaxonApiException, IOException, InterruptedException {
 | 
			
		||||
        Processor processor = new Processor(false);
 | 
			
		||||
 | 
			
		||||
        XsltCompiler compiler = processor.newXsltCompiler();
 | 
			
		||||
        XsltExecutable stylesheet = compiler.compile(new StreamSource( new StringReader(transform) ));
 | 
			
		||||
        String filesPath = "/tmp/"+UUID.randomUUID()+"/";
 | 
			
		||||
        ArrayList<String> xmlFilesUri = new ArrayList<>();
 | 
			
		||||
        try{
 | 
			
		||||
            Path processPath = Paths.get(filesPath);
 | 
			
		||||
            Files.createDirectories(processPath);
 | 
			
		||||
 | 
			
		||||
            for (XMLMultipleFilesData fileData : data) {
 | 
			
		||||
                Path filePath = Files.createFile( Paths.get(filesPath + fileData.getFilename() ) );
 | 
			
		||||
                try (FileWriter writer = new FileWriter(filePath.toFile())) {
 | 
			
		||||
                    writer.write(fileData.getData());
 | 
			
		||||
                    xmlFilesUri.add(filesPath + fileData.getFilename());
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            StringWriter sw = new StringWriter();
 | 
			
		||||
            Serializer out = processor.newSerializer(sw);
 | 
			
		||||
            out.setOutputProperty(Serializer.Property.METHOD, "xml");
 | 
			
		||||
            out.setOutputProperty(Serializer.Property.INDENT, "yes");
 | 
			
		||||
            Xslt30Transformer transformer = stylesheet.load30();
 | 
			
		||||
            transformer.setResourceResolver(  );
 | 
			
		||||
            processor.setCatalogFiles(xmlFilesUri.toArray(new String[0]));
 | 
			
		||||
            transformer.transform( new StreamSource( new File(filesPath+data[0].getFilename()) ) , out );
 | 
			
		||||
            return sw.toString();
 | 
			
		||||
 | 
			
		||||
        } finally {
 | 
			
		||||
            Thread.sleep(1000000);
 | 
			
		||||
            Files
 | 
			
		||||
                    .walk( Paths.get(filesPath) )
 | 
			
		||||
                    .sorted(Comparator.reverseOrder())
 | 
			
		||||
                    .map(Path::toFile)
 | 
			
		||||
                    .forEach(File::delete);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Transforms string containing xml document via xslt
 | 
			
		||||
     * @param data xml to be transformed
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,10 @@
 | 
			
		||||
package com.r11.tools.xml;
 | 
			
		||||
 | 
			
		||||
import com.r11.tools.model.XMLMultipleFilesData;
 | 
			
		||||
import com.r11.tools.model.XPathQueryResult;
 | 
			
		||||
import net.sf.saxon.s9api.SaxonApiException;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
 | 
			
		||||
public interface XmlEngine {
 | 
			
		||||
    XPathQueryResult processXPath(String data, String query, String version) throws Exception;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user