Conditions.java
package fr.sii.ogham.core.condition.fluent;
import java.util.List;
import java.util.regex.Pattern;
import fr.sii.ogham.core.condition.AndCondition;
import fr.sii.ogham.core.condition.Condition;
import fr.sii.ogham.core.condition.FixedCondition;
import fr.sii.ogham.core.condition.NotCondition;
import fr.sii.ogham.core.condition.OrCondition;
import fr.sii.ogham.core.condition.PropertyPatternCondition;
import fr.sii.ogham.core.condition.PropertyValueCondition;
import fr.sii.ogham.core.condition.RequiredClassCondition;
import fr.sii.ogham.core.condition.RequiredPropertyCondition;
import fr.sii.ogham.core.env.PropertyResolver;
/**
* Helper to write fluent conditions like:
*
* <pre>
* requiredClass("javax.mail.Transport").and(not(requiredClass("foo.Bar")));
* </pre>
*
* To do this, you need to add the following static import:
*
* <pre>
* import static fr.sii.ogham.core.condition.fluent.Conditions.*;
* </pre>
*
* <p>
* If you are using Java 7, you may need to use {@link MessageConditions}
* instead because Java 7 doesn't resolve correctly generics chaining.
*
* @author Aurélien Baudet
*
*/
public final class Conditions {
/**
* Parenthesis operator to handle priorities:
*
* <pre>
* $(requiredProperty(propertyResolver, "mail.host").or(requiredProperty(propertyResolver, "mail.smtp.host")))
* .and(requiredProperty(propertyResolver, "mail.port").or(requiredProperty(propertyResolver, "mail.smtp.port")))
* </pre>
*
* Meaning "(mail.host is defined OR mail.smtp.host is defined) AND
* (mail.port is defined OR mail.smtp.port is defined)".
*
* <p>
* Without this operator, you had to write this:
*
* <pre>
* requiredProperty(propertyResolver, "mail.host").or(requiredProperty(propertyResolver, "mail.smtp.host"))
* .and(requiredProperty(propertyResolver, "mail.port").or(requiredProperty(propertyResolver, "mail.smtp.port"))
* </pre>
*
* Meaning "mail.host is defined OR mail.smtp.host is defined AND (mail.port
* is defined OR mail.smtp.port is defined)".
*
* So the behavior won't be the same.
*
* @param condition
* the condition to surround
* @param <T>
* the type of the object that is under condition
* @return the fluent condition
*/
@SuppressWarnings("squid:S00100")
public static <T> FluentCondition<T> $(Condition<T> condition) {
return new FluentCondition<>(condition);
}
/**
* And operator between the provided conditions:
*
* <pre>
* and(requiredClass("javax.mail.Transport"), requiredClass("foo.Bar"));
* </pre>
*
* Means that the result will be true only if
* <code>javax.mail.Transport</code> and <code>foo.Bar</code> classes are
* present in the classpath.
*
* <p>
* If one of the condition result is false, then other conditions are not
* evaluated.
* </p>
*
* @param conditions
* one or several conditions
* @param <T>
* the type of the object that is under condition
* @return the fluent condition
*/
@SafeVarargs
public static <T> FluentCondition<T> and(Condition<T>... conditions) {
return new FluentCondition<>(new AndCondition<>(conditions));
}
/**
* And operator between the provided conditions. It is a helper method that
* is useful when you need to construct conditions separately:
*
* <pre>
* List<Condition<Message>> conditions = new ArrayList<>();
* conditions.add(requiredClass("javax.mail.Transport"));
* conditions.add(requiredClass("foo.Bar"));
*
* and(conditions);
* </pre>
*
* Means that the result will be true only if
* <code>javax.mail.Transport</code> and <code>foo.Bar</code> classes are
* present in the classpath.
*
* <p>
* If one of the condition result is false, then other conditions are not
* evaluated.
* </p>
*
* @param conditions
* one or several conditions
* @param <T>
* the type of the object that is under condition
* @return the fluent condition
*/
public static <T> FluentCondition<T> and(List<Condition<T>> conditions) {
return new FluentCondition<>(new AndCondition<>(conditions));
}
/**
* Or operator between the provided conditions:
*
* <pre>
* or(requiredClass("javax.mail.Transport"), requiredClass("foo.Bar"));
* </pre>
*
* Means that the result will be true if either
* <code>javax.mail.Transport</code> or <code>foo.Bar</code> class is
* present in the classpath.
*
* <p>
* If one of the condition result is true, then other conditions are not
* evaluated.
* </p>
*
* @param conditions
* one or several conditions
* @param <T>
* the type of the object that is under condition
* @return the fluent condition
*/
@SafeVarargs
public static <T> FluentCondition<T> or(Condition<T>... conditions) {
return new FluentCondition<>(new OrCondition<>(conditions));
}
/**
* Or operator between the provided conditions. It is a helper method that
* is useful when you need to construct conditions separately:
*
* <pre>
* List<Condition<Message>> conditions = new ArrayList<>();
* conditions.add(requiredClass("javax.mail.Transport"));
* conditions.add(requiredClass("foo.Bar"));
*
* or(conditions);
* </pre>
*
* Means that the result will be true if either
* <code>javax.mail.Transport</code> or <code>foo.Bar</code> class is
* present in the classpath.
*
* <p>
* If one of the condition result is true, then other conditions are not
* evaluated.
* </p>
*
* @param conditions
* one or several conditions
* @param <T>
* the type of the object that is under condition
* @return the fluent condition
*/
public static <T> FluentCondition<T> or(List<Condition<T>> conditions) {
return new FluentCondition<>(new OrCondition<>(conditions));
}
/**
* Not operator to reverse provided condition:
*
* <pre>
* not(requiredClass("javax.mail.Transport));
* </pre>
*
* Means that the result will be true if the class
* <code>javax.mail.Transport</code> is not present in the classpath.
*
* @param condition
* the condition to reverse
* @param <T>
* the type of the object that is under condition
* @return the fluent condition
*/
public static <T> FluentCondition<T> not(Condition<T> condition) {
return new FluentCondition<>(new NotCondition<>(condition));
}
/**
* Check if a property is present in the configuration properties. The
* configuration properties are available through the property resolver.
*
* <pre>
* requiredProperty(propertyResolver, "mail.host");
* </pre>
*
* Means that the result will be true only if the property
* <code>mail.host</code> is present in the property resolver.
*
* @param propertyResolver
* the resolver that is used to access property values
* @param property
* the property name
* @param <T>
* the type of the object that is under condition
* @return the fluent condition
*/
public static <T> FluentCondition<T> requiredProperty(PropertyResolver propertyResolver, String property) {
return new FluentCondition<>(new RequiredPropertyCondition<>(property, propertyResolver));
}
/**
* Check if a property has a particular value in the configuration
* properties. The configuration properties are available through the
* property resolver.
*
* <pre>
* requiredPropertyValue(propertyResolver, "mail.host", "localhost");
* </pre>
*
* Means that the result will be true only if the property
* <code>mail.host</code> is present in the property resolver and its value
* is exactly <code>localhost</code>.
*
* @param propertyResolver
* the resolver that is used to access property values
* @param property
* the property name
* @param value
* the exact value to match
* @param <T>
* the type of the object that is under condition
* @return the fluent condition
*/
public static <T> FluentCondition<T> requiredPropertyValue(PropertyResolver propertyResolver, String property, String value) {
return new FluentCondition<>(new PropertyValueCondition<>(property, value, propertyResolver));
}
/**
* Check if a property value matches the pattern in the configuration
* properties. The configuration properties are available through the
* property resolver.
*
* <pre>
* requiredPropertyValue(propertyResolver, "mail.host", Pattern.compile("local.*"));
* </pre>
*
* Means that the result will be true only if the property
* <code>mail.host</code> is present in the property resolver and its value
* matches the pattern <code>local.*</code>.
*
* @param propertyResolver
* the resolver that is used to access property values
* @param property
* the property name
* @param pattern
* the pattern used to check if the value matches
* @param <T>
* the type of the object that is under condition
* @return the fluent condition
*/
public static <T> FluentCondition<T> requiredPropertyValue(PropertyResolver propertyResolver, String property, Pattern pattern) {
return new FluentCondition<>(new PropertyPatternCondition<>(property, pattern, propertyResolver));
}
/**
* Check if a class is present in the classpath.
*
* <pre>
* requiredClass("javax.mail.Transport");
* </pre>
*
* Means that the result will be true only if the class
* <code>javax.mail.Transport</code> is present in the classpath.
*
* @param className
* the class to check
* @param <T>
* the type of the object that is under condition
* @return the fluent condition
*/
public static <T> FluentCondition<T> requiredClass(String className) {
return new FluentCondition<>(new RequiredClassCondition<>(className));
}
/**
* A condition that always returns true.
*
* @param <T>
* the type of the object that is under condition
* @return the fluent condition
*/
public static <T> FluentCondition<T> alwaysTrue() {
return new FluentCondition<>(new FixedCondition<>(true));
}
/**
* A condition that always returns false.
*
* @param <T>
* the type of the object that is under condition
* @return the fluent condition
*/
public static <T> FluentCondition<T> alwaysFalse() {
return new FluentCondition<>(new FixedCondition<>(false));
}
private Conditions() {
super();
}
}