Skip to content

Commit b35bdaf

Browse files
authored
Release 1.0.2 (#3)
* Fixed #2 - Fixed log4j2 properties * Initializing 1.0.2-SNAPSHOT * Project refactored - Added snapshot auto load * Fixed SnapshotLoaderTest case * Fixed try-with-resources when writing snapshot into a file * Fixed 19 code smells * Added Snapshot Watcher * Snapshot Watcher - Fixed some code smells * Snapshot Watcher - Fixed some code smells #2 * feat: Re-worked built-in mock implementation * fix: Minor issue with test case - testModelEntry * readme: Fixed minor doc issues * feat: Updated javadoc
1 parent 89bd68e commit b35bdaf

49 files changed

Lines changed: 2352 additions & 393 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

pom.xml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<groupId>com.github.petruki</groupId>
99
<artifactId>switcher-client</artifactId>
1010
<packaging>jar</packaging>
11-
<version>1.0.1</version>
11+
<version>1.0.2</version>
1212

1313
<name>Switcher Client</name>
1414
<description>Switcher Client for working with Switcher API</description>
@@ -57,12 +57,14 @@
5757
<!-- test -->
5858
<log4j.version>2.13.1</log4j.version>
5959
<powermock-module-junit4.version>2.0.2</powermock-module-junit4.version>
60+
<awaitility.version>3.0.0</awaitility.version>
6061

6162
<!-- Sonar -->
6263
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
6364
<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
6465
<sonar.jacoco.reportPath>${project.basedir}/target/coverage-reports/jacoco-unit.exec</sonar.jacoco.reportPath>
6566
<sonar.language>java</sonar.language>
67+
<sonar.coverage.exclusions>com/github/petruki/switcher/client/model/*</sonar.coverage.exclusions>
6668
</properties>
6769

6870
<dependencies>
@@ -129,6 +131,12 @@
129131
<version>${powermock-module-junit4.version}</version>
130132
<scope>test</scope>
131133
</dependency>
134+
<dependency>
135+
<groupId>org.awaitility</groupId>
136+
<artifactId>awaitility</artifactId>
137+
<version>${awaitility.version}</version>
138+
<scope>test</scope>
139+
</dependency>
132140
</dependencies>
133141

134142
<!--

readme.md

Lines changed: 79 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,19 @@
66

77
![Switcher API: Java Client: Cloud-based Feature Flag API](https://github.com/petruki/switcherapi-assets/blob/master/logo/switcherapi_java_client.png)
88

9-
# Install
10-
- Using the source code
11-
`mvn clean install`
9+
# About
10+
Client Java for working with Switcher-API.
11+
https://github.com/petruki/switcher-api
12+
13+
- Able to work offline using a snapshot file downloaded from your remote Switcher-API Domain.
14+
- Silent mode automatically enables a contingent sub-process in case of connectivity issues.
15+
- Built-in mock implementation for automated testing.
16+
- Easy to setup. Switcher Context is responsible to manage all the complexity between your application and API.
17+
18+
# Usage
1219

20+
## Install
21+
- Using the source code `mvn clean install`
1322
- Adding as a dependency - Maven
1423
```xml
1524
<dependency>
@@ -19,64 +28,98 @@
1928
</dependency>
2029
```
2130

22-
# About
23-
Client Java for working with Switcher-API.
24-
https://github.com/petruki/switcher-api
31+
## Context properties
32+
The context map properties stores all information regarding connectivity and strategy settings. These constants can be accessed using *SwitcherContextParam*.
2533

26-
Switcher Client is a friendly lib to interact with the Switcher API by:
27-
- Simplifying validations throughout your remote Switcher configuration.
28-
- Able to work offline using a snapshot claimed from your remote Switcher-API.
29-
- Able to run in silent mode that will prevent your application to not be 100% dependent on the online API.
30-
- Being flexible in order to remove the complexity of multi-staging (add as many environments as you want).
31-
- Being friendly by making possible to manipulate switchers without changing your online switchers. (useful for automated tests - see below some examples about bypassing switchers).
32-
- Being secure by using OAuth 2 flow. Requests are made using tokens that will validate your domain, component, environment and API key.
33-
Tokens have an expiration time and are not stored. The Switcher Client is responsible to renew it using your settings.
34-
35-
# Example
36-
## Client configuration
3734
```java
38-
properties.put(SwitcherContextParam.URL, "http://localhost:3000/criteria");
35+
properties.put(SwitcherContextParam.URL, "https://switcher-load-balance.herokuapp.com");
3936
properties.put(SwitcherContextParam.APIKEY, "API_KEY");
4037
properties.put(SwitcherContextParam.DOMAIN, "MyDomain");
4138
properties.put(SwitcherContextParam.COMPONENT, "MyApp");
4239
properties.put(SwitcherContextParam.ENVIRONMENT, "default");
4340
properties.put(SwitcherContextParam.SILENT_MODE, true);
4441
properties.put(SwitcherContextParam.RETRY_AFTER, "5s");
45-
properties.put(SwitcherContextParam.SNAPSHOT_LOCATION, SNAPSHOTS_LOCAL + "default.json");
42+
properties.put(SwitcherContextParam.SNAPSHOT_LOCATION, "/src/resources");
4643

4744
SwitcherFactory.buildContext(properties, false);
48-
Switcher switcher = SwitcherFactory.getSwitcher("FF2FOR2020");
45+
Switcher switcher = SwitcherFactory.getSwitcher("FEATURE01");
46+
switcher.isItOn();
47+
```
48+
49+
- URL: Endpoint of your Swither-API.
50+
- APIKEY: Switcher-API key generated after creating a domain.
51+
- DOMAIN: Domain name.
52+
- COMPONENT: Application name.
53+
- ENVIRONMENT: Environment name. Production environment is named as 'default'.
54+
- SILENT_MODE: (boolean) Activate contingency in case of some problem with connectivity with the API.
55+
- RETRY_AFTER: Time given to the module to re-establish connectivity with the API - e.g. 5s (s: seconds - m: minutes - h: hours)
56+
- SNAPSHOT_LOCATION: Set the folder location where snapshot files will be saved.
57+
- SNAPSHOT_AUTO_LOAD: (boolean) Set the module to automatically download the snapshot configuration.
58+
59+
## Executing
60+
There are a few different ways to call the API using the java library.
61+
Here are some examples:
62+
63+
1. **No parameters**
64+
Invoking the API can be done by obtaining the switcher object and calling *isItOn*. It can also be forced to call another key any time you want.
65+
66+
```java
67+
Switcher switcher = SwitcherFactory.getSwitcher("FEATURE01");
4968
switcher.isItOn();
69+
//or
70+
switcher.isItOn("FEATURE01");
71+
```
72+
73+
2. **Strategy validation - preparing input**
74+
Loading information into the switcher can be made by using *prepareEntry*, in case you want to include input from a different place of your code. Otherwise, it is also possible to include everything in the same call.
75+
76+
```java
77+
List<Entry> entries = new ArrayList<>();
78+
entries.add(new Entry(Entry.DATE, "2019-12-10"));
79+
entries.add(new Entry(Entry.DATE, "2020-12-10"));
80+
81+
switcher.prepareEntry(entries);
82+
switcher.isItOn();
83+
//or
84+
switcher.isItOn(entries);
85+
```
86+
87+
3. **Strategy validation - all-in-one execution**
88+
All-in-one method is fast and include everything you need to execute a complex call to the API. Stack inputs changing the last parameter to *true* in case you need to add more values to the strategy validator.
89+
90+
```java
91+
switcher.isItOn("FEATURE01", new Entry(Entry.NETWORK, "10.0.0.3"), false);
5092
```
51-
- **APIKEY**: Obtained after creating your domain using the Switcher-API project.
52-
- **ENVIRONMENT**: You can run multiple environments. Production environment is 'default' which is created automatically after creating the domain.
53-
- **DOMAIN**: This is your business name identification.
54-
- **COMPONENT**: This is the name of the application that will be using this API.
55-
- **URL**: Endpoint of your Swither-API.
56-
- **SILENT_MODE**: Enable the client work in silent mode if some problem network issues happen. It's necessary to save the snapshot localy.
57-
- **RETRY_AFTER**: Represents the time a retry to reach the API should take.
5893

5994
## Offline settings
95+
You can also force the Switcher library to work offline. In this case, the snapshot location must be set up and the context re-built using the offline flag.
96+
6097
```java
61-
properties.put(SwitcherContextParam.SNAPSHOT_LOCATION, SNAPSHOTS_LOCAL + "default.json");
98+
properties.put(SwitcherContextParam.SNAPSHOT_LOCATION, "/src/resources");
6299
SwitcherFactory.buildContext(properties, true);
63100

64-
Switcher switcher = SwitcherFactory.getSwitcher("FF2FOR2020");
101+
Switcher switcher = SwitcherFactory.getSwitcher("FEATURE01");
65102
switcher.isItOn();
66103
```
67104

68-
## Bypass example
105+
## Built-in mock feature
106+
Write automated tests using this built-in mock mechanism to guide your test scenario according to what you want to test.
107+
</br>*SwitcherExecutor* implementation has 2 methods that can make mock tests easier. Use assume to force a value to a switcher and forget to reset its original state.
108+
69109
```java
70-
Switcher switcher = SwitcherFactory.getSwitcher("FF2FOR2020");
71-
switcher.isItOn(); // Pretending your API or Snapshot return 'true'
110+
Switcher switcher = SwitcherFactory.getSwitcher("FEATURE01");
72111

73-
switcher.assume("FF2FOR2020", false);
74-
switcher.isItOn(); // Now, it's going to return 'false'
112+
SwitcherExecutor.assume("FEATURE01", false);
113+
switcher.isItOn(); // 'false'
75114

76-
switcher.forget("FF2FOR2020");
77-
switcher.isItOn(); // Now, it's going to return 'true'
115+
SwitcherExecutor.forget("FEATURE01");
116+
switcher.isItOn(); // Now, it's going to return the result retrieved from the API or the Snaopshot file
78117
```
79118

80119
# Version Log
120+
- 1.0.2:
121+
- Improved performance when loading snapshot file.
122+
- Snapshot file auto load when updated.
123+
- Re-worked built-in mock implementation
81124
- 1.0.1: Security patch - Log4J has been updated
82125
- 1.0.0: Working release

src/main/java/com/github/petruki/switcher/client/SwitcherFactory.java

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,16 @@
55
import org.apache.logging.log4j.LogManager;
66
import org.apache.logging.log4j.Logger;
77

8-
import com.github.petruki.switcher.client.domain.Switcher;
8+
import com.github.petruki.switcher.client.exception.SwitcherException;
99
import com.github.petruki.switcher.client.exception.SwitcherFactoryContextException;
10+
import com.github.petruki.switcher.client.exception.SwitcherSnapshotLoadException;
1011
import com.github.petruki.switcher.client.factory.SwitcherExecutor;
1112
import com.github.petruki.switcher.client.factory.SwitcherOffline;
1213
import com.github.petruki.switcher.client.factory.SwitcherOnline;
14+
import com.github.petruki.switcher.client.model.Switcher;
15+
import com.github.petruki.switcher.client.service.ClientService;
1316
import com.github.petruki.switcher.client.utils.SwitcherContextParam;
17+
import com.github.petruki.switcher.client.utils.SwitcherUtils;
1418

1519
/**
1620
* Configure context (using {@link #buildContext(Map, boolean)} and claim switcher (using {@link #getSwitcher(String)} by using this factory.
@@ -42,14 +46,16 @@ private SwitcherFactory() {}
4246
* <br>
4347
* <br> <b>Optional</b>
4448
* <br> {@link SwitcherContextParam#SNAPSHOT_LOCATION}
49+
* <br> {@link SwitcherContextParam#SNAPSHOT_FILE}
4550
* <br> {@link SwitcherContextParam#SILENT_MODE}
4651
* <br> {@link SwitcherContextParam#RETRY_AFTER}
4752
* <br>
4853
* @param offline If set to true, this client will find the configuration inside the configured snapshot file
54+
* @throws SwitcherSnapshotLoadException in case it was not possible to load snapshot
4955
*
5056
* @see SwitcherContextParam
5157
*/
52-
public static void buildContext(final Map<String, Object> properties, boolean offline) {
58+
public static void buildContext(final Map<String, Object> properties, boolean offline) throws SwitcherException {
5359

5460
if (logger.isDebugEnabled()) {
5561
logger.debug(String.format("properties: %s", properties));
@@ -58,12 +64,13 @@ public static void buildContext(final Map<String, Object> properties, boolean of
5864

5965
if (instance == null) {
6066
if (offline) {
61-
instance = new SwitcherOffline((String) properties.get(SwitcherContextParam.SNAPSHOT_LOCATION));
67+
instance = new SwitcherOffline(properties);
6268
} else {
6369
instance = new SwitcherOnline(properties);
6470
}
6571
} else {
6672
instance.updateContext(properties);
73+
SwitcherExecutor.getBypass().clear();
6774
}
6875
}
6976

@@ -86,5 +93,40 @@ public static Switcher getSwitcher(final String key) throws SwitcherFactoryConte
8693

8794
return new Switcher(key, instance);
8895
}
96+
97+
/**
98+
* Validate and update local snapshot file
99+
*
100+
* @throws SwitcherException
101+
* If an error has occrured when invoking {@link ClientService#SNAPSHOT_URL} and {@link ClientService#SNAPSHOT_VERSION_CHECK}
102+
*/
103+
public static void validateSnapshot() throws SwitcherException {
104+
105+
if (instance == null) {
106+
throw new SwitcherFactoryContextException();
107+
}
108+
109+
if (!instance.checkSnapshotVersion()) {
110+
instance.updateSnapshot();
111+
}
112+
}
113+
114+
/**
115+
* Start watching snapshot file for changes. As it has changed, it will update the domain in memory
116+
*/
117+
public static void watchSnapshot() {
118+
119+
SwitcherUtils.watchSnapshot(instance);
120+
}
121+
122+
/**
123+
* Unregister snapshot location and terminates the Thread watcher
124+
*
125+
* @throws SwitcherException if watch thread never started
126+
*/
127+
public static void stopWatchingSnapshot() throws SwitcherException {
128+
129+
SwitcherUtils.stopWatchingSnapshot();
130+
}
89131

90132
}

src/main/java/com/github/petruki/switcher/client/domain/criteria/Config.java

Lines changed: 0 additions & 31 deletions
This file was deleted.

src/main/java/com/github/petruki/switcher/client/domain/criteria/Domain.java

Lines changed: 0 additions & 25 deletions
This file was deleted.

src/main/java/com/github/petruki/switcher/client/domain/criteria/Group.java

Lines changed: 0 additions & 25 deletions
This file was deleted.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.github.petruki.switcher.client.exception;
2+
3+
/**
4+
* @author rogerio
5+
* @since 2020-05-13
6+
*/
7+
public class SwitcherSnapshotWatcherException extends SwitcherException {
8+
9+
private static final long serialVersionUID = 4548138997211494541L;
10+
11+
public SwitcherSnapshotWatcherException(final String message, final Exception ex) {
12+
13+
super(String.format("Something went wrong: %s", message), ex);
14+
}
15+
16+
}

0 commit comments

Comments
 (0)