Skip to content

Commit

Permalink
Validators + XMLLoader.
Browse files Browse the repository at this point in the history
  • Loading branch information
NukeWilliams authored Dec 16, 2024
1 parent 526466a commit 1453a5e
Show file tree
Hide file tree
Showing 5 changed files with 271 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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<Context> {

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<Context>[] configs) {
for (final ValidatingConfig<Context> config : configs) {
config.validate(context, errors);
}
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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<ValidationError> {

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();
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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 extends ValidatingConfig<T>> T getObjectFromString(final String uri, final Class<T> 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 extends ValidatingConfig<T>> T getObjectFromUri(final URI uri, final Class<T> 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 extends ValidatingConfig<T>> T getObjectFromStream(final InputStream stream, final Class<T> 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> T getObjectFromStreamNoValidation(final InputStream stream, final Class<T> 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 <T extends ValidatingConfig<T>> 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);
}
}

1 comment on commit 1453a5e

@NukeWilliams
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue #1

Please sign in to comment.