Design Pattern suits for this if else condition? - java

I have three services A, B and C. Every service process input and gives 3 type of output i.e Invalid(I), Valid(V) and Unknown(U).
We have to check if input is valid, invalid or unknown. if any service returns Valid or Invalid we can return that output but if service returns unknown we have to check with other service. Similarly we have to do with every service available A, B, C. If any service gives invalid or valid we can return that and we don't have to check with other service.
Which Design pattern suits for this case?
output validate(input, country) {
response;
if A support this country {
response = A(input);
if response == Invalid or response == Valid {
return response;
}
}
if B support this country {
if ((response is null) or (response is unknown)){
response = B(input);
}
if response == Invalid or response == Valid {
return response;
}
}
if C support this country {
if ((response is null) or (response is unknown)){
response = C(input);
}
if response == Invalid or response == Valid {
return response;
}
}
return response;
}

I would solve this with a Service interface.
interface Service {
Collection<Object> supportedCountries();
Optional<Response> processInput(Object input);
}
Have a array of your services
List<Service> services = {A,B,C};
for(Service service : services) {
if(service.supportedCountries().contains(country)) {
Optional<Response> oResponse = service.processInput(input);
if(oResponse.isPresent()){
return oResponse.get();
}
}
}
return Response.INVALID; // or null

I think you could use a strategy pattern to see if applies given a certain condition, and then execute what has to be done if it applies
You can see a very detail example here

Related

Make multiple API requests with different request body sequentially

