Skip to content

Commit 1f2c816

Browse files
authored
Fixes dependency on concrete impl and code smells (#312)
* Fixes dependency on concrete impl and code smells * Moved Switcher operations from Builder to interface * Removed get optional state from Switcher minimal contract
1 parent 900bdd5 commit 1f2c816

File tree

8 files changed

+181
-110
lines changed

8 files changed

+181
-110
lines changed

src/main/java/com/github/switcherapi/client/SwitcherContextBase.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,8 @@ public static void watchSnapshot(SnapshotEventHandler handler) {
310310
}
311311

312312
if (watcher == null) {
313-
watcher = new SnapshotWatcher((SwitcherLocalService) instance, handler);
313+
watcher = new SnapshotWatcher((SwitcherLocalService) instance, handler,
314+
contextStr(ContextKey.SNAPSHOT_LOCATION));
314315
}
315316

316317
initWatcherExecutorService();

src/main/java/com/github/switcherapi/client/model/AsyncSwitcher.java

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,16 @@ public class AsyncSwitcher implements Runnable {
2424

2525
private final ExecutorService executorService;
2626

27-
private final Switcher switcher;
27+
private final SwitcherInterface switcherInterface;
28+
29+
private final long delay;
2830

2931
private long nextRun = 0;
3032

31-
public AsyncSwitcher(final Switcher switcher) {
33+
public AsyncSwitcher(final SwitcherInterface switcherInterface, long delay) {
3234
this.executorService = Executors.newCachedThreadPool();
33-
this.switcher = switcher;
35+
this.switcherInterface = switcherInterface;
36+
this.delay = delay;
3437
}
3538

3639
/**
@@ -43,19 +46,21 @@ public synchronized void execute() {
4346
if (nextRun < System.currentTimeMillis()) {
4447
SwitcherUtils.debug(logger, "Running AsyncSwitcher");
4548

46-
this.nextRun = System.currentTimeMillis() + switcher.delay;
49+
this.nextRun = System.currentTimeMillis() + this.delay;
4750
this.executorService.submit(this);
4851
}
4952
}
5053

5154
@Override
5255
public void run() {
5356
try {
54-
final CriteriaResponse response = switcher.getContext().executeCriteria(switcher);
55-
switcher.getHistoryExecution().removeIf(item ->
56-
switcher.getSwitcherKey().equals(item.getSwitcherKey()) &&
57-
switcher.getEntry().equals(item.getEntry()));
58-
switcher.getHistoryExecution().add(response);
57+
final CriteriaResponse response = switcherInterface.executeCriteria();
58+
59+
switcherInterface.getHistoryExecution().removeIf(item ->
60+
switcherInterface.getSwitcherKey().equals(item.getSwitcherKey()) &&
61+
switcherInterface.getEntry().equals(item.getEntry()));
62+
63+
switcherInterface.getHistoryExecution().add(response);
5964
} catch (SwitcherException e) {
6065
logger.error(e);
6166
}

src/main/java/com/github/switcherapi/client/model/Switcher.java

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,6 @@ public Switcher(final String switcherKey, final SwitcherExecutor context) {
4242
this.switcherKey = switcherKey;
4343
this.historyExecution = new HashSet<>();
4444
}
45-
46-
private boolean canUseAsync() {
47-
return super.delay > 0 && !this.historyExecution.isEmpty();
48-
}
49-
50-
private Optional<CriteriaResponse> getFromHistory() {
51-
for (CriteriaResponse criteriaResponse : historyExecution) {
52-
if (criteriaResponse.getEntry().equals(getEntry())) {
53-
return Optional.of(criteriaResponse);
54-
}
55-
}
56-
return Optional.empty();
57-
}
5845

5946
@Override
6047
public Switcher build() {
@@ -103,7 +90,7 @@ public CriteriaResponse submit() throws SwitcherException {
10390

10491
if (canUseAsync()) {
10592
if (asyncSwitcher == null) {
106-
asyncSwitcher = new AsyncSwitcher(this);
93+
asyncSwitcher = new AsyncSwitcher(this, super.delay);
10794
}
10895

10996
asyncSwitcher.execute();
@@ -117,6 +104,26 @@ public CriteriaResponse submit() throws SwitcherException {
117104
this.historyExecution.add(response);
118105
return response;
119106
}
107+
108+
@Override
109+
public CriteriaResponse executeCriteria() {
110+
return this.context.executeCriteria(this);
111+
}
112+
113+
@Override
114+
public synchronized Set<CriteriaResponse> getHistoryExecution() {
115+
return this.historyExecution;
116+
}
117+
118+
@Override
119+
public String getSwitcherKey() {
120+
return this.switcherKey;
121+
}
122+
123+
@Override
124+
public List<Entry> getEntry() {
125+
return this.entry;
126+
}
120127

121128
/**
122129
* This method builds up the request made by the client to reach the Switcher API.
@@ -129,24 +136,29 @@ public GsonInputRequest getInputRequest() {
129136
this.entry.toArray(new Entry[0]) : null);
130137
}
131138

132-
public boolean isBypassMetrics() {
133-
return bypassMetrics;
134-
}
135-
136-
public String getSwitcherKey() {
137-
return this.switcherKey;
139+
public long getDelay() {
140+
return super.delay;
138141
}
139142

140-
public List<Entry> getEntry() {
141-
return this.entry;
143+
public boolean isBypassMetrics() {
144+
return bypassMetrics;
142145
}
143146

144147
public void resetEntry() {
145148
this.entry = new ArrayList<>();
146149
}
147150

148-
public synchronized Set<CriteriaResponse> getHistoryExecution() {
149-
return this.historyExecution;
151+
private boolean canUseAsync() {
152+
return super.delay > 0 && !this.historyExecution.isEmpty();
153+
}
154+
155+
private Optional<CriteriaResponse> getFromHistory() {
156+
for (CriteriaResponse criteriaResponse : historyExecution) {
157+
if (criteriaResponse.getEntry().equals(getEntry())) {
158+
return Optional.of(criteriaResponse);
159+
}
160+
}
161+
return Optional.empty();
150162
}
151163

152164
@Override

src/main/java/com/github/switcherapi/client/model/SwitcherBuilder.java

Lines changed: 1 addition & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
package com.github.switcherapi.client.model;
22

3-
import com.github.switcherapi.client.SwitcherContext;
43
import com.github.switcherapi.client.SwitcherExecutor;
54
import com.github.switcherapi.client.exception.SwitcherContextException;
6-
import com.github.switcherapi.client.exception.SwitcherException;
7-
import com.github.switcherapi.client.model.response.CriteriaResponse;
85
import org.apache.commons.lang3.StringUtils;
96

107
import java.util.ArrayList;
@@ -16,7 +13,7 @@
1613
*
1714
* @author Roger Floriano (petruki)
1815
*/
19-
public abstract class SwitcherBuilder {
16+
public abstract class SwitcherBuilder implements SwitcherInterface {
2017

2118
protected final SwitcherExecutor context;
2219

@@ -170,68 +167,6 @@ public SwitcherBuilder bypassMetrics() {
170167
return this;
171168
}
172169

173-
/**
174-
* This method builds the Switcher object.<br>
175-
* Uses to isolate Switcher creation from the execution.<br>
176-
*
177-
* For example:
178-
* <pre>
179-
* Switcher switcher = SwitcherContext
180-
* .getSwitcher(MY_SWITCHER)
181-
* .remote(true)
182-
* .throttle(1000)
183-
* .checkValue("value")
184-
* .build();
185-
* </pre>
186-
*
187-
* @return {@link Switcher}
188-
*/
189-
public abstract Switcher build();
190-
191-
/**
192-
* Prepare the Switcher including a list of inputs necessary to run the criteria afterward.
193-
*
194-
* @param entry input object
195-
* @return {@link Switcher}
196-
*/
197-
public abstract Switcher prepareEntry(final List<Entry> entry);
198-
199-
/**
200-
* Prepare the Switcher including a list of inputs necessary to run the criteria afterward.
201-
*
202-
* @param entry input object
203-
* @param add if false, the list will be cleaned and the entry provided will be the only input for this Switcher.
204-
* @return {@link Switcher}
205-
*/
206-
public abstract Switcher prepareEntry(final Entry entry, final boolean add);
207-
208-
/**
209-
* It adds an input to the list of inputs.
210-
* <br>Under the table it calls {@link #prepareEntry(Entry, boolean)} passing true to the second argument.
211-
*
212-
* @param entry input object
213-
* @return {@link Switcher}
214-
*/
215-
public abstract Switcher prepareEntry(final Entry entry);
216-
217-
/**
218-
* Execute criteria based on a given switcher key provided via {@link SwitcherContext#getSwitcher(String)}.
219-
* <br>The detailed result is available in list of {@link CriteriaResponse}.
220-
*
221-
* @return criteria result
222-
* @throws SwitcherException connectivity or criteria errors regarding reading malformed snapshots
223-
*/
224-
public abstract boolean isItOn() throws SwitcherException;
225-
226-
/**
227-
* Execute criteria based on a given switcher key provided via {@link SwitcherContext#getSwitcher(String)}.
228-
* <br>The detailed result is available in list of {@link CriteriaResponse}.
229-
*
230-
* @return {@link CriteriaResponse}
231-
* @throws SwitcherException connectivity or criteria errors regarding reading malformed snapshots
232-
*/
233-
public abstract CriteriaResponse submit() throws SwitcherException;
234-
235170
public boolean isRemote() {
236171
return remote;
237172
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package com.github.switcherapi.client.model;
2+
3+
import com.github.switcherapi.client.SwitcherContext;
4+
import com.github.switcherapi.client.exception.SwitcherException;
5+
import com.github.switcherapi.client.model.response.CriteriaResponse;
6+
7+
import java.util.List;
8+
import java.util.Set;
9+
10+
/**
11+
* Defines minimal contract for Switcher implementations for:
12+
*
13+
* <ul>
14+
* <li>Switcher creation</li>
15+
* <li>Switcher execution</li>
16+
* <li>Switcher get input/output</li>
17+
* </ul>
18+
*/
19+
public interface SwitcherInterface {
20+
21+
/**
22+
* This method builds the Switcher object.<br>
23+
* Uses to isolate Switcher creation from the execution.<br>
24+
*
25+
* For example:
26+
* <pre>
27+
* Switcher switcher = SwitcherContext
28+
* .getSwitcher(MY_SWITCHER)
29+
* .remote(true)
30+
* .throttle(1000)
31+
* .checkValue("value")
32+
* .build();
33+
* </pre>
34+
*
35+
* @return {@link Switcher}
36+
*/
37+
Switcher build();
38+
39+
/**
40+
* Prepare the Switcher including a list of inputs necessary to run the criteria afterward.
41+
*
42+
* @param entry input object
43+
* @return {@link Switcher}
44+
*/
45+
Switcher prepareEntry(final List<Entry> entry);
46+
47+
/**
48+
* Prepare the Switcher including a list of inputs necessary to run the criteria afterward.
49+
*
50+
* @param entry input object
51+
* @param add if false, the list will be cleaned and the entry provided will be the only input for this Switcher.
52+
* @return {@link Switcher}
53+
*/
54+
Switcher prepareEntry(final Entry entry, final boolean add);
55+
56+
/**
57+
* It adds an input to the list of inputs.
58+
* <br>Under the table it calls {@link #prepareEntry(Entry, boolean)} passing true to the second argument.
59+
*
60+
* @param entry input object
61+
* @return {@link Switcher}
62+
*/
63+
Switcher prepareEntry(final Entry entry);
64+
65+
/**
66+
* Execute criteria based on a given switcher key provided via {@link SwitcherContext#getSwitcher(String)}.
67+
* <br>The detailed result is available in list of {@link CriteriaResponse}.
68+
*
69+
* @return criteria result
70+
* @throws SwitcherException connectivity or criteria errors regarding reading malformed snapshots
71+
*/
72+
boolean isItOn() throws SwitcherException;
73+
74+
/**
75+
* Execute criteria based on a given switcher key provided via {@link SwitcherContext#getSwitcher(String)}.
76+
* <br>The detailed result is available in list of {@link CriteriaResponse}.
77+
*
78+
* @return {@link CriteriaResponse}
79+
* @throws SwitcherException connectivity or criteria errors regarding reading malformed snapshots
80+
*/
81+
CriteriaResponse submit() throws SwitcherException;
82+
83+
/**
84+
* Execute the criteria evaluation.
85+
*
86+
* @return the criteria response
87+
*/
88+
CriteriaResponse executeCriteria();
89+
90+
/**
91+
* Get the history of executions.
92+
*
93+
* @return the history of executions
94+
*/
95+
Set<CriteriaResponse> getHistoryExecution();
96+
97+
/**
98+
* Get the key of the switcher.
99+
*
100+
* @return the key of the switcher
101+
*/
102+
String getSwitcherKey();
103+
104+
/**
105+
* Get the entry input list for the switcher.
106+
*
107+
* @return the entry of the switcher
108+
*/
109+
List<Entry> getEntry();
110+
111+
}

src/main/java/com/github/switcherapi/client/model/response/CriteriaResponse.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ public CriteriaResponse buildFromSwitcher(Switcher switcher) {
4747
this.entry = switcher.getEntry();
4848

4949
if (Objects.nonNull(entry)) {
50-
for (Entry entry : entry) {
51-
if (entryWhen.containsKey(entry.getStrategy()) && !entryWhen.get(entry.getStrategy()).contains(entry.getInput())) {
50+
for (Entry inputEntry : entry) {
51+
if (!isEntryMatching(inputEntry)) {
5252
return new CriteriaResponse(!this.result, this.reason, switcher);
5353
}
5454
}
@@ -57,6 +57,11 @@ public CriteriaResponse buildFromSwitcher(Switcher switcher) {
5757
return this;
5858
}
5959

60+
private boolean isEntryMatching(Entry inputEntry) {
61+
return entryWhen.containsKey(inputEntry.getStrategy()) &&
62+
entryWhen.get(inputEntry.getStrategy()).contains(inputEntry.getInput());
63+
}
64+
6065
public static CriteriaResponse buildFromDefault(Switcher switcher) {
6166
return new CriteriaResponse(Boolean.parseBoolean(switcher.getDefaultResult()), DEFAULT_REASON, switcher);
6267
}

src/main/java/com/github/switcherapi/client/test/SwitcherTestExtension.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ public Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContex
3434
SwitcherTest switcherTest = context.getRequiredTestMethod().getAnnotation(SwitcherTest.class);
3535

3636
if (switcherTest.abTest()) {
37-
final SwitcherTestTemplate templateA = new SwitcherTestTemplate(switcherTest, true);
38-
final SwitcherTestTemplate templateB = new SwitcherTestTemplate(switcherTest);
39-
return Stream.of(templateA, templateB);
37+
return Stream.of(
38+
new SwitcherTestTemplate(switcherTest, true),
39+
new SwitcherTestTemplate(switcherTest));
4040
}
4141

4242
final SwitcherTestTemplate template = new SwitcherTestTemplate(switcherTest);

0 commit comments

Comments
 (0)