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
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,13 +154,13 @@ Switcher switcher = MyAppFeatures.getSwitcher(FEATURE01);
switcher.isItOn();
```

Or, you can submit the switcher request and get the criteria response, which contains result, reason and metadata that can be used for any additional verification.
Or, you can submit the switcher request and get the switcher result, which contains result, reason and metadata that can be used for any additional verification.

```java
CriteriaResponse response = switcher.submit();
response.isItOn(); // true/false
response.getReason(); // Descriptive response based on result value
response.getMetadata(YourMetadata.class); // Additional information
SwitcherResult result = switcher.submit();
result.isItOn(); // true/false
result.getReason(); // Descriptive response based on result value
result.getMetadata(YourMetadata.class); // Additional information
```

2. **Strategy validation - preparing input**
Expand Down
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
<sonar.language>java</sonar.language>
<sonar.coverage.exclusions>
**/model/**/*.java,
**/remote/dto/*.java,
**/exception/**/*.java,
**/service/validators/RegexValidatorV8.java,
**/client/remote/Constants.java
Expand Down
31 changes: 31 additions & 0 deletions src/main/java/com/github/switcherapi/client/SwitcherConfig.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.github.switcherapi.client;

import com.github.switcherapi.client.model.ContextKey;

abstract class SwitcherConfig {

protected String url;
Expand All @@ -20,6 +22,35 @@ abstract class SwitcherConfig {
this.truststore = new TruststoreConfig();
}

/**
* Update Switcher Configurations state using pre-configured properties.
*
* @param properties Switcher Properties
*/
protected void updateSwitcherConfig(SwitcherProperties properties) {
setUrl(properties.getValue(ContextKey.URL));
setApikey(properties.getValue(ContextKey.APIKEY));
setDomain(properties.getValue(ContextKey.DOMAIN));
setComponent(properties.getValue(ContextKey.COMPONENT));
setEnvironment(properties.getValue(ContextKey.ENVIRONMENT));
setLocal(properties.getBoolean(ContextKey.LOCAL_MODE));
setSilent(properties.getValue(ContextKey.SILENT_MODE));
setTimeout(properties.getInt(ContextKey.TIMEOUT_MS));
setPoolSize(properties.getInt(ContextKey.POOL_CONNECTION_SIZE));

SnapshotConfig snapshotConfig = new SnapshotConfig();
snapshotConfig.setLocation(properties.getValue(ContextKey.SNAPSHOT_LOCATION));
snapshotConfig.setAuto(properties.getBoolean(ContextKey.SNAPSHOT_AUTO_LOAD));
snapshotConfig.setSkipValidation(properties.getBoolean(ContextKey.SNAPSHOT_SKIP_VALIDATION));
snapshotConfig.setUpdateInterval(properties.getValue(ContextKey.SNAPSHOT_AUTO_UPDATE_INTERVAL));
setSnapshot(snapshotConfig);

TruststoreConfig truststoreConfig = new TruststoreConfig();
truststoreConfig.setPath(properties.getValue(ContextKey.TRUSTSTORE_PATH));
truststoreConfig.setPassword(properties.getValue(ContextKey.TRUSTSTORE_PASSWORD));
setTruststore(truststoreConfig);
}

/**
* Initialize the Switcher Client.<br>
* - Build context {@link ContextBuilder}<br>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@
*
* Features.initializeClient();
* }
*
* </pre>
*
* @see SwitcherKey
Expand Down Expand Up @@ -118,21 +117,28 @@ protected void configureClient() {
.truststorePath(truststore.getPath())
.truststorePassword(truststore.getPassword()));

switcherProperties.setValue(ContextKey.CONTEXT_LOCATION, contextBase.getClass().getName());
initializeClient();
}

@Override
protected void configureClient(String contextFile) {
setContextBase(this);
loadProperties(contextFile);

loadProperties(contextFile);
switcherProperties.setValue(ContextKey.CONTEXT_LOCATION, contextBase.getClass().getName());

updateSwitcherConfig(switcherProperties);
initializeClient();
}

private static synchronized void setContextBase(SwitcherContextBase contextBase) {
SwitcherContextBase.contextBase = contextBase;
/**
* Manually register Switcher Keys.<br>
* Use this method before calling {@link #configureClient()} to register the Switcher Keys.
*
* @param switcherKeys to be registered
*/
protected void registerSwitcherKeys(String... switcherKeys) {
setSwitcherKeys(new HashSet<>(Arrays.asList(switcherKeys)));
}

/**
Expand Down Expand Up @@ -172,7 +178,7 @@ public static void loadProperties(String contextFilename) {
*/
public static void initializeClient() {
validateContext();
validateSwitcherKeys();
registerSwitcherKeys();
instance = buildInstance();

loadSwitchers();
Expand All @@ -194,9 +200,10 @@ private static SwitcherExecutor buildInstance() {

if (contextBol(ContextKey.LOCAL_MODE)) {
return new SwitcherLocalService(clientRemote, clientLocal, switcherProperties);
} else {
return new SwitcherRemoteService(clientRemote, new SwitcherLocalService(clientRemote, clientLocal, switcherProperties));
}

return new SwitcherRemoteService(clientRemote, new SwitcherLocalService(clientRemote,
clientLocal, switcherProperties));
}

/**
Expand All @@ -211,10 +218,9 @@ private static void validateContext() throws SwitcherContextException {
}

/**
* Validate Switcher Keys.<br>
* It will ensure that only properly annotated Switchers can be used.
* Register Switcher Keys based on context properties
*/
private static void validateSwitcherKeys() {
private static void registerSwitcherKeys() {
if (Objects.nonNull(contextBase)) {
registerSwitcherKey(contextBase.getClass().getFields());
} else {
Expand All @@ -233,7 +239,7 @@ private static void validateSwitcherKeys() {
* @param fields to be registered
*/
private static void registerSwitcherKey(Field[] fields) {
switcherKeys = new HashSet<>();
switcherKeys = Optional.ofNullable(switcherKeys).orElse(new HashSet<>());
for (Field field : fields) {
if (field.isAnnotationPresent(SwitcherKey.class)) {
switcherKeys.add(field.getName());
Expand All @@ -245,7 +251,7 @@ private static void registerSwitcherKey(Field[] fields) {
* Load Switcher instances into a map cache
*/
private static void loadSwitchers() {
if (switchers == null) {
if (Objects.isNull(switchers)) {
switchers = new HashMap<>();
}

Expand Down Expand Up @@ -413,7 +419,7 @@ public static void watchSnapshot(SnapshotEventHandler handler) {
throw new SwitcherException("Cannot watch snapshot when using remote", new UnsupportedOperationException());
}

if (watcherSnapshot == null) {
if (Objects.isNull(watcherSnapshot)) {
watcherSnapshot = new SnapshotWatcher((SwitcherLocalService) instance, handler,
contextStr(ContextKey.SNAPSHOT_LOCATION));
}
Expand All @@ -428,7 +434,7 @@ public static void watchSnapshot(SnapshotEventHandler handler) {
* @throws SwitcherException if watch thread never started
*/
public static void stopWatchingSnapshot() {
if (watcherSnapshot != null) {
if (Objects.nonNull(watcherSnapshot)) {
watcherExecutorService.shutdownNow();
watcherSnapshot.terminate();
watcherSnapshot = null;
Expand Down Expand Up @@ -496,10 +502,18 @@ public static void configure(ContextBuilder builder) {
* Cancel existing scheduled task for updating local Snapshot
*/
public static void terminateSnapshotAutoUpdateWorker() {
if (scheduledExecutorService != null) {
if (Objects.nonNull(scheduledExecutorService)) {
scheduledExecutorService.shutdownNow();
scheduledExecutorService = null;
}
}

private static synchronized void setContextBase(SwitcherContextBase contextBase) {
SwitcherContextBase.contextBase = contextBase;
}

private static synchronized void setSwitcherKeys(Set<String> switcherKeys) {
SwitcherContextBase.switcherKeys = switcherKeys;
}

}
39 changes: 18 additions & 21 deletions src/main/java/com/github/switcherapi/client/SwitcherExecutor.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import com.github.switcherapi.client.model.Switcher;
import com.github.switcherapi.client.model.criteria.Domain;
import com.github.switcherapi.client.model.criteria.Snapshot;
import com.github.switcherapi.client.model.response.CriteriaResponse;
import com.github.switcherapi.client.model.SwitcherResult;
import com.github.switcherapi.client.service.remote.ClientRemote;
import com.github.switcherapi.client.utils.SnapshotLoader;
import com.github.switcherapi.client.utils.SwitcherUtils;
Expand All @@ -17,6 +17,7 @@

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
Expand All @@ -30,7 +31,7 @@ public abstract class SwitcherExecutor {

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

private static final Map<String, CriteriaResponse> bypass = new HashMap<>();
private static final Map<String, SwitcherResult> bypass = new HashMap<>();

protected final SwitcherProperties switcherProperties;

Expand All @@ -46,7 +47,7 @@ protected SwitcherExecutor(final SwitcherProperties switcherProperties) {
* @param switcher to be evaluated
* @return Criteria response containing the evaluation details
*/
public abstract CriteriaResponse executeCriteria(final Switcher switcher);
public abstract SwitcherResult executeCriteria(final Switcher switcher);

/**
* Check the snapshot versions against the Remote configuration.
Expand Down Expand Up @@ -77,10 +78,10 @@ protected SwitcherExecutor(final SwitcherProperties switcherProperties) {
protected boolean checkSnapshotVersion(ClientRemote clientRemote, final Domain domain) {
final String environment = switcherProperties.getValue(ContextKey.ENVIRONMENT);
SwitcherUtils.debug(logger, "verifying snapshot version - environment: {}", environment);

return clientRemote.checkSnapshotVersion(domain.getVersion());
}

protected Domain initializeSnapshotFromAPI(ClientRemote clientRemote)
throws SwitcherRemoteException, SwitcherSnapshotWriteException {
final String environment = switcherProperties.getValue(ContextKey.ENVIRONMENT);
Expand All @@ -89,25 +90,21 @@ protected Domain initializeSnapshotFromAPI(ClientRemote clientRemote)
final Snapshot snapshot = clientRemote.resolveSnapshot();
final String snapshotLocation = switcherProperties.getValue(ContextKey.SNAPSHOT_LOCATION);

if (snapshotLocation != null) {
if (Objects.nonNull(snapshotLocation)) {
SnapshotLoader.saveSnapshot(snapshot, snapshotLocation, environment);
}

return snapshot.getDomain();
}

public boolean isLocalEnabled() {
return switcherProperties.getBoolean(ContextKey.LOCAL_MODE);
}

/**
* It manipulates the result of a given Switcher key.
*
* @param key name of the key that you want to change the result
* @param expectedResult that will be returned when performing isItOn
* @return CriteriaResponse with the manipulated result
* @return SwitcherResult with the manipulated result
*/
public static CriteriaResponse assume(final String key, boolean expectedResult) {
public static SwitcherResult assume(final String key, boolean expectedResult) {
return assume(key, expectedResult, null);
}

Expand All @@ -117,20 +114,20 @@ public static CriteriaResponse assume(final String key, boolean expectedResult)
* @param key name of the key that you want to change the result
* @param metadata additional information about the assumption (JSON)
* @param expectedResult that will be returned when performing isItOn
* @return CriteriaResponse with the manipulated result
* @return SwitcherResult with the manipulated result
*/
public static CriteriaResponse assume(final String key, boolean expectedResult, String metadata) {
CriteriaResponse criteriaResponse = new CriteriaResponse();
criteriaResponse.setResult(expectedResult);
criteriaResponse.setReason("Switcher bypassed");
public static SwitcherResult assume(final String key, boolean expectedResult, String metadata) {
SwitcherResult switcherResult = new SwitcherResult();
switcherResult.setResult(expectedResult);
switcherResult.setReason("Switcher bypassed");

if (StringUtils.isNotBlank(metadata)) {
Gson gson = new Gson();
criteriaResponse.setMetadata(gson.fromJson(metadata, Object.class));
switcherResult.setMetadata(gson.fromJson(metadata, Object.class));
}

bypass.put(key, criteriaResponse);
return criteriaResponse;
bypass.put(key, switcherResult);
return switcherResult;
}

/**
Expand All @@ -142,7 +139,7 @@ public static void forget(final String key) {
bypass.remove(key);
}

public static Map<String, CriteriaResponse> getBypass() {
public static Map<String, SwitcherResult> getBypass() {
return bypass;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.github.switcherapi.client.model;

import com.github.switcherapi.client.exception.SwitcherException;
import com.github.switcherapi.client.model.response.CriteriaResponse;
import com.github.switcherapi.client.utils.SwitcherUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -19,19 +18,19 @@
* @since 2021-11-27
*
*/
public class AsyncSwitcher {
public class AsyncSwitcher<T> {

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

private final ExecutorService executorService;

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

private final long delay;

private long nextRun = 0;

public AsyncSwitcher(final SwitcherInterface switcherInterface, long delay) {
public AsyncSwitcher(final SwitcherInterface<T> switcherInterface, long delay) {
this.executorService = Executors.newCachedThreadPool(r -> {
Thread thread = new Thread(r);
thread.setName(SWITCHER_ASYNC_WORKER.toString());
Expand Down Expand Up @@ -60,7 +59,7 @@ public synchronized void execute() {

public void run() {
try {
final CriteriaResponse response = switcherInterface.executeCriteria();
final SwitcherResult response = switcherInterface.executeCriteria();
switcherInterface.updateHistoryExecution(response);
} catch (SwitcherException e) {
logger.error(e.getMessage(), e);
Expand Down
Loading