Skip to content

Commit 547580a

Browse files
author
nicolaiparlog
committed
[!] New class 'ExecuteWhen' builds 'ExecuteAlwaysWhen' and 'ExecuteOnceWhen'. Constructor visibility reduced to package. Also included wildcards were possible and improved comments.
ATTENTION: Unfortunately this revision does not compile! I screwed things up... :(
1 parent 5743975 commit 547580a

File tree

4 files changed

+169
-8
lines changed

4 files changed

+169
-8
lines changed

src/main/java/org/codefx/libfx/concurrent/when/ExecuteAlwaysWhen.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
* If the observable is manipulated by several threads during {@code executeWhen()}, this class does not guarantee that
2525
* the first value to pass the condition is the one handed to the action. Depending on the interaction of those threads
2626
* it might be the initial value or one of several which were set by those threads.
27+
* <p>
28+
* Use {@link ExecuteWhen} to build an instance of this class.
2729
*
2830
* @param <T>
2931
* the type the observed {@link ObservableValue}'s wraps
@@ -66,17 +68,17 @@ public class ExecuteAlwaysWhen<T> {
6668
/**
6769
* The condition the {@link #observable}'s value must fulfill for {@link #action} to be executed.
6870
*/
69-
private final Predicate<T> condition;
71+
private final Predicate<? super T> condition;
7072

7173
/**
7274
* The action which will be executed.
7375
*/
74-
private final Consumer<T> action;
76+
private final Consumer<? super T> action;
7577

7678
/**
7779
* The listener which executes {@link #action} and sets {@link #alreadyExecuted} accordingly.
7880
*/
79-
private final ChangeListener<T> listenerWhichExecutesAction;
81+
private final ChangeListener<? super T> listenerWhichExecutesAction;
8082

8183
/**
8284
* Indicates whether {@link #executeWhen()} was already called. If so, it can not be called again.
@@ -107,7 +109,7 @@ public class ExecuteAlwaysWhen<T> {
107109
* @param action
108110
* the action which will be executed
109111
*/
110-
public ExecuteAlwaysWhen(ObservableValue<T> observable, Predicate<T> condition, Consumer<T> action) {
112+
ExecuteAlwaysWhen(ObservableValue<T> observable, Predicate<? super T> condition, Consumer<? super T> action) {
111113
this.observable = observable;
112114
this.condition = condition;
113115
this.action = action;

src/main/java/org/codefx/libfx/concurrent/when/ExecuteOnceWhen.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
* If the observable is manipulated by several threads, this class does not guarantee that the first value to pass the
2424
* condition is the one handed to the action. Depending on the interaction of those threads it might be the initial
2525
* value (the one tested during {@code executeWhen()}) or one of several which were set by those threads.
26-
*
26+
* <p>
27+
* Use {@link ExecuteWhen} to build an instance of this class.
28+
*
2729
* @param <T>
2830
* the type the observed {@link ObservableValue}'s wraps
2931
*/
@@ -56,12 +58,12 @@ public class ExecuteOnceWhen<T> {
5658
/**
5759
* The condition the {@link #observable}'s value must fulfill for {@link #action} to be executed.
5860
*/
59-
private final Predicate<T> condition;
61+
private final Predicate<? super T> condition;
6062

6163
/**
6264
* The action which will be executed.
6365
*/
64-
private final Consumer<T> action;
66+
private final Consumer<? super T> action;
6567

6668
/**
6769
* Indicates whether {@link #action} might still be executed at some point in the future. Is used to prevent the
@@ -93,7 +95,7 @@ public class ExecuteOnceWhen<T> {
9395
* @param action
9496
* the action which will be executed
9597
*/
96-
public ExecuteOnceWhen(ObservableValue<T> observable, Predicate<T> condition, Consumer<T> action) {
98+
ExecuteOnceWhen(ObservableValue<T> observable, Predicate<? super T> condition, Consumer<? super T> action) {
9799
this.observable = observable;
98100
this.condition = condition;
99101
this.action = action;
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
package org.codefx.libfx.concurrent.when;
2+
3+
import java.util.Objects;
4+
import java.util.Optional;
5+
import java.util.function.Consumer;
6+
import java.util.function.Predicate;
7+
8+
import javafx.beans.value.ObservableValue;
9+
10+
/**
11+
* Builder for {@link ExecuteAlwaysWhen} and {@link ExecuteOnceWhen}.
12+
* <p>
13+
* <h2>Example</h2>A typical use would look like this:
14+
*
15+
* <pre>
16+
* ObservableValue<State> workerState;
17+
* ExecuteWhen.on(workerState)
18+
* .when(state -> state == State.SUCCEEDED)
19+
* .thenOnce(state -> logSuccess())
20+
* .executeWhen();
21+
* </pre>
22+
*
23+
* @param <T>
24+
* the type the {@link ObservableValue} which will be observed by the constructed instance wraps
25+
*/
26+
public class ExecuteWhen<T> {
27+
28+
// #region FIELDS
29+
30+
/**
31+
* The {@link ObservableValue} upon whose value the action's execution depends.
32+
*/
33+
private final ObservableValue<T> observable;
34+
35+
/**
36+
* The condition the {@link #observable}'s value must fulfill for the action to be executed.
37+
*/
38+
private Optional<Predicate<? super T>> condition;
39+
40+
// #end FIELDS
41+
42+
// #region CONSTRUCTION
43+
44+
/**
45+
* Creates a new instance for the specified observable
46+
*
47+
* @param observable
48+
* the {@link ObservableValue} which will be observed by the created {@code Execute...When} instances
49+
*/
50+
private ExecuteWhen(ObservableValue<T> observable) {
51+
this.observable = observable;
52+
condition = Optional.empty();
53+
}
54+
55+
/**
56+
* Creates a new builder. The built instance of {@code Execute...When} will observe the specified observable.
57+
*
58+
* @param <T>
59+
* the type the {@link ObservableValue} which will be observed by the constructed instance wraps
60+
* @param observable
61+
* the {@link ObservableValue} which will be observed by the created {@code Execute...When} instances
62+
* @return a new builder instance
63+
*/
64+
public static <T> ExecuteWhen<T> on(ObservableValue<T> observable) {
65+
return new ExecuteWhen<>(observable);
66+
}
67+
68+
// #end CONSTRUCTION
69+
70+
// #region SETTING VALUES
71+
72+
/**
73+
* Specifies the condition the observable's value must fulfill in order for the action to be executed.
74+
*
75+
* @param condition
76+
* the condition as a {@link Predicate}
77+
* @return this builder
78+
*/
79+
public ExecuteWhen<T> when(Predicate<? super T> condition) {
80+
Objects.requireNonNull(condition, "The argument 'condition' must not be null.");
81+
this.condition = Optional.of(condition);
82+
return this;
83+
}
84+
85+
// #end SETTING VALUES
86+
87+
// #region BUILD
88+
89+
/**
90+
* Creates an instance which:
91+
* <ul>
92+
* <li>observes the {@link ObservableValue} (specified for this builder's construction) for new values
93+
* <li>checks each new value against the condition set with {@link #when(Predicate)} (calling which is required)
94+
* <li>executes the specified {@code action} once if a value fulfills the condition
95+
* </ul>
96+
* Note that the observation does not start until {@link ExecuteOnceWhen#executeWhen()} is called. See
97+
* {@link ExecuteOnceWhen} for details.
98+
*
99+
* @param action
100+
* the {@link Consumer} of the value which passed the condition
101+
* @return an instance of {@link ExecuteOnceWhen}
102+
* @throws IllegalStateException
103+
* if {@link #when(Predicate)} was not called
104+
*/
105+
public ExecuteOnceWhen<T> thenOnce(Consumer<? super T> action) throws IllegalStateException {
106+
ensureConditionWasSet();
107+
return new ExecuteOnceWhen<T>(observable, condition.get(), action);
108+
}
109+
110+
/**
111+
* Creates an instance which:
112+
* <ul>
113+
* <li>observes the {@link ObservableValue} (specified for this builder's construction) for new values
114+
* <li>checks each new value against the condition set with {@link #when(Predicate)} (calling which is required)
115+
* <li>executes the specified {@code action} every time a value fulfills the condition
116+
* </ul>
117+
* Note that the observation does not start until {@link ExecuteAlwaysWhen#executeWhen()} is called. See
118+
* {@link ExecuteAlwaysWhen} for details.
119+
*
120+
* @param action
121+
* the {@link Consumer} of the value which passed the condition
122+
* @return an instance of {@link ExecuteOnceWhen}
123+
* @throws IllegalStateException
124+
* if {@link #when(Predicate)} was not called
125+
*/
126+
public ExecuteAlwaysWhen<T> thenAlways(Consumer<? super T> action) throws IllegalStateException {
127+
ensureConditionWasSet();
128+
return new ExecuteAlwaysWhen<T>(observable, condition.get(), action);
129+
}
130+
131+
/**
132+
* Makes sure that {@link #condition} was set, i.e. the {@link Optional} is not empty.
133+
*
134+
* @throws IllegalStateException
135+
* if {@link #condition} was not set
136+
*/
137+
private void ensureConditionWasSet() throws IllegalStateException {
138+
boolean noCondition = !condition.isPresent();
139+
if (noCondition)
140+
throw new IllegalStateException(
141+
"Set a condition with 'when(Predicate<? super T>)' before calling any 'then' method.");
142+
}
143+
144+
// #end BUILD
145+
146+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* With {@link org.codefx.libfx.concurrent.when.ExecuteOnceWhen ExecuteOnceWhen} and
3+
* {@link org.codefx.libfx.concurrent.when.ExecuteAlwaysWhen ExecuteAlwaysWhen} this package provides two classes which
4+
* help to make sure some action which is triggered by a change on an {@link javafx.beans.value.ObservableValue
5+
* ObservableValue} gets executed under threading. Refer to the two classes for a detailed description.
6+
* <p>
7+
* Instances of those classes can be built with {@link org.codefx.libfx.concurrent.when.ExecuteWhen ExecuteWhen}.
8+
*
9+
* @see org.codefx.libfx.concurrent.when.ExecuteWhen ExecuteWhen
10+
*/
11+
package org.codefx.libfx.concurrent.when;

0 commit comments

Comments
 (0)