The use case : I need to send some request in the server using android client (retrofit). After I get my first answer , i need to update the sending object values (that depend on the last item that I get) and resend it until all data are downloaded. I want to know how can I achieve this with Retrofit and RxJava (I don't want to use while loops etc)
EDIT :
The thing is , I don't know the exact number of the "flat maps" because the data might get larger or smaller . I have lets say 420000 records and for every request I donwload 1000 data
You could flatMap them, and using its response in the next one, by using the it parameter, which is the response of the previous.
mathApi.multiplyByTwo(1)
.flatMap {
mathApi.multiplyByTwo(it)
}.flatMap {
mathApi.multiplyByTwo(it)
}.subscribe {
// here "it" will be 4 (1*2*2)
}
And in case you don't know how many flatMaps you will end up having, you could, for instance, do it with a recursive function.
private fun multiplyByTwo(number: Int) {
mathApi.multiplyByTwo(number).subscribe {
if (it < Integer.MAX_VALUE) { // When you run out of data.
multiplyByTwo(it)
}
}
}
You could use the generate function that holds a mutable state:
data class ApiResponse(
val nextPage: Int? = null
)
data class GeneratorState(
var lastResponse: ApiResponse
)
fun makeApiCall(page: Int): ApiResponse {
return ApiResponse(page + 1)
}
Flowable
.generate(
Callable { GeneratorState(makeApiCall(0)) },
BiConsumer { state: GeneratorState, emitter: Emitter<ApiResponse> ->
val latest = state.lastResponse
if (latest.nextPage != null) {
val response = makeApiCall(latest.nextPage)
state.lastResponse = response
emitter.onNext(response)
} else {
emitter.onComplete()
}
})
.subscribe(object : FlowableSubscriber<ApiResponse> {
var subscription: Subscription? = null
override fun onSubscribe(s: Subscription) {
subscription = s
s.request(1)
}
override fun onNext(response: ApiResponse) {
println("onNext :$response")
if (response.nextPage != null && response.nextPage < 10) {
subscription?.request(1)
} else {
subscription?.cancel()
}
}
override fun onComplete() {
println("Completed")
}
override fun onError(t: Throwable) {
t.printStackTrace()
}
})

Java GSON check data

I'm having trouble with gson:
For example I have this output from website:
[["connected"], ["user1":"Hello"], ["user2":"Hey"], ["disconnected"]]
But I want parse this JSON and output something like this:
connected
user1 says: Hello
user2 says: Hey
disconnected
I quicly wrote this code:
public static void PrintEvents(String id){
String response = Post.getResponse(Server()+"events?id="+id,"");
// response is [["connected"],["user1":"Hello"],["user2":"Hey"],["disconnected"]]
JsonElement parse = (new JsonParser()).parse(response); //found this in internet
int bound = ????????????; // Should be 4
for (int i=1;i<=bound;i++){
String data = ???????????;
if (data == "connected" || data == "disconnected") then {
System.out.println(data);
}else if(?????==2){// to check how many strings there is, if it's ["abc","def"] or ["abc"]
String data2 = ??????????????;
System.out.println(data+" says: "+data2);
}else{
//something else
}
};
}
What should I insert to these parts with question marks to make code work?
I cannot find any way to make it work...
Sorry for my bad English.
EDIT: Changed response to [["connected"], ["user1","Hello"], ["user2","Hey"], ["disconnected"]]. Earlier response was not valid JSON.
The response that you have pasted is not a valid json. paste it in http://www.jsoneditoronline.org/ and see the error.
Please find the below code snippet:
public static void printEvents(String id)
{
String response = "[[\"connected\"] ,[\"user1:Hello\"],[\"user2:Hey\"],[\"disconnected\"]]";
JsonElement parse = (new JsonParser()).parse(response); //found this in internet
int bound = ((JsonArray)parse).size(); // Should be 4
for (int i = 0; i < bound; i++) {
String data = ((JsonArray)parse).get(0).getAsString();
if (data.equals("connected") || data.equals("disconnected")) {
System.out.println(data);
continue;
}
String[] splittedData = data.split(":");
if (splittedData.length
== 2) {// to check how many strings there is, if it's ["abc","def"] or ["abc"]
System.out.println(splittedData[0] + " says: " + splittedData[1]);
}
/*
*else{
* your else logic goes here
* }
* */
}
}
Couple of suggestions:
If you are new to json world, use jackson instead of Gson.
the response is not a good design. Slightly correct json:
{
"firstKey": "connected",
"userResponses": [
{
"user1": "hey"
},
{
"user2": "hi"
}
],
"lastKey": "disconnected"
}
Also try to define pojos , instead of working inline with json.
You need to define a separate class like this:
class MyClass{
String name;
String value;
}
and then:
List<MyClass> myclasses = new Gson().fromJson(response, new TypeToken<List<MyClass>>(){}.getType());
then
for(MyClass myclass: myclasses){
...
}

Rest Search Parameters Validation

I have a rest end point that takes the urls with the following 3 parameters as valid:
regno, hostid, location
regno, domid, location
regno, provider
Anything other than these combinations are invalid.
I have a validator method that checks this
if (!StringUtils.isEmpty(criteria.getRegno())) {
if ((!StringUtils.isEmpty(criteria.getHostid()) || !StringUtils.isEmpty(criteria.getDomId())) && !StringUtils.isEmpty(criteria.getLocation())) {
criteria.setSearchType(GET_HOST_SEARCH_TYPE);
} else if (!StringUtils.isEmpty(criteria.getProvider()) && (StringUtils.isEmpty(criteria.getLocation()) && StringUtils.isEmpty(criteria.getHostid) && StringUtils.isEmpty(criteria.getDomId()))) {
criteria.setSearchType(GET_PROVIDER_SEARCH_TYPE);
} else {
throw new BadRequestException("Either Provider, Location, Hostid or domid is missing");
}
} else {
throw new BadRequestException("Regno is missing");
}
I dont like the fact that I am using a lot of if else statements. If there is a better readable way of doing this please feel free to help.
You may try the following approach, it will reduce the need of if else drastically..
public String detectSearchType(String url) throws BadRequestException{
final String condition1 = "(?=.*location)(?=.*(?:hostid|domid))";
final String condition2 = "(?=.*provider)(?!.*hostid)(?!.*domid)(?!.*location)";
if(!url.contains("regno="))
throw new BadRequestException("Regno is missing");
else if(Pattern.compile(condition1).matcher(url).find())
return "GET_HOST_SEARCH_TYPE";
else if(Pattern.compile(condition2).matcher(url).find())
return "GET_PROVIDER_SEARCH_TYPE";
else
throw new BadRequestException("Either Provider, Location, Hostid or domid is missing");
}
You need to pass the url strings to this method. such as the following:
detectSearchType("localhost/search?location=india&regno=12532&hostid=gdy-101");
detectSearchType("localhost/search?location=india&regno=12532&domid=gdy-101");
detectSearchType("localhost/search?regno=12532&provider=mrt");
detectSearchType("localhost/search?regno=12532&provider=mrt&host=abul");
detectSearchType("localhost/abc?regno=1&hostid=2");

How to test if a JSONObject is null or doesn't exist

I have a set of JSONObject values which i receive from a server and operate on. Most times I get a JSONObject with a value (let's say statistics) and sometimes, it returns an Error object with a code and a description of the error.
How do I structure my code so that it doesn't break if it returns the error. I thought I could do this, but doesn't work.
public void processResult(JSONObject result) {
try {
if(result.getJSONObject(ERROR) != null ){
JSONObject error = result.getJSONObject(ERROR);
String error_detail = error.getString(DESCRIPTION);
if(!error_detail.equals(null)) {
//show error login here
}
finish();
}
else {
JSONObject info = result.getJSONObject(STATISTICS);
String stats = info.getString("production Stats"));
}
}
}
Use .has(String) and .isNull(String)
A conservative usage could be;
if (record.has("my_object_name") && !record.isNull("my_object_name")) {
// Do something with object.
}
It might be little late(it is for sure) but posting it for future readers
You can use JSONObject optJSONObject (String name) which will not throw any exception and
Returns the value mapped by name if it exists and is a JSONObject, or null otherwise.
so you can do
JSONObject obj = null;
if( (obj = result.optJSONObject("ERROR"))!=null ){
// it's an error , now you can fetch the error object values from obj
}
or if you just want to test nullity without fetching the value then
if( result.optJSONObject("ERROR")!=null ){
// error object found
}
There is whole family of opt functions which either return null or you can also use the overloaded version to make them return any pre-defined values.
e.g
String optString (String name, String fallback)
Returns the value mapped by name if it exists, coercing it if
necessary, or fallback if no such mapping exists.
where coercing mean, it will try to convert the value into String type
A modified version of the #TheMonkeyMan answer to eliminate redundant look-ups
public void processResult(JSONObject result) {
JSONObject obj = null;
if( (obj = result.optJSONObject("ERROR"))!=null ){
//^^^^ either assign null or jsonobject to obj
// if not null then found error object , execute if body
String error_detail = obj.optString("DESCRIPTION","Something went wrong");
//either show error message from server or default string as "Something went wrong"
finish(); // kill the current activity
}
else if( (obj = result.optJSONObject("STATISTICS"))!=null ){
String stats = obj.optString("Production Stats");
//Do something
}
else
{
throw new Exception("Could not parse JSON Object!");
}
}
In JSONObject there is a 'Has' method that you can do to Determaine the key.
I have no idea if this will work but it looks Credible.
public void processResult(JSONObject result) {
if(result.has("ERROR"))
{
JSONObject error = result.getJSONObject("ERROR")
String error_detail = error.getString("DESCRIPTION");
if(error_detail != null)
{
//Show Error Login
finish();
}
}
else if(result.has("STATISTICS"))
{
JSONObject info = result.getJSONObject("STATISTICS");
String stats = info.getString("Production Stats");
//Do something
}
else
{
throw new Exception("Could not parse JSON Object!");
}
}
It is sometimes more convenient and less ambiguous to have a NULL object than to use Java's null value.
JSONObject.NULL.equals(null) returns true.
JSONObject.NULL.toString()returns "null".
Example:
System.out.println(test.get("address").equals(null)); // Preferred way
System.out.println(test.getString("address").equals("null"));
source -- JSONObject oracle docs
Just a note:
With EE8 json specs, I can do an exception-safe get:
result.asJsonObject().getString("ERROR", null);
if, however, I want to do a check I can do it with:
result.asJsonObject().get("ERROR").equals(JsonValue.NULL)
If at any point in your code, org.json.JSONObject json_object becomes null and you wish to avoid NullPointerException (java.lang.NullPointerException), then do check it as below:
if(json_object == null) {
System.out.println("json_object is found as null");
}
else {
System.out.println("json_object is found as not null");
}
If in any case, your jsonobject is null.
Then use this statement for checking jsonobject is null or not.
if (!obj.get("data").isJsonNull()){
//Not Null
}else{
//Null
}
And for checking jsonobject is exist or not, use .has:
if (!obj.has("data")){
//Not Exist
}else{
//Exist
}

Test for null parameter in .properties file for MessageFormat

Is it possible, with resource bundles and MessageFormat to have the following result?
when I call getBundle("message.07", "test") to get "Group test"
when I call getBundle("message.07", null) to get "No group selected"
Every example I found on the Internet is with planets, with files on the disk and so on.
I only need to check if one parameter is null (or doesn't exist) in the resource bundle's properties file. I hope to find a special format for the null parameter something like {0,choice,null#No group selected|notnull#Group {0}}.
The method I use to get the bundles is:
public String getBundle(String key, Object... params) {
try {
String message = resourceBundle.getString(key);
if (params.length == 0) {
return message;
} else {
return MessageFormat.format(message, params);
}
} catch (Exception e) {
return "???";
}
}
I also call this method for other bundles, like
getBundle("message.08", 1, 2) => "Page 1 of 2" (always parameters, no need to check for null)
getBundle("message.09") => "Open file" (no parameters, no need to check for null)
What should I write in my .properties file for message.07 to have the result described?
What I have now is:
message.07=Group {0}
message.08=Page {0} of {1} # message with parameters where I always send them
message.09=Open file # message without parameters
I'll recommend not trying to change the bundle functionality (even if you have a getBundle method encapsulating it).
Simply do in your code:
getBundle(param == null? "message.07.null": "message.07", param)
Or make another method:
getBundleOrNull("message.07", param, "message.07.null")
that does
public String getBundleOrNull(String key, value, nullKey) {
return getBundle(value == null? nullKey: key: value);
}
Your .properties file,
message.07=Group {0}
message.08=Page {0} of {1}
message.09=Open file
message.null = No group selected
And then you need to change your code to put an explicit check params for null. And if null then you can do something like resourceBundle.getString(NULL_MSG). Where NULL_MSG will be this,
private static final String NULL_MSG = "message.null";
So, now your original method would become something like this.
public String getBundle(String key, Object... params) {
String message = null;
try {
if (params == null) {
message = resourceBundle.getString(NULL_MSG);
} else {
message = MessageFormat.format(resourceBundle.getString(key), params);
}
} catch (Exception e) {
e.printStackTrace();
}
return message;
}
Calling my method like below,
getBundle("message.07", "test") // returning 'Group test'
getBundle("message.07", null) // returning 'No group selected'
getBundle("message.08", 1, 2) // returning 'Page 1 of 2'
getBundle("message.08", null) // returning 'No group selected'
getBundle("message.09", new Object[0]) // returning 'Open file'
getBundle("message.09", null) // returning 'No group selected'
Now tell me where is the problem?

Categories

Resources