From 1453a5e7e2e96574a5e4bd62b8c6a71dcdf2f50e Mon Sep 17 00:00:00 2001 From: Williams <82570807+NukeWilliams@users.noreply.github.com> Date: Mon, 16 Dec 2024 12:17:37 +0530 Subject: [PATCH] Validators + XMLLoader. --- .../xmlloader/ValidatingConfig.java | 37 ++++++ .../thunderpay/xmlloader/ValidationError.java | 48 ++++++++ .../xmlloader/ValidationErrors.java | 38 ++++++ .../xmlloader/ValidationException.java | 32 +++++ .../org/thunderpay/xmlloader/XMLLoader.java | 116 ++++++++++++++++++ 5 files changed, 271 insertions(+) create mode 100644 thunderpay-lib/xmlloader/src/main/java/org/thunderpay/xmlloader/ValidatingConfig.java create mode 100644 thunderpay-lib/xmlloader/src/main/java/org/thunderpay/xmlloader/ValidationError.java create mode 100644 thunderpay-lib/xmlloader/src/main/java/org/thunderpay/xmlloader/ValidationErrors.java create mode 100644 thunderpay-lib/xmlloader/src/main/java/org/thunderpay/xmlloader/ValidationException.java create mode 100644 thunderpay-lib/xmlloader/src/main/java/org/thunderpay/xmlloader/XMLLoader.java diff --git a/thunderpay-lib/xmlloader/src/main/java/org/thunderpay/xmlloader/ValidatingConfig.java b/thunderpay-lib/xmlloader/src/main/java/org/thunderpay/xmlloader/ValidatingConfig.java new file mode 100644 index 0000000..8a17408 --- /dev/null +++ b/thunderpay-lib/xmlloader/src/main/java/org/thunderpay/xmlloader/ValidatingConfig.java @@ -0,0 +1,37 @@ +/** + * @file ValidatingConfig.java + * @author Nuke Williams + * @brief Validator Config + * @version 1.0 + * @date 2024-11-25 + * + * @copyright Copyright (c) 2024 ThunderPayment Developers, Nuke Williams + * + */ + +package org.thunderpay.xmlloader; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; + +@XmlAccessorType(XmlAccessType.NONE) +public abstract class ValidatingConfig { + + protected Context root; + + public abstract ValidationErrors validate(Context root, ValidationErrors errors); + + public void initialize(final Context root) { + this.root = root; + } + + public Context getRoot() { + return root; + } + + protected void validateCollection(final Context context, final ValidationErrors errors, final ValidatingConfig[] configs) { + for (final ValidatingConfig config : configs) { + config.validate(context, errors); + } + } +} \ No newline at end of file diff --git a/thunderpay-lib/xmlloader/src/main/java/org/thunderpay/xmlloader/ValidationError.java b/thunderpay-lib/xmlloader/src/main/java/org/thunderpay/xmlloader/ValidationError.java new file mode 100644 index 0000000..41aa638 --- /dev/null +++ b/thunderpay-lib/xmlloader/src/main/java/org/thunderpay/xmlloader/ValidationError.java @@ -0,0 +1,48 @@ +/** + * @file ValidationError.java + * @author Nuke Williams + * @brief Validaton Error + * @version 1.0 + * @date 2024-11-25 + * + * @copyright Copyright (c) 2024 ThunderPayment Developers, Nuke Williams + * + */ + +package org.thunderpay.xmlloader; + +import org.slf4j.Logger; + +public class ValidationError { + + private final String description; + private final Class objectType; + private final String objectName; + + public ValidationError(final String description, final Class objectType, final String objectName) { + super(); + this.description = description; + this.objectType = objectType; + this.objectName = objectName; + } + + public String getDescription() { + return description; + } + + public Class getObjectType() { + return objectType; + } + + public String getObjectName() { + return objectName; + } + + public void log(final Logger log) { + log.error(String.format("%s (%s:%s)", description, objectType, objectName)); + } + + public String toString() { + return String.format("%s (%s:%s)%n", description, objectType, objectName); + } +} \ No newline at end of file diff --git a/thunderpay-lib/xmlloader/src/main/java/org/thunderpay/xmlloader/ValidationErrors.java b/thunderpay-lib/xmlloader/src/main/java/org/thunderpay/xmlloader/ValidationErrors.java new file mode 100644 index 0000000..12f7d5e --- /dev/null +++ b/thunderpay-lib/xmlloader/src/main/java/org/thunderpay/xmlloader/ValidationErrors.java @@ -0,0 +1,38 @@ +/** + * @file ValidationError.java + * @author Nuke Williams + * @brief Validaton Errors + * @version 1.0 + * @date 2024-11-25 + * + * @copyright Copyright (c) 2024 ThunderPayment Developers, Nuke Williams + * + */ + +package org.thunderpay.xmlloader; + +import java.util.ArrayList; +import org.slf4j.Logger; + +public class ValidationErrors extends ArrayList { + + private static final long serialVersionUID = 1L; + + public void add(final String description, final Class objectType, final String objectName) { + add(new ValidationError(description, objectType, objectName)); + } + + public void log(final Logger log) { + for (final ValidationError error : this) { + error.log(log); + } + } + + public String toString() { + final StringBuilder builder = new StringBuilder(); + for (final ValidationError error : this) { + builder.append(error.toString()); + } + return builder.toString(); + } +} \ No newline at end of file diff --git a/thunderpay-lib/xmlloader/src/main/java/org/thunderpay/xmlloader/ValidationException.java b/thunderpay-lib/xmlloader/src/main/java/org/thunderpay/xmlloader/ValidationException.java new file mode 100644 index 0000000..3e76b99 --- /dev/null +++ b/thunderpay-lib/xmlloader/src/main/java/org/thunderpay/xmlloader/ValidationException.java @@ -0,0 +1,32 @@ +/** + * @file ValidationException.java + * @author Nuke Williams + * @brief Validation Exceptions + * @version 1.0 + * @date 2024-11-25 + * + * @copyright Copyright (c) 2024 ThunderPayment Developers, Krisna Pranav + * + */ + +package org.thunderpay.xmlloader; + +import java.io.PrintStream; + +public class ValidationException extends Exception { + private final ValidationErrors errors; + + ValidationException(final ValidationError errors) { + this.errors = errors; + } + + public ValidationErrors getErrors() { + return errors; + } + + @Override + public void printStackTrace(final PrintStream arg0) { + arg0.print(errors.toString()); + super.printStackTrace(arg0); + } +} \ No newline at end of file diff --git a/thunderpay-lib/xmlloader/src/main/java/org/thunderpay/xmlloader/XMLLoader.java b/thunderpay-lib/xmlloader/src/main/java/org/thunderpay/xmlloader/XMLLoader.java new file mode 100644 index 0000000..fc5534c --- /dev/null +++ b/thunderpay-lib/xmlloader/src/main/java/org/thunderpay/xmlloader/XMLLoader.java @@ -0,0 +1,116 @@ +/** + * @file XMLLoader.java + * @author Nuke Williams + * @brief XMl Loader + * @version 1.0 + * @date 2024-11-25 + * + * @copyright Copyright (c) 2024 ThunderPayment Developers, Krisna Pranav + * + */ + +package org.thunderpay.xmlloader; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import javax.xml.XMLConstants; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.transform.TransformerException; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.SAXException; + +public class XMLLoader { + + private static final String DISABLE_VALIDATION_PROP = "org.thunderpay.xmlloader.disable.validation"; + + public static final Logger log = LoggerFactory.getLogger(XMLLoader.class); + + public static > T getObjectFromString(final String uri, final Class objectType) throws Exception { + if (uri == null) { + return null; + } + log.info("Initializing an object of class " + objectType.getName() + " from xml file at: " + uri); + + return getObjectFromStream(UriAccessor.accessUri(uri), objectType); + } + + public static > T getObjectFromUri(final URI uri, final Class objectType) throws Exception { + if (uri == null) { + return null; + } + log.info("Initializing an object of class " + objectType.getName() + " from xml file at: " + uri); + + return getObjectFromStream(UriAccessor.accessUri(uri), objectType); + } + + public static > T getObjectFromStream(final InputStream stream, final Class clazz) throws SAXException, JAXBException, IOException, TransformerException, ValidationException { + if (stream == null) { + return null; + } + + final Object o = unmarshaller(clazz).unmarshal(stream); + if (clazz.isInstance(o)) { + @SuppressWarnings("unchecked") final T castObject = (T) o; + try { + initializeAndValidate(castObject); + } catch (final ValidationException e) { + e.getErrors().log(log); + throw e; + } + return castObject; + } else { + return null; + } + } + + public static T getObjectFromStreamNoValidation(final InputStream stream, final Class clazz) throws SAXException, JAXBException, IOException, TransformerException { + final Object o = unmarshaller(clazz).unmarshal(stream); + if (clazz.isInstance(o)) { + @SuppressWarnings("unchecked") final T castObject = (T) o; + return castObject; + } else { + return null; + } + } + + public static > void initializeAndValidate(final T c) throws ValidationException { + c.initialize(c); + + if (shouldDisableValidation()) { + log.warn("Catalog validation has been disabled using property " + DISABLE_VALIDATION_PROP); + return; + } + + final ValidationErrors errs = c.validate(c, new ValidationErrors()); + if (!errs.isEmpty()) { + throw new ValidationException(errs); + } + } + + public static Unmarshaller unmarshaller(final Class clazz) throws JAXBException, SAXException, IOException, TransformerException { + final JAXBContext context = JAXBContext.newInstance(clazz); + + final SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + + factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + + final Unmarshaller um = context.createUnmarshaller(); + + final Schema schema = factory.newSchema(new StreamSource(XMLSchemaGenerator.xmlSchema(clazz))); + um.setSchema(schema); + + return um; + } + + private static boolean shouldDisableValidation() { + final String disableValidationProp = System.getProperty(DISABLE_VALIDATION_PROP); + return Boolean.parseBoolean(disableValidationProp); + } +}