Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import com.github.switcherapi.client.exception.SwitcherKeyNotFoundException;
import com.github.switcherapi.client.exception.SwitchersValidationException;
import com.github.switcherapi.client.model.ContextKey;
import com.github.switcherapi.client.model.Switcher;
import com.github.switcherapi.client.model.SwitcherRequest;

/**
* <b>Switcher Context</b>
Expand Down Expand Up @@ -54,7 +54,7 @@ public static void initializeClient() {
* @return a ready to use Switcher
* @throws SwitcherKeyNotFoundException in case the key was not properly loaded
*/
public static Switcher getSwitcher(String key, boolean keepEntries) {
public static SwitcherRequest getSwitcher(String key, boolean keepEntries) {
return SwitcherContextBase.getSwitcher(key, keepEntries);
}

Expand All @@ -64,7 +64,7 @@ public static Switcher getSwitcher(String key, boolean keepEntries) {
* @param key name
* @return a ready to use Switcher
*/
public static Switcher getSwitcher(String key) {
public static SwitcherRequest getSwitcher(String key) {
return SwitcherContextBase.getSwitcher(key);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import com.github.switcherapi.client.exception.SwitcherKeyNotFoundException;
import com.github.switcherapi.client.exception.SwitchersValidationException;
import com.github.switcherapi.client.model.ContextKey;
import com.github.switcherapi.client.model.Switcher;
import com.github.switcherapi.client.model.SwitcherRequest;
import com.github.switcherapi.client.remote.ClientWS;
import com.github.switcherapi.client.remote.ClientWSImpl;
import com.github.switcherapi.client.service.SwitcherValidator;
Expand Down Expand Up @@ -85,7 +85,7 @@ public abstract class SwitcherContextBase extends SwitcherConfig {

protected static SwitcherProperties switcherProperties;
protected static Set<String> switcherKeys;
protected static Map<String, Switcher> switchers;
protected static Map<String, SwitcherRequest> switchers;
protected static SwitcherExecutor instance;
private static ScheduledExecutorService scheduledExecutorService;
private static ExecutorService watcherExecutorService;
Expand Down Expand Up @@ -257,7 +257,7 @@ private static void loadSwitchers() {

switchers.clear();
for (String key : switcherKeys) {
switchers.put(key, new Switcher(key, instance));
switchers.put(key, new SwitcherRequest(key, instance));
}
}

Expand Down Expand Up @@ -353,14 +353,14 @@ private static ClientWS initRemotePoolExecutorService() {
* @return a ready to use Switcher
* @throws SwitcherKeyNotFoundException in case the key was not properly loaded
*/
public static Switcher getSwitcher(String key, boolean keepEntries) {
public static SwitcherRequest getSwitcher(String key, boolean keepEntries) {
SwitcherUtils.debug(logger, "key: {} - keepEntries: {}", key, keepEntries);

if (!switchers.containsKey(key)) {
throw new SwitcherKeyNotFoundException(key);
}

final Switcher switcher = switchers.get(key);
final SwitcherRequest switcher = switchers.get(key);
if (!keepEntries) {
switcher.resetEntry();
}
Expand All @@ -374,7 +374,7 @@ public static Switcher getSwitcher(String key, boolean keepEntries) {
* @param key name
* @return a ready to use Switcher
*/
public static Switcher getSwitcher(String key) {
public static SwitcherRequest getSwitcher(String key) {
return getSwitcher(key, false);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import com.github.switcherapi.client.exception.SwitcherRemoteException;
import com.github.switcherapi.client.exception.SwitcherSnapshotWriteException;
import com.github.switcherapi.client.model.ContextKey;
import com.github.switcherapi.client.model.Switcher;
import com.github.switcherapi.client.model.SwitcherRequest;
import com.github.switcherapi.client.model.criteria.Domain;
import com.github.switcherapi.client.model.criteria.Snapshot;
import com.github.switcherapi.client.model.SwitcherResult;
Expand Down Expand Up @@ -47,7 +47,7 @@ protected SwitcherExecutor(final SwitcherProperties switcherProperties) {
* @param switcher to be evaluated
* @return Criteria response containing the evaluation details
*/
public abstract SwitcherResult executeCriteria(final Switcher switcher);
public abstract SwitcherResult executeCriteria(final SwitcherRequest switcher);

/**
* Check the snapshot versions against the Remote configuration.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,27 @@
* @since 2021-11-27
*
*/
public class AsyncSwitcher<T> {
public class AsyncSwitcher {

private static final Logger logger = LoggerFactory.getLogger(AsyncSwitcher.class);

private final ExecutorService executorService;

private final SwitcherInterface<T> switcherInterface;
private final Switcher switcher;

private final long delay;

private long nextRun = 0;

public AsyncSwitcher(final SwitcherInterface<T> switcherInterface, long delay) {
public AsyncSwitcher(final Switcher switcher, long delay) {
this.executorService = Executors.newCachedThreadPool(r -> {
Thread thread = new Thread(r);
thread.setName(SWITCHER_ASYNC_WORKER.toString());
thread.setDaemon(true);
return thread;
});

this.switcherInterface = switcherInterface;
this.switcher = switcher;
this.delay = delay;
}

Expand All @@ -59,8 +59,8 @@ public synchronized void execute() {

public void run() {
try {
final SwitcherResult response = switcherInterface.executeCriteria();
switcherInterface.updateHistoryExecution(response);
final SwitcherResult response = switcher.executeCriteria();
switcher.updateHistoryExecution(response);
} catch (SwitcherException e) {
logger.error(e.getMessage(), e);
}
Expand Down
223 changes: 88 additions & 135 deletions src/main/java/com/github/switcherapi/client/model/Switcher.java
Original file line number Diff line number Diff line change
@@ -1,157 +1,110 @@
package com.github.switcherapi.client.model;

import com.github.switcherapi.client.SwitcherContext;
import com.github.switcherapi.client.SwitcherExecutor;
import com.github.switcherapi.client.exception.SwitcherException;

import java.util.*;
import java.util.List;

/**
* Switchers are the entry point to evaluate criteria and return the result.
* <br>To execute a criteria evaluation, use one of the available methods: {@link #isItOn()}.
*
* @author Roger Floriano (petruki)
* @since 2019-12-24
*
* @see #isItOn()
* @see #submit()
* The API that handles the switcher operations.
*
* <ul>
* <li>Switcher creation</li>
* <li>Switcher execution</li>
* <li>Switcher get input/output</li>
* </ul>
*/
public final class Switcher extends SwitcherBuilder {

public static final String KEY = "key";

public static final String SHOW_REASON = "showReason";

public static final String BYPASS_METRIC = "bypassMetric";
public interface Switcher {

private final SwitcherExecutor context;

private final String switcherKey;

private final Set<SwitcherResult> historyExecution;

private AsyncSwitcher<Switcher> asyncSwitcher;

/**
* Use {@link SwitcherContext#getSwitcher(String)} to create this object.
*
* @param switcherKey name of the key created
* @param context client context in which the switcher will be executed (local/remote)
* This method builds the Switcher object.<br>
* Uses to isolate Switcher creation from the execution.<br>
*
* For example:
* <pre>
* Switcher switcher = SwitcherContext
* .getSwitcher(MY_SWITCHER)
* .remote(true)
* .throttle(1000)
* .checkValue("value")
* .build();
* </pre>
*
* @return instance of SwitcherInterface
* @see SwitcherRequest
*/
public Switcher(final String switcherKey, final SwitcherExecutor context) {
super(context.getSwitcherProperties());
this.context = context;
this.switcherKey = switcherKey;
this.historyExecution = new HashSet<>();
this.entry = new ArrayList<>();
}

@Override
public Switcher build() {
return this;
}

@Override
public Switcher prepareEntry(final List<Entry> entry) {
this.entry = Optional.ofNullable(entry).orElse(new ArrayList<>());
return this;
}

@Override
public Switcher prepareEntry(final Entry entry, final boolean add) {
if (!add) {
this.entry.clear();
}

if (!this.entry.contains(entry)) {
this.entry.add(entry);
}

return this;
}

@Override
public Switcher prepareEntry(final Entry entry) {
return this.prepareEntry(entry, false);
}

@Override
public boolean isItOn() throws SwitcherException {
final SwitcherResult response = submit();
return response.isItOn();
}

@Override
public SwitcherResult submit() throws SwitcherException {
if (SwitcherExecutor.getBypass().containsKey(switcherKey)) {
return SwitcherExecutor.getBypass().get(switcherKey).buildFromSwitcher(switcherKey, entry);
}

if (canUseAsync()) {
if (Objects.isNull(asyncSwitcher)) {
asyncSwitcher = new AsyncSwitcher<>(this, super.delay);
}

asyncSwitcher.execute();
final Optional<SwitcherResult> response = getFromHistory();
if (response.isPresent()) {
return response.get();
}
}

final SwitcherResult response = this.context.executeCriteria(this);
this.updateHistoryExecution(response);
return response;
}
Switcher build();

@Override
public SwitcherResult executeCriteria() {
return this.context.executeCriteria(this);
}
/**
* Prepare the Switcher including a list of inputs necessary to run the criteria afterward.
*
* @param entry input object
* @return instance of SwitcherInterface
*/
Switcher prepareEntry(final List<Entry> entry);

@Override
public void updateHistoryExecution(final SwitcherResult response) {
this.historyExecution.removeIf(item ->
this.switcherKey.equals(item.getSwitcherKey()) && this.entry.equals(item.getEntry()));
/**
* Prepare the Switcher including a list of inputs necessary to run the criteria afterward.
*
* @param entry input object
* @param add if false, the list will be cleaned and the entry provided will be the only input for this Switcher.
* @return instance of SwitcherInterface
*/
Switcher prepareEntry(final Entry entry, final boolean add);

this.historyExecution.add(response);
}
/**
* It adds an input to the list of inputs.
* <br>Under the table it calls {@link #prepareEntry(Entry, boolean)} passing true to the second argument.
*
* @param entry input object
* @return instance of SwitcherInterface
*/
Switcher prepareEntry(final Entry entry);

@Override
public String getSwitcherKey() {
return this.switcherKey;
}
/**
* Execute criteria based on a given switcher key provided via {@link SwitcherContext#getSwitcher(String)}.
* <br>The detailed result is available in list of {@link SwitcherResult}.
*
* @return criteria result
* @throws SwitcherException connectivity or criteria errors regarding reading malformed snapshots
*/
boolean isItOn() throws SwitcherException;

@Override
public List<Entry> getEntry() {
return this.entry;
}
/**
* Execute criteria based on a given switcher key provided via {@link SwitcherContext#getSwitcher(String)}.
* <br>The detailed result is available in list of {@link SwitcherResult}.
*
* @return {@link SwitcherResult}
* @throws SwitcherException connectivity or criteria errors regarding reading malformed snapshots
*/
SwitcherResult submit() throws SwitcherException;

public boolean isBypassMetrics() {
return bypassMetrics;
}

public void resetEntry() {
this.entry = new ArrayList<>();
}
/**
* Execute the criteria evaluation.
*
* @return the switcher result
*/
SwitcherResult executeCriteria();

private boolean canUseAsync() {
return super.delay > 0 && !this.historyExecution.isEmpty();
}
/**
* Update the history of executions.
*
* @param response the response to be updated
*/
void updateHistoryExecution(SwitcherResult response);

private Optional<SwitcherResult> getFromHistory() {
for (SwitcherResult switcherResult : historyExecution) {
if (switcherResult.getEntry().equals(getEntry())) {
return Optional.of(switcherResult);
}
}
return Optional.empty();
}
/**
* Get the key of the switcher.
*
* @return the key of the switcher
*/
String getSwitcherKey();

@Override
public String toString() {
return String.format("Switcher [switcherKey= %s, entry= %s, bypassMetrics= %s]",
switcherKey, entry, bypassMetrics);
}
/**
* Get the entry input list for the switcher.
*
* @return the entry of the switcher
*/
List<Entry> getEntry();

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*
* @author Roger Floriano (petruki)
*/
public abstract class SwitcherBuilder implements SwitcherInterface<Switcher> {
public abstract class SwitcherBuilder implements Switcher {

protected final SwitcherProperties properties;

Expand Down
Loading