diff --git a/app/src/main/assets/barricade/random/failure.json b/app/src/main/assets/barricade/jokes/failure.json similarity index 100% rename from app/src/main/assets/barricade/random/failure.json rename to app/src/main/assets/barricade/jokes/failure.json diff --git a/app/src/main/assets/barricade/jokes/path/failure.json b/app/src/main/assets/barricade/jokes/path/failure.json new file mode 100644 index 0000000..7a73a41 --- /dev/null +++ b/app/src/main/assets/barricade/jokes/path/failure.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/app/src/main/assets/barricade/random/success.json b/app/src/main/assets/barricade/jokes/path/success.json similarity index 100% rename from app/src/main/assets/barricade/random/success.json rename to app/src/main/assets/barricade/jokes/path/success.json diff --git a/app/src/main/assets/barricade/jokes/random/failure.json b/app/src/main/assets/barricade/jokes/random/failure.json new file mode 100644 index 0000000..7a73a41 --- /dev/null +++ b/app/src/main/assets/barricade/jokes/random/failure.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/app/src/main/assets/barricade/jokes/random/success.json b/app/src/main/assets/barricade/jokes/random/success.json new file mode 100644 index 0000000..3161c2a --- /dev/null +++ b/app/src/main/assets/barricade/jokes/random/success.json @@ -0,0 +1,6 @@ +{ + "icon_url" : "https://assets.chucknorris.host/img/avatar/chuck-norris.png", + "id" : "gX6RQU9EQxC4oZd6kVeiSw", + "url" : "http://api.chucknorris.io/jokes/gX6RQU9EQxC4oZd6kVeiSw", + "value" : "When Chuck Norris was a kid, he made his mom eat her vegetables" +} \ No newline at end of file diff --git a/app/src/main/assets/barricade/jokes/success.json b/app/src/main/assets/barricade/jokes/success.json new file mode 100644 index 0000000..3161c2a --- /dev/null +++ b/app/src/main/assets/barricade/jokes/success.json @@ -0,0 +1,6 @@ +{ + "icon_url" : "https://assets.chucknorris.host/img/avatar/chuck-norris.png", + "id" : "gX6RQU9EQxC4oZd6kVeiSw", + "url" : "http://api.chucknorris.io/jokes/gX6RQU9EQxC4oZd6kVeiSw", + "value" : "When Chuck Norris was a kid, he made his mom eat her vegetables" +} \ No newline at end of file diff --git a/app/src/main/java/com/mutualmobile/barricade/sample/BarricadeSampleApplication.java b/app/src/main/java/com/mutualmobile/barricade/sample/BarricadeSampleApplication.java index 39de2b4..18bac86 100644 --- a/app/src/main/java/com/mutualmobile/barricade/sample/BarricadeSampleApplication.java +++ b/app/src/main/java/com/mutualmobile/barricade/sample/BarricadeSampleApplication.java @@ -7,6 +7,7 @@ public class BarricadeSampleApplication extends Application { @Override public void onCreate() { super.onCreate(); - new Barricade.Builder(this, BarricadeConfig.getInstance()).enableShakeToStart(this).install(); + Barricade barricade =new Barricade.Builder(this, BarricadeConfig.getInstance()).install(); + barricade.enableShakeListener(this); } } diff --git a/app/src/main/java/com/mutualmobile/barricade/sample/api/ChuckNorrisApiService.java b/app/src/main/java/com/mutualmobile/barricade/sample/api/ChuckNorrisApiService.java index 2b13567..b21ac95 100644 --- a/app/src/main/java/com/mutualmobile/barricade/sample/api/ChuckNorrisApiService.java +++ b/app/src/main/java/com/mutualmobile/barricade/sample/api/ChuckNorrisApiService.java @@ -1,19 +1,44 @@ package com.mutualmobile.barricade.sample.api; import com.mutualmobile.barricade.annotation.Barricade; +import com.mutualmobile.barricade.annotation.Params; +import com.mutualmobile.barricade.annotation.QueryParams; import com.mutualmobile.barricade.annotation.Response; +import com.mutualmobile.barricade.annotation.UrlPath; import com.mutualmobile.barricade.sample.api.model.Joke; - import java.util.List; import retrofit2.Call; import retrofit2.http.GET; +import retrofit2.http.Path; +import retrofit2.http.Query; public interface ChuckNorrisApiService { - @GET("/jokes/random") @Barricade(endpoint = "random", responses = { + @GET("/jokes/random") @Barricade(endpoint = "jokes/random", responses = { @Response(fileName = "success.json",isDefault = true), @Response(fileName = "failure.json", statusCode = 401) }) Call getRandomJoke(); + + /*Example of of using barricade with query params*/ + @GET("/jokes/random") + @Barricade(endpoint = "jokes/random", + queryParams = { + @QueryParams( params = {@Params(name = "path",value = "success")} , + response = @Response(fileName = "success.json",isDefault = true)), + @QueryParams( params = {@Params(name = "path",value = "failure")} , + response = @Response(fileName = "failure.json", statusCode = 401)) + }, + responses = { + @Response(fileName = "success.json",isDefault = true), + @Response(fileName = "failure.json", statusCode = 401) + }) Call getRandomJoke(@Query("path")String test); + + /*Using barricade with url path param */ + @GET("/jokes/{path}") + @Barricade(endpoint = "jokes/", + path = {@UrlPath(path = "path", responses = { @Response(fileName = "success.json") }) }) + Call getRandomJokePath(@Path("path") String test); + @GET("/jokes/categories") Call> getJokeCategories(); } diff --git a/app/src/test/java/com/mutualmobile/barricade/sample/api/ChuckNorrisApiServiceTest.java b/app/src/test/java/com/mutualmobile/barricade/sample/api/ChuckNorrisApiServiceTest.java index e242190..e4ba8ee 100644 --- a/app/src/test/java/com/mutualmobile/barricade/sample/api/ChuckNorrisApiServiceTest.java +++ b/app/src/test/java/com/mutualmobile/barricade/sample/api/ChuckNorrisApiServiceTest.java @@ -52,7 +52,27 @@ public class ChuckNorrisApiServiceTest { @Test public void canFetchRandomJokeFromBarricade() throws IOException { barricade.setEnabled(true); - Response response = getApiService().getRandomJoke().execute(); + Response response = getApiService().getRandomJoke("success").execute(); + + assertThat(response.isSuccessful()).isTrue(); + assertThat(response.code()).isEqualTo(200); + assertThat(response.body()).isNotNull(); + + Joke joke = response.body(); + assertThat(joke.id).isNotNull(); + assertThat(joke.id).isNotEmpty(); + assertThat(joke.id).isEqualTo("gX6RQU9EQxC4oZd6kVeiSw"); + assertThat(joke.value).isNotNull(); + assertThat(joke.value).isNotEmpty(); + assertThat(joke.value).isEqualTo("When Chuck Norris was a kid, he made his mom eat her vegetables"); + assertThat(joke.iconUrl).isNotNull(); + assertThat(joke.iconUrl).isNotEmpty(); + assertThat(joke.iconUrl).isEqualTo("https://assets.chucknorris.host/img/avatar/chuck-norris.png"); + } + + @Test public void canFetchRandomJokeFromBarricadeWithPathUrl() throws IOException { + barricade.setEnabled(true); + Response response = getApiService().getRandomJokePath("path").execute(); assertThat(response.isSuccessful()).isTrue(); assertThat(response.code()).isEqualTo(200); @@ -71,7 +91,7 @@ public class ChuckNorrisApiServiceTest { } @Test public void canSetBarricadeResponseAtRunTime() throws IOException { - barricade.setEnabled(true).setResponse(BarricadeConfig.Endpoints.RANDOM, BarricadeConfig.Responses.Random.FAILURE); + barricade.setEnabled(true).setResponse(BarricadeConfig.Endpoints.JOKESRANDOM, BarricadeConfig.Responses.Jokesrandom.FAILURE); Response response = getApiService().getRandomJoke().execute(); assertThat(response.isSuccessful()).isFalse(); assertThat(response.code()).isEqualTo(401); diff --git a/barricade-annotations/src/main/java/com/mutualmobile/barricade/IBarricadeConfig.java b/barricade-annotations/src/main/java/com/mutualmobile/barricade/IBarricadeConfig.java index 2c75fee..2602fd6 100644 --- a/barricade-annotations/src/main/java/com/mutualmobile/barricade/IBarricadeConfig.java +++ b/barricade-annotations/src/main/java/com/mutualmobile/barricade/IBarricadeConfig.java @@ -11,4 +11,5 @@ public interface IBarricadeConfig { HashMap getConfigs(); BarricadeResponse getResponseForEndpoint(String endpoint); + BarricadeResponse getResponseForParams(String endpoint,String params); } diff --git a/barricade-annotations/src/main/java/com/mutualmobile/barricade/annotation/Barricade.java b/barricade-annotations/src/main/java/com/mutualmobile/barricade/annotation/Barricade.java index 86ebd79..828a665 100644 --- a/barricade-annotations/src/main/java/com/mutualmobile/barricade/annotation/Barricade.java +++ b/barricade-annotations/src/main/java/com/mutualmobile/barricade/annotation/Barricade.java @@ -4,6 +4,7 @@ import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.Target; +import java.util.HashMap; import static java.lang.annotation.RetentionPolicy.CLASS; @@ -12,6 +13,8 @@ */ @Documented @Retention(CLASS) @Target(ElementType.METHOD) public @interface Barricade { String endpoint() default ""; - + UrlPath[] path() default {}; + QueryParams[] queryParams() default {}; + RequestJson[] requestJson() default {}; Response[] responses() default {}; } diff --git a/barricade-annotations/src/main/java/com/mutualmobile/barricade/annotation/Params.java b/barricade-annotations/src/main/java/com/mutualmobile/barricade/annotation/Params.java new file mode 100644 index 0000000..51efa52 --- /dev/null +++ b/barricade-annotations/src/main/java/com/mutualmobile/barricade/annotation/Params.java @@ -0,0 +1,9 @@ +package com.mutualmobile.barricade.annotation; + +/** + * Annotation to declare a params of API. + */ +public @interface Params { + String name(); + String value(); +} diff --git a/barricade-annotations/src/main/java/com/mutualmobile/barricade/annotation/QueryParams.java b/barricade-annotations/src/main/java/com/mutualmobile/barricade/annotation/QueryParams.java new file mode 100644 index 0000000..8df7765 --- /dev/null +++ b/barricade-annotations/src/main/java/com/mutualmobile/barricade/annotation/QueryParams.java @@ -0,0 +1,9 @@ +package com.mutualmobile.barricade.annotation; + +/** + * Annotations to declare query parameters and response for corresponding query params + */ +public @interface QueryParams { + Params[] params(); + Response response(); +} diff --git a/barricade-annotations/src/main/java/com/mutualmobile/barricade/annotation/RequestJson.java b/barricade-annotations/src/main/java/com/mutualmobile/barricade/annotation/RequestJson.java new file mode 100644 index 0000000..d3d1510 --- /dev/null +++ b/barricade-annotations/src/main/java/com/mutualmobile/barricade/annotation/RequestJson.java @@ -0,0 +1,9 @@ +package com.mutualmobile.barricade.annotation; + +/** + * Annotations for Post Request body and corresponding response + */ +public @interface RequestJson { + String body(); + Response response(); +} diff --git a/barricade-annotations/src/main/java/com/mutualmobile/barricade/annotation/UrlPath.java b/barricade-annotations/src/main/java/com/mutualmobile/barricade/annotation/UrlPath.java new file mode 100644 index 0000000..06ee1a8 --- /dev/null +++ b/barricade-annotations/src/main/java/com/mutualmobile/barricade/annotation/UrlPath.java @@ -0,0 +1,12 @@ +package com.mutualmobile.barricade.annotation; + +/** + * Support for dynamic url path + * @path will appended after endpoint. + * for eg. if your retrofit url is user/{path}/class + * you barricade code will be endpoint = user , UrlPath{ path= {expected value}/class} + */ +public @interface UrlPath { + String path(); + Response[] responses(); +} diff --git a/barricade-annotations/src/main/java/com/mutualmobile/barricade/response/BarricadeResponse.java b/barricade-annotations/src/main/java/com/mutualmobile/barricade/response/BarricadeResponse.java index 4a4c46d..68173dd 100644 --- a/barricade-annotations/src/main/java/com/mutualmobile/barricade/response/BarricadeResponse.java +++ b/barricade-annotations/src/main/java/com/mutualmobile/barricade/response/BarricadeResponse.java @@ -5,17 +5,20 @@ public class BarricadeResponse { public int statusCode; public String responseFileName; + public String filePath; public String contentType; - public BarricadeResponse(int statusCode, String responseFileName, String contentType) { + public BarricadeResponse(int statusCode, String responseFileName, String contentType,String filePath) { this.statusCode = statusCode; this.responseFileName = responseFileName; this.contentType = contentType; + this.filePath = filePath; } - public BarricadeResponse(Response response) { + public BarricadeResponse(Response response,String filePath) { this.statusCode = response.statusCode(); this.responseFileName = response.fileName(); this.contentType = response.type(); + this.filePath = filePath; } } diff --git a/barricade-annotations/src/main/java/com/mutualmobile/barricade/response/BarricadeResponseSet.java b/barricade-annotations/src/main/java/com/mutualmobile/barricade/response/BarricadeResponseSet.java index b7d08a3..fb68479 100644 --- a/barricade-annotations/src/main/java/com/mutualmobile/barricade/response/BarricadeResponseSet.java +++ b/barricade-annotations/src/main/java/com/mutualmobile/barricade/response/BarricadeResponseSet.java @@ -1,5 +1,6 @@ package com.mutualmobile.barricade.response; +import com.mutualmobile.barricade.annotation.QueryParams; import java.util.List; /** @@ -15,4 +16,4 @@ public BarricadeResponseSet(List responses, int defaultIndex) this.defaultIndex = defaultIndex; this.originalDefaultIndex = defaultIndex; } -} +} \ No newline at end of file diff --git a/barricade-compiler/src/main/java/com/mutualmobile/barricade/compiler/BarricadeProcessor.java b/barricade-compiler/src/main/java/com/mutualmobile/barricade/compiler/BarricadeProcessor.java index 013bd82..be9c0d1 100644 --- a/barricade-compiler/src/main/java/com/mutualmobile/barricade/compiler/BarricadeProcessor.java +++ b/barricade-compiler/src/main/java/com/mutualmobile/barricade/compiler/BarricadeProcessor.java @@ -2,13 +2,18 @@ import com.google.auto.service.AutoService; import com.mutualmobile.barricade.annotation.Barricade; +import com.mutualmobile.barricade.annotation.Params; +import com.mutualmobile.barricade.annotation.QueryParams; +import com.mutualmobile.barricade.annotation.RequestJson; import com.mutualmobile.barricade.annotation.Response; +import com.mutualmobile.barricade.annotation.UrlPath; import com.mutualmobile.barricade.response.BarricadeResponse; import com.mutualmobile.barricade.response.BarricadeResponseSet; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.Messager; @@ -29,59 +34,100 @@ */ @AutoService(Processor.class) public class BarricadeProcessor extends AbstractProcessor { - private Messager messager; - - @Override public synchronized void init(ProcessingEnvironment processingEnvironment) { - super.init(processingEnvironment); - messager = processingEnvironment.getMessager(); - } - - @Override public Set getSupportedAnnotationTypes() { - return singleton(Barricade.class.getCanonicalName()); - } - - @Override public SourceVersion getSupportedSourceVersion() { - return latestSupported(); - } - - @Override - public boolean process(Set set, RoundEnvironment roundEnvironment) { - try { - HashMap configs = new HashMap<>(); - // Iterate over all @Barricade annotated elements - for (Element annotatedElement : roundEnvironment.getElementsAnnotatedWith(Barricade.class)) { - Barricade barricade = annotatedElement.getAnnotation(Barricade.class); - messager.printMessage(NOTE, "[Barricade] Processing endpoint: " + barricade.endpoint()); - - List responses = new ArrayList<>(barricade.responses().length); - int defaultIndex = 0; - - for (int i = 0; i < barricade.responses().length; i++) { - Response option = barricade.responses()[i]; - responses.add(new BarricadeResponse(option)); - if (option.isDefault()) { - defaultIndex = i; - } - } - configs.put(barricade.endpoint(), new BarricadeResponseSet(responses, defaultIndex)); - } - - // This method is called multiple times, but we want to generate code only once - if (!configs.isEmpty()) { - generateCode(configs); - } - } catch (Exception e) { - messager.printMessage(ERROR, "Couldn't process class:" + e.getMessage()); - } - - return true; - } - - private void generateCode(HashMap configs) throws IOException { - if (configs.isEmpty()) { - messager.printMessage(ERROR, "Couldn't find any endpoints to barricade"); - } else { - CodeGenerator.generateClass(processingEnv, configs, messager); - } - } + private Messager messager; + + @Override public synchronized void init(ProcessingEnvironment processingEnvironment) { + super.init(processingEnvironment); + messager = processingEnvironment.getMessager(); + } + + @Override public Set getSupportedAnnotationTypes() { + return singleton(Barricade.class.getCanonicalName()); + } + + @Override public SourceVersion getSupportedSourceVersion() { + return latestSupported(); + } + + @Override public boolean process(Set set, RoundEnvironment roundEnvironment) { + try { + HashMap configs = new HashMap<>(); + HashMap> paramConfig = new HashMap<>(); + // Iterate over all @Barricade annotated elements + for (Element annotatedElement : roundEnvironment.getElementsAnnotatedWith(Barricade.class)) { + Barricade barricade = annotatedElement.getAnnotation(Barricade.class); + messager.printMessage(NOTE, "[Barricade] Processing Start for endpoint: " + barricade.endpoint()); + if (barricade.queryParams().length > 0) { + Map responseMap = mapQueryParams(barricade); + paramConfig.put(barricade.endpoint(), responseMap); + } else if (barricade.requestJson().length > 0) { + Map responseMap = mapRequestJson(barricade); + paramConfig.put(barricade.endpoint(), responseMap); + } else if (barricade.path().length > 0) { + for (int i = 0; i < barricade.path().length; i++) { + UrlPath urlPath = barricade.path()[i]; + String endPoint = barricade.endpoint() + urlPath.path(); + configs.putAll(mapEndPoints(endPoint, urlPath.responses())); + } + } else { + configs.putAll(mapEndPoints(barricade.endpoint(), barricade.responses())); + } + } + + // This method is called multiple times, but we want to generate code only once + if (!configs.isEmpty()||!paramConfig.isEmpty()) { + generateCode(paramConfig,configs); + } + } catch (Exception e) { + messager.printMessage(ERROR, "Couldn't process class:" + e.getMessage()); + } + + return true; + } + + private Map mapEndPoints(String endPoint, Response[] responses){ + Map responseMap = new HashMap(); + List responseList = new ArrayList(responses.length); + int defaultIndex = 0; + + for (int i = 0; i < responses.length; i++) { + Response option = responses[i]; + responseList.add(new BarricadeResponse(option,endPoint)); + if (option.isDefault()) { + defaultIndex = i; + } + } + responseMap.put(endPoint, new BarricadeResponseSet(responseList, defaultIndex)); + return responseMap; + } + + + private Map mapQueryParams(Barricade barricade){ + Map responseMap = new HashMap<>(barricade.queryParams().length); + for (QueryParams queryParams : barricade.queryParams()) { + StringBuilder query = new StringBuilder(); + for (Params params : queryParams.params()) { + query.append(params.name()).append("=").append(params.value()).append("&"); + } + responseMap.put(query.toString(), new BarricadeResponse(queryParams.response(),barricade.endpoint())); + } + return responseMap; + } + + private Map mapRequestJson(Barricade barricade){ + Map responseMap = new HashMap<>(barricade.queryParams().length); + for (RequestJson postJson : barricade.requestJson()) { + String query = postJson.body(); + responseMap.put(query, new BarricadeResponse(postJson.response(),barricade.endpoint())); + } + return responseMap; + } + + private void generateCode(HashMap> paramConfigs,HashMap configs) throws IOException { + if (configs.isEmpty()&& paramConfigs.isEmpty()) { + messager.printMessage(ERROR, "Couldn't find any endpoints"); + } else { + CodeGenerator.generateClass(processingEnv,paramConfigs,configs, messager); + } + } } diff --git a/barricade-compiler/src/main/java/com/mutualmobile/barricade/compiler/CodeGenerator.java b/barricade-compiler/src/main/java/com/mutualmobile/barricade/compiler/CodeGenerator.java index 1abb825..70ed2c8 100755 --- a/barricade-compiler/src/main/java/com/mutualmobile/barricade/compiler/CodeGenerator.java +++ b/barricade-compiler/src/main/java/com/mutualmobile/barricade/compiler/CodeGenerator.java @@ -25,6 +25,7 @@ import static javax.lang.model.element.Modifier.PRIVATE; import static javax.lang.model.element.Modifier.PUBLIC; import static javax.lang.model.element.Modifier.STATIC; +import static javax.tools.Diagnostic.Kind.ERROR; /** * Generates code for a Barricade configuration. @@ -37,9 +38,18 @@ final class CodeGenerator { private static final ClassName TYPE_BARRICADE_RESPONSE_SET = ClassName.get(BarricadeResponseSet.class); + private static final ClassName TYPE_BARRICADE_RESPONSE = + ClassName.get(BarricadeResponse.class); private static final ParameterizedTypeName TYPE_CONFIG = ParameterizedTypeName.get(ClassName.get(HashMap.class), ClassName.get(String.class), ClassName.get(BarricadeResponseSet.class)); + private static final ParameterizedTypeName PARAM_CONFIG = + ParameterizedTypeName.get(ClassName.get(HashMap.class), ClassName.get(String.class), + ParameterizedTypeName.get(ClassName.get(Map.class), ClassName.get(String.class), + ClassName.get(BarricadeResponse.class))); + private static final ParameterizedTypeName BARRICADE_RESPONSE_MAP = + ParameterizedTypeName.get(ClassName.get(Map.class), ClassName.get(String.class), + ClassName.get(BarricadeResponse.class)); private CodeGenerator() { } @@ -49,10 +59,11 @@ private CodeGenerator() { * * @param processingEnv Processing environment * @param configs Configuration detected by annotation processing + * @param paramConfigs parameters detected by annotation processing * @param messager Messager to print logs * @throws IOException */ - static void generateClass(ProcessingEnvironment processingEnv, + static void generateClass(ProcessingEnvironment processingEnv,HashMap> paramConfigs, HashMap configs, Messager messager) throws IOException { messager.printMessage(Diagnostic.Kind.NOTE, "Generating configuration code..."); @@ -60,24 +71,30 @@ static void generateClass(ProcessingEnvironment processingEnv, TypeSpec.Builder classBuilder = classBuilder(CLASS_NAME).addModifiers(PUBLIC, FINAL); FieldSpec valuesField = FieldSpec.builder(TYPE_CONFIG, "configs").addModifiers(PRIVATE).build(); + FieldSpec paramsField = FieldSpec.builder(PARAM_CONFIG, "paramConfigs").addModifiers(PRIVATE).build(); FieldSpec instanceField = FieldSpec.builder(ClassName.get(PACKAGE_NAME, CLASS_NAME), "barricadeConfig") .addModifiers(PRIVATE, STATIC) .build(); MethodSpec.Builder instanceMethodBuilder = generateGetInstanceMethodBuilder(); - MethodSpec.Builder constructorMethodBuilder = generateConstructorBuilder(configs, messager); - MethodSpec.Builder valuesMethod = generateGetConfigsMethodBuilder(); + MethodSpec.Builder constructorMethodBuilder = generateConstructorBuilder(configs,paramConfigs, messager); + MethodSpec.Builder valuesMethod = generateGetConfigsMethodBuilder(); MethodSpec.Builder getResponseMethodBuilder = generateGetResponseMethodBuilder(); + MethodSpec.Builder getResponseForParamsMethodBuilder = generateGetResponseForParamsMethodBuilder(); + MethodSpec.Builder getResponseFromParamsMethodBuilder = generateGetResponseFromParamsMethodBuilder(); classBuilder.addType(generateEndpointsInnerClass(configs.keySet())); classBuilder.addType(generateResponsesInnerClass(configs)); classBuilder.addField(instanceField); classBuilder.addField(valuesField); + classBuilder.addField(paramsField); classBuilder.addMethod(instanceMethodBuilder.build()); classBuilder.addMethod(constructorMethodBuilder.build()); classBuilder.addMethod(valuesMethod.build()); classBuilder.addMethod(getResponseMethodBuilder.build()); + classBuilder.addMethod(getResponseForParamsMethodBuilder.build()); + classBuilder.addMethod(getResponseFromParamsMethodBuilder.build()); classBuilder.addSuperinterface(IBarricadeConfig.class); @@ -139,28 +156,44 @@ private static MethodSpec.Builder generateGetConfigsMethodBuilder() { } private static MethodSpec.Builder generateConstructorBuilder( - HashMap values, Messager messager) { + HashMap values,HashMap> paramConfigs, Messager messager) { MethodSpec.Builder methodBuilder = MethodSpec.constructorBuilder().addModifiers(PUBLIC); methodBuilder.addStatement("configs = new HashMap<>()"); + methodBuilder.addStatement("paramConfigs = new HashMap<>()"); for (Map.Entry entry : values.entrySet()) { BarricadeResponseSet barricadeResponseSet = entry.getValue(); - String listName = "barricadeResponsesFor" + entry.getKey(); + String listName = "barricadeResponsesFor" + entry.getKey().replaceAll("[^a-zA-Z0-9_]+",""); methodBuilder.addStatement("$T<$T> " + listName + " = new $T<>()", List.class, BarricadeResponse.class, ArrayList.class); for (BarricadeResponse barricadeResponse : barricadeResponseSet.responses) { - methodBuilder.addStatement(listName + ".add(new $T($L, $S, $S))", BarricadeResponse.class, + methodBuilder.addStatement(listName + ".add(new $T($L, $S, $S, $S))", BarricadeResponse.class, barricadeResponse.statusCode, barricadeResponse.responseFileName, - barricadeResponse.contentType); + barricadeResponse.contentType,entry.getKey()); } methodBuilder.addStatement( "configs.put($S, new $T(" + listName + ", " + barricadeResponseSet.defaultIndex + "))", entry.getKey(), TYPE_BARRICADE_RESPONSE_SET); } + for (Map.Entry> entry : paramConfigs.entrySet()) { + Map paramResponse = entry.getValue(); + String mapName = "paramValueMapFor" + entry.getKey().replaceAll("[^a-zA-Z0-9_]+",""); + + methodBuilder.addStatement("$T<$T,$T> " + mapName + " = new $T<>()", Map.class, String.class, + BarricadeResponse.class, HashMap.class); + + for (Map.Entry paramEntries : paramResponse.entrySet()) { + methodBuilder.addStatement(mapName + ".put($S,new $T($L, $S, $S, $S))",paramEntries.getKey(), BarricadeResponse.class, + paramEntries.getValue().statusCode, paramEntries.getValue().responseFileName, + paramEntries.getValue().contentType,entry.getKey()); + } + methodBuilder.addStatement( + "paramConfigs.put($S," + mapName +")",entry.getKey()); + } return methodBuilder; } @@ -178,7 +211,51 @@ private static MethodSpec.Builder generateGetResponseMethodBuilder() { .addParameter(String.class, "endpoint") .returns(BarricadeResponse.class) .addStatement("$T responseSet = configs.get(endpoint)", BarricadeResponseSet.class) - .addStatement("if(responseSet==null) return null") + .beginControlFlow("if(responseSet==null)") + .beginControlFlow("for (String key : configs.keySet())") + .beginControlFlow("if ((key.endsWith(\"/*\")&& endpoint.contains(key.substring(0,key.length()-2)))||endpoint.endsWith(key))") + .addStatement("responseSet = configs.get(key)") + .addStatement("return responseSet.responses.get(responseSet.defaultIndex)") + .endControlFlow() + .endControlFlow() + .addStatement("return null") + .endControlFlow() .addStatement("return responseSet.responses.get(responseSet.defaultIndex)"); } + + private static MethodSpec.Builder generateGetResponseForParamsMethodBuilder() { + return MethodSpec.methodBuilder("getResponseForParams") + .addModifiers(PUBLIC) + .addParameter(String.class, "endpoint") + .addParameter(String.class,"params") + .returns(BarricadeResponse.class) + .addStatement("$T<$T,$T> paramMap = paramConfigs.get(endpoint)", Map.class,String.class,BarricadeResponse.class) + .beginControlFlow("if(paramMap==null)") + .beginControlFlow("for (String key : paramConfigs.keySet())") + .beginControlFlow("if (endpoint.endsWith(key))") + .addStatement("paramMap= paramConfigs.get(key)") + .addStatement("return getResponseFromParamMap(paramMap,params)") + .endControlFlow() + .endControlFlow() + .addStatement("return null") + .endControlFlow() + .addStatement("return getResponseFromParamMap(paramMap,params)"); + } + + private static MethodSpec.Builder generateGetResponseFromParamsMethodBuilder() { + return MethodSpec.methodBuilder("getResponseFromParamMap") + .addModifiers(PRIVATE) + .addParameter(BARRICADE_RESPONSE_MAP, "paramMap") + .addParameter(String.class,"params") + .returns(BarricadeResponse.class) + .addStatement("BarricadeResponse response = paramMap.get(params)") + .beginControlFlow("if(response == null)") + .beginControlFlow("for(String key:paramMap.keySet())") + .beginControlFlow("if(params.contains(key))") + .addStatement("return paramMap.get(key)") + .endControlFlow() + .endControlFlow() + .endControlFlow() + .addStatement("return response"); + } } diff --git a/barricade/build.gradle b/barricade/build.gradle index 292eba7..93ace5a 100644 --- a/barricade/build.gradle +++ b/barricade/build.gradle @@ -35,7 +35,7 @@ ext { } dependencies { - implementation project(':barricade-annotations') + api project(':barricade-annotations') implementation "androidx.appcompat:appcompat:${SUPPORT_LIB_VERSION}" implementation "androidx.legacy:legacy-support-v4:${SUPPORT_LIB_VERSION}" diff --git a/barricade/src/androidTest/java/com/mutualmobile/barricade/ApplicationTest.java b/barricade/src/androidTest/java/com/mutualmobile/barricade/ApplicationTest.java deleted file mode 100644 index 9807aa5..0000000 --- a/barricade/src/androidTest/java/com/mutualmobile/barricade/ApplicationTest.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.mutualmobile.barricade; - -import android.app.Application; -import android.test.ApplicationTestCase; - -/** - * Testing Fundamentals - */ -public class ApplicationTest extends ApplicationTestCase { - public ApplicationTest() { - super(Application.class); - } -} \ No newline at end of file diff --git a/barricade/src/main/java/com/mutualmobile/barricade/Barricade.java b/barricade/src/main/java/com/mutualmobile/barricade/Barricade.java index 6c71904..ccefb33 100644 --- a/barricade/src/main/java/com/mutualmobile/barricade/Barricade.java +++ b/barricade/src/main/java/com/mutualmobile/barricade/Barricade.java @@ -35,6 +35,7 @@ public class Barricade { private long delay = DEFAULT_DELAY; private boolean enabled = false; + private BarricadeShakeListener barricadeShakeListener; /** * @return The singleton instance of the Barricade @@ -50,14 +51,25 @@ public static Barricade getInstance() { private Barricade() { } - private Barricade(AssetFileManager fileManager, IBarricadeConfig barricadeConfig, long delay, Application application) { + public void enableShakeListener(Application application){ + if (application != null && barricadeShakeListener == null) { + barricadeShakeListener= new BarricadeShakeListener(application); + }else if(barricadeShakeListener!=null){ + barricadeShakeListener.enableShakeListener(); + } + } + + public void disableShakeListener() { + if (barricadeShakeListener != null) { + barricadeShakeListener.disableShakeListener(); + } + } + + + private Barricade(AssetFileManager fileManager, IBarricadeConfig barricadeConfig, long delay) { this.barricadeConfig = barricadeConfig; this.fileManager = fileManager; this.delay = delay; - - if (application != null) { - new BarricadeShakeListener(application); - } } public boolean isEnabled() { @@ -82,11 +94,6 @@ public Builder(IBarricadeConfig barricadeConfig, AssetFileManager fileManager) { this.fileManager = fileManager; } - public Builder enableShakeToStart(Application application) { - this.application = application; - return this; - } - public Builder setGlobalDelay(long delay) { this.delay = delay; return this; @@ -100,7 +107,7 @@ public Builder setGlobalDelay(long delay) { */ public Barricade install() { if (instance == null) { - instance = new Barricade(fileManager, barricadeConfig, delay, application); + instance = new Barricade(fileManager, barricadeConfig, delay); } else { Logger.getLogger(TAG).info("Barricade already installed, install() will be ignored."); } @@ -120,7 +127,28 @@ okhttp3.Response getResponse(Interceptor.Chain chain, String endpoint) { if (barricadeResponse == null) { return null; } - String fileResponse = getResponseFromFile(endpoint, barricadeResponse.responseFileName); + String fileResponse = getResponseFromFile(barricadeResponse.filePath, barricadeResponse.responseFileName); + return new okhttp3.Response.Builder().code(barricadeResponse.statusCode).message("Barricade OK") + .request(chain.request()) + .protocol(Protocol.HTTP_1_0) + .body(ResponseBody.create(MediaType.parse(barricadeResponse.contentType), fileResponse.getBytes())) + .addHeader("content-type", barricadeResponse.contentType) + .build(); + } + + /** + * Returns a barricaded response for an endpoint and matching params + * + * @param chain OkHttp Interceptor chain + * @param endpoint Endpoint that is being hit + * @return Barricaded response (if available), null otherwise + */ + okhttp3.Response getResponseForParams(Interceptor.Chain chain, String endpoint,String params) { + BarricadeResponse barricadeResponse = barricadeConfig.getResponseForParams(endpoint,params); + if (barricadeResponse == null) { + return getResponse(chain,endpoint); + } + String fileResponse = getResponseFromFile(barricadeResponse.filePath, barricadeResponse.responseFileName); return new okhttp3.Response.Builder().code(barricadeResponse.statusCode).message("Barricade OK") .request(chain.request()) .protocol(Protocol.HTTP_1_0) diff --git a/barricade/src/main/java/com/mutualmobile/barricade/BarricadeInterceptor.java b/barricade/src/main/java/com/mutualmobile/barricade/BarricadeInterceptor.java index cec8721..3948cc0 100644 --- a/barricade/src/main/java/com/mutualmobile/barricade/BarricadeInterceptor.java +++ b/barricade/src/main/java/com/mutualmobile/barricade/BarricadeInterceptor.java @@ -1,6 +1,7 @@ package com.mutualmobile.barricade; import java.io.IOException; +import java.util.Iterator; import java.util.List; import java.util.logging.Logger; import okhttp3.Interceptor; @@ -17,10 +18,14 @@ public class BarricadeInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { if (barricade.isEnabled()) { Request request = chain.request(); - List pathSegments = request.url().pathSegments(); - String endpoint = pathSegments.get(pathSegments.size() - 1); - - Response response = barricade.getResponse(chain, endpoint); + String endpoint = request.url().encodedPath(); + String queryString = getParams(request); + Response response = null; + if(!queryString.isEmpty()){ + response = barricade.getResponseForParams(chain, endpoint,queryString); + }else { + response = barricade.getResponse(chain, endpoint); + } if (response != null) { try { Thread.sleep(barricade.getDelay()); @@ -36,4 +41,33 @@ public class BarricadeInterceptor implements Interceptor { return chain.proceed(chain.request()); } } + + private String getParams(Request request){ + String requestType = request.method(); + switch (requestType.trim().toUpperCase()){ + case "PUT" : + case "POST" : { + //Todo : fetch parameters from post request + return ""; + } + case "GET" : + default : { + return getFormattedQuery(request); + } + } + } + + + private String getFormattedQuery(Request request){ + Iterator paramIterator = request.url().queryParameterNames().iterator(); + StringBuilder query = new StringBuilder(); + while(paramIterator.hasNext()){ + String paramName =paramIterator.next(); + Listvalues = request.url().queryParameterValues(paramName); + for(String value: values){ + query.append(paramName).append("=").append(value).append("&"); + } + } + return query.toString(); + } } diff --git a/barricade/src/main/java/com/mutualmobile/barricade/utils/BarricadeShakeListener.java b/barricade/src/main/java/com/mutualmobile/barricade/utils/BarricadeShakeListener.java index 6cacce8..6faa375 100644 --- a/barricade/src/main/java/com/mutualmobile/barricade/utils/BarricadeShakeListener.java +++ b/barricade/src/main/java/com/mutualmobile/barricade/utils/BarricadeShakeListener.java @@ -8,102 +8,100 @@ import android.hardware.SensorManager; import android.os.Bundle; import com.mutualmobile.barricade.Barricade; +import com.mutualmobile.barricade.activity.BarricadeActivity; import static android.content.Context.SENSOR_SERVICE; -public class BarricadeShakeListener - implements SensorEventListener, Application.ActivityLifecycleCallbacks { +public class BarricadeShakeListener implements SensorEventListener, Application.ActivityLifecycleCallbacks { - private final Application application; - private static final int SHAKE_THRESHOLD = 1200; - private long lastUpdate = 0; - private float lastX, lastY, lastZ; + private final Application application; + private static final int SHAKE_THRESHOLD = 1200; + private long lastUpdate = 0; + private float lastX, lastY, lastZ; - private int shakeCount = 0; - private int activityCount = 0; - private SensorManager sensorManager; + private int shakeCount = 0; + private boolean listenerRegistered; + private SensorManager sensorManager; - public BarricadeShakeListener(Application application) { - this.application = application; - this.sensorManager = (SensorManager) application.getSystemService(SENSOR_SERVICE); + public BarricadeShakeListener(Application application) { + this.application = application; + this.sensorManager = (SensorManager) application.getSystemService(SENSOR_SERVICE); - application.registerActivityLifecycleCallbacks(this); - } + application.registerActivityLifecycleCallbacks(this); + } - @Override public void onSensorChanged(SensorEvent sensorEvent) { - long curTime = System.currentTimeMillis(); - if ((curTime - lastUpdate) > 100) { - long diffTime = (curTime - lastUpdate); - lastUpdate = curTime; + @Override public void onSensorChanged(SensorEvent sensorEvent) { + long curTime = System.currentTimeMillis(); + if ((curTime - lastUpdate) > 100) { + long diffTime = (curTime - lastUpdate); + lastUpdate = curTime; - float x, y, z; - x = sensorEvent.values[0]; - y = sensorEvent.values[1]; - z = sensorEvent.values[2]; + float x, y, z; + x = sensorEvent.values[0]; + y = sensorEvent.values[1]; + z = sensorEvent.values[2]; - float speed = Math.abs(x + y + z - lastX - lastY - lastZ) / diffTime * 10000; + float speed = Math.abs(x + y + z - lastX - lastY - lastZ) / diffTime * 10000; - if (speed > SHAKE_THRESHOLD) { - shakeCount++; - } else { - shakeCount = 0; - } - if (shakeCount >= 2) { - shakeCount = 0; - Barricade.getInstance().launchConfigActivity(application); - } - lastX = x; - lastY = y; - lastZ = z; - } - } + if (speed > SHAKE_THRESHOLD) { + shakeCount++; + } else { + shakeCount = 0; + } + if (shakeCount >= 2) { + shakeCount = 0; + Barricade.getInstance().launchConfigActivity(application); + } + lastX = x; + lastY = y; + lastZ = z; + } + } - private void enableShakeListener() { - sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), - SensorManager.SENSOR_DELAY_GAME); - } + public void enableShakeListener() { + if (!listenerRegistered) { + listenerRegistered = + sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), + SensorManager.SENSOR_DELAY_GAME); + } + } - private void disableShakeListener() { - sensorManager.unregisterListener(this); - } + public void disableShakeListener() { + sensorManager.unregisterListener(this); + listenerRegistered = false; + } - @Override public void onAccuracyChanged(Sensor sensor, int i) { + @Override public void onAccuracyChanged(Sensor sensor, int i) { - } + } - @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { + @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { - } + } - @Override public void onActivityStarted(Activity activity) { - activityCount++; + @Override public void onActivityStarted(Activity activity) { + enableShakeListener(); + } - if (activityCount == 1) { - enableShakeListener(); - } - } + @Override public void onActivityResumed(Activity activity) { + enableShakeListener(); + } - @Override public void onActivityResumed(Activity activity) { + @Override public void onActivityPaused(Activity activity) { - } + } - @Override public void onActivityPaused(Activity activity) { + @Override public void onActivityStopped(Activity activity) { + if (activity.isTaskRoot() && !(activity instanceof BarricadeActivity)) { + disableShakeListener(); + } + } - } + @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { - @Override public void onActivityStopped(Activity activity) { - activityCount--; + } - if (activityCount == 0) { - disableShakeListener(); - } - } + @Override public void onActivityDestroyed(Activity activity) { - @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { - - } - - @Override public void onActivityDestroyed(Activity activity) { - - } + } } diff --git a/build.gradle b/build.gradle index 4f10e86..fd259d5 100644 --- a/build.gradle +++ b/build.gradle @@ -2,13 +2,14 @@ buildscript { repositories { + mavenLocal() jcenter() - google() + google() } dependencies { classpath 'com.android.tools.build:gradle:3.2.1' classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3' - classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' + classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -20,6 +21,7 @@ allprojects { google() jcenter() } + tasks.withType(Javadoc).all { enabled = false } } task clean(type: Delete) { @@ -28,7 +30,7 @@ task clean(type: Delete) { ext { OKHTTP_VERSION = "3.8.0" - SUPPORT_LIB_VERSION = '1.0.0-beta01' + SUPPORT_LIB_VERSION = '1.0.0' RETROFIT_VERSION = "2.4.0" ESPRESSO_VERSION = '3.1.0-alpha4' RUNNER_VERSION = '1.1.0-alpha4' diff --git a/gradle.properties b/gradle.properties index 6562b23..715af1b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,7 +17,7 @@ # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true GROUP=com.mutualmobile -VERSION_NAME=0.1.8 +VERSION_NAME=0.2.0-alpha POM_DESCRIPTION=A network interceptor for OkHttp and Retrofit to return mocked data POM_SITE_URL=https://github.com/mutualmobile/Barricade POM_GIT_URL=scm:git:git://github.com/mutualmobile/Barricade.git