You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by tb...@apache.org on 2013/05/28 17:17:19 UTC
svn commit: r1486962 - in
/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller:
internal/ClusterControllerImpl.java utilities/PredicateBuilder.java
Author: tbeerbower
Date: Tue May 28 15:17:19 2013
New Revision: 1486962
URL: http://svn.apache.org/r1486962
Log:
AMBARI-1405 - Improve docs to make PredicateBuilder more usable
Modified:
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterControllerImpl.java
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/PredicateBuilder.java
Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterControllerImpl.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterControllerImpl.java?rev=1486962&r1=1486961&r2=1486962&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterControllerImpl.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterControllerImpl.java Tue May 28 15:17:19 2013
@@ -260,28 +260,28 @@ public class ClusterControllerImpl imple
Iterable<Resource> resources = getResources(type, readRequest, predicate);
PredicateBuilder pb = new PredicateBuilder();
- PredicateBuilder.PredicateBuilderWithPredicate pbWithPredicate = null;
+ PredicateBuilder.PredicateBuilderPredicate pbPredicate = null;
for (Resource resource : resources) {
- if (pbWithPredicate != null) {
- pb = pbWithPredicate.or();
+ if (pbPredicate != null) {
+ pb = pbPredicate.or();
}
- pb = pb.begin();
- pbWithPredicate = null;
+ pb = pb.begin();
+ pbPredicate = null;
for (String keyPropertyId : keyPropertyIds) {
- if (pbWithPredicate != null) {
- pb = pbWithPredicate.and();
+ if (pbPredicate != null) {
+ pb = pbPredicate.and();
}
- pbWithPredicate =
+ pbPredicate =
pb.property(keyPropertyId).equals((Comparable) resource.getPropertyValue(keyPropertyId));
}
- if (pbWithPredicate != null) {
- pbWithPredicate = pbWithPredicate.end();
+ if (pbPredicate != null) {
+ pbPredicate = pbPredicate.end();
}
}
- return pbWithPredicate == null ? null : pbWithPredicate.toPredicate();
+ return pbPredicate == null ? null : pbPredicate.toPredicate();
}
/**
Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/PredicateBuilder.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/PredicateBuilder.java?rev=1486962&r1=1486961&r2=1486962&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/PredicateBuilder.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/PredicateBuilder.java Tue May 28 15:17:19 2013
@@ -32,6 +32,65 @@ import java.util.List;
/**
* Builder for predicates.
+ * <p/>
+ * The builder enforces a domain specific language according to the following
+ * grammar :
+ * <p/>
+ * <predicate> ::= <property_name> <relational_operator> <value>
+ * <predicate> ::= NOT <predicate>
+ * <predicate> ::= ( <predicate> )
+ * <predicate> ::= <predicate> AND <predicate>
+ * <predicate> ::= <predicate> OR <predicate>
+ *
+ * <relational_operator> ::= =|>|<|>=|<=
+ * <p/>
+ * The predicate builder uses the normal method chaining of the builder pattern
+ * along with intermediate objects. The use of intermediate objects allows
+ * for compiler checked constraints.
+ * <p/>
+ * For example, the predicate builder can be used to build a predicate where
+ * property1=="foo" && property2=="bar".
+ *
+ * <pre>
+ * {@code
+ * PredicateBuilder builder = new PredicateBuilder();
+ *
+ * Predicate predicate = builder.property(property1).equals("foo").
+ * and().property(property2).equals("bar").toPredicate();
+ * }
+ * </pre>
+ *
+ * In this example, we are starting with an instance of {@link PredicateBuilder}.
+ * Calling the method {@link PredicateBuilder#property(String)} returns an
+ * instance of {@link PredicateBuilderProperty} which exposes methods for attaching
+ * a relational operator to the property to form a simple predicate.
+ * <p/>
+ * Notice that the method {@link PredicateBuilderProperty#equals(Comparable)}
+ * returns an instance of {@link PredicateBuilderPredicate} which exposes methods
+ * for using predicates with logical operators to create complex predicates.
+ * <p/>
+ * Calling the method {@link PredicateBuilderPredicate#and()} returns an instance
+ * of {@link PredicateBuilder} which allows us to start over building the predicate
+ * for property2.
+ * <p/>
+ * The reason for having these intermediate return objects is that they only
+ * expose the methods that make sense for that point in the building process.
+ * In other words, we can use the compiler to check the syntax of our DSL
+ * grammar at compile time rather than having a single builder class with a
+ * bunch of runtime checks.
+ * <p/>
+ * For example, if the user tries to make an inappropriate call to the and()
+ * method ...
+ *
+ * <pre>
+ * {@code
+ *
+ * Predicate predicate = builder.property(property1).and().
+ * property(property2).equals("bar").toPredicate();
+ * }
+ * </pre>
+ *
+ * ... the compiler will flag it as an error and the code will simply not compile.
*/
public class PredicateBuilder {
@@ -42,47 +101,122 @@ public class PredicateBuilder {
private boolean done = false;
private boolean not = false;
+
+ // ----- Constructors ------------------------------------------------------
+
+ /**
+ * Construct a predicate builder.
+ */
public PredicateBuilder() {
this.outer = null;
}
+ /**
+ * Construct a predicate builder within another predicate builder.
+ *
+ * @param outer the outer predicate builder
+ */
private PredicateBuilder(PredicateBuilder outer) {
this.outer = outer;
}
+
+ // ----- enums ------------------------------------------------------
+
+ /**
+ * Logical operators
+ */
private enum Operator {
And,
Or
}
- public PredicateBuilderWithProperty property(String id) {
+
+ // ----- PredicateBuilder --------------------------------------------------
+
+ /**
+ * Create a property from the given property id. This supports method
+ * chaining by returning an instance of {@link PredicateBuilderProperty}
+ * which is an intermediate object that represents the property in the DSL.
+ *
+ * @param id the property id
+ *
+ * @return a property that can be used in the building of the predicate.
+ *
+ * @throws IllegalStateException if an attempt is made to reuse a predicate builder
+ */
+ public PredicateBuilderProperty property(String id) {
checkDone();
propertyId = id;
- return new PredicateBuilderWithProperty();
+ return new PredicateBuilderProperty();
}
+ /**
+ * Set the builder to negate the predicate being built. This supports method
+ * chaining by returning an instance of {@link PredicateBuilder} which can be
+ * used to continue building the predicate.
+ *
+ * For example, the following shows a usage of the not() method to
+ * produce a predicate where property "p1" does not equal "foo".
+ *
+ * <pre>
+ * {@code
+ * Predicate predicate = builder.not().property("p1").equals("foo").toPredicate();
+ * }
+ * </pre>
+ *
+ * @return a builder to be used to continue building the predicate
+ */
public PredicateBuilder not() {
not = true;
return this;
}
+ /**
+ * Set the builder to begin a block around the predicate being built. Calling this
+ * method is the equivalent of using a left parenthesis. This supports method
+ * chaining by returning an instance of {@link PredicateBuilder} which can be
+ * used to continue building the predicate.
+ *
+ * For example, the following shows a usage of the begin() method to
+ * produce a predicate where p1==foo && (p2==bar || p3 == cat).
+ *
+ * <pre>
+ * {@code
+ * Predicate predicate = builder.property("p1").equals("foo").and().
+ * begin().property("p2").equals("bar").or().property("p3").equals("cat").end().
+ * toPredicate();
+ * }
+ * </pre>
+ *
+ * @return a builder to be used to continue building the predicate
+ *
+ * @throws IllegalStateException if an attempt is made to reuse a predicate builder
+ */
public PredicateBuilder begin() {
checkDone();
return new PredicateBuilder(this);
}
+ /**
+ * Produce a {@link Predicate} object from the builder.
+ *
+ * @return the predicate object
+ */
public Predicate toPredicate() {
return getPredicate();
}
+ // ----- helper methods ----------------------------------------------------
+
private void checkDone() {
if (done) {
throw new IllegalStateException("Can't reuse a predicate builder.");
}
}
- private PredicateBuilderWithPredicate getPredicateBuilderWithPredicate() {
- return new PredicateBuilderWithPredicate();
+ private PredicateBuilderPredicate getPredicateBuilderWithPredicate() {
+ return new PredicateBuilderPredicate();
}
private void addPredicate(Predicate predicate) {
@@ -127,60 +261,212 @@ public class PredicateBuilder {
throw new IllegalStateException("Can't return a predicate.");
}
- public class PredicateBuilderWithProperty {
+ // ----- inner classes -----------------------------------------------------
+
+ // ----- PredicateBuilderProperty ------------------------------------------
- // ----- Equals -----
- public <T>PredicateBuilderWithPredicate equals(Comparable<T> value) {
+ /**
+ * A builder object that represents the property portion of the predicate being built.
+ * The PredicateBuilderProperty is itself a builder object that may be returned for
+ * method chaining of the predicate builder methods.
+ */
+ public class PredicateBuilderProperty {
+
+ /**
+ * Create a {@link PredicateBuilderPredicate} representing an equals
+ * predicate for the property represented by this builder for the given
+ * value. This supports method chaining by returning an instance of
+ * {@link PredicateBuilderPredicate} which can be used to continue building
+ * the predicate.
+ *
+ * For example, the following shows a usage of the equals() method to
+ * produce a predicate where p1==foo.
+ *
+ * <pre>
+ * {@code
+ * Predicate predicate = builder.property("p1").equals("foo").
+ * toPredicate();
+ * }
+ * </pre>
+ *
+ * @param value the right operand (value) of the = operator
+ * @param <T> the type of the property
+ *
+ * @return a new builder representing an equals predicate
+ *
+ * @throws IllegalStateException if no property name was specified on this builder
+ */
+ public <T>PredicateBuilderPredicate equals(Comparable<T> value) {
if (propertyId == null) {
throw new IllegalStateException("No property.");
}
addPredicate(new EqualsPredicate<T>(propertyId, value));
- return new PredicateBuilderWithPredicate();
+ return new PredicateBuilderPredicate();
}
- // ----- Greater than -----
- public <T>PredicateBuilderWithPredicate greaterThan(Comparable<T> value) {
+ /**
+ * Create a {@link PredicateBuilderPredicate} representing an greater than
+ * predicate for the property represented by this builder for the given
+ * value. This supports method chaining by returning an instance of
+ * {@link PredicateBuilderPredicate} which can be used to continue building
+ * the predicate.
+ *
+ * For example, the following shows a usage of the greaterThan() method to
+ * produce a predicate where p1 > 5.
+ *
+ * <pre>
+ * {@code
+ * Predicate predicate = builder.property("p1").greaterThan(5).
+ * toPredicate();
+ * }
+ * </pre>
+ *
+ * @param value the right operand (value) of the > operator
+ * @param <T> the type of the property
+ *
+ * @return a new builder representing a greater than predicate
+ *
+ * @throws IllegalStateException if no property name was specified on this builder
+ */
+ public <T>PredicateBuilderPredicate greaterThan(Comparable<T> value) {
if (propertyId == null) {
throw new IllegalStateException("No property.");
}
addPredicate(new GreaterPredicate<T>(propertyId, value));
- return new PredicateBuilderWithPredicate();
+ return new PredicateBuilderPredicate();
}
- // ----- Greater than equal to -----
- public <T>PredicateBuilderWithPredicate greaterThanEqualTo(Comparable<T> value) {
+ /**
+ * Create a {@link PredicateBuilderPredicate} representing a
+ * greater than or equals predicate for the property represented by this
+ * builder for the given value. This supports method chaining by returning
+ * an instance of {@link PredicateBuilderPredicate} which can be used to
+ * continue building the predicate.
+ *
+ * For example, the following shows a usage of the greaterThanEqualTo()
+ * method to produce a predicate where p1 >= 5.
+ *
+ * <pre>
+ * {@code
+ * Predicate predicate = builder.property("p1").greaterThanEqualTo(5).
+ * toPredicate();
+ * }
+ * </pre>
+ *
+ * @param value the right operand (value) of the >= operator
+ * @param <T> the type of the property
+ *
+ * @return a new builder representing a greater than or equals predicate
+ *
+ * @throws IllegalStateException if no property name was specified on this builder
+ */
+ public <T>PredicateBuilderPredicate greaterThanEqualTo(Comparable<T> value) {
if (propertyId == null) {
throw new IllegalStateException("No property.");
}
addPredicate(new GreaterEqualsPredicate<T>(propertyId, value));
- return new PredicateBuilderWithPredicate();
+ return new PredicateBuilderPredicate();
}
- // ----- Less than -----
- public <T>PredicateBuilderWithPredicate lessThan(Comparable<T> value) {
+ /**
+ * Create a {@link PredicateBuilderPredicate} representing a
+ * less than predicate for the property represented by this builder
+ * for the given value. This supports method chaining by returning
+ * an instance of {@link PredicateBuilderPredicate} which can be used to
+ * continue building the predicate.
+ *
+ * For example, the following shows a usage of the lessThan()
+ * method to produce a predicate where p1 < 5.
+ *
+ * <pre>
+ * {@code
+ * Predicate predicate = builder.property("p1").lessThan(5).
+ * toPredicate();
+ * }
+ * </pre>
+ *
+ * @param value the right operand (value) of the < operator
+ * @param <T> the type of the property
+ *
+ * @return a new builder representing a less than predicate
+ *
+ * @throws IllegalStateException if no property name was specified on this builder
+ */
+ public <T>PredicateBuilderPredicate lessThan(Comparable<T> value) {
if (propertyId == null) {
throw new IllegalStateException("No property.");
}
addPredicate(new LessPredicate<T>(propertyId, value));
- return new PredicateBuilderWithPredicate();
+ return new PredicateBuilderPredicate();
}
- // ----- Less than equal to -----
- public <T>PredicateBuilderWithPredicate lessThanEqualTo(Comparable<T> value) {
+ /**
+ * Create a {@link PredicateBuilderPredicate} representing a
+ * less than or equals predicate for the property represented by this
+ * builder for the given value. This supports method chaining by returning
+ * an instance of {@link PredicateBuilderPredicate} which can be used to
+ * continue building the predicate.
+ *
+ * For example, the following shows a usage of the lessThanEqualTo()
+ * method to produce a predicate where p1 <= 5.
+ *
+ * <pre>
+ * {@code
+ * Predicate predicate = builder.property("p1").lessThanEqualTo(5).
+ * toPredicate();
+ * }
+ * </pre>
+ *
+ * @param value the right operand (value) of the <= operator
+ * @param <T> the type of the property
+ *
+ * @return a new builder representing a less than or equals predicate
+ *
+ * @throws IllegalStateException if no property name was specified on this builder
+ */
+ public <T>PredicateBuilderPredicate lessThanEqualTo(Comparable<T> value) {
if (propertyId == null) {
throw new IllegalStateException("No property.");
}
addPredicate(new LessEqualsPredicate<T>(propertyId, value));
- return new PredicateBuilderWithPredicate();
+ return new PredicateBuilderPredicate();
}
}
- public class PredicateBuilderWithPredicate {
+ // ----- PredicateBuilderPredicate -----------------------------------------
+
+ /**
+ * A builder object that represents an inner predicate portion of the predicate being built.
+ * Note that the predicate represented by an instance of PredicateBuilderPredicate may be
+ * part of a larger complex predicate being built by the predicate builder. The
+ * PredicateBuilderPredicate is itself a builder object that may be returned for method
+ * chaining of the predicate builder methods.
+ */
+ public class PredicateBuilderPredicate {
+
+ /**
+ * Get a {@link PredicateBuilder} object that can be used to build a
+ * predicate that will be ANDed with the predicate represented by this
+ * PredicateBuilderPredicate.
+ *
+ * For example, the following shows a usage of the and() method to
+ * produce a predicate where p1==foo && p2==bar.
+ *
+ * <pre>
+ * {@code
+ * Predicate predicate = builder.property(p1).equals("foo").
+ * and().property(p2).equals("bar").toPredicate();
+ * }
+ * </pre>
+ *
+ * @return a new predicate builder that should be used to build the predicate
+ * being ANDed with the predicate from this builder
+ */
public PredicateBuilder and() {
if (operator != Operator.And) {
@@ -190,6 +476,24 @@ public class PredicateBuilder {
return PredicateBuilder.this;
}
+ /**
+ * Get a {@link PredicateBuilder} object that can be used to build a
+ * predicate that will be ORed with the predicate represented by this
+ * PredicateBuilderPredicate.
+ *
+ * For example, the following shows a usage of the and() method to
+ * produce a predicate where p1==foo || p2==bar.
+ *
+ * <pre>
+ * {@code
+ * Predicate predicate = builder.property(p1).equals("foo").
+ * or().property(p2).equals("bar").toPredicate();
+ * }
+ * </pre>
+ *
+ * @return a new predicate builder that should be used to build the predicate
+ * being ORed with the predicate from this builder
+ */
public PredicateBuilder or() {
if (operator != Operator.Or) {
@@ -199,6 +503,13 @@ public class PredicateBuilder {
return PredicateBuilder.this;
}
+ /**
+ * Produce a {@link Predicate} object from the builder.
+ *
+ * @return the predicate object
+ *
+ * @throws IllegalStateException if the block is unbalanced (missing end call)
+ */
public Predicate toPredicate() {
if (outer != null) {
throw new IllegalStateException("Unbalanced block - missing end.");
@@ -207,7 +518,28 @@ public class PredicateBuilder {
return getPredicate();
}
- public PredicateBuilderWithPredicate end() {
+ /**
+ * Set the builder to end a block around the predicate being built. Calling this
+ * method is the equivalent of using a right parenthesis. This supports method
+ * chaining by returning an instance of {@link PredicateBuilderPredicate} which can
+ * be used to continue building the predicate.
+ *
+ * For example, the following shows a usage of the end() method to
+ * produce a predicate where p1==foo && (p2==bar || p3 == cat).
+ *
+ * <pre>
+ * {@code
+ * Predicate predicate = builder.property("p1").equals("foo").and().
+ * begin().property("p2").equals("bar").or().property("p3").equals("cat").end().
+ * toPredicate();
+ * }
+ * </pre>
+ *
+ * @return a builder to be used to continue building the predicate
+ *
+ * @throws IllegalStateException if the block is unbalanced (missing end call)
+ */
+ public PredicateBuilderPredicate end() {
if (outer == null) {
throw new IllegalStateException("Unbalanced block - missing begin.");
}