
com.github.valid8j.pcond.validator.Validator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of valid8j Show documentation
Show all versions of valid8j Show documentation
Java Library Providing Uniformed Programming Experiences across DbC, Value Checking, and Test Assertions
package com.github.valid8j.pcond.validator;
import com.github.valid8j.pcond.core.*;
import com.github.valid8j.pcond.forms.Predicates;
import com.github.valid8j.pcond.internals.InternalUtils;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
import static com.github.valid8j.pcond.validator.Validator.Configuration.Utils.instantiate;
import static com.github.valid8j.pcond.validator.Validator.Configuration.Utils.loadPcondProperties;
import static java.lang.String.format;
import static java.util.Collections.emptyList;
/**
* An interface of a policy for behaviours on 'contract violations'.
*/
public interface Validator {
/**
* A constant field that holds the default provider instance.
*/
ThreadLocal INSTANCE = ThreadLocal.withInitial(() -> create(loadPcondProperties()));
/**
* Returns a configuration object that determines behaviors of this object.
*
* @return A configuration object.
*/
Configuration configuration();
/**
* Returns a provider instance created from a given `Properties` object.
* This method reads the value for the FQCN of this class (`com.github.valid8j.pcond.provider.AssertionProvider`) and creates an instance of a class specified by the value.
* If the value is not set, this value instantiates an object of `DefaultAssertionProvider` and returns it.
*
* @param properties A {@code Properties} object from which an {@code AssertionProvider} is created
* @return Created provider instance.
*/
static Validator create(Properties properties) {
return new Impl(configurationFromProperties(properties));
}
/**
* Checks a value if it is {@code null} or not.
* If it is not a {@code null}, this method returns the given value itself.
*
* @param value The given value.
* @param The type of the value.
* @return The {@code value}.
*/
default T requireNonNull(T value) {
return require(value, Predicates.isNotNull(), configuration().exceptionComposer().forRequire()::exceptionForNonNullViolation);
}
/**
* Checks a value if it meets a requirement specified by {@code cond}.
* If it does, the value itself will be returned.
*
* @param value The value to be checked.
* @param cond The requirement to check the {@code value}.
* @param The type of the value.
* @return The value.
*/
default T requireArgument(T value, Predicate super T> cond) {
return require(value, cond, configuration().exceptionComposer().forRequire()::exceptionForIllegalArgument);
}
/**
* Checks a value if it meets a requirement specified by {@code cond}.
* If it does, the value itself will be returned.
*
* @param value The value to be checked.
* @param cond The requirement to check the {@code value}.
* @param The type of the value.
* @return The value.
*/
default T requireState(T value, Predicate super T> cond) {
return require(value, cond, configuration().exceptionComposer().forRequire()::exceptionForIllegalState);
}
/**
* A method to check if a given `value` satisfies a precondition given as `cond`.
* If the `cond` is satisfied, the `value` itself will be returned.
* Otherwise, an exception returned by `configuration().exceptionComposer().forRequire().exceptionForGeneralViolation(String)`
* will be thrown.
*
* @param value A value to be checked.
* @param cond A condition to check if `value` satisfies.
* @param The of the `value`.
* @return The `value`, if `cond` is satisfied.
*/
default T require(T value, Predicate super T> cond) {
return require(value, cond, msg -> configuration().exceptionComposer().forRequire().exceptionForGeneralViolation(msg));
}
/**
* A method to check if a given `value` satisfies a precondition given as `cond`.
* If the `cond` is satisfied, the `value` itself will be returned.
* Otherwise, an exception created by `exceptionFactory` is thrown.
*
* @param value A value to be checked.
* @param cond A condition to check if `value` satisfies.
* @param exceptionFactory A function to create an exception thrown when `cond`
* is not satisfied by `value`.
* @param The of the `value`.
* @return The `value`, if `cond` is satisfied.
*/
default T require(T value, Predicate super T> cond, Function exceptionFactory) {
return checkValueAndThrowIfFails(
value,
cond,
this.configuration().messageComposer()::composeMessageForPrecondition,
explanation -> squashStackTraceElements(exceptionFactory.apply(explanation.toString())));
}
/**
* Validates the given `value`.
* If the value satisfies a condition `cond`, the value itself will be returned.
* Otherwise, an exception created by `forValidate.exceptionForGeneralViolation()`
* will be thrown.
* This method is intended to be used by {@code Validates#validate(Object, Predicate, Function)}
* method in `valid8j` library.
*
* @param value The value to be checked.
* @param cond A condition to validate the `value`.
* @param forValidate An exception composer for "validate" methods.
* @param The type of the value.
* @return The value itself.
*/
default T validate(T value, Predicate super T> cond, ExceptionComposer.ForValidate forValidate) {
return validate(value, cond, forValidate::exceptionForGeneralViolation);
}
/**
* Validates the given `value`.
* If the value is not `null`, the value itself will be returned.
* Otherwise, an exception created by `forValidate.exceptionForGeneralViolation()`
* will be thrown.
* This method is intended to be used by {@code Validates#validateNonNull(Object)}
* method in the **valid8j** library.
*
* @param value The value to be checked.
* @param forValidate An exception composer for "validate" methods.
* @param The type of the value.
* @return The value itself.
*/
default T validateNonNull(T value, ExceptionComposer.ForValidate forValidate) {
return validate(value, Predicates.isNotNull(), forValidate::exceptionForNonNullViolation);
}
/**
* Validates the given argument variable `value`.
* If the value satisfies a condition `cond` for checking an argument variable, the value itself will be returned.
* Otherwise, an exception created by `forValidate.exceptionForIllegalArgument()`
* will be thrown.
* This method is intended to be used by {@code Validates#validateArgument(Object, Predicate)}
* method in `valid8j` library.
*
* @param value The value to be checked.
* @param cond A condition to validate the `value`.
* @param forValidate An exception composer for "validate" methods.
* @param The type of the value.
* @return The value itself.
*/
default T validateArgument(T value, Predicate super T> cond, ExceptionComposer.ForValidate forValidate) {
return validate(value, cond, forValidate::exceptionForIllegalArgument);
}
/**
* Validates the given state variable `value`.
* If the value satisfies a condition `cond` for checking a state, the value itself will be returned.
* Otherwise, an exception created by `forValidate.exceptionForIllegalState()`
* will be thrown.
* This method is intended to be used by {@code Validates#validateState(Object, Predicate)}
* method in valid8j library.
*
* @param value The value to be checked.
* @param cond A condition to validate the `value`.
* @param forValidate An exception composer for "validate" methods.
* @param The type of the value.
* @return The value itself.
*/
default T validateState(T value, Predicate super T> cond, ExceptionComposer.ForValidate forValidate) {
return validate(value, cond, forValidate::exceptionForIllegalState);
}
/**
* Validates the given variable `value`.
* If the value satisfies a condition `cond`, the value itself will be returned.
* Otherwise, an exception created by `exceptionFactory` will be thrown.
* This method is intended to be used by {@code Validates#validate(Object, Predicate, Function)}
* method in the **valid8j** library.
*
* @param value The value to be checked.
* @param cond A condition to validate the `value`.
* @param exceptionFactory A function to create an exception when the `cond` is not satisfied.
* @param The type of the value.
* @return The value itself.
*/
default T validate(T value, Predicate super T> cond, Function exceptionFactory) {
return validate_2(value, cond, explanation -> squashStackTraceElements(exceptionFactory.apply(explanation.toString())));
}
static Throwable squashStackTraceElements(Throwable throwable) {
StackTraceElement[] stackTraceElements = throwable.getStackTrace();
StackTraceElement first = stackTraceElements[0];
throwable.setStackTrace(Stream.concat(Stream.of(new StackTraceElement(first.getClassName(), "STACKTRACE_WAS_SQUASHED", first.getFileName(), first.getLineNumber())),
Arrays.stream(stackTraceElements)
.filter(e -> !e.getClassName().startsWith("com.github.valid8j.")))
.toArray(StackTraceElement[]::new));
return throwable;
}
default T validate_2(T value, Predicate super T> cond, ExceptionFactory exceptionFactory) {
return checkValueAndThrowIfFails(
value,
cond,
configuration().messageComposer()::composeMessageForValidation,
exceptionFactory);
}
/**
* Checks a value if it is not `null`.
* If it is not `null`, the value itself will be returned.
* If it is, an exception created by `configuration().exceptionComposer().forEnsure().exceptionForNonNullViolation()` will be thrown.
* This method is intended for ensuring a "post-condition".
*
* @param value The value to be checked.
* @param The type of the value.
* @return The value.
*/
default T ensureNonNull(T value) {
return ensure(value, Predicates.isNotNull(), configuration().exceptionComposer().forEnsure()::exceptionForNonNullViolation);
}
/**
* Checks a value if it meets a requirement specified by {@code cond}.
* If it does, the value itself will be returned.
* If it does not, an exception created by `configuration().exceptionComposer().forEnsure().exceptionForIllegalState()` will be thrown.
* This method is intended for ensuring a "post-condition" of a state.
*
* @param value The value to be checked.
* @param cond The requirement to check the {@code value}.
* @param The type of the value.
* @return The value.
*/
default T ensureState(T value, Predicate super T> cond) {
return ensure(value, cond, configuration().exceptionComposer().forEnsure()::exceptionForIllegalState);
}
/**
* Checks a value if it meets a requirement specified by {@code cond}.
* If it does, the value itself will be returned.
* If it does not, an exception created by `configuration().exceptionComposer().forEnsure().exceptionForGeneralViolation()` will be thrown.
* This method is intended for ensuring a "post-condition".
*
* @param value The value to be checked.
* @param cond The requirement to check the {@code value}.
* @param The type of the value.
* @return The value.
*/
default T ensure(T value, Predicate super T> cond) {
return ensure(value, cond, msg -> configuration().exceptionComposer().forEnsure().exceptionForGeneralViolation(msg));
}
/**
* Checks a value if it meets a requirement specified by {@code cond}.
* If it does, the value itself will be returned.
* If it does not, an exception created by `exceptionComposer` will be thrown.
* This method is intended for ensuring a "post-condition".
*
* @param value The value to be checked.
* @param cond The requirement to check the {@code value}.
* @param exceptionComposer A function to create an exception to be thrown when
* `cond` is not met.
* @param The type of the value.
* @return The value.
*/
default T ensure(T value, Predicate super T> cond, Function exceptionComposer) {
return checkValueAndThrowIfFails(
value,
cond,
configuration().messageComposer()::composeMessageForPostcondition,
explanation -> squashStackTraceElements(exceptionComposer.apply(explanation.toString())));
}
/**
* A method to check if a `value` satisfies a predicate `cond`.
*
* This method is intended to be used by {@code Assertions#that(Object, Predicate)} in valid8j library.
* If the condition is not satisfied, an exception created by `this.exceptionComposer().forAssert().exceptionInvariantConditionViolation()`
* method will be thrown.
*
* @param value A value to be checked.
* @param cond A condition to check the `value`.
* @param The type of `value`.
*/
default void checkInvariant(T value, Predicate super T> cond) {
checkValueAndThrowIfFails(
value,
cond,
configuration().messageComposer()::composeMessageForAssertion,
explanation -> configuration().exceptionComposer().forAssert().exceptionInvariantConditionViolation(explanation.toString()));
}
/**
* A method to check if a `value` satisfies a predicate `cond`.
*
* This method is intended to be used by {@code Assertions#precondition(Object, Predicate)} in valid8j library.
* If the condition is not satisfied, an exception created by `this.exceptionComposer().forAssert().exceptionPreconditionViolation()`
* method will be thrown.
*
* @param value A value to be checked.
* @param cond A condition to check the `value`.
* @param The type of `value`.
*/
default void checkPrecondition(T value, Predicate super T> cond) {
checkValueAndThrowIfFails(
value,
cond,
configuration().messageComposer()::composeMessageForPrecondition,
explanation -> configuration().exceptionComposer().forAssert().exceptionPreconditionViolation(explanation.toString()));
}
/**
* A method to check if a `value` satisfies a predicate `cond`.
*
* This method is intended to be used by {@code Assertions#postcondition(Object, Predicate)} in valid8j library.
* If the condition is not satisfied, an exception created by `this.exceptionComposer().forAssert().exceptionPostconditionViolation()`
* method will be thrown.
*
* @param value A value to be checked.
* @param cond A condition to check the `value`.
* @param The type of `value`.
*/
default void checkPostcondition(T value, Predicate super T> cond) {
checkValueAndThrowIfFails(
value,
cond,
configuration().messageComposer()::composeMessageForPostcondition,
explanation -> configuration().exceptionComposer().forAssert().exceptionPostconditionViolation(explanation.toString()));
}
/**
* Executes a test assertion for a given `value` using a predicate `cond`.
* If the `cond` is not satisfied by the `value`, an exception created by `configuration().messageComposer().composeMessageForAssertion()`
* will be thrown.
*
* @param value A value to be checked.
* @param cond A predicate to check a given `value`.
* @param The type of the `value`.
*/
default void assertThat(T value, Predicate super T> cond) {
checkValueAndThrowIfFails(
value,
cond,
configuration().messageComposer()::composeMessageForAssertion,
explanation -> configuration().exceptionComposer().forAssertThat().testFailedException(explanation, configuration().reportComposer()));
}
/**
* Executes a test assumption check for a given `value` using a predicate `cond`.
* If the `cond` is not satisfied by the `value`, an exception created by `configuration().messageComposer().composeMessageForAssertion()`
* will be thrown.
*
* @param value A value to be checked.
* @param cond A predicate to check a given `value`.
* @param The type of the `value`.
*/
default void assumeThat(T value, Predicate super T> cond) {
checkValueAndThrowIfFails(
value,
cond,
configuration().messageComposer()::composeMessageForAssertion,
explanation -> configuration().exceptionComposer().forAssertThat().testSkippedException(explanation, configuration().reportComposer()));
}
/**
* The core method of the `ValueChecker`.
* This method checks if the given `evaluationContext` satisfies a condition, passed as `cond`.
* If it does, the `evaluationContext` itself will be returned.
* If not, an appropriate message will be composed based on the `evaluationContext` and `cond` by the `messageComposerFunction`.
* Internally in this method, an `Explanation` of the failure is created by a {@link ReportComposer}
* object returned by `configuration().reportComposer()` method.
* The `Explanation` is passed to the `exceptionComposerFunction` and the exception
* created by the function will be thrown.
*
* @param The type of the `evaluationContext`.
* @param value A value to be checked.
* @param cond A predicate that checks the `evaluationContext`.
* @param messageComposerFunction A function that composes an error message from the `evaluationContext` and the predicate `cond`.
* @param exceptionComposerFunction A function that creates an exception from a failure report created inside this method.
* @return The `evaluationContext` itself.
*/
@SuppressWarnings("unchecked")
default T checkValueAndThrowIfFails(
T value,
Predicate super T> cond,
BiFunction, String> messageComposerFunction,
ExceptionFactory exceptionComposerFunction) {
ValueHolder valueHolder = ValueHolder.forValue(value);
Evaluable evaluable = InternalUtils.toEvaluableIfNecessary(cond);
EvaluableIo, Boolean> evaluableIo = new EvaluableIo<>(valueHolder, EvaluationContext.resolveEvaluationEntryType(evaluable), evaluable);
EvaluationContext evaluationContext = new EvaluationContext<>();
if (this.configuration().useEvaluator() && cond instanceof Evaluable) {
Evaluator evaluator = Evaluator.create();
((Evaluable) cond).accept(evaluableIo, evaluationContext, evaluator);
if (evaluableIo.output().isValueReturned() && Objects.equals(true, evaluableIo.output().value()))
return value;
List entries = evaluationContext.resultEntries();
throw exceptionComposerFunction.create(configuration()
.reportComposer()
.composeExplanation(
messageComposerFunction.apply(value, cond),
entries
));
} else {
if (!cond.test(valueHolder.returnedValue()))
throw exceptionComposerFunction.create(configuration()
.reportComposer()
.composeExplanation(
messageComposerFunction.apply(value, cond),
emptyList()
));
return value;
}
}
static Validator instance() {
return INSTANCE.get();
}
static void reconfigure(Consumer configurator) {
Configuration.Builder b = instance().configuration().parentBuilder();
reconfigure(configurator, b);
}
static void reconfigure(Consumer configurator, Configuration.Builder b) {
Objects.requireNonNull(configurator).accept(b);
INSTANCE.set(new Impl(b.build()));
}
static void resetToDefault() {
reconfigure(b -> {
});
}
static Configuration configurationFromProperties(Properties properties) {
return Configuration.Builder.fromProperties(properties).build();
}
interface ExceptionFactory extends Function {
default RuntimeException create(Explanation explanation) {
return createException(this, explanation);
}
static RuntimeException createException(ExceptionFactory> exceptionFactory, Explanation explanation) {
Throwable t = squashStackTraceElements(exceptionFactory.apply(explanation));
if (t instanceof Error)
throw (Error) t;
if (t instanceof RuntimeException)
throw (RuntimeException) t;
throw new AssertionError(format("Checked exception(%s) cannot be used for validation.", t.getClass()), t);
}
}
interface Configuration {
/**
* When `com.github.valid8j.pcond.debug` is not `true`, it is assumed that those methods in this interface return `false`.
*/
interface Debugging {
default boolean suppressSquashing() {
return true;
}
default boolean enableDebugLog() {
return true;
}
default boolean showEvaluableDetail() {
return true;
}
default boolean reportIgnoredEntries() {
return true;
}
default boolean passThroughComparisonFailure() {
return true;
}
}
int summarizedStringLength();
boolean useEvaluator();
/**
* Returns a message composer, which is responsible for composing an appropriate message for
* a context.
*
* @return A message composer.
*/
MessageComposer messageComposer();
/**
* Returns a report composer, which is responsible for composing an appropriate "report" for
* a context.
*
* @return A report composer
*/
ReportComposer reportComposer();
/**
* Returns an exception composer, which is responsible for creating an exception
* object of an appropriate type for a context.
*
* @return An exception composer.
*/
ExceptionComposer exceptionComposer();
Optional debugging();
Builder parentBuilder();
enum Utils {
;
@SuppressWarnings("unchecked")
static E instantiate(@SuppressWarnings("unused") Class baseClass, String className) {
try {
return (E) Class.forName(className).newInstance();
} catch (InstantiationException | IllegalAccessException |
ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
public static Properties loadPcondProperties() {
try {
Properties ret = new Properties();
System.getProperties().forEach((k, v) -> {
String key = Objects.toString(k);
String value = Objects.toString(v);
String prefix = "com.github.valid8j.pcond.";
if (key.startsWith(prefix)) {
ret.put(key.replace(prefix, ""), value);
}
});
try (InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("pcond.properties")) {
if (inputStream == null)
return ret;
ret.load(inputStream);
return ret;
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
class Builder implements Cloneable {
boolean useEvaluator;
int summarizedStringLength;
MessageComposer messageComposer;
ReportComposer reportComposer;
private ExceptionComposer.ForRequire exceptionComposerForRequire;
private ExceptionComposer.ForEnsure exceptionComposerForEnsure;
private ExceptionComposer.ForValidate defaultExceptionComposerForValidate;
private ExceptionComposer.ForAssertion exceptionComposerForAssert;
private ExceptionComposer.ForTestAssertion exceptionComposerForTestFailures;
public Builder() {
}
public Builder useEvaluator(boolean useEvaluator) {
this.useEvaluator = useEvaluator;
return this;
}
public Builder summarizedStringLength(int summarizedStringLength) {
this.summarizedStringLength = summarizedStringLength;
return this;
}
public Builder exceptionComposerForRequire(ExceptionComposer.ForRequire exceptionComposerForRequire) {
this.exceptionComposerForRequire = exceptionComposerForRequire;
return this;
}
public Builder exceptionComposerForEnsure(ExceptionComposer.ForEnsure exceptionComposerForEnsure) {
this.exceptionComposerForEnsure = exceptionComposerForEnsure;
return this;
}
public Builder defaultExceptionComposerForValidate(ExceptionComposer.ForValidate exceptionComposerForValidate) {
this.defaultExceptionComposerForValidate = exceptionComposerForValidate;
return this;
}
public Builder exceptionComposerForAssert(ExceptionComposer.ForAssertion exceptionComposerForAssert) {
this.exceptionComposerForAssert = exceptionComposerForAssert;
return this;
}
public Builder exceptionComposerForAssertThat(ExceptionComposer.ForTestAssertion exceptionComposerForAssertThat) {
this.exceptionComposerForTestFailures = exceptionComposerForAssertThat;
return this;
}
public Builder messageComposer(MessageComposer messageComposer) {
this.messageComposer = messageComposer;
return this;
}
public Builder reportComposer(ReportComposer reportComposer) {
this.reportComposer = reportComposer;
return this;
}
public Builder useOpentest4J() {
this.exceptionComposerForTestFailures = new ExceptionComposer.ForTestAssertion.Opentest4J();
return this;
}
public Configuration build() {
if (!isClassPresent("org.junit.ComparisonFailure"))
this.useOpentest4J();
return new Configuration() {
private final Debugging debugging = new Debugging() {
};
private final ExceptionComposer exceptionComposer = new ExceptionComposer.Impl(
exceptionComposerForRequire,
exceptionComposerForEnsure,
defaultExceptionComposerForValidate,
exceptionComposerForAssert,
exceptionComposerForTestFailures
);
@Override
public int summarizedStringLength() {
return Builder.this.summarizedStringLength;
}
@Override
public boolean useEvaluator() {
return Builder.this.useEvaluator;
}
/**
* Returns an exception composer, which is responsible for creating an exception
* object of an appropriate type for a context.
*
* @return An exception composer.
*/
public ExceptionComposer exceptionComposer() {
return this.exceptionComposer;
}
@Override
public Optional debugging() {
if (Boolean.parseBoolean(System.getProperty("com.github.valid8j.pcond.debug"))) {
return Optional.of(this.debugging);
}
return Optional.empty();
}
@Override
public MessageComposer messageComposer() {
return Builder.this.messageComposer;
}
@Override
public ReportComposer reportComposer() {
return Builder.this.reportComposer;
}
@Override
public Builder parentBuilder() {
return Builder.this.clone();
}
};
}
private static boolean isClassPresent(String s) {
try {
Class.forName(s);
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
@Override
public Builder clone() {
try {
return (Builder) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
static Builder fromProperties(Properties properties) {
return new Builder()
.useEvaluator(Boolean.parseBoolean(properties.getProperty("useEvaluator", "true")))
.summarizedStringLength(Integer.parseInt(properties.getProperty("summarizedStringLength", "40")))
.exceptionComposerForRequire(instantiate(ExceptionComposer.ForRequire.class, properties.getProperty("exceptionComposerForRequire", "com.github.valid8j.pcond.validator.ExceptionComposer$ForRequire$Default")))
.exceptionComposerForEnsure(instantiate(ExceptionComposer.ForEnsure.class, properties.getProperty("exceptionComposerForEnsure", "com.github.valid8j.pcond.validator.ExceptionComposer$ForEnsure$Default")))
.defaultExceptionComposerForValidate(instantiate(ExceptionComposer.ForValidate.class, properties.getProperty("defaultExceptionComposerForValidate", "com.github.valid8j.pcond.validator.ExceptionComposer$ForValidate$Default")))
.exceptionComposerForAssert(instantiate(ExceptionComposer.ForAssertion.class, properties.getProperty("exceptionComposerForAssert", "com.github.valid8j.pcond.validator.ExceptionComposer$ForAssertion$Default")))
.exceptionComposerForAssertThat(instantiate(ExceptionComposer.ForTestAssertion.class, properties.getProperty("exceptionComposerForTestFailures", "com.github.valid8j.pcond.validator.ExceptionComposer$ForTestAssertion$JUnit4")))
.messageComposer(instantiate(MessageComposer.class, properties.getProperty("messageComposer", "com.github.valid8j.pcond.validator.MessageComposer$Default")))
.reportComposer(instantiate(ReportComposer.class, properties.getProperty("reportComposer", "com.github.valid8j.pcond.validator.ReportComposer$Default")));
}
}
}
class Impl implements Validator {
private final Configuration configuration;
public Impl(Configuration configuration) {
this.configuration = Objects.requireNonNull(configuration);
}
@Override
public Configuration configuration() {
return this.configuration;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy