Refactored tools services endpoints system and fixed json formatter. (#91)
Co-authored-by: Artur Kołecki <koleckiartur@icloud.com> Co-authored-by: Adam Bem <adam.bem@zoho.eu> Reviewed-on: R11/release11-tools-web#91
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
package com.r11.tools;
|
||||
|
||||
import com.r11.tools.controller.JsonController;
|
||||
import com.r11.tools.controller.ProcessorInfoController;
|
||||
import com.r11.tools.controller.XPathController;
|
||||
import com.r11.tools.controller.XsdController;
|
||||
import com.r11.tools.controller.XsltController;
|
||||
import com.r11.tools.controller.internal.RestControllerRegistry;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import spark.Spark;
|
||||
|
||||
public class SparkApplication {
|
||||
|
||||
public static void run() {
|
||||
// TODO: read port from config
|
||||
Spark.port(8081);
|
||||
|
||||
Spark.after((request, response) -> {
|
||||
response.header("Access-Control-Allow-Origin", "*");
|
||||
response.header("access-control-allow-headers", "*");
|
||||
response.header("access-control-expose-headers", "*");
|
||||
response.header("Access-Control-Allow-Methods", "POST");
|
||||
});
|
||||
|
||||
Logger logger = LogManager.getLogger(SparkApplication.class);
|
||||
|
||||
RestControllerRegistry registry = new RestControllerRegistry();
|
||||
registry.registerController(new ProcessorInfoController(logger));
|
||||
registry.registerController(new XsdController(logger));
|
||||
registry.registerController(new XPathController(logger));
|
||||
registry.registerController(new XsltController(logger));
|
||||
registry.registerController(new JsonController());
|
||||
|
||||
registry.register();
|
||||
|
||||
logger.info("Server is online at port: " + Spark.port());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.r11.tools;
|
||||
|
||||
public class SparkInitializer {
|
||||
public static void main(String[] args) {
|
||||
SparkApplication.run();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.r11.tools.controller;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.r11.tools.controller.internal.GlobalControllerManifest;
|
||||
import com.r11.tools.controller.internal.HandlerType;
|
||||
import com.r11.tools.controller.internal.RestController;
|
||||
import com.r11.tools.controller.internal.ScopedControllerManifest;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
|
||||
@GlobalControllerManifest(path = "/json")
|
||||
public class JsonController implements RestController {
|
||||
|
||||
private final Gson prettyGson = new GsonBuilder()
|
||||
.disableHtmlEscaping()
|
||||
.setPrettyPrinting()
|
||||
.create();
|
||||
|
||||
private final Gson gson = new GsonBuilder()
|
||||
.disableHtmlEscaping()
|
||||
.create();
|
||||
|
||||
@ScopedControllerManifest(method = HandlerType.POST, path = "/formatting")
|
||||
public void formatting(Request request, Response response) {
|
||||
try {
|
||||
JsonObject jsonObject = this.gson.fromJson(request.body(), JsonObject.class);
|
||||
response.status(200);
|
||||
response.body(this.prettyGson.toJson(jsonObject));
|
||||
} catch (Exception e) {
|
||||
response.status(500);
|
||||
Throwable cause = e.getCause();
|
||||
if (cause == null) {
|
||||
response.body(e.getMessage());
|
||||
} else {
|
||||
response.body(cause.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ScopedControllerManifest(method = HandlerType.POST, path = "/minimize")
|
||||
public void minimize(Request request, Response response) {
|
||||
try {
|
||||
JsonObject jsonObject = this.prettyGson.fromJson(request.body(), JsonObject.class);
|
||||
response.status(200);
|
||||
response.body(this.gson.toJson(jsonObject));
|
||||
} catch (Exception e) {
|
||||
response.status(500);
|
||||
Throwable cause = e.getCause();
|
||||
if (cause == null) {
|
||||
response.body(e.getMessage());
|
||||
} else {
|
||||
response.body(cause.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.r11.tools.controller;
|
||||
|
||||
import com.r11.tools.controller.internal.GlobalControllerManifest;
|
||||
import com.r11.tools.controller.internal.HandlerType;
|
||||
import com.r11.tools.controller.internal.RestController;
|
||||
import com.r11.tools.controller.internal.ScopedControllerManifest;
|
||||
import com.r11.tools.xml.Saxon;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
|
||||
@GlobalControllerManifest
|
||||
public class ProcessorInfoController implements RestController {
|
||||
|
||||
private final Logger logger;
|
||||
|
||||
public ProcessorInfoController(Logger logger) {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler that returns processor version
|
||||
*/
|
||||
@ScopedControllerManifest(method = HandlerType.GET, path = "/procinfo")
|
||||
public void processorInfo(Request request, Response response) {
|
||||
try {
|
||||
response.header("processor", "Saxon " + Saxon.getVersion() + " over s9api");
|
||||
response.body(Saxon.getVersion());
|
||||
} catch (Exception ex) {
|
||||
this.logger.error("Error on retrieving engine version. " + ex);
|
||||
response.body(ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package com.r11.tools.controller;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.r11.tools.controller.internal.GlobalControllerManifest;
|
||||
import com.r11.tools.controller.internal.HandlerType;
|
||||
import com.r11.tools.controller.internal.RestController;
|
||||
import com.r11.tools.controller.internal.ScopedControllerManifest;
|
||||
import com.r11.tools.xml.Saxon;
|
||||
import com.r11.tools.xml.Xalan;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
|
||||
@GlobalControllerManifest
|
||||
public class XPathController implements RestController {
|
||||
|
||||
private final Logger logger;
|
||||
|
||||
public XPathController(Logger logger) {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@ScopedControllerManifest(method = HandlerType.POST, path = "/xpath")
|
||||
public void transform(Request request, Response response) throws JsonProcessingException {
|
||||
String body = request.body();
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
Map<String, String> requestMap = new HashMap<>();
|
||||
Map<String, String> responseMap = new HashMap<>();
|
||||
try {
|
||||
requestMap = mapper.readValue(body, Map.class);
|
||||
} catch (JsonProcessingException ex) {
|
||||
this.logger.error("Request JSON error. " + ex);
|
||||
responseMap.put("result", ex.getMessage());
|
||||
responseMap.put("processor", "N/A");
|
||||
responseMap.put("status", "ERR");
|
||||
responseMap.put("time", "N/A");
|
||||
response.status(400);
|
||||
response.body(mapper.writeValueAsString(responseMap));
|
||||
return;
|
||||
}
|
||||
|
||||
String data = requestMap.get("data");
|
||||
String query = requestMap.get("process");
|
||||
String processor = requestMap.get("processor");
|
||||
String version = requestMap.get("version");
|
||||
|
||||
|
||||
String tmp = "";
|
||||
long timeStart;
|
||||
long duration;
|
||||
|
||||
if (processor == null) {
|
||||
response.body("saxon, xalan");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (processor) {
|
||||
case "saxon":
|
||||
response.header("processor", "Saxon " + Saxon.getVersion() + " " + version + " over s9api");
|
||||
timeStart = System.currentTimeMillis();
|
||||
try {
|
||||
tmp = Saxon.processXPath(data, query, version).trim();
|
||||
responseMap.put("result", tmp);
|
||||
responseMap.put("status", "OK");
|
||||
} catch (Exception ex) {
|
||||
this.logger.error("Error on processing XPath using Saxon. " + ex);
|
||||
responseMap.put("result", ex.getMessage());
|
||||
responseMap.put("status", "ERR");
|
||||
response.status(400);
|
||||
}
|
||||
duration = System.currentTimeMillis() - timeStart;
|
||||
this.logger.info("Request" + body + " processed in " + duration + " ms.");
|
||||
responseMap.put("processor", "Saxon " + Saxon.getVersion() + " " + version + " over s9api");
|
||||
responseMap.put("time", "" + duration);
|
||||
response.body(mapper.writeValueAsString(responseMap));
|
||||
return;
|
||||
|
||||
case "xalan":
|
||||
response.header("processor", Xalan.getVersion());
|
||||
timeStart = System.currentTimeMillis();
|
||||
try {
|
||||
tmp = Xalan.processXPath(data, query).trim();
|
||||
responseMap.put("result", tmp);
|
||||
responseMap.put("status", "OK");
|
||||
} catch (Exception ex) {
|
||||
this.logger.error("Error on processing XPath using Xalan. " + ex);
|
||||
responseMap.put("result", ex.getMessage());
|
||||
responseMap.put("status", "ERR");
|
||||
response.status(400);
|
||||
}
|
||||
duration = System.currentTimeMillis() - timeStart;
|
||||
this.logger.info("Request: " + body + " processed in " + duration + " ms.");
|
||||
responseMap.put("processor", Xalan.getVersion());
|
||||
responseMap.put("time", Long.toString(duration));
|
||||
response.body(mapper.writeValueAsString(responseMap));
|
||||
return;
|
||||
default:
|
||||
response.body("saxon, xalan");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.r11.tools.controller;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.r11.tools.controller.internal.GlobalControllerManifest;
|
||||
import com.r11.tools.controller.internal.HandlerType;
|
||||
import com.r11.tools.controller.internal.RestController;
|
||||
import com.r11.tools.controller.internal.ScopedControllerManifest;
|
||||
import com.r11.tools.xml.Xalan;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
|
||||
@GlobalControllerManifest
|
||||
public class XsdController implements RestController {
|
||||
|
||||
private final Logger logger;
|
||||
|
||||
public XsdController(Logger logger) {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@ScopedControllerManifest(method = HandlerType.POST, path = "/xsd")
|
||||
public Response transform(Request req, Response resp) throws JsonProcessingException {
|
||||
String body = req.body();
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
Map<String, String> requestMap = new HashMap<>();
|
||||
Map<String, String> responseMap = new HashMap<>();
|
||||
|
||||
try {
|
||||
requestMap = mapper.readValue(body, Map.class);
|
||||
} catch (JsonProcessingException ex) {
|
||||
this.logger.error("Request JSON error. " + ex);
|
||||
responseMap.put("result", ex.getMessage());
|
||||
responseMap.put("processor", "N/A");
|
||||
responseMap.put("status", "ERR");
|
||||
responseMap.put("time", "N/A");
|
||||
resp.status(400);
|
||||
resp.body(mapper.writeValueAsString(responseMap));
|
||||
return resp;
|
||||
}
|
||||
|
||||
String data = requestMap.get("data");
|
||||
String xsd = requestMap.get("process");
|
||||
|
||||
resp.header("processor", Xalan.getVersion());
|
||||
long timeStart = System.currentTimeMillis();
|
||||
String tmp;
|
||||
try {
|
||||
tmp = Xalan.validate(data, xsd).trim();
|
||||
responseMap.put("result", tmp);
|
||||
responseMap.put("status", "OK");
|
||||
} catch (Exception ex) {
|
||||
this.logger.error("Error on validation against XSD using Xalan. " + ex);
|
||||
responseMap.put("result", ex.getMessage());
|
||||
responseMap.put("status", "ERR");
|
||||
resp.status(400);
|
||||
}
|
||||
|
||||
long duration = System.currentTimeMillis() - timeStart;
|
||||
this.logger.info("Request: " + body + " processed in " + duration + " ms.");
|
||||
responseMap.put("processor", Xalan.getVersion());
|
||||
responseMap.put("time", "" + duration);
|
||||
resp.body(mapper.writeValueAsString(responseMap));
|
||||
return resp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package com.r11.tools.controller;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.r11.tools.controller.internal.GlobalControllerManifest;
|
||||
import com.r11.tools.controller.internal.HandlerType;
|
||||
import com.r11.tools.controller.internal.RestController;
|
||||
import com.r11.tools.controller.internal.ScopedControllerManifest;
|
||||
import com.r11.tools.xml.Saxon;
|
||||
import com.r11.tools.xml.Xalan;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import spark.Request;
|
||||
import spark.Response;
|
||||
|
||||
@GlobalControllerManifest
|
||||
public class XsltController implements RestController {
|
||||
|
||||
private final Logger logger;
|
||||
|
||||
public XsltController(Logger logger) {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@ScopedControllerManifest(method = HandlerType.POST, path = "/xslt")
|
||||
public void transform(Request request, Response response) throws JsonProcessingException {
|
||||
String body = request.body();
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
Map<String, String> requestMap = new HashMap<>();
|
||||
Map<String, String> responseMap = new HashMap<>();
|
||||
try {
|
||||
requestMap = mapper.readValue(body, Map.class);
|
||||
} catch (JsonMappingException | JsonParseException ex) {
|
||||
this.logger.error("Request JSON error. " + ex);
|
||||
responseMap.put("result", ex.getMessage());
|
||||
responseMap.put("processor", "N/A");
|
||||
responseMap.put("status", "ERR");
|
||||
responseMap.put("time", "N/A");
|
||||
response.status(400);
|
||||
response.body(mapper.writeValueAsString(responseMap));
|
||||
return;
|
||||
}
|
||||
|
||||
String data = requestMap.get("data");
|
||||
String query = requestMap.get("process");
|
||||
String processor = requestMap.get("processor");
|
||||
String version = requestMap.get("version");
|
||||
|
||||
if (processor == null) {
|
||||
response.body("saxon, xalan");
|
||||
return;
|
||||
}
|
||||
|
||||
String tmp;
|
||||
long timeStart;
|
||||
long duration;
|
||||
switch (processor) {
|
||||
case "saxon":
|
||||
timeStart = System.currentTimeMillis();
|
||||
try {
|
||||
tmp = Saxon.processXSLT(data, query);
|
||||
responseMap.put("result", tmp);
|
||||
responseMap.put("status", "OK");
|
||||
} catch (Exception ex) {
|
||||
this.logger.error("Error on processing XSLT using Saxon. " + ex);
|
||||
responseMap.put("result", ex.getMessage());
|
||||
responseMap.put("status", "ERR");
|
||||
response.status(400);
|
||||
}
|
||||
|
||||
duration = System.currentTimeMillis() - timeStart;
|
||||
this.logger.info("Request: " + body + " processed in " + duration + " ms.");
|
||||
responseMap.put("processor", "Saxon " + Saxon.getVersion() + " " + version);
|
||||
responseMap.put("time", Long.toString(duration));
|
||||
response.body(mapper.writeValueAsString(responseMap));
|
||||
return;
|
||||
|
||||
case "xalan":
|
||||
timeStart = System.currentTimeMillis();
|
||||
try {
|
||||
tmp = Xalan.processXSLT(data, query);
|
||||
responseMap.put("result", tmp);
|
||||
responseMap.put("status", "OK");
|
||||
} catch (Exception ex) {
|
||||
this.logger.error("Error on processing XSLT using Xalan. " + ex);
|
||||
responseMap.put("result", ex.getMessage());
|
||||
responseMap.put("status", "ERR");
|
||||
response.status(400);
|
||||
}
|
||||
|
||||
duration = System.currentTimeMillis() - timeStart;
|
||||
this.logger.info("Request: " + body + " processed in " + duration + " ms.");
|
||||
responseMap.put("processor", Xalan.getVersion());
|
||||
responseMap.put("time", Long.toString(duration));
|
||||
response.body(mapper.writeValueAsString(responseMap));
|
||||
return;
|
||||
|
||||
default:
|
||||
response.body("saxon, xalan");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.r11.tools.controller.internal;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface GlobalControllerManifest {
|
||||
|
||||
String path() default "";
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.r11.tools.controller.internal;
|
||||
|
||||
public enum HandlerType {
|
||||
|
||||
GET, POST, PUT, DELETE
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.r11.tools.controller.internal;
|
||||
|
||||
public interface RestController {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.r11.tools.controller.internal;
|
||||
|
||||
import com.r11.tools.controller.internal.path.PathBuilder;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import spark.Spark;
|
||||
|
||||
public class RestControllerRegistry {
|
||||
|
||||
private final Set<RestController> registeredControllers;
|
||||
|
||||
public RestControllerRegistry() {
|
||||
this.registeredControllers = new HashSet<>();
|
||||
}
|
||||
|
||||
public void registerController(RestController restController) {
|
||||
this.registeredControllers.add(restController);
|
||||
}
|
||||
|
||||
public void register() {
|
||||
this.registeredControllers.forEach(controller -> {
|
||||
if (controller.getClass().isAnnotationPresent(GlobalControllerManifest.class)) {
|
||||
for (Method method : controller.getClass().getMethods()) {
|
||||
this.registerAssignableHandlers(controller.getClass(), controller, method);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void registerAssignableHandlers(Class<? extends RestController> parent, RestController parentValue, Method method) {
|
||||
if (
|
||||
(parent.isAnnotationPresent(GlobalControllerManifest.class)) &&
|
||||
(method.isAnnotationPresent(ScopedControllerManifest.class))
|
||||
) {
|
||||
HandlerType handlerType = method.getAnnotation(ScopedControllerManifest.class).method();
|
||||
|
||||
String path = PathBuilder.resolvePathOf(
|
||||
parent.getAnnotation(GlobalControllerManifest.class).path(),
|
||||
method.getAnnotation(ScopedControllerManifest.class).path()
|
||||
);
|
||||
|
||||
switch (handlerType) {
|
||||
case GET:
|
||||
Spark.get(path, (request, response) -> method.invoke(parentValue, request, response));
|
||||
break;
|
||||
case PUT:
|
||||
Spark.put(path, (request, response) -> method.invoke(parentValue, request, response));
|
||||
break;
|
||||
case POST:
|
||||
Spark.post(path, (request, response) -> method.invoke(parentValue, request, response));
|
||||
break;
|
||||
case DELETE:
|
||||
Spark.delete(path, (request, response) -> method.invoke(parentValue, request, response));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.r11.tools.controller.internal;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface ScopedControllerManifest {
|
||||
|
||||
HandlerType method();
|
||||
|
||||
String path();
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.r11.tools.controller.internal.path;
|
||||
|
||||
public final class PathBuilder {
|
||||
|
||||
private static final String PATH_SEPARATOR = "/";
|
||||
|
||||
private PathBuilder() {
|
||||
|
||||
}
|
||||
|
||||
public static String resolvePathOf(String globalPath, String scopedPath) {
|
||||
String resolvedPath =
|
||||
PathBuilder.removeTrailingPathSeparator(globalPath) +
|
||||
PathBuilder.removeTrailingPathSeparator(scopedPath);
|
||||
|
||||
if (resolvedPath.endsWith(PATH_SEPARATOR)) {
|
||||
resolvedPath = resolvedPath.substring(0, resolvedPath.length() - 1);
|
||||
}
|
||||
|
||||
return PATH_SEPARATOR + resolvedPath;
|
||||
}
|
||||
|
||||
private static String removeTrailingPathSeparator(String path) {
|
||||
if (path.endsWith(PATH_SEPARATOR)) {
|
||||
return path.substring(0, path.length() - 1);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.r11.tools.xml;
|
||||
|
||||
import net.sf.saxon.om.NamespaceMap;
|
||||
import net.sf.saxon.s9api.XPathCompiler;
|
||||
import net.sf.saxon.s9api.XdmNode;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Handler for saxon namespace scan engine.
|
||||
* All found namespaces are stored within {@link #namespaceMap}
|
||||
* @author Wojciech Czop
|
||||
*/
|
||||
public class NewNamespaceResolver {
|
||||
private static final Logger LOG = LogManager.getLogger("NewNamespaceResolver");
|
||||
|
||||
private NamespaceMap namespaceMap;
|
||||
|
||||
/**
|
||||
* Initializes {@link #namespaceMap} with namespace values
|
||||
* @param doc dom structure object
|
||||
* @return map of namespaces
|
||||
*/
|
||||
|
||||
// TODO: Closer inspection. Return value is never used according to IntelliJ
|
||||
//
|
||||
public NamespaceMap process(XdmNode doc) {
|
||||
namespaceMap = NamespaceMap.emptyMap();
|
||||
// TODO: remove
|
||||
for (XdmNode tmp : doc.children()) {
|
||||
extractNamespace(tmp);
|
||||
}
|
||||
// end
|
||||
return namespaceMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through {@link #namespaceMap} and declares namespaces in {@link XPathCompiler}
|
||||
* @param compiler compiler used to compile xpath statements
|
||||
*/
|
||||
public void exportNamespaces(XPathCompiler compiler){
|
||||
namespaceMap.forEach(namespaceBinding -> compiler.declareNamespace(namespaceBinding.getPrefix(), namespaceBinding.getURI()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses recurrency to dive deep dom structure and appends {@link #namespaceMap} with every found namespace
|
||||
* @param node dom structure object
|
||||
*/
|
||||
private void extractNamespace(XdmNode node) {
|
||||
NamespaceMap tmp;
|
||||
if ((tmp = node.getUnderlyingNode().getAllNamespaces()) != null) {
|
||||
namespaceMap = namespaceMap.putAll(tmp);
|
||||
}
|
||||
if (node.children().iterator().hasNext()) {
|
||||
|
||||
for (XdmNode rNode : node.children()) {
|
||||
if (rNode.getUnderlyingNode().getPrefix().isEmpty() && !rNode.getParent().getUnderlyingNode().getPrefix().isEmpty()) {
|
||||
LOG.warn("Missing prefix. Parent has " + rNode.getParent().getUnderlyingNode().getPrefix() + ", but child has none");
|
||||
}
|
||||
|
||||
extractNamespace(rNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.r11.tools.xml;
|
||||
|
||||
import net.sf.saxon.s9api.*;
|
||||
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
* Handler for Saxon engine
|
||||
* @author Wojciech Czop
|
||||
*/
|
||||
public class Saxon {
|
||||
|
||||
/**
|
||||
* Transforms string containing xml document via xslt
|
||||
* @param data xml to be transformed
|
||||
* @param transform xslt
|
||||
* @return transformed xml
|
||||
* @throws SaxonApiException thrown on stylesheet or transformation errors
|
||||
*/
|
||||
public static String processXSLT(String data, String transform) throws SaxonApiException {
|
||||
Processor processor = new Processor(false);
|
||||
XsltCompiler compiler = processor.newXsltCompiler();
|
||||
XsltExecutable stylesheet = compiler.compile(new StreamSource(new StringReader(transform)));
|
||||
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.transform(new StreamSource(new StringReader(data)), out);
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process xpath and return either node or wrapped atomic value
|
||||
* @param data xml to be querried
|
||||
* @param query xpath queryy
|
||||
* @param version processor version
|
||||
* @return string xml representation of the node
|
||||
* @throws Exception thrown on node building errors or invalid xpath
|
||||
*/
|
||||
public static String processXPath(String data, String query, String version) throws Exception {
|
||||
Processor p = new Processor(false);
|
||||
XPathCompiler compiler = p.newXPathCompiler();
|
||||
DocumentBuilder builder = p.newDocumentBuilder();
|
||||
XdmNode doc = builder.build(new StreamSource(new StringReader(data)));
|
||||
|
||||
compiler.setLanguageVersion(version);
|
||||
|
||||
NewNamespaceResolver resolver = new NewNamespaceResolver();
|
||||
|
||||
resolver.process(doc);
|
||||
|
||||
resolver.exportNamespaces(compiler);
|
||||
|
||||
XdmValue result = compiler.evaluate(query, doc);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (XdmItem xdmItem : result) {
|
||||
sb.append(xdmItem);
|
||||
sb.append('\n');
|
||||
}
|
||||
return sb.toString();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns version of the processor
|
||||
* @return version of the processor
|
||||
*/
|
||||
public static String getVersion() {
|
||||
return new Processor(false).getSaxonProductVersion();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package com.r11.tools.xml;
|
||||
|
||||
import org.apache.xpath.XPathAPI;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.traversal.NodeIterator;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.transform.*;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import javax.xml.validation.Schema;
|
||||
import javax.xml.validation.SchemaFactory;
|
||||
import javax.xml.validation.Validator;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Handler for Xalan engine
|
||||
* @author Wojciech Czop
|
||||
*/
|
||||
public class Xalan {
|
||||
|
||||
/**
|
||||
* Transforms string containing xml document via xslt
|
||||
* @param data xml to be transformed
|
||||
* @param transform xslt
|
||||
* @return transformed xml
|
||||
* @throws Exception thrown on stylesheet or transformation errors
|
||||
*/
|
||||
public static String processXSLT(String data, String transform) throws Exception{
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||
Document document = builder.parse(new InputSource(new StringReader(data)));
|
||||
|
||||
StreamSource stylesource = new StreamSource(new StringReader(transform));
|
||||
Transformer transformer = TransformerFactory.newInstance().newTransformer(stylesource);
|
||||
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
|
||||
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||
|
||||
Source source = new DOMSource(document);
|
||||
StringWriter sw = new StringWriter();
|
||||
Result outputTarget = new StreamResult(sw);
|
||||
transformer.transform(source, outputTarget);
|
||||
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
private static boolean isTextNode(Node n) {
|
||||
if (n == null)
|
||||
return false;
|
||||
short nodeType = n.getNodeType();
|
||||
return nodeType == Node.CDATA_SECTION_NODE || nodeType == Node.TEXT_NODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process xpath and return either node or wrapped atomic value
|
||||
* @param data xml
|
||||
* @param transform xpath
|
||||
* @return xml processed using given xpath
|
||||
* @throws Exception thrown on node building errors or invalid xpath
|
||||
*/
|
||||
public static String processXPath(String data, String transform) throws Exception {
|
||||
|
||||
// Set up a DOM tree to query.
|
||||
InputSource in = new InputSource(new StringReader(data));
|
||||
DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
|
||||
dfactory.setNamespaceAware(true);
|
||||
Document doc = dfactory.newDocumentBuilder().parse(in);
|
||||
|
||||
// Set up an identity transformer to use as serializer.
|
||||
Transformer serializer = TransformerFactory.newInstance().newTransformer();
|
||||
serializer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
|
||||
|
||||
// Use the simple XPath API to select a nodeIterator.
|
||||
NodeIterator nl = XPathAPI.selectNodeIterator(doc, transform);
|
||||
|
||||
// Serialize the found nodes to result object.
|
||||
StringBuilder result = new StringBuilder();
|
||||
Node n;
|
||||
while ((n = nl.nextNode())!= null) {
|
||||
StringBuilder sb;
|
||||
if (isTextNode(n)) {
|
||||
// DOM may have more than one node corresponding to a
|
||||
// single XPath text node. Coalesce all contiguous text nodes
|
||||
// at this level
|
||||
for (Node nn = n.getNextSibling(); isTextNode(nn); nn = nn.getNextSibling()) {
|
||||
result.append(nn.getNodeValue());
|
||||
}
|
||||
} else {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
serializer.transform(new DOMSource(n), new StreamResult(new OutputStreamWriter(outputStream)));
|
||||
result.append(outputStream);
|
||||
}
|
||||
result.append("\n");
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns version of the processor
|
||||
* @return version of the processor
|
||||
*/
|
||||
public static String getVersion(){
|
||||
return org.apache.xalan.Version.getVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates string representation of the xml document against xsd schema
|
||||
* @param data xml document
|
||||
* @param xsd xsd schema
|
||||
* @return statement of validity
|
||||
* @throws Exception thrown on invalid xsd schema or xml
|
||||
*/
|
||||
public static String validate(String data, String xsd) throws Exception{
|
||||
Source dataSource = new StreamSource(new StringReader(data));
|
||||
Source xsdSource = new StreamSource(new StringReader(xsd));
|
||||
SchemaFactory schemaFactory = SchemaFactory
|
||||
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
|
||||
Schema schema = schemaFactory.newSchema(xsdSource);
|
||||
Validator validator = schema.newValidator();
|
||||
validator.validate(dataSource);
|
||||
return "XML file is valid";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package com.r11.tools.xml;
|
||||
|
||||
import org.w3c.dom.*;
|
||||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.namespace.NamespaceContext;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Contains methods that scan document for namespaces and store them in map objects.
|
||||
* @deprecated
|
||||
* Class no longer in use. It has been replaced by {@link NewNamespaceResolver}
|
||||
* @author Wojciech Czop
|
||||
*/
|
||||
public class XalanNamespaceResolver implements NamespaceContext {
|
||||
private static final String DEFAULT_NS = "DEFAULT";
|
||||
private Map<String, String> prefix2Uri = new HashMap<String, String>();
|
||||
private Map<String, String> uri2Prefix = new HashMap<String, String>();
|
||||
|
||||
/**
|
||||
* This constructor parses the document and stores all namespaces it can
|
||||
* find. If toplevelOnly is true, only namespaces in the root are used.
|
||||
*
|
||||
* @param document
|
||||
* source document
|
||||
* @param toplevelOnly
|
||||
* restriction of the search to enhance performance
|
||||
*/
|
||||
public XalanNamespaceResolver(Document document, boolean toplevelOnly) {
|
||||
examineNode(document.getFirstChild(), toplevelOnly);
|
||||
System.out.println("The list of the cached namespaces:");
|
||||
for (String key : prefix2Uri.keySet()) {
|
||||
System.out.println("prefix " + key + ": uri " + prefix2Uri.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A single node is read, the namespace attributes are extracted and stored.
|
||||
*
|
||||
* @param node
|
||||
* to examine
|
||||
* @param attributesOnly,
|
||||
* if true no recursion happens
|
||||
*/
|
||||
private void examineNode(Node node, boolean attributesOnly) {
|
||||
NamedNodeMap attributes = node.getAttributes();
|
||||
for (int i = 0; i < attributes.getLength(); i++) {
|
||||
Node attribute = attributes.item(i);
|
||||
storeAttribute((Attr) attribute);
|
||||
}
|
||||
|
||||
if (!attributesOnly) {
|
||||
NodeList chields = node.getChildNodes();
|
||||
for (int i = 0; i < chields.getLength(); i++) {
|
||||
Node chield = chields.item(i);
|
||||
if (chield.getNodeType() == Node.ELEMENT_NODE){
|
||||
examineNode(chield, false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method looks at an attribute and stores it, if it is a namespace
|
||||
* attribute.
|
||||
*
|
||||
* @param attribute
|
||||
* to examine
|
||||
*/
|
||||
private void storeAttribute(Attr attribute) {
|
||||
// examine the attributes in namespace xmlns
|
||||
String uri = attribute.getNamespaceURI();
|
||||
String name = attribute.getLocalName();
|
||||
String name2 = attribute.getName();
|
||||
String value = attribute.getNodeValue();
|
||||
if (attribute.getNodeValue() != null
|
||||
/*&& attribute.getNamespaceURI().equals(
|
||||
XMLConstants.XMLNS_ATTRIBUTE_NS_URI)*/) {
|
||||
// Default namespace xmlns="uri goes here"
|
||||
if (attribute.getNodeName().equals(XMLConstants.XMLNS_ATTRIBUTE)) {
|
||||
putInCache(DEFAULT_NS, attribute.getNodeValue());
|
||||
} else {
|
||||
// The defined prefixes are stored here
|
||||
putInCache(attribute.getName().replace("xmlns:", ""), attribute.getNodeValue());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores namespace prefix ass well as its uri in map
|
||||
* @param prefix
|
||||
* @param uri
|
||||
*/
|
||||
private void putInCache(String prefix, String uri) {
|
||||
prefix2Uri.put(prefix, uri);
|
||||
uri2Prefix.put(uri, prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by XPath. It returns the default namespace, if the
|
||||
* prefix is null or "".
|
||||
*
|
||||
* @param prefix
|
||||
* to search for
|
||||
* @return uri
|
||||
*/
|
||||
public String getNamespaceURI(String prefix) {
|
||||
if (prefix == null || prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) {
|
||||
return prefix2Uri.get(DEFAULT_NS);
|
||||
} else {
|
||||
return prefix2Uri.get(prefix);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is not needed in this context, but can be implemented in a
|
||||
* similar way.
|
||||
*/
|
||||
public String getPrefix(String namespaceURI) {
|
||||
return uri2Prefix.get(namespaceURI);
|
||||
}
|
||||
|
||||
public Iterator getPrefixes(String namespaceURI) {
|
||||
// Not implemented
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
# Set root logger level to DEBUG and its only appender to A1.
|
||||
log4j.rootLogger=ERROR, A1
|
||||
|
||||
# A1 is set to be a ConsoleAppender.
|
||||
log4j.appender.A1=org.apache.log4j.ConsoleAppender
|
||||
|
||||
# A1 uses PatternLayout.
|
||||
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
|
||||
21
Backend/tools-services/src/main/resources/log4j2.xml
Normal file
21
Backend/tools-services/src/main/resources/log4j2.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration status="WARN">
|
||||
<Appenders>
|
||||
<Console name="Console" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%c] %-5level - %msg%n"/>
|
||||
</Console>
|
||||
<File name="File" fileName="/tmp/xml_tools_java_backend.log" append="true">
|
||||
<PatternLayout>
|
||||
<Pattern>%d{HH:mm:ss.SSS} [%c] %-5level - %msg%n</Pattern>
|
||||
</PatternLayout>
|
||||
</File>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Logger name="com.r11.tools.SparkApplication" level="info" additivity="true">
|
||||
<AppenderRef ref="Console"/>
|
||||
</Logger>
|
||||
<Root level="info">
|
||||
<AppenderRef ref="File"/>
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
||||
Reference in New Issue
Block a user