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 ProcessorInfoController(logger, saxon, xalan)); | ||||||
|  |  | ||||||
|         registry.registerController(new XmlController(gson, 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.registerController(new JsonController(gson, jsongson, logger)); | ||||||
|  |  | ||||||
|         registry.register(); |         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.google.gson.Gson; | ||||||
| import com.r11.tools.controller.internal.*; | import com.r11.tools.controller.internal.*; | ||||||
|  | import com.r11.tools.model.XMLMultipleFilesBody; | ||||||
| import com.r11.tools.model.XMLRequestBody; | import com.r11.tools.model.XMLRequestBody; | ||||||
| import com.r11.tools.model.XMLResponseBody; | import com.r11.tools.model.XMLResponseBody; | ||||||
| import com.r11.tools.model.XPathQueryResult; | 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; | package com.r11.tools.xml; | ||||||
|  |  | ||||||
|  | import com.r11.tools.model.XMLMultipleFilesData; | ||||||
| import com.r11.tools.model.XPathQueryResult; | import com.r11.tools.model.XPathQueryResult; | ||||||
|  | import net.sf.saxon.Configuration; | ||||||
|  | import net.sf.saxon.lib.CatalogResourceResolver; | ||||||
| import net.sf.saxon.s9api.*; | import net.sf.saxon.s9api.*; | ||||||
|  |  | ||||||
| import javax.xml.transform.stream.StreamSource; | import javax.xml.transform.stream.StreamSource; | ||||||
| import java.io.StringReader; | import java.io.*; | ||||||
| import java.io.StringWriter; | import java.nio.file.*; | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.Comparator; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.UUID; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Handler for Saxon engine |  * Handler for Saxon engine | ||||||
| @@ -13,6 +20,54 @@ import java.io.StringWriter; | |||||||
|  */ |  */ | ||||||
| public class Saxon implements XmlEngine{ | 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 |      * Transforms string containing xml document via xslt | ||||||
|      * @param data xml to be transformed |      * @param data xml to be transformed | ||||||
|   | |||||||
| @@ -1,6 +1,10 @@ | |||||||
| package com.r11.tools.xml; | package com.r11.tools.xml; | ||||||
|  |  | ||||||
|  | import com.r11.tools.model.XMLMultipleFilesData; | ||||||
| import com.r11.tools.model.XPathQueryResult; | import com.r11.tools.model.XPathQueryResult; | ||||||
|  | import net.sf.saxon.s9api.SaxonApiException; | ||||||
|  |  | ||||||
|  | import java.io.IOException; | ||||||
|  |  | ||||||
| public interface XmlEngine { | public interface XmlEngine { | ||||||
|     XPathQueryResult processXPath(String data, String query, String version) throws Exception; |     XPathQueryResult processXPath(String data, String query, String version) throws Exception; | ||||||
|   | |||||||
| @@ -104,6 +104,7 @@ function prepareRequestBody():string { | |||||||
|         "processor": engine.value, |         "processor": engine.value, | ||||||
|         "version": version.value |         "version": version.value | ||||||
|     }); |     }); | ||||||
|  |     console.log(requestBody) | ||||||
|     return requestBody; |     return requestBody; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user