From f5e05873f5d57dff589e66589acf2b6c66a1ece9 Mon Sep 17 00:00:00 2001 From: Macarescu Sebastian Date: Thu, 24 Mar 2016 14:32:11 +0200 Subject: [PATCH 01/22] Added rxjava. Events, EventChain and EventChain-Events calls, pagination params --- pom.xml | 6 + src/main/bookingbugAPI/api/AdminURLS.java | 10 ++ src/main/bookingbugAPI/api/PublicURLS.java | 15 ++- .../models/BookableAvailability.java | 44 ++++-- src/main/bookingbugAPI/models/Company.java | 53 ++++++-- src/main/bookingbugAPI/models/EventChain.java | 33 +++++ .../bookingbugAPI/models/params/Params.java | 41 +++++- .../models/params/TimeDataParams.java | 126 ++++++++++++++++++ src/main/helpers/Utils.java | 20 +++ 9 files changed, 319 insertions(+), 29 deletions(-) create mode 100644 src/main/bookingbugAPI/models/params/TimeDataParams.java diff --git a/pom.xml b/pom.xml index 01e0494..4bbf841 100644 --- a/pom.xml +++ b/pom.xml @@ -74,6 +74,12 @@ 1.1 + + io.reactivex + rxjava + 1.1.0 + + diff --git a/src/main/bookingbugAPI/api/AdminURLS.java b/src/main/bookingbugAPI/api/AdminURLS.java index e4ba96e..d2b2df2 100644 --- a/src/main/bookingbugAPI/api/AdminURLS.java +++ b/src/main/bookingbugAPI/api/AdminURLS.java @@ -625,6 +625,16 @@ public static UriTemplate eventChainReadUsingRefId() { .path(UriTemplateBuilder.var("refId")) .build(); } + + public static UriTemplate eventChainEventsList() { + return UriTemplate.buildFromTemplate(new Config().serverUrl) + .literal("/admin") + .path(UriTemplateBuilder.var("companyId")) + .literal("/event_chains") + .path(UriTemplateBuilder.var("eventChainId")) + .literal("/events") + .build(); + } } diff --git a/src/main/bookingbugAPI/api/PublicURLS.java b/src/main/bookingbugAPI/api/PublicURLS.java index acfae19..6764889 100644 --- a/src/main/bookingbugAPI/api/PublicURLS.java +++ b/src/main/bookingbugAPI/api/PublicURLS.java @@ -179,8 +179,11 @@ public static class Event { * @return UriTemplate */ public static UriTemplate eventList(){ - return UriTemplate.buildFromTemplate(new Config().serverUrl).path(UriTemplateBuilder.var("companyId")) - .literal("/" + eventsLink).build(); + return UriTemplate.buildFromTemplate(new Config().serverUrl) + .path(UriTemplateBuilder.var("companyId")) + .literal("/" + eventsLink) + .query(UriTemplateBuilder.var("page"), UriTemplateBuilder.var("per_page")) + .build(); } /** @@ -244,7 +247,9 @@ public static UriTemplate availabilityDaysForBookableItem() { */ public static UriTemplate availabilityTimesForBookableItem() { return UriTemplate.buildFromTemplate(new Config().serverUrl).path(UriTemplateBuilder.var("companyId")) - .literal("/time_data").build(); + .literal("/time_data") + .query("event_id", "service_id", "resource_id","resource_ids", "person_id", "group_id", "location", + "date", "end_date", "duration", "num_resources").build(); } /** @@ -314,7 +319,9 @@ public static class EventChain { */ public static UriTemplate eventChainList(){ return UriTemplate.buildFromTemplate(new Config().serverUrl).path(UriTemplateBuilder.var("companyId")) - .literal("/" + eventChainsLink).build(); + .literal("/" + eventChainsLink) + .query(UriTemplateBuilder.var("page"), UriTemplateBuilder.var("per_page")) + .build(); } /** diff --git a/src/main/bookingbugAPI/models/BookableAvailability.java b/src/main/bookingbugAPI/models/BookableAvailability.java index 0a42f4a..7879c42 100644 --- a/src/main/bookingbugAPI/models/BookableAvailability.java +++ b/src/main/bookingbugAPI/models/BookableAvailability.java @@ -50,20 +50,36 @@ public Date getDateTimeObj(){ return datetime; } - public boolean isAvailable(Date datetime){ - Calendar calendar = Calendar.getInstance(); - calendar.setTime(datetime); - int hour_to_check = calendar.get(Calendar.HOUR_OF_DAY); - - ArrayList times = new ArrayList<>(getRep().getResourcesByRel("times")); - for (ReadableRepresentation rep : times) { - int time_min = Integer.parseInt((String) rep.getValue("time")); - int avail = Integer.parseInt((String) rep.getValue("avail")); - - int hour = time_min / 60; - if(hour_to_check >= hour && hour_to_check < hour + 1 && avail == 1) - return true; + public ArrayList getAvailTimes(){ + + ArrayList times_reps = new ArrayList<>(getRep().getResourcesByRel("times")); + ArrayList times = new ArrayList<>(); + + for (ReadableRepresentation rep : times_reps) { + AvailTime timeObj = new AvailTime(); + timeObj.time_minutes = Integer.parseInt((String) rep.getValue("time")); + timeObj.avail = Integer.parseInt((String) rep.getValue("avail")) == 1 ? true : false; + timeObj.price = Integer.parseInt((String) rep.getValue("price")); + times.add(timeObj); + } + return times; + } + + public static class AvailTime { + int time_minutes; + boolean avail; + int price; + + public int getTime_minutes() { + return time_minutes; + } + + public boolean isAvail() { + return avail; + } + + public int getPrice() { + return price; } - return false; } } diff --git a/src/main/bookingbugAPI/models/Company.java b/src/main/bookingbugAPI/models/Company.java index 8c36265..ebe7b8b 100644 --- a/src/main/bookingbugAPI/models/Company.java +++ b/src/main/bookingbugAPI/models/Company.java @@ -322,9 +322,21 @@ public Resource companyDetails(String companyId) throws IOException { * @throws IOException */ public BBCollection eventList() throws IOException { - URL url = new URL(PublicURLS.Event.eventList().set("companyId", this.id).expand()); - BBCollection events = new BBCollection(HttpService.api_GET(url, auth_token), auth_token, "events", Event.class); - return events; + return eventList(new Params()); + } + + /** + * Get a List of Bookable Events. + * @param params Parameters for pagination + * @return BBCollection + * @throws IOException + */ + public BBCollection eventList(Params params) throws IOException { + UriTemplate template = Utils.TemplateWithPagination( + PublicURLS.Event.eventList().set("companyId", this.id), + params); + URL url = new URL(template.expand()); + return new BBCollection(HttpService.api_GET(url, auth_token), auth_token, "events", Event.class); } @@ -369,9 +381,13 @@ public BBCollection bookableItemsByDate(String date) throws IOExce * @return Resource * @throws IOException */ - public BBCollection availabilityDaysForBookableItem() throws IOException { - URL url = new URL(PublicURLS.Bookable.availabilityDaysForBookableItem().set("companyId", this.id).expand()); - return new BBCollection(HttpService.api_GET(url, auth_token), auth_token, "events", BookableAvailability.class); + public BBRoot availabilityDaysForBookableItem(TimeDataParams params) throws IOException { + URL url = new URL( + PublicURLS.Bookable.availabilityDaysForBookableItem() + .set("companyId", this.id) + .set((Map)params.getParams()) + .expand()); + return new BBRoot(HttpService.api_GET(url, auth_token), auth_token); } @@ -380,9 +396,13 @@ public BBCollection availabilityDaysForBookableItem() thro * @return Resource * @throws IOException */ - public Resource availabilityTimesForBookableItem() throws IOException { - URL url = new URL(PublicURLS.Bookable.availabilityTimesForBookableItem().set("companyId", this.id).expand()); - return new Resource(HttpService.api_GET(url, auth_token), auth_token); + public BBCollection availabilityTimesForBookableItem(TimeDataParams params) throws IOException { + URL url = new URL( + PublicURLS.Bookable.availabilityTimesForBookableItem() + .set("companyId", this.id) + .set((Map)params.getParams()) + .expand()); + return new BBCollection(HttpService.api_GET(url, auth_token), auth_token, "events", BookableAvailability.class); } @@ -439,7 +459,20 @@ public EventGroup eventGroupRead(String eventGroupId) throws IOException { * @throws IOException */ public BBCollection eventChainList() throws IOException { - URL url = new URL (PublicURLS.EventChain.eventChainList().set("companyId", this.id).expand()); + return eventChainList(new Params()); + } + + /** + * Get a List of Courses or Repeating Events for a Company. + * @param params Parameters for pagination + * @return BBCollection + * @throws IOException + */ + public BBCollection eventChainList(Params params) throws IOException { + UriTemplate template = Utils.TemplateWithPagination( + PublicURLS.EventChain.eventChainList().set("companyId", this.id), + params); + URL url = new URL(template.expand()); BBCollection eventChains = new BBCollection(HttpService.api_GET(url, auth_token), auth_token, "event_chains", EventChain.class); return eventChains; } diff --git a/src/main/bookingbugAPI/models/EventChain.java b/src/main/bookingbugAPI/models/EventChain.java index dc32cbe..a68bdd3 100644 --- a/src/main/bookingbugAPI/models/EventChain.java +++ b/src/main/bookingbugAPI/models/EventChain.java @@ -1,6 +1,17 @@ package bookingbugAPI.models; +import bookingbugAPI.api.AdminURLS; +import bookingbugAPI.api.PublicURLS; +import bookingbugAPI.models.params.Params; +import bookingbugAPI.services.HttpService; +import com.damnhandy.uri.template.UriTemplate; import helpers.HttpServiceResponse; +import helpers.Utils; +import rx.Observable; + +import java.io.IOException; +import java.net.URL; +import java.util.concurrent.Callable; public class EventChain extends BBRoot{ @@ -18,4 +29,26 @@ public EventChain(HttpServiceResponse httpServiceResponse, String auth_token){ public EventChain() {} + /** + * Get a List of Bookable Events for an EventChain. + * @param params Parameters for pagination + * @return BBCollection + * @throws IOException + */ + public BBCollection eventList(Params params) throws IOException { + UriTemplate template = Utils.TemplateWithPagination( + Utils.paginatedUriTemplate(getLink("events")), + params); + URL url = new URL(template.expand()); + return new BBCollection(HttpService.api_GET(url, auth_token), auth_token, "events", Event.class); + } + + public Observable> eventListObs(final Params params){ + return Observable.fromCallable(new Callable>() { + @Override + public BBCollection call() throws Exception { + return eventList(params); + } + }); + } } diff --git a/src/main/bookingbugAPI/models/params/Params.java b/src/main/bookingbugAPI/models/params/Params.java index d2a8f09..8065b67 100644 --- a/src/main/bookingbugAPI/models/params/Params.java +++ b/src/main/bookingbugAPI/models/params/Params.java @@ -1,10 +1,16 @@ package bookingbugAPI.models.params; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; -public abstract class Params { +public class Params { + + private int page = 1; + private int per_page = 100; public Params() {} @@ -12,6 +18,19 @@ public Params(Map args){ setNotNullStringMap(args); } + public static Params withPagination(int page, int per_page){ + Params params = new Params(); + params.page = page; + params.per_page = per_page; + return params; + } + + public static Params withPagination(int page){ + Params params = new Params(); + params.page = page; + return params; + } + public Map getNotNullStringMap() { Map result = new HashMap(); Field[] declaredFields = this.getClass().getDeclaredFields(); @@ -44,4 +63,24 @@ public void setNotNullStringMap(Map map) { public Map getParams(){ return getNotNullStringMap(); } + + public int getPage() { + return page; + } + + public int getPer_page() { + return per_page; + } + + @Override + public String toString(){ + String json = ""; + try { + json = new ObjectMapper().writeValueAsString(this); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + return json; + } + } \ No newline at end of file diff --git a/src/main/bookingbugAPI/models/params/TimeDataParams.java b/src/main/bookingbugAPI/models/params/TimeDataParams.java new file mode 100644 index 0000000..bbfab58 --- /dev/null +++ b/src/main/bookingbugAPI/models/params/TimeDataParams.java @@ -0,0 +1,126 @@ +package bookingbugAPI.models.params; + +import com.fasterxml.jackson.databind.util.ISO8601DateFormat; + +import javax.print.DocFlavor; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Date; +import java.util.StringTokenizer; + +/** + * Created by sebi on 27.02.2016. + */ +public class TimeDataParams extends Params { + + String event_id; + String service_id; + String resource_id; + String resource_ids; + String person_id; + String group_id; + String location; + String date; + String end_date; + String duration; + String num_resources; + + public String getEvent_id() { + return event_id; + } + + public void setEvent_id(String event_id) { + this.event_id = event_id; + } + + public String getNum_resources() { + return num_resources; + } + + public void setNum_resources(String num_resources) { + this.num_resources = num_resources; + } + + public int getDuration() { + return Integer.parseInt(duration); + } + + public void setDuration(int duration) { + this.duration = String.valueOf(duration); + } + + public String getEnd_date() { + return end_date; + } + + public void setEnd_date(Date end_date) { + this.end_date = new ISO8601DateFormat().format(end_date); + } + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + + public String getDate() { + return date; + } + + public void setDate(Date date) { + this.date = new ISO8601DateFormat().format(date); + } + + + + public String getPerson_id() { + return person_id; + } + + public void setPerson_id(String person_id) { + this.person_id = person_id; + } + + public String getGroup_id() { + return group_id; + } + + public void setGroup_id(String group_id) { + this.group_id = group_id; + } + + public String getService_id() { + return service_id; + } + + public void setService_id(String service_id) { + this.service_id = service_id; + } + + public String getResource_id() { + return resource_id; + } + + public void setResource_id(String resource_id) { + this.resource_id = resource_id; + } + + public ArrayList getResource_ids() { + ArrayList res = new ArrayList<>(); + StringTokenizer tokenizer = new StringTokenizer(resource_ids, ","); + while (tokenizer.hasMoreTokens()) + res.add(tokenizer.nextToken()); + return res; + } + + public void setResource_ids(ArrayList resource_ids) { + this.resource_ids = ""; + for(int i = 0; i < resource_ids.size(); i++) { + this.resource_ids += resource_ids.get(i); + if(i + 1 < resource_ids.size()) + this.resource_ids += ","; + } + } +} diff --git a/src/main/helpers/Utils.java b/src/main/helpers/Utils.java index 1129a96..8788cd5 100644 --- a/src/main/helpers/Utils.java +++ b/src/main/helpers/Utils.java @@ -1,6 +1,8 @@ package helpers; +import bookingbugAPI.models.params.Params; import com.damnhandy.uri.template.UriTemplate; +import com.damnhandy.uri.template.UriTemplateBuilder; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -45,6 +47,24 @@ public static String absoluteURL(String url){ return absoluteURL(url, null); } + /** + * Given a string url returns a templated url with pagination + * @param fromTemplate String to convert to UriTemplate + * @return + */ + public static UriTemplate paginatedUriTemplate(String fromTemplate){ + return UriTemplate.buildFromTemplate(fromTemplate) + .query(UriTemplateBuilder.var("page"), UriTemplateBuilder.var("per_page")) + .build(); + } + + public static UriTemplate TemplateWithPagination(UriTemplate template, Params params){ + if(params != null){ + template.set("page", params.getPage()); + template.set("per_page", params.getPer_page()); + } + return template; + } /** * @param content From 5e8cfa428aa6813a8fee1df3fe46043b7fbf7d05 Mon Sep 17 00:00:00 2001 From: Macarescu Sebastian Date: Thu, 31 Mar 2016 18:22:24 +0300 Subject: [PATCH 02/22] Added call and model for company settings. Added basic ignore test for company --- pom.xml | 2 +- src/main/bookingbugAPI/api/AdminURLS.java | 1 + src/main/bookingbugAPI/api/PublicURLS.java | 4 +- src/main/bookingbugAPI/models/BBRoot.java | 12 +++ src/main/bookingbugAPI/models/Company.java | 18 ++-- .../bookingbugAPI/models/CompanySettings.java | 55 ++++++++++++ src/main/bookingbugAPI/models/Currency.java | 33 +++++++ src/main/bookingbugAPI/models/EventChain.java | 22 +++-- src/main/bookingbugAPI/models/Login.java | 3 + .../models/params/EventListParams.java | 85 +++++++++++++++++++ .../bookingbugAPI/models/params/Params.java | 10 +++ src/test/bookingbugAPI/api/CompanyTest.java | 43 ++++++++++ 12 files changed, 273 insertions(+), 15 deletions(-) create mode 100644 src/main/bookingbugAPI/models/CompanySettings.java create mode 100644 src/main/bookingbugAPI/models/Currency.java create mode 100644 src/main/bookingbugAPI/models/params/EventListParams.java create mode 100644 src/test/bookingbugAPI/api/CompanyTest.java diff --git a/pom.xml b/pom.xml index 4bbf841..900c64d 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ BookingBug-SDK BookingBug-SDK - 1.4 + 1.5 diff --git a/src/main/bookingbugAPI/api/AdminURLS.java b/src/main/bookingbugAPI/api/AdminURLS.java index d2b2df2..5ddfc9b 100644 --- a/src/main/bookingbugAPI/api/AdminURLS.java +++ b/src/main/bookingbugAPI/api/AdminURLS.java @@ -11,6 +11,7 @@ public static class Company { public static UriTemplate company() { return UriTemplate.buildFromTemplate(new Config().serverUrl) .literal("/admin") + .path(UriTemplateBuilder.var("companyId")) .literal("/company") .build(); } diff --git a/src/main/bookingbugAPI/api/PublicURLS.java b/src/main/bookingbugAPI/api/PublicURLS.java index 6764889..4aac65f 100644 --- a/src/main/bookingbugAPI/api/PublicURLS.java +++ b/src/main/bookingbugAPI/api/PublicURLS.java @@ -182,7 +182,9 @@ public static UriTemplate eventList(){ return UriTemplate.buildFromTemplate(new Config().serverUrl) .path(UriTemplateBuilder.var("companyId")) .literal("/" + eventsLink) - .query(UriTemplateBuilder.var("page"), UriTemplateBuilder.var("per_page")) + .query("page", "per_page", "event_chain_id", + "start_date", "end_date", "resource_id", "person_id", + "event_group_id", "summary", "member_level_id") .build(); } diff --git a/src/main/bookingbugAPI/models/BBRoot.java b/src/main/bookingbugAPI/models/BBRoot.java index ac369ea..ccbaa6e 100644 --- a/src/main/bookingbugAPI/models/BBRoot.java +++ b/src/main/bookingbugAPI/models/BBRoot.java @@ -107,6 +107,18 @@ public String get(String key){ return val; } + public boolean getBoolean(String key, boolean defaultValue) { + String val = this.get(key); + if(val != null) return Boolean.parseBoolean(val); + return defaultValue; + } + + public int getInteger(String key, int defaultValue) { + String val = this.get(key); + if(val != null) return Integer.parseInt(val); + return defaultValue; + } + public String getAuth_token() { return auth_token; diff --git a/src/main/bookingbugAPI/models/Company.java b/src/main/bookingbugAPI/models/Company.java index ebe7b8b..dc786c2 100644 --- a/src/main/bookingbugAPI/models/Company.java +++ b/src/main/bookingbugAPI/models/Company.java @@ -12,6 +12,7 @@ import com.fasterxml.jackson.module.jsonSchema.factories.SchemaFactoryWrapper; import com.theoryinpractise.halbuilder.api.ContentRepresentation; import bookingbugAPI.services.HttpService; +import com.theoryinpractise.halbuilder.api.ReadableRepresentation; import com.theoryinpractise.halbuilder.json.JsonRepresentationFactory; import helpers.HttpServiceResponse; import helpers.Utils; @@ -19,6 +20,7 @@ import java.io.*; import java.net.MalformedURLException; import java.net.URL; +import java.util.List; import java.util.Map; import static com.theoryinpractise.halbuilder.api.RepresentationFactory.HAL_JSON; @@ -638,18 +640,24 @@ public Resource spaceStatusList() throws IOException { } + /** * Loads all of the public settings for a company, this allows you to configure a booking widget, * and shows all of the details need to book and show an appropriate widget. - * @return Resource + * @return CompanySettings * @throws IOException */ - public Resource settingsDetails() throws IOException { - URL url = new URL(PublicURLS.Company.settingsDetails().set("companyId", this.id).expand()); - return new Resource(HttpService.api_GET(url)); + public CompanySettings getSettings() throws IOException { + if(getRep().getResourcesByRel("settings").size() > 0) { + //Return settings from embedded + return new CompanySettings(new HttpServiceResponse((ContentRepresentation) getRep().getResourcesByRel("settings").get(0))); + } else { + //Call API + URL url = new URL(PublicURLS.Company.settingsDetails().set("companyId", this.id).expand()); + return new CompanySettings(HttpService.api_GET(url)); + } } - /** * You can either get all the company questions or pass a param to specifiy that you only want company questions * that apply to either a service, resource, person, company: diff --git a/src/main/bookingbugAPI/models/CompanySettings.java b/src/main/bookingbugAPI/models/CompanySettings.java new file mode 100644 index 0000000..a1fd5e1 --- /dev/null +++ b/src/main/bookingbugAPI/models/CompanySettings.java @@ -0,0 +1,55 @@ +package bookingbugAPI.models; + +import helpers.HttpServiceResponse; + +/** + * Created by sebi on 31.03.2016. + */ +public class CompanySettings extends BBRoot { + + public CompanySettings(HttpServiceResponse httpServiceResponse, String auth_token) { + super(httpServiceResponse, auth_token); + } + + public CompanySettings(HttpServiceResponse response) { + super(response); + } + + public boolean has_coupons() { + return getBoolean("has_coupons", false); + } + + public boolean has_deals() { + return getBoolean("has_deals", false); + } + + public boolean has_products() { + return getBoolean("has_products", false); + } + + public boolean has_events() { + return getBoolean("has_events", false); + } + + public boolean has_classes() { + return getBoolean("has_classes", false); + } + + public boolean requires_login() { + return getBoolean("requires_login", false); + } + + public boolean has_wallets() { + return getBoolean("has_wallets", false); + } + + public int getPaymentTax() { + return getInteger("payment_tax", 0); + } + + + + public Currency getCurrency() { + return Currency.fromString(get("currency")); + } +} diff --git a/src/main/bookingbugAPI/models/Currency.java b/src/main/bookingbugAPI/models/Currency.java new file mode 100644 index 0000000..1cf3c6b --- /dev/null +++ b/src/main/bookingbugAPI/models/Currency.java @@ -0,0 +1,33 @@ +package bookingbugAPI.models; + +/** + * Created by sebi on 31.03.2016. + */ +public enum Currency { + GBP("GBP"), + EUR("EUR"); + + private final String apiValue; + + private Currency(String apiValue) { + this.apiValue = apiValue; + } + + public String symbol() { + switch (this) { + case GBP: return "\u00a3"; + case EUR: return "\u20ac"; + default: return ""; + } + } + + public static Currency fromString(String str) { + if(str != null) { + for(Currency currency : Currency.values()) { + if(str.equalsIgnoreCase(currency.apiValue)) + return currency; + } + } + return null; + } +} diff --git a/src/main/bookingbugAPI/models/EventChain.java b/src/main/bookingbugAPI/models/EventChain.java index a68bdd3..2d88b8f 100644 --- a/src/main/bookingbugAPI/models/EventChain.java +++ b/src/main/bookingbugAPI/models/EventChain.java @@ -1,8 +1,7 @@ package bookingbugAPI.models; -import bookingbugAPI.api.AdminURLS; import bookingbugAPI.api.PublicURLS; -import bookingbugAPI.models.params.Params; +import bookingbugAPI.models.params.EventListParams; import bookingbugAPI.services.HttpService; import com.damnhandy.uri.template.UriTemplate; import helpers.HttpServiceResponse; @@ -35,15 +34,22 @@ public EventChain() {} * @return BBCollection * @throws IOException */ - public BBCollection eventList(Params params) throws IOException { - UriTemplate template = Utils.TemplateWithPagination( - Utils.paginatedUriTemplate(getLink("events")), - params); - URL url = new URL(template.expand()); + public BBCollection eventList(EventListParams params) throws IOException { + UriTemplate template; + if(getLink("events") != null) { + template = Utils.TemplateWithPagination( + Utils.paginatedUriTemplate(getLink("events")), + params); + } else { + params.setEvent_chain_id(this.id); + template = PublicURLS.Event.eventList().set("companyId", get("company_id")); + } + + URL url = new URL(template.expand(params.getParamsMapObj())); return new BBCollection(HttpService.api_GET(url, auth_token), auth_token, "events", Event.class); } - public Observable> eventListObs(final Params params){ + public Observable> eventListObs(final EventListParams params){ return Observable.fromCallable(new Callable>() { @Override public BBCollection call() throws Exception { diff --git a/src/main/bookingbugAPI/models/Login.java b/src/main/bookingbugAPI/models/Login.java index 303f445..050d5b6 100644 --- a/src/main/bookingbugAPI/models/Login.java +++ b/src/main/bookingbugAPI/models/Login.java @@ -5,7 +5,10 @@ import com.damnhandy.uri.template.UriTemplate; import com.theoryinpractise.halbuilder.api.ContentRepresentation; import com.theoryinpractise.halbuilder.api.Link; +import helpers.Config; import helpers.HttpServiceResponse; +import helpers.TokenGenerator; +import org.json.simple.JSONObject; import java.io.IOException; import java.net.MalformedURLException; diff --git a/src/main/bookingbugAPI/models/params/EventListParams.java b/src/main/bookingbugAPI/models/params/EventListParams.java new file mode 100644 index 0000000..48ed147 --- /dev/null +++ b/src/main/bookingbugAPI/models/params/EventListParams.java @@ -0,0 +1,85 @@ +package bookingbugAPI.models.params; + +/** + * Created by sebi on 31.03.2016. + */ +public class EventListParams extends Params { + String resource_id; + String event_chain_id; + String person_id; + String event_group_id; + String summary; + String member_level_id; + String start_date; + String end_date; + + public EventListParams() {} + + public EventListParams(int page){ + super(page); + } + + public String getResource_id() { + return resource_id; + } + + public void setResource_id(String resource_id) { + this.resource_id = resource_id; + } + + public String getPerson_id() { + return person_id; + } + + public void setPerson_id(String person_id) { + this.person_id = person_id; + } + + public String getEvent_group_id() { + return event_group_id; + } + + public void setEvent_group_id(String event_group_id) { + this.event_group_id = event_group_id; + } + + public String getSummary() { + return summary; + } + + public void setSummary(String summary) { + this.summary = summary; + } + + public String getMember_level_id() { + return member_level_id; + } + + public void setMember_level_id(String member_level_id) { + this.member_level_id = member_level_id; + } + + public String getStart_date() { + return start_date; + } + + public void setStart_date(String start_date) { + this.start_date = start_date; + } + + public String getEnd_date() { + return end_date; + } + + public void setEnd_date(String end_date) { + this.end_date = end_date; + } + + public String getEvent_chain_id() { + return event_chain_id; + } + + public void setEvent_chain_id(String event_chain_id) { + this.event_chain_id = event_chain_id; + } +} diff --git a/src/main/bookingbugAPI/models/params/Params.java b/src/main/bookingbugAPI/models/params/Params.java index 8065b67..a1b468f 100644 --- a/src/main/bookingbugAPI/models/params/Params.java +++ b/src/main/bookingbugAPI/models/params/Params.java @@ -14,6 +14,10 @@ public class Params { public Params() {} + public Params(int page) { + this.page = page; + } + public Params(Map args){ setNotNullStringMap(args); } @@ -64,6 +68,12 @@ public Map getParams(){ return getNotNullStringMap(); } + public Map getParamsMapObj() { + Map objectMap = new HashMap<>(); + objectMap.putAll(getParams()); + return objectMap; + } + public int getPage() { return page; } diff --git a/src/test/bookingbugAPI/api/CompanyTest.java b/src/test/bookingbugAPI/api/CompanyTest.java new file mode 100644 index 0000000..09d50eb --- /dev/null +++ b/src/test/bookingbugAPI/api/CompanyTest.java @@ -0,0 +1,43 @@ +package bookingbugAPI.api; + +import bookingbugAPI.models.Company; +import bookingbugAPI.models.Currency; +import bookingbugAPI.models.HttpException; +import bookingbugAPI.models.Login; +import bookingbugAPI.services.HttpService; +import helpers.TokenGenerator; +import org.json.simple.JSONObject; +import org.junit.Ignore; +import org.junit.Test; + +import java.net.MalformedURLException; +import java.net.URL; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +/** + * Created by sebi on 31.03.2016. + */ + +@Ignore +public class CompanyTest { + + private static final String companyId = "37028"; + private static final String token = "7gcmPMDS-G2gpNiPSUQA4A"; + + @Test + public void companySettings(){ + Company company = null; + try { + URL url = new URL(AdminURLS.Company.company().set("companyId", companyId).expand()); + company = new Company(HttpService.api_GET(url, token), token); + assertNotNull(company); + assertNotNull(company.getSettings()); + assertEquals(company.getSettings().getCurrency(), Currency.GBP); + }catch (Exception e) { + e.printStackTrace(); + } + } +} From 1f385e93a4b0aeb3d0a7c28772da761f3f9a4710 Mon Sep 17 00:00:00 2001 From: Macarescu Sebastian Date: Wed, 13 Apr 2016 18:32:06 +0300 Subject: [PATCH 03/22] Implemented Custom UrlEncoder for Map, GenericEncoder, JsonEncoder. Params.getMap returns now generic map. Added posibillity to add json to params objects --- pom.xml | 2 +- src/main/bookingbugAPI/models/BBRoot.java | 13 ++ src/main/bookingbugAPI/models/Company.java | 9 +- src/main/bookingbugAPI/models/SchemaForm.java | 58 +++++++ .../models/params/BookingCreateParams.java | 32 +--- .../bookingbugAPI/models/params/Params.java | 42 ++++- .../bookingbugAPI/services/HttpService.java | 111 +++--------- src/main/helpers/Http.java | 162 ++++++++++++++++++ src/main/helpers/HttpServiceResponse.java | 28 +-- .../CustomJsonRepresentationReader.java | 2 +- src/test/bookingbugAPI/api/CompanyTest.java | 25 ++- src/test/bookingbugAPI/models/ParamsTest.java | 17 +- .../services/UrlEncoderTest.java | 67 ++++++++ 13 files changed, 419 insertions(+), 149 deletions(-) create mode 100644 src/main/bookingbugAPI/models/SchemaForm.java create mode 100644 src/main/helpers/Http.java create mode 100644 src/test/bookingbugAPI/services/UrlEncoderTest.java diff --git a/pom.xml b/pom.xml index 900c64d..4f08a46 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ BookingBug-SDK BookingBug-SDK - 1.5 + 1.6 diff --git a/src/main/bookingbugAPI/models/BBRoot.java b/src/main/bookingbugAPI/models/BBRoot.java index ccbaa6e..8cbca12 100644 --- a/src/main/bookingbugAPI/models/BBRoot.java +++ b/src/main/bookingbugAPI/models/BBRoot.java @@ -3,6 +3,9 @@ import bookingbugAPI.services.HttpService; import com.damnhandy.uri.template.UriTemplate; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; import com.theoryinpractise.halbuilder.api.ContentRepresentation; import com.theoryinpractise.halbuilder.api.Link; import com.theoryinpractise.halbuilder.api.RepresentationException; @@ -150,6 +153,16 @@ public String toString() { return response.getRep().getContent(); } + public String toPrettyString() { + ObjectMapper mapper = new ObjectMapper(); + try { + return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(response.getRep()); + } catch (JsonProcessingException e) { + e.printStackTrace(); + return toString(); + } + } + public String getCurl() { curl = "curl \"" + getSelf() + "\" " + response.getParamsStr() + " -X " + response.getMethod(); diff --git a/src/main/bookingbugAPI/models/Company.java b/src/main/bookingbugAPI/models/Company.java index dc786c2..8a87354 100644 --- a/src/main/bookingbugAPI/models/Company.java +++ b/src/main/bookingbugAPI/models/Company.java @@ -12,7 +12,6 @@ import com.fasterxml.jackson.module.jsonSchema.factories.SchemaFactoryWrapper; import com.theoryinpractise.halbuilder.api.ContentRepresentation; import bookingbugAPI.services.HttpService; -import com.theoryinpractise.halbuilder.api.ReadableRepresentation; import com.theoryinpractise.halbuilder.json.JsonRepresentationFactory; import helpers.HttpServiceResponse; import helpers.Utils; @@ -20,7 +19,6 @@ import java.io.*; import java.net.MalformedURLException; import java.net.URL; -import java.util.List; import java.util.Map; import static com.theoryinpractise.halbuilder.api.RepresentationFactory.HAL_JSON; @@ -1077,6 +1075,11 @@ public Resource deleteBasketCoupon() throws IOException { return new Resource(HttpService.api_DELETE(url), auth_token); } + public SchemaForm getNewBookingSchema() throws IOException { + String link = getRep().getLinkByRel("new_booking").getHref(); + URL url = new URL(UriTemplate.fromTemplate(link).expand()); + return new SchemaForm(HttpService.api_GET(url, auth_token)); + } public Booking bookingCreate_Admin(BookingCreateParams bCParams) throws IOException { String urlStr = AdminURLS.Bookings.bookingCreate().set("companyId", this.id).expand(); @@ -1111,6 +1114,8 @@ public Booking bookingRead_Admin(String bookingId) throws IOException { } + + /** * Get all the coupons for a Company. * @return BBCollection diff --git a/src/main/bookingbugAPI/models/SchemaForm.java b/src/main/bookingbugAPI/models/SchemaForm.java new file mode 100644 index 0000000..3c98cd7 --- /dev/null +++ b/src/main/bookingbugAPI/models/SchemaForm.java @@ -0,0 +1,58 @@ +package bookingbugAPI.models; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import helpers.HttpServiceResponse; + +import java.util.Map; + +/** + * Created by sebi on 11.04.2016. + */ +public class SchemaForm extends BBRoot { + public SchemaForm(HttpServiceResponse httpServiceResponse, String auth_token) { + super(httpServiceResponse, auth_token); + } + + public SchemaForm(HttpServiceResponse response) { + super(response); + } + + public String getSchemaStr() { + return getSchemaJson().toString(); + } + + public JsonNode getSchemaJson() { + JsonNodeFactory factory = JsonNodeFactory.instance; + ObjectMapper mapper = new ObjectMapper(); + + // Defaults to empty json + JsonNode schema = factory.objectNode(); + + + if(getRep().getValue("schema", null) != null) { + schema = mapper.convertValue(getRep().getValue("schema"), JsonNode.class); + } + + return schema; + } + + public String getFormStr() { + return getFormJson().toString(); + } + + public JsonNode getFormJson() { + JsonNodeFactory factory = JsonNodeFactory.instance; + ObjectMapper mapper = new ObjectMapper(); + + // Defaults to empty json + JsonNode form = factory.objectNode(); + + if(getRep().getValue("form", null) != null) { + form = mapper.convertValue(getRep().getValue("form"), JsonNode.class); + } + + return form; + } +} diff --git a/src/main/bookingbugAPI/models/params/BookingCreateParams.java b/src/main/bookingbugAPI/models/params/BookingCreateParams.java index f0bb1bb..01ce2e0 100644 --- a/src/main/bookingbugAPI/models/params/BookingCreateParams.java +++ b/src/main/bookingbugAPI/models/params/BookingCreateParams.java @@ -17,36 +17,8 @@ public class BookingCreateParams extends Params{ public BookingCreateParams(){} - public BookingCreateParams(Map args){ - if (args==null || args.isEmpty()) { - return; - } - - String strValue; - - for (Map.Entry entry : args.entrySet()) { - final String[] value = entry.getValue(); - if (value[0]!=null && !value[0].trim().isEmpty()) { - strValue = null; - } else { - strValue = value[0]; - } - - switch(entry.getKey()) { - case "datetime": datetime = strValue; - break; - case "service_id": service_id = strValue; - break; - case "person_id": person_id = strValue; - break; - case "resource_id": resource_id = strValue; - break; - case "member_id": member_id = strValue; - break; - case "notifications": notifications = strValue; - break; - } - } + public BookingCreateParams(Map args){ + super(args); } public String getDatetime() { diff --git a/src/main/bookingbugAPI/models/params/Params.java b/src/main/bookingbugAPI/models/params/Params.java index a1b468f..ae46ff0 100644 --- a/src/main/bookingbugAPI/models/params/Params.java +++ b/src/main/bookingbugAPI/models/params/Params.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; @@ -12,6 +13,9 @@ public class Params { private int page = 1; private int per_page = 100; + public boolean hasJson = false; + private String jsonContent; + public Params() {} public Params(int page) { @@ -35,6 +39,11 @@ public static Params withPagination(int page){ return params; } + public void setJson(String json) { + hasJson = true; + jsonContent = json; + } + public Map getNotNullStringMap() { Map result = new HashMap(); Field[] declaredFields = this.getClass().getDeclaredFields(); @@ -64,10 +73,32 @@ public void setNotNullStringMap(Map map) { } } - public Map getParams(){ - return getNotNullStringMap(); + /** + * Get parameters. If hasJson is true (setJson method has been called) then the parameters will be extracted from + * json string. Otherwise all non null declared fields of this object will be included + * + * @return Generic Map with parameters + */ + public Map getParams(){ + if(!hasJson) + // Return default map + return getNotNullStringMap(); + + // Return map from jsonContent + ObjectMapper mapper = new ObjectMapper(); + HashMap map = new HashMap<>(); + try { + map = mapper.readValue(jsonContent, HashMap.class); + } catch (IOException e) { + e.printStackTrace(); + } + return map; } + /** + * @see Params#getParams() + * @return + */ public Map getParamsMapObj() { Map objectMap = new HashMap<>(); objectMap.putAll(getParams()); @@ -84,13 +115,12 @@ public int getPer_page() { @Override public String toString(){ - String json = ""; + String jsonThis = ""; try { - json = new ObjectMapper().writeValueAsString(this); + jsonThis = new ObjectMapper().writeValueAsString(this); } catch (JsonProcessingException e) { e.printStackTrace(); } - return json; + return hasJson ? jsonContent : jsonThis; } - } \ No newline at end of file diff --git a/src/main/bookingbugAPI/services/HttpService.java b/src/main/bookingbugAPI/services/HttpService.java index 283bcba..349beae 100644 --- a/src/main/bookingbugAPI/services/HttpService.java +++ b/src/main/bookingbugAPI/services/HttpService.java @@ -3,21 +3,18 @@ import bookingbugAPI.models.HttpException; import bookingbugAPI.models.PublicRoot; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import com.theoryinpractise.halbuilder.api.ContentRepresentation; import com.theoryinpractise.halbuilder.api.RepresentationFactory; -import com.theoryinpractise.halbuilder.json.JsonRepresentationFactory; import helpers.Config; import bookingbugAPI.models.BBRoot; +import helpers.Http; import helpers.HttpServiceResponse; import helpers.hal_addon.CustomJsonRepresentationFactory; import java.io.*; import java.lang.reflect.InvocationTargetException; import java.net.HttpURLConnection; -import java.net.ProtocolException; import java.net.URL; -import java.net.URLEncoder; import java.util.Map; import java.util.logging.Logger; @@ -29,50 +26,13 @@ public class HttpService { public final static String jsonContentType = "application/json"; public final static String urlEncodedContentType = "application/x-www-form-urlencoded"; + public final static String UTF8Encoding = "UTF-8"; - public static String encodeParams(Map params) { - StringBuilder postData = new StringBuilder(); - try{ - for (Map.Entry param : params.entrySet()) { - if (postData.length() != 0) postData.append('&'); - postData.append(URLEncoder.encode(param.getKey(), "UTF-8")); - postData.append('='); - postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8")); - } - } catch(UnsupportedEncodingException e){ - log.warning(e.getMessage()); - } - return postData.toString(); - } - - public static String encodeParamsJson(Map params) { - String json = ""; - try { - json = new ObjectMapper().writeValueAsString(params); - } catch (JsonProcessingException e) { - e.printStackTrace(); - } - return json; - } - - public static byte[] encodeUTF8(Map params, String contentType) { - byte[] data = new byte[0]; - String encodedParams = ""; - - //Convert to json instead - if(contentType == urlEncodedContentType) - encodedParams = encodeParams(params); - else if(contentType == jsonContentType) - encodedParams = encodeParamsJson(params); - - try { - data = encodedParams.getBytes("UTF-8"); - //data = json.getBytes("UTF-8"); - } catch (UnsupportedEncodingException e) { - log.warning(e.getMessage()); - } - return data; + public static byte[] encodeUTF8(Map params, String contentType) throws Http.UnknownContentType, Http.EncodingException, UnsupportedEncodingException { + return Http.getEncoder(contentType) + .encode(params) + .getBytes(UTF8Encoding); } public static HttpServiceResponse api_GET(URL url, boolean testingMode) throws HttpException { @@ -99,23 +59,23 @@ public static HttpServiceResponse api_POST(URL url, String auth_token) throws Ht return callApi(url, auth_token, "POST", urlEncodedContentType, null); } - public static HttpServiceResponse api_POST(URL url, Map params) throws HttpException { + public static HttpServiceResponse api_POST(URL url, Map params) throws HttpException { return callApi(url, null, "POST", urlEncodedContentType, params); } - public static HttpServiceResponse api_POST(URL url, Map params, String auth_token) throws HttpException { + public static HttpServiceResponse api_POST(URL url, Map params, String auth_token) throws HttpException { return callApi(url, auth_token, "POST", urlEncodedContentType, params); } - public static HttpServiceResponse api_PUT(URL url, Map params) throws HttpException { + public static HttpServiceResponse api_PUT(URL url, Map params) throws HttpException { return callApi(url, null, "PUT", urlEncodedContentType, params); } - public static HttpServiceResponse api_PUT(URL url, Map params, String auth_token) throws HttpException { + public static HttpServiceResponse api_PUT(URL url, Map params, String auth_token) throws HttpException { return callApi(url, auth_token, "PUT", urlEncodedContentType, params); } - public static HttpServiceResponse api_PUT(URL url, String contentType, Map params, String auth_token) throws HttpException { + public static HttpServiceResponse api_PUT(URL url, String contentType, Map params, String auth_token) throws HttpException { return callApi(url, auth_token, "PUT", contentType, params); } @@ -127,17 +87,18 @@ public static HttpServiceResponse api_DELETE(URL url, String auth_token) throws return callApi(url, auth_token, "DELETE", urlEncodedContentType, null); } - public static HttpServiceResponse api_DELETE(URL url, String contentType, Map params, String auth_token) throws HttpException { + public static HttpServiceResponse api_DELETE(URL url, String contentType, Map params, String auth_token) throws HttpException { return callApi(url, auth_token, "DELETE", contentType, params); } - private static HttpServiceResponse callApi(URL url, String auth_token, String method, String contentType, Map params) throws HttpException { + private static HttpServiceResponse callApi(URL url, String auth_token, String method, String contentType, Map params) throws HttpException { return callApi(url, auth_token, method, contentType, params, false); } - private static HttpServiceResponse callApi(URL url, String auth_token, String method, String contentType, Map params, boolean testingMode) throws HttpException { + private static HttpServiceResponse callApi(URL url, String auth_token, String method, String contentType, Map params, boolean testingMode) throws HttpException { String returnString = ""; String errorMessage = ""; + byte[] bodyBytes = new byte[0]; int responseCode = 200; boolean throwError = false; HttpURLConnection urlConnection = null; @@ -158,7 +119,8 @@ private static HttpServiceResponse callApi(URL url, String auth_token, String me if(params != null) { //Set params in body urlConnection.setDoOutput(true); - urlConnection.getOutputStream().write(encodeUTF8(params, contentType)); + bodyBytes = encodeUTF8(params, contentType); + urlConnection.getOutputStream().write(bodyBytes); } responseCode = urlConnection.getResponseCode(); @@ -191,50 +153,25 @@ private static HttpServiceResponse callApi(URL url, String auth_token, String me if (!testingMode) { if(throwError) { - errorMessage = "The call to " + url.toString() + " returned " + urlConnection.getResponseCode() + " . Error message: " + returnString; + errorMessage = "The call to " + url.toString() + + "with parameters " + new String(bodyBytes, UTF8Encoding) + " returned " + + urlConnection.getResponseCode() + " . Error message: " + returnString; //System.out.println("Error message: "+ errorMessage); } else { Reader reader = new InputStreamReader(new ByteArrayInputStream(returnString.getBytes())); - return new HttpServiceResponse(representationFactory.readRepresentation(HAL_JSON, reader), method, params, auth_token); + return new HttpServiceResponse(representationFactory.readRepresentation(HAL_JSON, reader), method, contentType, params, auth_token); } } else { Reader reader = new InputStreamReader(new ByteArrayInputStream(returnString.getBytes())); - return new HttpServiceResponse(representationFactory.readRepresentation(HAL_JSON, reader), method, params, auth_token); + return new HttpServiceResponse(representationFactory.readRepresentation(HAL_JSON, reader), method, contentType, params, auth_token); } - } catch (IOException e) { throw new HttpException("Error", returnString, e) ; + } catch (Http.EncodingException | Http.UnknownContentType e) { + throw new HttpException("Error when writing body params", e) ; } finally { if(urlConnection != null) urlConnection.disconnect(); } throw new HttpException(errorMessage, returnString, responseCode); } - - public PublicRoot start() throws IOException { - URL url = new URL(new Config().serverUrl); - return new PublicRoot(api_GET(url)); - } - - public BBRoot start(Class type) throws IOException { - URL url = new URL(new Config().serverUrl); - ContentRepresentation representation = api_GET(url).getRep(); - Object obj = null; - - Class[] args = new Class[2]; - args[0] = representation.getClass(); - args[1] = this.getClass(); - - try { - obj = type.getConstructor(ContentRepresentation.class, HttpService.class).newInstance(representation, this); - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } - return (BBRoot)obj; - } } \ No newline at end of file diff --git a/src/main/helpers/Http.java b/src/main/helpers/Http.java new file mode 100644 index 0000000..9607b70 --- /dev/null +++ b/src/main/helpers/Http.java @@ -0,0 +1,162 @@ +package helpers; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.*; + +/** + * Created by sebi on 13.04.2016. + */ +public class Http { + public final static String jsonContentType = "application/json"; + public final static String urlEncodedContentType = "application/x-www-form-urlencoded"; + + public static Encoder getEncoder(String content_type) throws UnknownContentType { + if(jsonContentType.equals(content_type)) + return new JsonEncoder(); + else if(urlEncodedContentType.equals(content_type)) + return new UrlEncoder(); + + throw new UnknownContentType("Unknown content type: " + content_type + + ". Possible values are " + jsonContentType + ", " + urlEncodedContentType); + } + + public interface Encoder { + String encode(Map map) throws EncodingException; + } + + public static class UrlEncoder implements Encoder { + + private static final Set> PRIMITIVE_WRAPPER_TYPES; + static { + PRIMITIVE_WRAPPER_TYPES = new HashSet>(); + PRIMITIVE_WRAPPER_TYPES.add(Boolean.class); + PRIMITIVE_WRAPPER_TYPES.add(Character.class); + PRIMITIVE_WRAPPER_TYPES.add(String.class); + PRIMITIVE_WRAPPER_TYPES.add(Short.class); + PRIMITIVE_WRAPPER_TYPES.add(Integer.class); + PRIMITIVE_WRAPPER_TYPES.add(Long.class); + PRIMITIVE_WRAPPER_TYPES.add(Float.class); + PRIMITIVE_WRAPPER_TYPES.add(Double.class); + } + + private boolean ignoreNull = false; + + public UrlEncoder(){} + + public UrlEncoder(boolean ignoreNull) { + this.ignoreNull = ignoreNull; + } + + public String encode(Map map) throws EncodingException { + try { + ArrayList encoded = new ArrayList<>(); + for (Object o : map.entrySet()) { + Map.Entry pair = (Map.Entry) o; + + encoded.add(nest(pair.getKey().toString(), pair.getValue())); + } + return joinArray(encoded); + } catch (UnsupportedEncodingException e) { + throw new EncodingException("Exception when encoding to " + urlEncodedContentType, e); + } + } + + private String encode(String value) throws UnsupportedEncodingException { + return URLEncoder.encode(value, "UTF-8"); + } + + private static String joinArray(ArrayList arr) { + String res = ""; + for(int i = 0; i < arr.size(); i++) { + if(arr.get(i).toString().isEmpty()) continue; + res += arr.get(i).toString(); + //Last element + if(i == arr.size() - 1) continue; + res += '&'; + } + return res; + } + + private String arrayNest(String name, ArrayList value) throws UnsupportedEncodingException { + if(value == null) return ""; + + ArrayList encoded = new ArrayList<>(); + for(Object obj : value) { + encoded.add(nest(name + "[]", obj)); + } + return joinArray(encoded); + } + + private String objectNest(String name, Map value) throws UnsupportedEncodingException { + if(value == null) return ""; + + ArrayList encoded = new ArrayList<>(); + for (Object o : value.entrySet()) { + Map.Entry pair = (Map.Entry) o; + encoded.add(nest(name + '[' + pair.getKey().toString() + ']', pair.getValue())); + } + + return joinArray(encoded); + } + + private String nest(String name, Object value) throws UnsupportedEncodingException { + String res = ""; + + if(value == null) { + res = ignoreNull ? "" : encode(name) + '=' + "null"; + } else if(isPrimitiveWrapper(value.getClass())) { + res = encode(name) + '=' + encode(value.toString()); + } else if (value instanceof Collection) { + //Array + res = arrayNest(name, (ArrayList)value); + } else if (value instanceof Map) { + //Object + res = objectNest(name, (Map)value); + } + + return res; + } + + public static boolean isPrimitiveWrapper(Class clazz) + { + return PRIMITIVE_WRAPPER_TYPES.contains(clazz); + } + } + + public static class JsonEncoder implements Encoder { + + @Override + public String encode(Map map) throws EncodingException { + try { + return new ObjectMapper().writeValueAsString(map); + } catch (JsonProcessingException e) { + throw new EncodingException("Exception when encoding to " + jsonContentType, e); + } + } + } + + public static class EncodingException extends Exception { + + public EncodingException(String message) { + super(message); + } + + public EncodingException(String message, Throwable cause) { + super(message, cause); + } + + public EncodingException(Throwable cause) { + super(cause); + } + } + + public static class UnknownContentType extends Exception { + public UnknownContentType(String message) { + super(message); + } + } + +} diff --git a/src/main/helpers/HttpServiceResponse.java b/src/main/helpers/HttpServiceResponse.java index 622a00b..8626f12 100644 --- a/src/main/helpers/HttpServiceResponse.java +++ b/src/main/helpers/HttpServiceResponse.java @@ -1,5 +1,6 @@ package helpers; +import bookingbugAPI.services.HttpService; import com.theoryinpractise.halbuilder.api.ContentRepresentation; import java.util.Map; @@ -10,7 +11,8 @@ public class HttpServiceResponse { protected ContentRepresentation rep; protected String method; - protected Map params; + protected String contentType = HttpService.jsonContentType; + protected Map params; protected String authToken; @@ -22,7 +24,7 @@ public HttpServiceResponse(ContentRepresentation rep) { } - public HttpServiceResponse(ContentRepresentation rep, String method, Map params) { + public HttpServiceResponse(ContentRepresentation rep, String method, Map params) { this.rep = rep; this.method = method; this.params = params; @@ -30,9 +32,10 @@ public HttpServiceResponse(ContentRepresentation rep, String method, Map params, String auth_token) { + public HttpServiceResponse(ContentRepresentation rep, String method, String contentType, Map params, String auth_token) { this.rep = rep; this.method = method; + this.contentType = contentType; this.params = params; this.authToken = auth_token; } @@ -58,12 +61,12 @@ public void setMethod(String method) { } - public void setParams(Map params) { + public void setParams(Map params) { this.params = params; } - public Map getParams() { + public Map getParams() { return params; } @@ -84,18 +87,15 @@ public String getParamsStr() { paramsStr += " -H \"Auth_Token:" + authToken + "\""; } - if (params!=null) { + try { + paramsStr += " -H \"Content-Type: " + contentType + "\""; paramsStr += " -d \""; - int i=0; - for (Map.Entry param : params.entrySet()) { - if (i>0) { - paramsStr += "&"; - } - paramsStr += param.getKey() + "=" + param.getValue(); - i++; - } + paramsStr += Http.getEncoder(contentType).encode(params); paramsStr += "\""; } + catch (Http.EncodingException | Http.UnknownContentType | NullPointerException e) { + e.printStackTrace(); + } return paramsStr; } diff --git a/src/main/helpers/hal_addon/CustomJsonRepresentationReader.java b/src/main/helpers/hal_addon/CustomJsonRepresentationReader.java index c8aa67e..b51cc59 100644 --- a/src/main/helpers/hal_addon/CustomJsonRepresentationReader.java +++ b/src/main/helpers/hal_addon/CustomJsonRepresentationReader.java @@ -33,7 +33,7 @@ public CustomJsonRepresentationReader(AbstractRepresentationFactory representati this.mapper = new ObjectMapper(); SimpleModule simpleModule = new SimpleModule(); - simpleModule.addDeserializer(Object.class, new CustomJsonDeserializer()); + simpleModule.addDeserializer(String.class, new CustomJsonDeserializer()); this.mapper.registerModule(simpleModule); } diff --git a/src/test/bookingbugAPI/api/CompanyTest.java b/src/test/bookingbugAPI/api/CompanyTest.java index 09d50eb..7f9679e 100644 --- a/src/test/bookingbugAPI/api/CompanyTest.java +++ b/src/test/bookingbugAPI/api/CompanyTest.java @@ -1,16 +1,10 @@ package bookingbugAPI.api; -import bookingbugAPI.models.Company; -import bookingbugAPI.models.Currency; -import bookingbugAPI.models.HttpException; -import bookingbugAPI.models.Login; +import bookingbugAPI.models.*; import bookingbugAPI.services.HttpService; -import helpers.TokenGenerator; -import org.json.simple.JSONObject; import org.junit.Ignore; import org.junit.Test; -import java.net.MalformedURLException; import java.net.URL; import static org.junit.Assert.assertEquals; @@ -40,4 +34,21 @@ public void companySettings(){ e.printStackTrace(); } } + + @Test + public void companyBookingSchema(){ + Company company = null; + SchemaForm schemaForm = null; + try { + URL url = new URL(AdminURLS.Company.company().set("companyId", companyId).expand()); + company = new Company(HttpService.api_GET(url, token), token); + assertNotNull(company); + + schemaForm = company.getNewBookingSchema(); + assertNotNull(schemaForm); + schemaForm.getSchemaJson(); + } catch (Exception e) { + e.printStackTrace(); + } + } } diff --git a/src/test/bookingbugAPI/models/ParamsTest.java b/src/test/bookingbugAPI/models/ParamsTest.java index c53cfbc..cced630 100644 --- a/src/test/bookingbugAPI/models/ParamsTest.java +++ b/src/test/bookingbugAPI/models/ParamsTest.java @@ -2,11 +2,15 @@ import bookingbugAPI.models.params.BookingCreateParams; import bookingbugAPI.models.params.ClientCreateParams; +import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.Test; +import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; /** @@ -21,7 +25,7 @@ public void paramsMap(){ params.setService_id("service_id"); params.setMember_id("member_id"); - Map map = params.getParams(); + Map map = params.getParams(); assertTrue(map.size() == 3); assertTrue(map.containsKey("datetime")); @@ -56,4 +60,15 @@ public void clientCreateParamsFromMap(){ assertTrue(params2.getPostcode().equals("123")); assertTrue(params2.getMember_type().equals("3")); } + + @Test + public void jsonParamsTest() { + String json = "{\"str\":\"val\", \"num\":0, \"arr\":[29], \"arr2\":[{\"name\":\"mkyong1\"}, {\"name\":\"mkyong1\"}]}}"; + BookingCreateParams params = new BookingCreateParams(); + params.setJson(json); + Map m = params.getParams(); + assertNotNull(m); + assertTrue(m.containsKey("arr2") && m.get("arr2") != null && m.get("arr2") instanceof ArrayList); + assertTrue(m.containsKey("str") && "val".equals(m.get("str"))); + } } diff --git a/src/test/bookingbugAPI/services/UrlEncoderTest.java b/src/test/bookingbugAPI/services/UrlEncoderTest.java new file mode 100644 index 0000000..34ba573 --- /dev/null +++ b/src/test/bookingbugAPI/services/UrlEncoderTest.java @@ -0,0 +1,67 @@ +package bookingbugAPI.services; + +import com.fasterxml.jackson.databind.ObjectMapper; +import helpers.Http; +import org.junit.Test; + +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +import static org.junit.Assert.assertTrue; + +/** + * Created by sebi on 13.04.2016. + */ +public class UrlEncoderTest { + + final String json = "{\"str\":\"val\", \"num\":0, \"arr\":[3, {\"prop\": \"false\"}, 1, null, 6 ], \"obj\":{\"prop1\":null, \"prop2\":[\"elem\"]}}"; + final String nullTrueResCorrect = "arr%5B%5D=3&arr%5B%5D%5Bprop%5D=false&arr%5B%5D=1&arr%5B%5D=6&num=0&obj%5Bprop2%5D%5B%5D=elem&str=val"; + final String nullFalseCorrect = "str=val&num=0&arr%5B%5D=3&arr%5B%5D%5Bprop%5D=false&arr%5B%5D=1&arr%5B%5D=null&arr%5B%5D=6&obj%5Bprop1%5D=null&obj%5Bprop2%5D%5B%5D=elem"; + + private HashMap getMap() { + ObjectMapper mapper = new ObjectMapper(); + HashMap map = new HashMap<>(); + try { + map = mapper.readValue(json, HashMap.class); + } catch (IOException e) { + e.printStackTrace(); + } + return map; + } + + private boolean sameEncoding(String originalEncoding, String resultEncoding) { + String[] split = resultEncoding.split("&"); + Set set = new HashSet<>(Arrays.asList(originalEncoding.split("&"))); + + if(split.length != set.size()) return false; + if(!set.containsAll(Arrays.asList(split))) return false; + return true; + } + + @Test + public void encodeMapIgnoreNullTrue(){ + HashMap map = getMap(); + try { + Http.UrlEncoder encoder = new Http.UrlEncoder(true); + String res = encoder.encode(map); + assertTrue(sameEncoding(nullTrueResCorrect, res)); + } catch (Http.EncodingException e) { + e.printStackTrace(); + } + } + + @Test + public void encodeMapIgnoreNullFalse(){ + HashMap map = getMap(); + try { + Http.UrlEncoder encoder = new Http.UrlEncoder(false); + String res = encoder.encode(map); + assertTrue(sameEncoding(nullFalseCorrect, res)); + } catch (Http.EncodingException e) { + e.printStackTrace(); + } + } +} From 30f72261434f574609ceccdfc5749917bc8b8609 Mon Sep 17 00:00:00 2001 From: Macarescu Sebastian Date: Thu, 28 Apr 2016 11:43:30 +0300 Subject: [PATCH 04/22] Added some params test, call for schema in services and events. Finally fixed null error in mp when deserializing response from api --- pom.xml | 2 +- src/main/bookingbugAPI/api/AdminURLS.java | 12 +++ src/main/bookingbugAPI/api/PublicURLS.java | 4 +- src/main/bookingbugAPI/models/Company.java | 17 +++- src/main/bookingbugAPI/models/Event.java | 15 +++ src/main/bookingbugAPI/models/EventChain.java | 5 + src/main/bookingbugAPI/models/Service.java | 40 ++++++++ .../models/params/BookingListParams.java | 98 +++---------------- .../bookingbugAPI/models/params/Params.java | 23 ++++- .../models/params/ServiceListParams.java | 63 +----------- src/main/helpers/Utils.java | 31 +++--- .../hal_addon/CustomJsonDeserializer.java | 25 ++++- .../CustomJsonRepresentationReader.java | 2 +- src/test/bookingbugAPI/models/ParamsTest.java | 2 - .../services/HalCustomJsonDeserializer.java | 46 +++++++++ 15 files changed, 210 insertions(+), 175 deletions(-) create mode 100644 src/test/bookingbugAPI/services/HalCustomJsonDeserializer.java diff --git a/pom.xml b/pom.xml index 4f08a46..cb6d153 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ BookingBug-SDK BookingBug-SDK - 1.6 + 1.8 diff --git a/src/main/bookingbugAPI/api/AdminURLS.java b/src/main/bookingbugAPI/api/AdminURLS.java index 5ddfc9b..21141c0 100644 --- a/src/main/bookingbugAPI/api/AdminURLS.java +++ b/src/main/bookingbugAPI/api/AdminURLS.java @@ -86,6 +86,7 @@ public static UriTemplate serviceList(){ .literal("/admin") .path(UriTemplateBuilder.var("companyId")) .literal("/services") + .query(UriTemplateBuilder.var("page"), UriTemplateBuilder.var("per_page")) .build(); } @@ -97,6 +98,16 @@ public static UriTemplate serviceRead() { .path(UriTemplateBuilder.var("serviceId")) .build(); } + + public static UriTemplate serviceNewBooking() { + return UriTemplate.buildFromTemplate(new Config().serverUrl) + .literal("/admin") + .path(UriTemplateBuilder.var("companyId")) + .literal("/services") + .path(UriTemplateBuilder.var("serviceId")) + .literal("/new_booking") + .build(); + } } @@ -270,6 +281,7 @@ public static UriTemplate bookingList(){ .literal("/admin") .path(UriTemplateBuilder.var("companyId")) .literal("/bookings") + .query(UriTemplateBuilder.var("page"), UriTemplateBuilder.var("per_page")) .build(); } diff --git a/src/main/bookingbugAPI/api/PublicURLS.java b/src/main/bookingbugAPI/api/PublicURLS.java index 4aac65f..1be7644 100644 --- a/src/main/bookingbugAPI/api/PublicURLS.java +++ b/src/main/bookingbugAPI/api/PublicURLS.java @@ -67,7 +67,9 @@ public static class Service { */ public static UriTemplate serviceList(){ return UriTemplate.buildFromTemplate(new Config().serverUrl).path(UriTemplateBuilder.var("companyId")) - .literal("/" + servicesLink).build(); + .literal("/" + servicesLink) + .query(UriTemplateBuilder.var("page"), UriTemplateBuilder.var("per_page")) + .build(); } /** diff --git a/src/main/bookingbugAPI/models/Company.java b/src/main/bookingbugAPI/models/Company.java index 8a87354..8427f25 100644 --- a/src/main/bookingbugAPI/models/Company.java +++ b/src/main/bookingbugAPI/models/Company.java @@ -124,8 +124,10 @@ public Service serviceEdit_Admin(String serviceId) throws IOException { * @throws IOException */ public BBCollection serviceList_Admin(ServiceListParams slParams) throws IOException { - String urlStr = AdminURLS.Service.serviceList().set("companyId", this.id).expand(); - URL url = new URL(Utils.inflateLink(urlStr, slParams.getParams())); + UriTemplate template = Utils.TemplateWithPagination( + AdminURLS.Service.serviceList().set("companyId", this.id), + slParams); + URL url = new URL(template.expand()); BBCollection services = new BBCollection(HttpService.api_GET(url, auth_token), auth_token, "services", Service.class); return services; } @@ -470,7 +472,7 @@ public BBCollection eventChainList() throws IOException { */ public BBCollection eventChainList(Params params) throws IOException { UriTemplate template = Utils.TemplateWithPagination( - PublicURLS.EventChain.eventChainList().set("companyId", this.id), + AdminURLS.EventChain.eventChainList().set("companyId", this.id), params); URL url = new URL(template.expand()); BBCollection eventChains = new BBCollection(HttpService.api_GET(url, auth_token), auth_token, "event_chains", EventChain.class); @@ -1094,8 +1096,13 @@ public Booking bookingCreate_Admin(BookingCreateParams bCParams) throws IOExcept * @throws IOException */ public BBCollection bookingList_Admin(BookingListParams bLParams) throws IOException { - String urlStr = AdminURLS.Bookings.bookingList().set("companyId", this.id).expand(); - URL url = new URL(Utils.inflateLink(urlStr, bLParams.getParams())); + URL url; + if(getLink("bookings") != null) + url = new URL(Utils.inflateLink(getLink("bookings"), bLParams.getParams())); + else { + UriTemplate template = AdminURLS.Bookings.bookingList().set("companyId", this.id); + url = new URL(Utils.inflateLink(template, bLParams.getParams())); + } BBCollection bookings = new BBCollection(HttpService.api_GET(url, auth_token), auth_token, "bookings", Booking.class); return bookings; } diff --git a/src/main/bookingbugAPI/models/Event.java b/src/main/bookingbugAPI/models/Event.java index 575fb38..0daad2f 100644 --- a/src/main/bookingbugAPI/models/Event.java +++ b/src/main/bookingbugAPI/models/Event.java @@ -1,7 +1,12 @@ package bookingbugAPI.models; +import bookingbugAPI.services.HttpService; +import com.damnhandy.uri.template.UriTemplate; import helpers.HttpServiceResponse; +import java.io.IOException; +import java.net.URL; + public class Event extends BBRoot{ @@ -17,4 +22,14 @@ public Event(HttpServiceResponse httpServiceResponse, String auth_token){ public Event() {} + public SchemaForm getNewBookingSchema() throws IOException { + if(getLink("new_booking") != null) { + String link = getLink("new_booking"); + URL url = new URL(UriTemplate.fromTemplate(link).expand()); + return new SchemaForm(HttpService.api_GET(url, this.auth_token)); + } + // Throw exception: link is missing + throw new IOException("new_booking link missing"); + } + } diff --git a/src/main/bookingbugAPI/models/EventChain.java b/src/main/bookingbugAPI/models/EventChain.java index 2d88b8f..ee29033 100644 --- a/src/main/bookingbugAPI/models/EventChain.java +++ b/src/main/bookingbugAPI/models/EventChain.java @@ -28,6 +28,11 @@ public EventChain(HttpServiceResponse httpServiceResponse, String auth_token){ public EventChain() {} + public SchemaForm getNewBookingSchema() throws IOException { + URL url = new URL(UriTemplate.fromTemplate(this.getRep().getLinkByRel("new_booking").getHref()).expand()); + return new SchemaForm(HttpService.api_GET(url, this.auth_token)); + } + /** * Get a List of Bookable Events for an EventChain. * @param params Parameters for pagination diff --git a/src/main/bookingbugAPI/models/Service.java b/src/main/bookingbugAPI/models/Service.java index 63400d7..d6b0215 100644 --- a/src/main/bookingbugAPI/models/Service.java +++ b/src/main/bookingbugAPI/models/Service.java @@ -3,15 +3,20 @@ import bookingbugAPI.services.HttpService; import com.damnhandy.uri.template.UriTemplate; import com.theoryinpractise.halbuilder.api.Link; +import com.theoryinpractise.halbuilder.api.ReadableRepresentation; import helpers.HttpServiceResponse; import helpers.Utils; import java.io.IOException; import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; public class Service extends BBRoot { + private ArrayList durations; + private ArrayList prices; public Service(HttpServiceResponse httpServiceResponse) { super(httpServiceResponse); @@ -26,6 +31,15 @@ public Service(HttpServiceResponse httpServiceResponse, String auth_token) { public Service() { } + public SchemaForm getNewBookingSchema() throws IOException { + if(getLink("new_booking") != null) { + String link = getLink("new_booking"); + URL url = new URL(UriTemplate.fromTemplate(link).expand()); + return new SchemaForm(HttpService.api_GET(url, this.auth_token)); + } + // Throw exception: link is missing + throw new IOException("new_booking link missing"); + } public Service getService(Link link) throws IOException { String absUrl = Utils.absoluteURL(link.getHref()); @@ -34,5 +48,31 @@ public Service getService(Link link) throws IOException { return service; } + public ArrayList getDurations() { + if(durations == null) { + durations = new ArrayList<>(); + Object duration_reps = getRep().getValue("durations"); + if(duration_reps instanceof Collection) { + for (Object rep : (Collection) duration_reps) { + durations.add(Integer.parseInt(rep.toString())); + } + } + } + return durations; + } + + public ArrayList getPrices() { + if(prices == null) { + prices = new ArrayList<>(); + Object prices_reps = getRep().getValue("prices"); + if(prices_reps instanceof Collection) { + for (Object rep : (Collection) prices_reps) { + prices.add(Integer.parseInt(rep.toString())); + } + } + } + return prices; + } + } diff --git a/src/main/bookingbugAPI/models/params/BookingListParams.java b/src/main/bookingbugAPI/models/params/BookingListParams.java index 9544eac..007af21 100644 --- a/src/main/bookingbugAPI/models/params/BookingListParams.java +++ b/src/main/bookingbugAPI/models/params/BookingListParams.java @@ -4,7 +4,7 @@ import java.util.Map; -public class BookingListParams { +public class BookingListParams extends Params { String start_date; String end_date; @@ -15,80 +15,15 @@ public class BookingListParams { String modified_since; String created_since; String email; - String page; - String per_page; String client_id; + String order_by; public BookingListParams(){} - public BookingListParams(Map args){ - if (args==null || args.isEmpty()) { - return; - } - - String strValue; - - for (Map.Entry entry : args.entrySet()) { - final String[] value = entry.getValue(); - if (value[0]!=null && !value[0].trim().isEmpty()) { - strValue = null; - } else { - strValue = value[0]; - } - - switch(entry.getKey()) { - case "start_date": start_date = strValue; - break; - case "end_date": end_date = strValue; - break; - case "include_cancelled": include_cancelled = strValue; - break; - case "event_id": event_id = strValue; - break; - case "category_id": category_id = strValue; - break; - case "start_time": start_time = strValue; - break; - case "modified_since": modified_since = strValue; - break; - case "created_since": created_since = strValue; - break; - case "email": email = strValue; - break; - case "page": page = strValue; - break; - case "per_page": per_page = strValue; - break; - case "client_id": client_id = strValue; - break; - } - } - } - - - /** - * getParams - * @return Map - */ - public Map getParams() { - Map params = new HashMap(); - - params.put("start_date", new String[]{start_date}); - params.put("end_date", new String[]{end_date}); - params.put("include_cancelled", new String[]{include_cancelled}); - params.put("event_id", new String[]{event_id}); - params.put("category_id", new String[]{category_id}); - params.put("start_time", new String[]{start_time}); - params.put("modified_since", new String[]{modified_since}); - params.put("created_since", new String[]{created_since}); - params.put("email", new String[]{email}); - params.put("page", new String[]{page}); - params.put("per_page", new String[]{per_page}); - params.put("client_id", new String[]{client_id}); - - return params; + public BookingListParams(int page){ + super(page); } @@ -173,30 +108,21 @@ public BookingListParams setEmail(String email) { return this; } - public String getPage() { - return page; - } - - public BookingListParams setPage(String page) { - this.page = page; - return this; - } - - public String getPer_page() { - return per_page; + public String getClient_id() { + return client_id; } - public BookingListParams setPer_page(String per_page) { - this.per_page = per_page; + public BookingListParams setClient_id(String client_id) { + this.client_id = client_id; return this; } - public String getClient_id() { - return client_id; + public String getOrder_by() { + return order_by; } - public BookingListParams setClient_id(String client_id) { - this.client_id = client_id; + public BookingListParams setOrder_by(String order_by) { + this.order_by = order_by; return this; } } diff --git a/src/main/bookingbugAPI/models/params/Params.java b/src/main/bookingbugAPI/models/params/Params.java index ae46ff0..4ba3652 100644 --- a/src/main/bookingbugAPI/models/params/Params.java +++ b/src/main/bookingbugAPI/models/params/Params.java @@ -5,6 +5,8 @@ import java.io.IOException; import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -45,17 +47,22 @@ public void setJson(String json) { } public Map getNotNullStringMap() { - Map result = new HashMap(); + Map result = new HashMap<>(); Field[] declaredFields = this.getClass().getDeclaredFields(); for (Field field : declaredFields) { try { - if(field.getType() == String.class && (String)field.get(this) != null) - result.put(field.getName(), (String)field.get(this)); + if(field.get(this) != null) + result.put(field.getName(), field.get(this).toString()); } catch (IllegalAccessException e) { e.printStackTrace(); } } + + //Add pagination params + result.put("page", String.valueOf(getPage())); + result.put("per_page", String.valueOf(getPer_page())); + return result; } @@ -113,6 +120,16 @@ public int getPer_page() { return per_page; } + public Params setPerPage(int per_page) { + this.per_page = per_page; + return this; + } + + public Params setPage(int page) { + this.page = page; + return this; + } + @Override public String toString(){ String jsonThis = ""; diff --git a/src/main/bookingbugAPI/models/params/ServiceListParams.java b/src/main/bookingbugAPI/models/params/ServiceListParams.java index b41b33d..ea587af 100644 --- a/src/main/bookingbugAPI/models/params/ServiceListParams.java +++ b/src/main/bookingbugAPI/models/params/ServiceListParams.java @@ -4,67 +4,12 @@ import java.util.Map; -public class ServiceListParams { +public class ServiceListParams extends Params{ - String page; - String per_page; + public ServiceListParams() {} - - public ServiceListParams(){} - - - public ServiceListParams(Map args){ - if (args==null || args.isEmpty()) { - return; - } - - String strValue; - - for (Map.Entry entry : args.entrySet()) { - final String[] value = entry.getValue(); - if (value[0]!=null && !value[0].trim().isEmpty()) { - strValue = null; - } else { - strValue = value[0]; - } - - switch(entry.getKey()) { - case "page": page = strValue; - break; - case "per_page": per_page = strValue; - break; - } - } + public ServiceListParams(int page){ + super(page); } - - /** - * getParams - * @return Map - */ - public Map getParams() { - Map params = new HashMap(); - - params.put("page", new String[]{page}); - params.put("per_page", new String[]{per_page}); - - return params; - } - - - public String getPage() { - return page; - } - - public void setPage(String page) { - this.page = page; - } - - public String getPerPage() { - return per_page; - } - - public void setPerPage(String per_page) { - this.per_page = per_page; - } } diff --git a/src/main/helpers/Utils.java b/src/main/helpers/Utils.java index 8788cd5..5c821c9 100644 --- a/src/main/helpers/Utils.java +++ b/src/main/helpers/Utils.java @@ -99,25 +99,30 @@ public static boolean linkHasArgs(String link) { return vars.length > 0; } + public static String inflateLink(UriTemplate template, Map args) { + Map toInflate = new HashMap(); + + for (Object key : args.keySet()) { + final Object value = args.get(key); + + if(value == null || (value instanceof String && ((String) value).trim().isEmpty())) + continue; + + if(value instanceof String[] && (((String[])value).length > 0 || ((String[])value)[0].trim().isEmpty())) + continue; + + toInflate.put(key.toString(), value); + } + return template.expand(toInflate); + } /** * @param link * @param args * @return */ - public static String inflateLink(String link, Map args) { - UriTemplate template = UriTemplate.fromTemplate(link); - Map toInflate = new HashMap(); - - for (Map.Entry entry : args.entrySet()) { - final String key = entry.getKey(); - final String[] value = entry.getValue(); - - if (value[0]!=null && !value[0].trim().isEmpty()) { - toInflate.put(key, value); - } - } - return template.expand(toInflate); + public static String inflateLink(String link, Map args) { + return inflateLink(UriTemplate.fromTemplate(link), args); } diff --git a/src/main/helpers/hal_addon/CustomJsonDeserializer.java b/src/main/helpers/hal_addon/CustomJsonDeserializer.java index 14b255f..dfc65d2 100644 --- a/src/main/helpers/hal_addon/CustomJsonDeserializer.java +++ b/src/main/helpers/hal_addon/CustomJsonDeserializer.java @@ -3,22 +3,39 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer; +import com.fasterxml.jackson.databind.jsontype.TypeDeserializer; import java.io.IOException; +import java.util.HashMap; /** * Created by sebi on 04.02.2016. */ -public class CustomJsonDeserializer extends JsonDeserializer { +public class CustomJsonDeserializer extends UntypedObjectDeserializer { + + @Override + public Object deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { + if(jsonParser.getCurrentTokenId() == 11) { + return ""; + } + return super.deserialize(jsonParser, deserializationContext); + } + @Override - public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { - return jsonParser.getText(); + public Object deserializeWithType(JsonParser jsonParser, DeserializationContext deserializationContext, TypeDeserializer typeDeserializer) throws IOException, JsonProcessingException { + if(jsonParser.getCurrentTokenId() == 11) { + return ""; + } + return super.deserialize(jsonParser, deserializationContext, typeDeserializer); } @Override - public String getNullValue(){ + public Object getNullValue() { return ""; } } diff --git a/src/main/helpers/hal_addon/CustomJsonRepresentationReader.java b/src/main/helpers/hal_addon/CustomJsonRepresentationReader.java index b51cc59..c8aa67e 100644 --- a/src/main/helpers/hal_addon/CustomJsonRepresentationReader.java +++ b/src/main/helpers/hal_addon/CustomJsonRepresentationReader.java @@ -33,7 +33,7 @@ public CustomJsonRepresentationReader(AbstractRepresentationFactory representati this.mapper = new ObjectMapper(); SimpleModule simpleModule = new SimpleModule(); - simpleModule.addDeserializer(String.class, new CustomJsonDeserializer()); + simpleModule.addDeserializer(Object.class, new CustomJsonDeserializer()); this.mapper.registerModule(simpleModule); } diff --git a/src/test/bookingbugAPI/models/ParamsTest.java b/src/test/bookingbugAPI/models/ParamsTest.java index cced630..f99f54f 100644 --- a/src/test/bookingbugAPI/models/ParamsTest.java +++ b/src/test/bookingbugAPI/models/ParamsTest.java @@ -26,7 +26,6 @@ public void paramsMap(){ params.setMember_id("member_id"); Map map = params.getParams(); - assertTrue(map.size() == 3); assertTrue(map.containsKey("datetime")); assertTrue(map.containsKey("service_id")); @@ -45,7 +44,6 @@ public void clientCreateParamsFromMap(){ params.setLast_name("Last"); Map map = params.getParams(); - assertTrue(map.size() == 3); assertTrue(map.containsKey("first_name")); assertTrue(map.get("first_name").equals("first")); diff --git a/src/test/bookingbugAPI/services/HalCustomJsonDeserializer.java b/src/test/bookingbugAPI/services/HalCustomJsonDeserializer.java new file mode 100644 index 0000000..6d01400 --- /dev/null +++ b/src/test/bookingbugAPI/services/HalCustomJsonDeserializer.java @@ -0,0 +1,46 @@ +package bookingbugAPI.services; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import helpers.hal_addon.CustomJsonDeserializer; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertTrue; + +/** + * Created by sebi on 27.04.2016. + */ +public class HalCustomJsonDeserializer { + + private ObjectMapper mapper; + + @Before + public void setUp() { + this.mapper = new ObjectMapper(); + + SimpleModule simpleModule = new SimpleModule(); + simpleModule.addDeserializer(Object.class, new CustomJsonDeserializer()); + this.mapper.registerModule(simpleModule); + } + + @After + public void tearDown() throws Exception { + mapper = null; + } + + @Test + public void nullFieldJsonTest() throws IOException { + Map map = mapper.readValue("{\"settings\":{\"who_cancelled\":{\"embed\":null}, \"late\":1}}", Map.class); + assertTrue(map.get("settings") != null); + assertTrue(((Map)map.get("settings")).get("who_cancelled") != null); + assertTrue(((Map)((Map)map.get("settings")).get("who_cancelled")).get("embed") != null); + + } +} + From 4653d2f7c78c36f927b13f909912a5d37b974638 Mon Sep 17 00:00:00 2001 From: Macarescu Sebastian Date: Tue, 3 May 2016 16:01:20 +0300 Subject: [PATCH 05/22] wip --- src/main/bookingbugAPI/models/BBCollection.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/bookingbugAPI/models/BBCollection.java b/src/main/bookingbugAPI/models/BBCollection.java index 89061da..e412ed9 100644 --- a/src/main/bookingbugAPI/models/BBCollection.java +++ b/src/main/bookingbugAPI/models/BBCollection.java @@ -83,6 +83,10 @@ public int size() { return getRep().getResourcesByRel(collectionNameSpace).size(); } + public boolean hasNext() { + return getLink("next") != null; + } + public Iterator iterator() { return new BBCollectionIterator(this); From a3e576510783eb9500e7d554108c1b182bb272b3 Mon Sep 17 00:00:00 2001 From: Macarescu Sebastian Date: Tue, 3 May 2016 16:01:20 +0300 Subject: [PATCH 06/22] WIP: new API Structure with fluent interface. Added sql interface with default implementation, added config for apis --- pom.xml | 14 +- src/main/bookingbugAPI/api/API.java | 22 +++ src/main/bookingbugAPI/api/AbstractAPI.java | 54 +++++++ src/main/bookingbugAPI/api/AdminAPI.java | 133 ++---------------- src/main/bookingbugAPI/api/AuthedAPI.java | 9 +- src/main/bookingbugAPI/models/Company.java | 72 ++++++++++ .../bookingbugAPI/services/CacheService.java | 94 +++++++++++++ .../bookingbugAPI/services/HttpService.java | 103 ++++++++++++++ .../api/admin/BookingAPITest.java | 58 ++++++++ src/test/resources/bb_sdk_config.properties | 2 +- 10 files changed, 437 insertions(+), 124 deletions(-) create mode 100644 src/main/bookingbugAPI/api/API.java create mode 100644 src/main/bookingbugAPI/api/AbstractAPI.java create mode 100644 src/main/bookingbugAPI/services/CacheService.java create mode 100644 src/test/bookingbugAPI/api/admin/BookingAPITest.java diff --git a/pom.xml b/pom.xml index cb6d153..600449f 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ BookingBug-SDK BookingBug-SDK - 1.8 + 1.9 @@ -80,6 +80,18 @@ 1.1.0 + + org.xerial + sqlite-jdbc + 3.8.11.2 + + + + com.j256.ormlite + ormlite-jdbc + 4.43 + + diff --git a/src/main/bookingbugAPI/api/API.java b/src/main/bookingbugAPI/api/API.java new file mode 100644 index 0000000..358e675 --- /dev/null +++ b/src/main/bookingbugAPI/api/API.java @@ -0,0 +1,22 @@ +package bookingbugAPI.api; + +/** + * Created by sebi on 19.05.2016. + */ +public class API extends AbstractAPI { + + public API(ApiConfig config) { + super(config); + } + + public AdminAPI admin() { + return new AdminAPI(newConfig()); + } + + public static class APIBuilder extends AbstractAPI.ApiConfig { + + public API build() { + return new API(this); + } + } +} diff --git a/src/main/bookingbugAPI/api/AbstractAPI.java b/src/main/bookingbugAPI/api/AbstractAPI.java new file mode 100644 index 0000000..ad64347 --- /dev/null +++ b/src/main/bookingbugAPI/api/AbstractAPI.java @@ -0,0 +1,54 @@ +package bookingbugAPI.api; + +import bookingbugAPI.services.CacheService; + +/** + * Abstract API class + * Contains basic methods and members + */ +public abstract class AbstractAPI { + + String token; + CacheService cacheService; + + //TODO: Add HTTPService instance here + + AbstractAPI(ApiConfig config){ + // Copy configuration + this.token = config.token; + this.cacheService = config.cacheService; + } + + ApiConfig newConfig() { + return new ApiConfig() + .withToken(token) + .withCache(cacheService); + } + + /** + * Class which holds an API configuration + * @param Keep fluent interface for subclasses + */ + public static class ApiConfig { + + String token; + CacheService cacheService; + + public ApiConfig() {} + + public ApiConfig(ApiConfig config) { + this.token = config.token; + this.cacheService = config.cacheService; + } + + public T withToken(String token) { + this.token = token; + return (T)this; + } + + public T withCache(CacheService cacheService) { + this.cacheService = cacheService; + return (T)this; + } + } +} diff --git a/src/main/bookingbugAPI/api/AdminAPI.java b/src/main/bookingbugAPI/api/AdminAPI.java index b610f46..dab633b 100644 --- a/src/main/bookingbugAPI/api/AdminAPI.java +++ b/src/main/bookingbugAPI/api/AdminAPI.java @@ -1,139 +1,36 @@ package bookingbugAPI.api; import bookingbugAPI.models.*; +import bookingbugAPI.models.params.BookingListParams; import bookingbugAPI.services.HttpService; +import com.damnhandy.uri.template.UriTemplate; +import helpers.Utils; import java.io.IOException; import java.net.URL; -public class AdminAPI { +public class AdminAPI extends AbstractAPI { - static public class CompanyAPI extends AuthedAPI { - - public CompanyAPI(String token) { - super(token); - } - - public Company companyList(String companyId) throws IOException { - String uri = AdminURLS.Company.companyList().set("companyId", companyId).expand(); - URL url = new URL(uri); - - return new Company(HttpService.api_GET(url, auth_token)); - } - } - - static public class PersonAPI extends AuthedAPI { - - public PersonAPI(String token) { - super(token); - } - - public People personList(String companyId) throws IOException { - String uri = AdminURLS.Person.personList().set("companyId", companyId).expand(); - URL url = new URL (uri); - - return new People(HttpService.api_GET(url, auth_token)); - } - - public People personRead(String companyId, String personId) throws IOException { - String uri = AdminURLS.Person.personRead().set("companyId", companyId).set("personId", personId).expand(); - URL url = new URL (uri); - - return new People(HttpService.api_GET(url, auth_token)); - } - - public People personGetSchema(String companyId) throws IOException{ - String uri = AdminURLS.Person.personGetSchema().set("companyId", companyId).expand(); - URL url = new URL (uri); - - return new People(HttpService.api_GET(url, auth_token)); - } - - public People personCreate(String companyId, People person) throws IOException{ - String uri = AdminURLS.Person.personCreate().set("companyId", companyId).expand(); - URL url = new URL (uri); - - return new People(HttpService.api_POST(url, person.data, auth_token)); - } - - public People personUpdate(String companyId, People person) throws IOException{ - String uri = AdminURLS.Person.personUpdate().set("companyId", companyId).set("personId", person.id).expand(); - URL url = new URL (uri); - - return new People(HttpService.api_PUT(url, person.data, auth_token)); - } - - public People personDelete(String companyId, String personId) throws IOException{ - String uri = AdminURLS.Person.personDelete().set("companyId", companyId).set("personId", personId).expand(); - URL url = new URL (uri); - - return new People(HttpService.api_DELETE(url, auth_token)); - } + AdminAPI(ApiConfig builder) { + super(builder); } - static public class ServiceAPI extends AuthedAPI { - - public ServiceAPI(String token) { - super(token); - } - - public Service serviceList(String companyId) throws IOException { - String uri = AdminURLS.Service.serviceList().set("companyId", companyId).expand(); - URL url = new URL (uri); - - return new Service(HttpService.api_GET(url, auth_token)); - } - public Service serviceRead(String companyId, String serviceId) throws IOException { - String uri = AdminURLS.Service.serviceRead().set("companyId", companyId).set("serviceId", serviceId).expand(); - URL url = new URL (uri); - - return new Service(HttpService.api_GET(url, auth_token)); - } + public BookingAPI booking() { + return new BookingAPI(newConfig()); } + public class BookingAPI extends AbstractAPI { - static public class ResourceAPI extends AuthedAPI { - - public ResourceAPI(String token) { - super(token); - } - - public Resource getResources(String companyId) throws IOException { - String uri = AdminURLS.Resource.resourceList().set("companyId", companyId).expand(); - URL url = new URL (uri); - - return new Resource(HttpService.api_GET(url, auth_token)); + BookingAPI(ApiConfig config) { + super(config); } - public Resource getResource(String companyId, String resourceId) throws IOException { - String uri = AdminURLS.Resource.resourceRead().set("companyId", companyId).set("resourceId", resourceId).expand(); - URL url = new URL (uri); - - return new Resource(HttpService.api_GET(url, auth_token)); - } - } - - - static public class EventAPI extends AuthedAPI{ - - public EventAPI(String token) { - super(token); - } - - public Event eventList(String companyId) throws IOException { - String uri = AdminURLS.Event.eventList().set("companyId", companyId).expand(); - URL url = new URL (uri); - - return new Event(HttpService.api_GET(url, auth_token)); - } - - public Event eventRead(String companyId, String eventId) throws IOException { - String uri = AdminURLS.Event.eventRead().set("companyId", companyId).set("eventId", eventId).expand(); - URL url = new URL (uri); - - return new Event(HttpService.api_GET(url, auth_token)); + public BBCollection getBookings(Company company, BookingListParams bLParams) throws IOException { + URL url = new URL(Utils.inflateLink(company.get_bookingsLink(), bLParams.getParams())); + BBCollection bookings = new BBCollection(HttpService.api_GET(url, token), token, "bookings", Booking.class); + return bookings; } } diff --git a/src/main/bookingbugAPI/api/AuthedAPI.java b/src/main/bookingbugAPI/api/AuthedAPI.java index b61da4b..a117351 100644 --- a/src/main/bookingbugAPI/api/AuthedAPI.java +++ b/src/main/bookingbugAPI/api/AuthedAPI.java @@ -1,12 +1,13 @@ package bookingbugAPI.api; /** - * Created by sebi on 5/30/15. + * Created by sebi on 19.05.2016. */ -public abstract class AuthedAPI { +public class AuthedAPI { + String auth_token; - public AuthedAPI(String token){ - auth_token = token; + public AuthedAPI(String auth_token) { + this.auth_token = auth_token; } } diff --git a/src/main/bookingbugAPI/models/Company.java b/src/main/bookingbugAPI/models/Company.java index 8427f25..7d8dc4a 100644 --- a/src/main/bookingbugAPI/models/Company.java +++ b/src/main/bookingbugAPI/models/Company.java @@ -43,6 +43,78 @@ public Company(HttpServiceResponse httpServiceResponse, String auth_token){ public Company() {} + public String get_companyID() { + return get("id"); + } + + public String get_numericWidgetID() { + return get("numeric_widget_id"); + } + + public String get_addressID() { + return get("address_id"); + } + + public String get_name() { + return get("name"); + } + + public String get_currencyCode() { + return get("currency_code"); + } + + public String get_timezone() { + return get("timezone"); + } + + public String get_multiStatus() { + return get("multi_status"); + } + + public String get_website() { + return get("website"); + } + + public String get_description() { + return get("description"); + } + + public String get_countryCode() { + return get("country_code"); + } + + public String get_live() { + return get("live"); + } + + public String get_addressLink() { + return getLink("addresses"); + } + + public String get_peopleLink() { + return getLink("people"); + } + + public String get_categoriesLink() { + return getLink("categories"); + } + + public String get_eventsLinks() { + return getLink("events"); + } + + public String get_resourcesLink() { + return getLink("resources"); + } + + public String get_servicesLink() { + return getLink("services"); + } + + public String get_bookingsLink() { + return getLink("bookings"); + } + /* //TODO temp. until get the purchase from the content representation public Purchase getPurchase () { diff --git a/src/main/bookingbugAPI/services/CacheService.java b/src/main/bookingbugAPI/services/CacheService.java new file mode 100644 index 0000000..66ba6fc --- /dev/null +++ b/src/main/bookingbugAPI/services/CacheService.java @@ -0,0 +1,94 @@ +package bookingbugAPI.services; + +import com.j256.ormlite.dao.Dao; +import com.j256.ormlite.dao.DaoManager; +import com.j256.ormlite.jdbc.JdbcConnectionSource; +import com.j256.ormlite.stmt.QueryBuilder; +import com.j256.ormlite.support.ConnectionSource; +import com.j256.ormlite.table.TableUtils; + +import java.sql.SQLException; +import java.util.List; + +/** + * Class used for caching HTTP Responses + */ +public class CacheService { + + SQLite db; + + public CacheService() { + db = new JDBC_Sqlite(); + } + + public void storeResult(String url, String method, String resp) { + Dao respDao; + + try { + db.createIfNotExists(); + respDao = db.getDao(); + + HttpService.NetResponse response = new HttpService.NetResponse(url, method, resp); + respDao.create(response); + + } catch (SQLException e) { + e.printStackTrace(); + } + } + + public HttpService.NetResponse getDBResponse(String url, String method) { + try { + db.createIfNotExists(); + Dao respDao = db.getDao(); + QueryBuilder builder = respDao.queryBuilder(); + builder.where().eq("url", url).and().eq("method", method); + List responses = respDao.query(builder.prepare()); + if(responses.size() > 0) + return responses.get(0); + + } catch (SQLException e) { + e.printStackTrace(); + } + return null; + } + + + /** + * Classes should implement this interface to provide proper handling for SQLite db + */ + public interface SQLite { + + Dao getDao() throws SQLException; + ConnectionSource getConnectionSource() throws SQLException; + void createIfNotExists() throws SQLException; + + } + + /** + * Implementation for SQLite with JDBC + */ + public final class JDBC_Sqlite implements SQLite { + + ConnectionSource connectionSource; + Dao dao; + + @Override + public void createIfNotExists() throws SQLException { + TableUtils.createTableIfNotExists(getConnectionSource(), HttpService.NetResponse.class); + } + + @Override + public Dao getDao() throws SQLException { + if(dao == null) + dao = DaoManager.createDao(getConnectionSource(), HttpService.NetResponse.class); + return dao; + } + + @Override + public ConnectionSource getConnectionSource() throws SQLException { + if(connectionSource == null) + connectionSource = new JdbcConnectionSource("jdbc:sqlite:test.db"); + return connectionSource; + } + } +} diff --git a/src/main/bookingbugAPI/services/HttpService.java b/src/main/bookingbugAPI/services/HttpService.java index 349beae..330ba12 100644 --- a/src/main/bookingbugAPI/services/HttpService.java +++ b/src/main/bookingbugAPI/services/HttpService.java @@ -3,6 +3,14 @@ import bookingbugAPI.models.HttpException; import bookingbugAPI.models.PublicRoot; import com.fasterxml.jackson.core.JsonProcessingException; +import com.j256.ormlite.dao.Dao; +import com.j256.ormlite.dao.DaoManager; +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.jdbc.JdbcConnectionSource; +import com.j256.ormlite.stmt.QueryBuilder; +import com.j256.ormlite.support.ConnectionSource; +import com.j256.ormlite.table.DatabaseTable; +import com.j256.ormlite.table.TableUtils; import com.theoryinpractise.halbuilder.api.ContentRepresentation; import com.theoryinpractise.halbuilder.api.RepresentationFactory; import helpers.Config; @@ -15,6 +23,8 @@ import java.lang.reflect.InvocationTargetException; import java.net.HttpURLConnection; import java.net.URL; +import java.sql.SQLException; +import java.util.List; import java.util.Map; import java.util.logging.Logger; @@ -102,7 +112,17 @@ private static HttpServiceResponse callApi(URL url, String auth_token, String me int responseCode = 200; boolean throwError = false; HttpURLConnection urlConnection = null; + NetResponse cache = getDBResponse(url.toString(), method); + try { + + if(cache != null) { + CustomJsonRepresentationFactory representationFactory = new CustomJsonRepresentationFactory(); + representationFactory.withFlag(RepresentationFactory.STRIP_NULLS); + Reader reader = new InputStreamReader(new ByteArrayInputStream(cache.resp.getBytes())); + return new HttpServiceResponse(representationFactory.readRepresentation(HAL_JSON, reader), method, contentType, params, auth_token); + } + //http://stackoverflow.com/questions/7615645/ssl-handshake-alert-unrecognized-name-error-since-upgrade-to-java-1-7-0 System.setProperty("jsse.enableSNIExtension", "false"); Config config = new Config(); @@ -151,6 +171,8 @@ private static HttpServiceResponse callApi(URL url, String auth_token, String me in.close(); returnString = response.toString(); + storeResult(url.toString(), method, returnString); + if (!testingMode) { if(throwError) { errorMessage = "The call to " + url.toString() @@ -174,4 +196,85 @@ private static HttpServiceResponse callApi(URL url, String auth_token, String me if(urlConnection != null) urlConnection.disconnect(); } throw new HttpException(errorMessage, returnString, responseCode); } + + private static NetResponse getDBResponse(String url, String method) { + Dao respDao; + ConnectionSource connectionSource = null; + try { + + // create our data-source for the database + connectionSource = new JdbcConnectionSource("jdbc:sqlite:test.db"); + respDao = DaoManager.createDao(connectionSource, NetResponse.class); + TableUtils.createTableIfNotExists(connectionSource, NetResponse.class); + + QueryBuilder builder = respDao.queryBuilder(); + builder.where().eq("url", url).and().eq("method", method); + List responses = respDao.query(builder.prepare()); + if(responses.size() > 0) + return responses.get(0); + } catch (SQLException e) { + e.printStackTrace(); + } finally { + // destroy the data source which should close underlying connections + if (connectionSource != null) { + try { + connectionSource.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + } + return null; + } + + private static void storeResult(String url, String method, String str) { + + Dao respDao; + ConnectionSource connectionSource = null; + try { + + // create our data-source for the database + connectionSource = new JdbcConnectionSource("jdbc:sqlite:test.db"); + respDao = DaoManager.createDao(connectionSource, NetResponse.class); + TableUtils.createTableIfNotExists(connectionSource, NetResponse.class); + + NetResponse response = new NetResponse(url, method, str); + respDao.create(response); + + } catch (SQLException e) { + e.printStackTrace(); + } finally { + // destroy the data source which should close underlying connections + if (connectionSource != null) { + try { + connectionSource.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + } + } + + @DatabaseTable(tableName = "net_response") + public static class NetResponse { + @DatabaseField(generatedId = true) + private int id; + + @DatabaseField + private String url; + + @DatabaseField + private String method; + + @DatabaseField + private String resp; + + public NetResponse(){} + + public NetResponse(String url, String method, String resp) { + this.url = url; + this.method = method; + this.resp = resp; + } + } } \ No newline at end of file diff --git a/src/test/bookingbugAPI/api/admin/BookingAPITest.java b/src/test/bookingbugAPI/api/admin/BookingAPITest.java new file mode 100644 index 0000000..b1479db --- /dev/null +++ b/src/test/bookingbugAPI/api/admin/BookingAPITest.java @@ -0,0 +1,58 @@ +package bookingbugAPI.api.admin; + +import bookingbugAPI.api.API; +import bookingbugAPI.api.AdminAPI; +import bookingbugAPI.api.AdminURLS; +import bookingbugAPI.models.BBCollection; +import bookingbugAPI.models.Booking; +import bookingbugAPI.models.Company; +import bookingbugAPI.models.params.BookingListParams; +import bookingbugAPI.services.CacheService; +import bookingbugAPI.services.HttpService; +import org.junit.Test; + +import java.io.IOException; +import java.net.URL; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +/** + * Created by sebi on 18.05.2016. + */ +public class BookingAPITest { + + private static final String companyId = "37025"; + private static final String token = "x2_5PcI15mq7sEWm70JazA"; + + public Company getCompany() { + Company company = null; + try { + URL url = new URL(AdminURLS.Company.company().set("companyId", companyId).expand()); + company = new Company(HttpService.api_GET(url, token), token); + assertNotNull(company); + }catch (Exception e) { + e.printStackTrace(); + } + return company; + } + + @Test + public void getBookings(){ + Company company = getCompany(); + + API.APIBuilder builder = new API.APIBuilder().withCache(new CacheService()).withToken(token); + API api = builder.build(); + + try { + BBCollection bookings = api.admin().booking().getBookings(company, new BookingListParams(1)); + assertNotNull(bookings); + assertTrue(bookings.size() > 0); + + } catch (IOException e) { + e.printStackTrace(); + } + } + +} diff --git a/src/test/resources/bb_sdk_config.properties b/src/test/resources/bb_sdk_config.properties index 6495cae..4cfc291 100644 --- a/src/test/resources/bb_sdk_config.properties +++ b/src/test/resources/bb_sdk_config.properties @@ -1,4 +1,4 @@ application.auth.appid=edb1ef31 application.auth.appkey=7cda5a59e91113e7a0f1b3654dadca86 application.auth.useragent=BookingBug Java Client -application.auth.serverurl=https://assist-dev.bookingbug.com/api/v1 +application.auth.serverurl=https://assist-dev03.bookingbug.com/api/v1 From f691c02ce72c0a8f7be2e2429794641916578102 Mon Sep 17 00:00:00 2001 From: Macarescu Sebastian Date: Wed, 25 May 2016 16:59:31 +0300 Subject: [PATCH 07/22] Added OkHttpService which uses OkHttp to make requests. Refactored Config for api. Added basic unit testing for okhttp service --- pom.xml | 12 ++ src/main/bookingbugAPI/api/AbstractAPI.java | 113 +++++++++++++++--- src/main/bookingbugAPI/api/AdminAPI.java | 5 +- .../bookingbugAPI/services/CacheService.java | 19 ++- .../bookingbugAPI/services/HttpService.java | 4 + .../bookingbugAPI/services/OkHttpService.java | 70 +++++++++++ src/main/helpers/Utils.java | 12 +- .../api/admin/BookingAPITest.java | 3 +- .../services/OkHttpServiceTest.java | 103 ++++++++++++++++ 9 files changed, 312 insertions(+), 29 deletions(-) create mode 100644 src/main/bookingbugAPI/services/OkHttpService.java create mode 100644 src/test/bookingbugAPI/services/OkHttpServiceTest.java diff --git a/pom.xml b/pom.xml index 600449f..be49630 100644 --- a/pom.xml +++ b/pom.xml @@ -92,6 +92,18 @@ 4.43 + + com.squareup.okhttp3 + okhttp + 3.2.0 + + + com.squareup.okhttp + mockwebserver + 2.7.0 + test + + diff --git a/src/main/bookingbugAPI/api/AbstractAPI.java b/src/main/bookingbugAPI/api/AbstractAPI.java index ad64347..4c7386c 100644 --- a/src/main/bookingbugAPI/api/AbstractAPI.java +++ b/src/main/bookingbugAPI/api/AbstractAPI.java @@ -1,6 +1,14 @@ package bookingbugAPI.api; import bookingbugAPI.services.CacheService; +import bookingbugAPI.services.OkHttpService; + +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.io.StringReader; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; /** * Abstract API class @@ -8,21 +16,22 @@ */ public abstract class AbstractAPI { - String token; - CacheService cacheService; + protected OkHttpService httpService; + + public AbstractAPI(ApiConfig config){ + httpService = new OkHttpService(config); + } - //TODO: Add HTTPService instance here + public ApiConfig newConfig() { + return new ApiConfig(httpService.getConfig()); + } - AbstractAPI(ApiConfig config){ - // Copy configuration - this.token = config.token; - this.cacheService = config.cacheService; + public String getAuthToken(){ + return httpService.getConfig().auth_token; } - ApiConfig newConfig() { - return new ApiConfig() - .withToken(token) - .withCache(cacheService); + public void setAuthToken(String auth_token) { + httpService.getConfig().withAuthToken(auth_token); } /** @@ -31,18 +40,42 @@ ApiConfig newConfig() { */ public static class ApiConfig { - String token; - CacheService cacheService; + static final String propFileName = "bb_sdk_config.properties"; + private final static Logger logger = Logger.getLogger(ApiConfig.class.getName()); - public ApiConfig() {} + public String auth_token; + public String appId; + public String appKey; + public String userAgent; + public String serverUrl; + public CacheService cacheService; public ApiConfig(ApiConfig config) { - this.token = config.token; + this.auth_token = config.auth_token; + this.appId = config.appId; + this.appKey = config.appKey; + this.userAgent = config.userAgent; + this.serverUrl = config.serverUrl; this.cacheService = config.cacheService; } - public T withToken(String token) { - this.token = token; + public ApiConfig() { + loadConfigFile(null); + cacheService = CacheService.JDBC(); + } + + public T withNothing() { + auth_token = null; + appId = ""; + appKey = ""; + userAgent = ""; + serverUrl = null; + cacheService = null; + return (T) this; + } + + public T withAuthToken(String token) { + this.auth_token = token; return (T)this; } @@ -50,5 +83,51 @@ public T withCache(CacheService cacheService) { this.cacheService = cacheService; return (T)this; } + + public T withApp(String appId, String appKey) { + this.appId = appId; + this.appKey = appKey; + return (T)this; + } + + public T withUserAgent(String userAgent) { + this.userAgent = userAgent; + return (T)this; + } + + public T withServerUrl(String serverUrl) { + this.serverUrl = serverUrl; + return (T)this; + } + + public T withConfigString(String configString) { + loadConfigFile(configString); + return (T)this; + } + + private void loadConfigFile(String configString) { + try{ + Properties prop = new Properties(); + + if(configString != null) { + prop.load(new StringReader(configString)); + } + else { + InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(propFileName); + if (inputStream != null) { + prop.load(inputStream); + } else { + throw new FileNotFoundException("property file '" + propFileName + "' not found in the classpath"); + } + } + + appId = prop.getProperty("application.auth.appid"); + appKey = prop.getProperty("application.auth.appkey"); + userAgent = prop.getProperty("application.auth.useragent"); + serverUrl = prop.getProperty("application.auth.serverurl"); + } catch (Exception e) { + logger.log(Level.SEVERE, "Exception @ ApiConfig.withConfigFile(): " + e.getMessage()); + } + } } } diff --git a/src/main/bookingbugAPI/api/AdminAPI.java b/src/main/bookingbugAPI/api/AdminAPI.java index dab633b..d7809b3 100644 --- a/src/main/bookingbugAPI/api/AdminAPI.java +++ b/src/main/bookingbugAPI/api/AdminAPI.java @@ -3,7 +3,7 @@ import bookingbugAPI.models.*; import bookingbugAPI.models.params.BookingListParams; import bookingbugAPI.services.HttpService; -import com.damnhandy.uri.template.UriTemplate; +import bookingbugAPI.services.OkHttpService; import helpers.Utils; import java.io.IOException; @@ -29,7 +29,8 @@ public class BookingAPI extends AbstractAPI { public BBCollection getBookings(Company company, BookingListParams bLParams) throws IOException { URL url = new URL(Utils.inflateLink(company.get_bookingsLink(), bLParams.getParams())); - BBCollection bookings = new BBCollection(HttpService.api_GET(url, token), token, "bookings", Booking.class); + BBCollection bookings = new BBCollection(httpService.api_GET(url), getAuthToken(), "bookings", Booking.class); + //BBCollection bookings = new BBCollection(HttpService.api_GET(url, getAuthToken()), getAuthToken(), "bookings", Booking.class); return bookings; } } diff --git a/src/main/bookingbugAPI/services/CacheService.java b/src/main/bookingbugAPI/services/CacheService.java index 66ba6fc..3f448c5 100644 --- a/src/main/bookingbugAPI/services/CacheService.java +++ b/src/main/bookingbugAPI/services/CacheService.java @@ -16,12 +16,24 @@ public class CacheService { SQLite db; + boolean mock; - public CacheService() { - db = new JDBC_Sqlite(); + public CacheService(SQLite db, boolean mock) { + this.db = db; + this.mock = mock; + } + + public static CacheService JDBC() { + return new CacheService(new JDBC_Sqlite(), false); + } + + public static CacheService MOCK() { + return new CacheService(new JDBC_Sqlite(), true); } public void storeResult(String url, String method, String resp) { + if(mock) return; + Dao respDao; try { @@ -37,6 +49,7 @@ public void storeResult(String url, String method, String resp) { } public HttpService.NetResponse getDBResponse(String url, String method) { + if(mock) return null; try { db.createIfNotExists(); Dao respDao = db.getDao(); @@ -67,7 +80,7 @@ public interface SQLite { /** * Implementation for SQLite with JDBC */ - public final class JDBC_Sqlite implements SQLite { + public static final class JDBC_Sqlite implements SQLite { ConnectionSource connectionSource; Dao dao; diff --git a/src/main/bookingbugAPI/services/HttpService.java b/src/main/bookingbugAPI/services/HttpService.java index 330ba12..9b46474 100644 --- a/src/main/bookingbugAPI/services/HttpService.java +++ b/src/main/bookingbugAPI/services/HttpService.java @@ -276,5 +276,9 @@ public NetResponse(String url, String method, String resp) { this.method = method; this.resp = resp; } + + public String getResp() { + return resp; + } } } \ No newline at end of file diff --git a/src/main/bookingbugAPI/services/OkHttpService.java b/src/main/bookingbugAPI/services/OkHttpService.java new file mode 100644 index 0000000..286b236 --- /dev/null +++ b/src/main/bookingbugAPI/services/OkHttpService.java @@ -0,0 +1,70 @@ +package bookingbugAPI.services; + +import bookingbugAPI.api.AbstractAPI; +import bookingbugAPI.models.HttpException; +import helpers.HttpServiceResponse; +import helpers.Utils; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +import java.io.IOException; +import java.net.URL; +import java.util.Map; + + +/** + * Created by sebi on 23.05.2016. + */ +public class OkHttpService { + + AbstractAPI.ApiConfig config; + private final OkHttpClient client = new OkHttpClient(); + + public OkHttpService(AbstractAPI.ApiConfig config) { + this.config = config; + } + + public AbstractAPI.ApiConfig getConfig() { + return config; + } + + public HttpServiceResponse api_GET(URL url) throws HttpException { + return callApi(url, "GET", HttpService.urlEncodedContentType, null); + } + + public HttpServiceResponse callApi(URL url, String method, String contentType, Map params) throws HttpException { + HttpService.NetResponse cache = config.cacheService.getDBResponse(url.toString(), method); + + if(cache != null) { + return new HttpServiceResponse(Utils.stringToContentRep(cache.getResp()), method, contentType, params, config.auth_token); + } + + Request.Builder builder = new Request.Builder() + .header("User-Agent", config.userAgent) + .header("App-Id", config.appId) + .header("App-Key", config.appKey) + .url(url.toString()); + + if(config.auth_token != null) + builder.header("Auth-Token", config.auth_token); + + Request request = builder.build(); + + Response response; + try { + response = client.newCall(request).execute(); + if (!response.isSuccessful()) + throw new HttpException("Unexpected code " + response, response.message(), response.code()); + + String raw_resp = response.body().string(); + config.cacheService.storeResult(url.toString(), method, raw_resp); + + return new HttpServiceResponse(Utils.stringToContentRep(raw_resp), method, contentType, params, config.auth_token); + } catch (IOException e) { + if(e instanceof HttpException) throw (HttpException)e; + throw new HttpException("Error", e) ; + } + + } +} diff --git a/src/main/helpers/Utils.java b/src/main/helpers/Utils.java index 5c821c9..4b83d71 100644 --- a/src/main/helpers/Utils.java +++ b/src/main/helpers/Utils.java @@ -8,7 +8,9 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.theoryinpractise.halbuilder.api.ContentRepresentation; import com.theoryinpractise.halbuilder.api.Link; +import com.theoryinpractise.halbuilder.api.RepresentationFactory; import com.theoryinpractise.halbuilder.json.JsonRepresentationFactory; +import helpers.hal_addon.CustomJsonRepresentationFactory; import javax.servlet.http.HttpSession; import java.io.ByteArrayInputStream; @@ -70,11 +72,11 @@ public static UriTemplate TemplateWithPagination(UriTemplate template, Params pa * @param content * @return */ - public static ContentRepresentation stringToContent(String content) { - JsonRepresentationFactory representationFactory = new JsonRepresentationFactory(); - InputStream ins = new ByteArrayInputStream(content.getBytes()); - Reader instr = new InputStreamReader(ins); - return representationFactory.readRepresentation(HAL_JSON, instr); + public static ContentRepresentation stringToContentRep(String content) { + CustomJsonRepresentationFactory representationFactory = new CustomJsonRepresentationFactory(); + representationFactory.withFlag(RepresentationFactory.STRIP_NULLS); + Reader reader = new InputStreamReader(new ByteArrayInputStream(content.getBytes())); + return representationFactory.readRepresentation(HAL_JSON, reader); } diff --git a/src/test/bookingbugAPI/api/admin/BookingAPITest.java b/src/test/bookingbugAPI/api/admin/BookingAPITest.java index b1479db..c7752b0 100644 --- a/src/test/bookingbugAPI/api/admin/BookingAPITest.java +++ b/src/test/bookingbugAPI/api/admin/BookingAPITest.java @@ -1,7 +1,6 @@ package bookingbugAPI.api.admin; import bookingbugAPI.api.API; -import bookingbugAPI.api.AdminAPI; import bookingbugAPI.api.AdminURLS; import bookingbugAPI.models.BBCollection; import bookingbugAPI.models.Booking; @@ -42,7 +41,7 @@ public Company getCompany() { public void getBookings(){ Company company = getCompany(); - API.APIBuilder builder = new API.APIBuilder().withCache(new CacheService()).withToken(token); + API.APIBuilder builder = new API.APIBuilder().withCache(CacheService.JDBC()).withAuthToken(token); API api = builder.build(); try { diff --git a/src/test/bookingbugAPI/services/OkHttpServiceTest.java b/src/test/bookingbugAPI/services/OkHttpServiceTest.java new file mode 100644 index 0000000..1fbc51f --- /dev/null +++ b/src/test/bookingbugAPI/services/OkHttpServiceTest.java @@ -0,0 +1,103 @@ +package bookingbugAPI.services; + +import bookingbugAPI.api.AbstractAPI; +import bookingbugAPI.models.HttpException; +import com.squareup.okhttp.mockwebserver.Dispatcher; +import com.squareup.okhttp.mockwebserver.MockResponse; +import com.squareup.okhttp.mockwebserver.MockWebServer; +import com.squareup.okhttp.mockwebserver.RecordedRequest; +import org.junit.Test; + +import java.io.IOException; +import java.net.URL; + +import static junit.framework.Assert.assertNotNull; +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertNull; + +/** + * Created by sebi on 25.05.2016. + */ +public class OkHttpServiceTest { + + String appId = "edb1ef31"; + String appKey = "7cda5a59e91113e7a0f1b3654dadca86"; + String auth_token = "x2_5PcI15mq7sEWm70JazA"; + + + final Dispatcher dispatcher = new Dispatcher() { + + @Override + public MockResponse dispatch(RecordedRequest request) throws InterruptedException { + + //Check appId and appKey headers + if (!request.getHeader("App-Id").equals(appId) || !request.getHeader("App-Key").equals(appKey)) + return new MockResponse().setResponseCode(401); + + //Check auth token on protected path + if(request.getPath().equals("/admin/") && !auth_token.equals(request.getHeader("Auth-Token"))) + return new MockResponse().setResponseCode(401); + + return new MockResponse().setResponseCode(200).setBody("{}"); + } + }; + + private AbstractAPI.ApiConfig getConfig() { + AbstractAPI.ApiConfig config = new AbstractAPI.ApiConfig(); + + config.withApp(appId, appKey).withCache(CacheService.MOCK()); + + return config; + } + + private HttpException tryGet(OkHttpService httpService, URL url) { + HttpException ex = null; + try { + httpService.api_GET(url); + } catch (HttpException e) { + ex = e; + } + return ex; + } + + /** + * Tests that HttpService correctly sets-up headers from config + * @throws IOException + */ + @Test + public void headerTest() throws IOException { + AbstractAPI.ApiConfig config = new AbstractAPI.ApiConfig().withNothing().withCache(CacheService.MOCK()); + OkHttpService httpService = new OkHttpService(config); + + MockWebServer server = new MockWebServer(); + server.setDispatcher(dispatcher); + server.start(); + + HttpException ex; + URL rootURL = server.url("").url(); + URL adminURL = server.url("/admin/").url(); + + //Test appId and appKey missing + ex = tryGet(httpService, rootURL); + assertNotNull("HttpService should raise exception when headers are missing", ex); + assertEquals("Status code should be 401 when headers are missing", ex.getStatusCode(), 401); + + //Test basic headers (appId and appKey included) + config.withApp(appId, appKey); + ex = tryGet(httpService, rootURL); + assertNull("No exception should be raised when headers are included", ex); + + //Test admin path without auth_token + ex = tryGet(httpService, adminURL); + assertNotNull("HttpService should raise exception when auth_token is missing on admin", ex); + assertEquals("Status code should be 401 when auth_token is missing on admin path", ex.getStatusCode(), 401); + + //Test admin path with auth_token + config.withAuthToken(auth_token); + ex = tryGet(httpService, adminURL); + assertNull("No exception should be raised when auth_token is included on admin path", ex); + + server.shutdown(); + } + +} From 2fb0916409719bcb16cf04e7670eb3deda1068f4 Mon Sep 17 00:00:00 2001 From: Macarescu Sebastian Date: Thu, 26 May 2016 17:03:53 +0300 Subject: [PATCH 08/22] Implemented put and delete methods. Added javadoc for OkHttpService. Implemented unit testing for OkHttpService --- .../bookingbugAPI/services/OkHttpService.java | 135 +++++++++++++++++- .../services/OkHttpServiceTest.java | 128 +++++++++++++++++ 2 files changed, 259 insertions(+), 4 deletions(-) diff --git a/src/main/bookingbugAPI/services/OkHttpService.java b/src/main/bookingbugAPI/services/OkHttpService.java index 286b236..682ce72 100644 --- a/src/main/bookingbugAPI/services/OkHttpService.java +++ b/src/main/bookingbugAPI/services/OkHttpService.java @@ -2,15 +2,15 @@ import bookingbugAPI.api.AbstractAPI; import bookingbugAPI.models.HttpException; +import helpers.Http; import helpers.HttpServiceResponse; import helpers.Utils; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; +import okhttp3.*; import java.io.IOException; import java.net.URL; import java.util.Map; +import java.util.Objects; /** @@ -25,15 +25,123 @@ public OkHttpService(AbstractAPI.ApiConfig config) { this.config = config; } + /** + * Get current service configuration + * @return {@link bookingbugAPI.api.AbstractAPI.ApiConfig} + */ public AbstractAPI.ApiConfig getConfig() { return config; } + + /** + * Makes a synchronous GET request + * @param url URL to get + * @return {@link HttpServiceResponse} + * @throws HttpException + */ public HttpServiceResponse api_GET(URL url) throws HttpException { return callApi(url, "GET", HttpService.urlEncodedContentType, null); } - public HttpServiceResponse callApi(URL url, String method, String contentType, Map params) throws HttpException { + + /** + * Makes a synchronous POST request with {@link Http#urlEncodedContentType} contentType + * @param url URL to post to + * @param params Map, a generic Map containing data to post + * @return {@link HttpServiceResponse} + * @throws HttpException + */ + public HttpServiceResponse api_POST(URL url, Map params) throws HttpException { + return callApi(url, "POST", HttpService.urlEncodedContentType, params); + } + + + /** + * Makes a synchronous POST request with specific contentType + * @param url URL to post to + * @param contentType String, can be {@link Http#urlEncodedContentType} or {@link Http#jsonContentType}. + * @param params Map, a generic Map containing data to post + * @return {@link HttpServiceResponse} + * @throws HttpException + */ + public HttpServiceResponse api_POST(URL url, String contentType, Map params) throws HttpException { + return callApi(url, "POST", contentType, params); + } + + + /** + * Makes a synchronous PUT request with {@link Http#urlEncodedContentType} contentType + * @param url URL to put to + * @param params Map, a generic Map containing data to put + * @return {@link HttpServiceResponse} + * @throws HttpException + */ + public HttpServiceResponse api_PUT(URL url, Map params) throws HttpException { + return callApi(url, "PUT", HttpService.urlEncodedContentType, params); + } + + + /** + * Makes a synchronous PUT request with specific contentType + * @param url URL to put to + * @param contentType String, can be {@link Http#urlEncodedContentType} or {@link Http#jsonContentType}. + * @param params Map, a generic Map containing data to put + * @return {@link HttpServiceResponse} + * @throws HttpException + */ + public HttpServiceResponse api_PUT(URL url, String contentType, Map params) throws HttpException { + return callApi(url, "PUT", contentType, params); + } + + + /** + * Makes a synchronous DELETE request + * @param url URL to delete to + * @return {@link HttpServiceResponse} + * @throws HttpException + */ + public HttpServiceResponse api_DELETE(URL url) throws HttpException { + return callApi(url, "DELETE", HttpService.urlEncodedContentType, null); + } + + + /** + * Makes a synchronous DELETE request with parameters and {@link Http#urlEncodedContentType} contentType + * @param url URL to delete to + * @param params Map, a generic Map containing data to put + * @return {@link HttpServiceResponse} + * @throws HttpException + */ + public HttpServiceResponse api_DELETE(URL url, Map params) throws HttpException { + return callApi(url, "DELETE", HttpService.urlEncodedContentType, params); + } + + + /** + * Makes a synchronous DELETE request with parameters and specific contentType + * @param url URL to delete to + * @param contentType String, can be {@link Http#urlEncodedContentType} or {@link Http#jsonContentType}. + * @param params Map, a generic Map containing data to put + * @return {@link HttpServiceResponse} + * @throws HttpException + */ + public HttpServiceResponse api_DELETE(URL url, String contentType, Map params) throws HttpException { + return callApi(url, "DELETE", contentType, params); + } + + + /** + * Make a synchronous configurable network request. Uses headers and other config from {@link OkHttpService#config} + * @param url URL to call + * @param method String, can be GET, POST, PUT, DELETE, UPDATE + * @param contentType String, can be {@link Http#urlEncodedContentType} or {@link Http#jsonContentType} + * @param params Map, a generic Map with parameters for POST, PUT or UPDATE. Will be serialized according + * to {@code contentType} + * @return {@link HttpServiceResponse} + * @throws HttpException + */ + private HttpServiceResponse callApi(URL url, String method, String contentType, Map params) throws HttpException { HttpService.NetResponse cache = config.cacheService.getDBResponse(url.toString(), method); if(cache != null) { @@ -49,6 +157,25 @@ public HttpServiceResponse callApi(URL url, String method, String contentType, M if(config.auth_token != null) builder.header("Auth-Token", config.auth_token); + String body = null; + if(params != null) { + try { + body = Http.getEncoder(contentType).encode(params); + } catch (Http.EncodingException | Http.UnknownContentType e) { + throw new HttpException("Error", e) ; + } + } + + if(Objects.equals(method, "POST") && body != null) { + builder.post(RequestBody.create(MediaType.parse(contentType), body)); + } else if(Objects.equals(method, "PUT") && body != null) { + builder.put(RequestBody.create(MediaType.parse(contentType), body)); + } else if(Objects.equals(method, "DELETE") && body != null) { + builder.delete(RequestBody.create(MediaType.parse(contentType), body)); + } else if(Objects.equals(method, "DELETE")) { + builder.delete(); + } + Request request = builder.build(); Response response; diff --git a/src/test/bookingbugAPI/services/OkHttpServiceTest.java b/src/test/bookingbugAPI/services/OkHttpServiceTest.java index 1fbc51f..485d03c 100644 --- a/src/test/bookingbugAPI/services/OkHttpServiceTest.java +++ b/src/test/bookingbugAPI/services/OkHttpServiceTest.java @@ -6,10 +6,14 @@ import com.squareup.okhttp.mockwebserver.MockResponse; import com.squareup.okhttp.mockwebserver.MockWebServer; import com.squareup.okhttp.mockwebserver.RecordedRequest; +import helpers.HttpServiceResponse; import org.junit.Test; import java.io.IOException; import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; import static junit.framework.Assert.assertNotNull; import static junit.framework.TestCase.assertEquals; @@ -38,6 +42,21 @@ public MockResponse dispatch(RecordedRequest request) throws InterruptedExceptio if(request.getPath().equals("/admin/") && !auth_token.equals(request.getHeader("Auth-Token"))) return new MockResponse().setResponseCode(401); + //Check post data + if(request.getPath().equals("/post/") && Objects.equals(request.getMethod(), "POST") && request.getBodySize() != 0) { + return new MockResponse().setResponseCode(201).setBody("{\"status\":\"201\"}"); + } + + //Check put data + if(request.getPath().equals("/put/") && Objects.equals(request.getMethod(), "PUT") && request.getBodySize() != 0) { + return new MockResponse().setResponseCode(201).setBody("{\"status\":\"updated\"}"); + } + + //Check delete data + if(request.getPath().equals("/delete/") && Objects.equals(request.getMethod(), "DELETE")) { + return new MockResponse().setResponseCode(201).setBody("{\"status\":\"deleted\"}"); + } + return new MockResponse().setResponseCode(200).setBody("{}"); } }; @@ -100,4 +119,113 @@ public void headerTest() throws IOException { server.shutdown(); } + /** + * Test POST api + * @throws IOException + */ + @Test + public void testPOST() throws IOException { + AbstractAPI.ApiConfig config = new AbstractAPI.ApiConfig().withCache(CacheService.MOCK()); + OkHttpService httpService = new OkHttpService(config); + + MockWebServer server = new MockWebServer(); + server.setDispatcher(dispatcher); + server.start(); + + HttpException ex = null; + HttpServiceResponse response = null; + URL postURL = server.url("/post/").url(); + + Map params = new HashMap(); + params.put("param1", "val1"); + + try { + //With specific encoding + response = httpService.api_POST(postURL, HttpService.urlEncodedContentType, params); + assertEquals("Received status should be 201", response.getRep().getContent(), "{\"status\":\"201\"}"); + + //With default encoding + response = httpService.api_POST(postURL, params); + assertEquals("Received status should be 201", response.getRep().getContent(), "{\"status\":\"201\"}"); + } catch (HttpException e) { + ex = e; + } + assertNull(ex); + server.shutdown(); + } + + /** + * Test PUT api + * @throws IOException + */ + @Test + public void testPUT() throws IOException { + AbstractAPI.ApiConfig config = new AbstractAPI.ApiConfig().withCache(CacheService.MOCK()); + OkHttpService httpService = new OkHttpService(config); + + MockWebServer server = new MockWebServer(); + server.setDispatcher(dispatcher); + server.start(); + + HttpException ex = null; + HttpServiceResponse response = null; + URL putURL = server.url("/put/").url(); + + Map params = new HashMap(); + params.put("param1", "val1"); + + try { + //With specific encoding + response = httpService.api_PUT(putURL, HttpService.urlEncodedContentType, params); + assertEquals("Received status should be 201", response.getRep().getContent(), "{\"status\":\"updated\"}"); + + //With default encoding + response = httpService.api_PUT(putURL, params); + assertEquals("Received status should be 201", response.getRep().getContent(), "{\"status\":\"updated\"}"); + } catch (HttpException e) { + ex = e; + } + assertNull(ex); + server.shutdown(); + } + + /** + * Test DELETE api + * @throws IOException + */ + @Test + public void testDELETE() throws IOException { + AbstractAPI.ApiConfig config = new AbstractAPI.ApiConfig().withCache(CacheService.MOCK()); + OkHttpService httpService = new OkHttpService(config); + + MockWebServer server = new MockWebServer(); + server.setDispatcher(dispatcher); + server.start(); + + HttpException ex = null; + HttpServiceResponse response = null; + URL deleteURL = server.url("/delete/").url(); + + Map params = new HashMap(); + params.put("param1", "val1"); + + try { + //Without params + response = httpService.api_DELETE(deleteURL); + assertEquals("Received status should be 200", response.getRep().getContent(), "{\"status\":\"deleted\"}"); + + //With specific encoding + response = httpService.api_DELETE(deleteURL, HttpService.urlEncodedContentType, params); + assertEquals("Received status should be 201", response.getRep().getContent(), "{\"status\":\"deleted\"}"); + + //With default encoding + response = httpService.api_DELETE(deleteURL, params); + assertEquals("Received status should be 201", response.getRep().getContent(), "{\"status\":\"deleted\"}"); + } catch (HttpException e) { + ex = e; + } + assertNull(ex); + server.shutdown(); + } + } From 102cf3cc5510ab042e7c08f0cb74052bd980ac6a Mon Sep 17 00:00:00 2001 From: Macarescu Sebastian Date: Thu, 26 May 2016 18:22:16 +0300 Subject: [PATCH 09/22] Event model: getters, unittesting, javadoc --- src/main/bookingbugAPI/models/BBRoot.java | 32 ++-- src/main/bookingbugAPI/models/Event.java | 179 ++++++++++++++++++- src/test/bookingbugAPI/models/EventTest.java | 70 ++++++++ src/test/bookingbugAPI/models/ModelTest.java | 25 +++ src/test/resources/json/event.json | 38 ++++ 5 files changed, 323 insertions(+), 21 deletions(-) create mode 100644 src/test/bookingbugAPI/models/EventTest.java create mode 100644 src/test/bookingbugAPI/models/ModelTest.java create mode 100644 src/test/resources/json/event.json diff --git a/src/main/bookingbugAPI/models/BBRoot.java b/src/main/bookingbugAPI/models/BBRoot.java index 8cbca12..6c1cb9b 100644 --- a/src/main/bookingbugAPI/models/BBRoot.java +++ b/src/main/bookingbugAPI/models/BBRoot.java @@ -5,17 +5,18 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; import com.theoryinpractise.halbuilder.api.ContentRepresentation; import com.theoryinpractise.halbuilder.api.Link; import com.theoryinpractise.halbuilder.api.RepresentationException; import com.theoryinpractise.halbuilder.json.JsonRepresentationFactory; import helpers.Config; import helpers.HttpServiceResponse; +import org.joda.time.DateTime; import java.io.*; import java.net.URL; -import java.util.*; +import java.util.List; +import java.util.Map; import java.util.logging.Logger; import static com.theoryinpractise.halbuilder.api.RepresentationFactory.HAL_JSON; @@ -26,7 +27,7 @@ * Child classes should implement getters for relevant parts from the response. */ @JsonIgnoreProperties({ - "rep", "auth_token", "id", "data", "links" + "rep", "auth_token", "id", "data", "links" }) public class BBRoot { @@ -46,7 +47,7 @@ public BBRoot(HttpServiceResponse httpServiceResponse) { } - public BBRoot(String auth_token){ + public BBRoot(String auth_token) { this.auth_token = auth_token; } @@ -62,13 +63,13 @@ public BBRoot() {} public BBRoot getLoginSchema() throws IOException { - URL url = new URL (UriTemplate.fromTemplate(response.getRep().getLinkByRel("new_login").getHref()).expand()); + URL url = new URL(UriTemplate.fromTemplate(response.getRep().getLinkByRel("new_login").getHref()).expand()); HttpServiceResponse response = HttpService.api_GET(url); return new BBRoot(response); } - public Login auth(Map params) throws IOException{ + public Login auth(Map params) throws IOException { HttpServiceResponse resp; try { URL url = new URL(UriTemplate.fromTemplate(new Config().serverUrl + "/login").expand()); @@ -92,18 +93,18 @@ public Login auth(Map params) throws IOException{ } - public Login auth(Map params, Link link) throws IOException{ - URL url = new URL (link.getHref()); + public Login auth(Map params, Link link) throws IOException { + URL url = new URL(link.getHref()); HttpServiceResponse resp = HttpService.api_POST(url, params); auth_token = (String) resp.getRep().getValue("auth_token"); return new Login(resp); } - public String get(String key){ + public String get(String key) { String val = null; - try{ - val = (String)response.getRep().getValue(key); + try { + val = (String) response.getRep().getValue(key); } catch (RepresentationException e) { //e.printStackTrace(); } @@ -112,16 +113,19 @@ public String get(String key){ public boolean getBoolean(String key, boolean defaultValue) { String val = this.get(key); - if(val != null) return Boolean.parseBoolean(val); + if (val != null) return Boolean.parseBoolean(val); return defaultValue; } public int getInteger(String key, int defaultValue) { String val = this.get(key); - if(val != null) return Integer.parseInt(val); + if (val != null) return Integer.parseInt(val); return defaultValue; } + public DateTime getDate(String key) { + return new DateTime(get(key)); + } public String getAuth_token() { return auth_token; @@ -171,7 +175,7 @@ public String getCurl() { public String getSelf() { - if(response.getRep().getResourceLink() != null) + if (response.getRep().getResourceLink() != null) return response.getRep().getResourceLink().getHref(); return ""; } diff --git a/src/main/bookingbugAPI/models/Event.java b/src/main/bookingbugAPI/models/Event.java index 0daad2f..58b0f7c 100644 --- a/src/main/bookingbugAPI/models/Event.java +++ b/src/main/bookingbugAPI/models/Event.java @@ -2,28 +2,32 @@ import bookingbugAPI.services.HttpService; import com.damnhandy.uri.template.UriTemplate; +import com.fasterxml.jackson.databind.util.ISO8601DateFormat; import helpers.HttpServiceResponse; +import org.joda.time.DateTime; import java.io.IOException; import java.net.URL; +import java.util.Date; +public class Event extends BBRoot { -public class Event extends BBRoot{ + private int integerDefaultValue = 0; + private boolean booleanDefaultValue = false; - public Event(HttpServiceResponse httpServiceResponse){ + public Event(HttpServiceResponse httpServiceResponse) { super(httpServiceResponse); } - - public Event(HttpServiceResponse httpServiceResponse, String auth_token){ + public Event(HttpServiceResponse httpServiceResponse, String auth_token) { super(httpServiceResponse, auth_token); } - - public Event() {} + public Event() { + } public SchemaForm getNewBookingSchema() throws IOException { - if(getLink("new_booking") != null) { + if (getLink("new_booking") != null) { String link = getLink("new_booking"); URL url = new URL(UriTemplate.fromTemplate(link).expand()); return new SchemaForm(HttpService.api_GET(url, this.auth_token)); @@ -32,4 +36,165 @@ public SchemaForm getNewBookingSchema() throws IOException { throw new IOException("new_booking link missing"); } + /** + * Returns the Event id. + * + * @return The id associated with the current Event object. + */ + public Integer getId() { + return getInteger("id", integerDefaultValue); + } + + /** + * Returns the Event date and time in {@link DateTime DateTime()} format. + * + * @return The date associated with the current Event object. + */ + public DateTime getDatetime() { + return getDate("datetime"); + } + + /** + * Returns the Event description. + * + * @return The description associated with the current Event object. + */ + public String getDescription() { + return get("description"); + } + + /** + * Returns the Event status. + * + * @return The status associated with the current Event object. + */ + public Integer getStatus() { + return getInteger("status", integerDefaultValue); + } + + /** + * Returns the Event spaces booked. + * + * @return The spaces booked associated with the current Event object. + */ + public Integer getSpacesBooked() { + return getInteger("spaces_booked", integerDefaultValue); + } + + /** + * Returns the Event spaces reserved. + * + * @return The spaces reserved associated with the current Event object. + */ + public Integer getSpacesReserved() { + return getInteger("spaces_reserved", integerDefaultValue); + } + + /** + * Returns the Event spaces blocked. + * + * @return The spaces blocked associated with the current Event object. + */ + public Integer getSpacesBlocked() { + return getInteger("spaces_blocked", integerDefaultValue); + } + + /** + * Returns the Event spaces held. + * + * @return The spaces held associated with the current Event object. + */ + public Integer getSpacesHeld() { + return getInteger("spaces_held", integerDefaultValue); + } + + /** + * Returns the Event number of spaces. + * + * @return The number of spaces associated with the current Event object. + */ + public Integer getNumSpaces() { + return getInteger("num_spaces", integerDefaultValue); + } + + /** + * Returns the Event wait spaces. + * + * @return The wait spaces associated with the current Event object. + */ + public Integer getSpacesWait() { + return getInteger("spaces_wait", integerDefaultValue); + } + + /** + * Returns the Event event chain id. + * + * @return The event chain id associated with the current Event object. + */ + public Integer getEventChainId() { + return getInteger("event_chain_id", integerDefaultValue); + } + + /** + * Returns the Event service id. + * + * @return The service id associated with the current Event object. + */ + public Integer getServiceId() { + return getInteger("service_id", integerDefaultValue); + } + + /** + * Returns the Event duration with unit provided by {@link #getDurationUnits() getDurationUnits()} + * + * @return The duration associated with the current Event object. + */ + public Integer getDuration() { + return getInteger("duration", integerDefaultValue); + } + + /** + * Returns the event duration size unit. + * + * @return The duration size unit associated with the current Event object. + */ + public String getDurationUnits() { + return get("units"); + } + + /** + * Returns the Event price. + * + * @return The price associated with the current Event object. + */ + public Integer getPrice() { + return getInteger("price", integerDefaultValue); + } + + /** + * Returns the Event event groups link. + * + * @return The event groups link associated with the current Event object. + */ + public String getEventGroupsLink() { + return getLink("event_groups"); + } + + /** + * Returns the Event event chains link. + * + * @return The event chains link associated with the current Event object. + */ + public String getEventChainsLink() { + return getLink("event_chains"); + } + + /** + * Returns the Event book link. + * + * @return The book link associated with the current Event object. + */ + public String getBookLink() { + return getLink("book"); + } } diff --git a/src/test/bookingbugAPI/models/EventTest.java b/src/test/bookingbugAPI/models/EventTest.java new file mode 100644 index 0000000..ab156d4 --- /dev/null +++ b/src/test/bookingbugAPI/models/EventTest.java @@ -0,0 +1,70 @@ +package bookingbugAPI.models; + +import helpers.HttpServiceResponse; +import helpers.Utils; +import org.joda.time.DateTime; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.*; + +import static org.junit.Assert.assertTrue; + +public class EventTest extends ModelTest { + + private JSONObject jsonObject; + + @Override + @Before + public void setUp() { + ClassLoader classLoader = getClass().getClassLoader(); + String fileName = null; + try { + fileName = classLoader.getResource("json/event.json").getFile(); + } catch (NullPointerException e) { + e.printStackTrace(); + } + + JSONParser parser = new JSONParser(); + try { + jsonObject = (JSONObject) parser.parse(new FileReader(fileName)); + } catch (ParseException | IOException e) { + e.printStackTrace(); + } + } + + @Override + @Test + public void modelInit() throws java.text.ParseException { + Event event = new Event(new HttpServiceResponse(Utils.stringToContentRep(jsonObject.toString()))); + JSONObject jsonLinks = (JSONObject) jsonObject.get("_links"); + assertTrue(event.getId().toString().equals(jsonObject.get("id").toString())); + assertTrue(event.getDatetime().equals(new DateTime(jsonObject.get("datetime").toString()))); + assertTrue(event.getDescription().equals(jsonObject.get("description").toString())); + assertTrue(event.getStatus().toString().equals(jsonObject.get("status").toString())); + assertTrue(event.getSpacesHeld().toString().equals(jsonObject.get("spaces_held").toString())); + assertTrue(event.getSpacesBooked().toString().equals(jsonObject.get("spaces_booked").toString())); + assertTrue(event.getSpacesReserved().toString().equals(jsonObject.get("spaces_reserved").toString())); + assertTrue(event.getSpacesBlocked().toString().equals(jsonObject.get("spaces_blocked").toString())); + assertTrue(event.getNumSpaces().toString().equals(jsonObject.get("num_spaces").toString())); + assertTrue(event.getSpacesWait().toString().equals(jsonObject.get("spaces_wait").toString())); + assertTrue(event.getEventChainId().toString().equals(jsonObject.get("event_chain_id").toString())); + assertTrue(event.getServiceId().toString().equals(jsonObject.get("service_id").toString())); + assertTrue(event.getDuration().toString().equals(jsonObject.get("duration").toString())); + assertTrue(event.getPrice().toString().equals(jsonObject.get("price").toString())); + assertTrue(event.getEventGroupsLink().equals(((JSONObject) jsonLinks.get("event_groups")).get("href"))); + assertTrue(event.getEventChainsLink().equals(((JSONObject) jsonLinks.get("event_chains")).get("href"))); + assertTrue(event.getBookLink().equals(((JSONObject) jsonLinks.get("book")).get("href"))); + } + + @Override + @After + public void tearDown() { + jsonObject = null; + } + +} diff --git a/src/test/bookingbugAPI/models/ModelTest.java b/src/test/bookingbugAPI/models/ModelTest.java new file mode 100644 index 0000000..f3cb906 --- /dev/null +++ b/src/test/bookingbugAPI/models/ModelTest.java @@ -0,0 +1,25 @@ +package bookingbugAPI.models; + +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import java.text.ParseException; + +/** + * Abstract ModelTest class. Must be inherited by all tests for bb models + * Has setUp, tearDown and modelInit methods + */ +@Ignore +public abstract class ModelTest { + + @Before + public abstract void setUp(); + + @Test + public abstract void modelInit() throws ParseException; + + @After + public abstract void tearDown(); +} diff --git a/src/test/resources/json/event.json b/src/test/resources/json/event.json new file mode 100644 index 0000000..fa8f1ce --- /dev/null +++ b/src/test/resources/json/event.json @@ -0,0 +1,38 @@ +{ + "id": 12680457, + "datetime": "2016-04-26T09:00:00+02:00", + "description": "My Recurring Event", + "status": 4, + "spaces_booked": 0, + "spaces_reserved": 0, + "spaces_blocked": 0, + "spaces_held": 0, + "num_spaces": 21, + "spaces_wait": 0, + "event_chain_id": 97149, + "service_id": 59377, + "duration": 60, + "price": 0, + "ticket_spaces": { + "10394": { + "name": "", + "left": 21 + } + }, + "_links": { + "self": { + "href": "https://uk.bookingbug.com/api/v1/37901/events/12680457{?embed}" + }, + "event_groups": { + "href": "https://uk.bookingbug.com/api/v1/37901/event_groups/59377" + }, + "event_chains": { + "href": "https://uk.bookingbug.com/api/v1/37901/event_chains/97149{?member_level_id}", + "templated": true + }, + "book": { + "href": "https://uk.bookingbug.com/api/v1/37901/basket/add_item?event_id=12680457&event_chain_id=97149{&member_id,service_id,product_id,attachment_id,deal_id,package_id,bulk_purchase_id}", + "templated": true + } + } +} From 05818372b96b8fcc14cbcf982136be82cdcfcb2b Mon Sep 17 00:00:00 2001 From: Macarescu Sebastian Date: Fri, 27 May 2016 10:19:32 +0300 Subject: [PATCH 10/22] Client model: getters, unittesting, javadoc. Empty Answer model. --- src/main/bookingbugAPI/models/Answer.java | 117 +++++++++ src/main/bookingbugAPI/models/BBRoot.java | 72 +++++- src/main/bookingbugAPI/models/Client.java | 242 +++++++++++++++++- .../hal_addon/CustomJsonDeserializer.java | 10 + .../CustomJsonRepresentationReader.java | 6 +- src/test/bookingbugAPI/models/AnswerTest.java | 54 ++++ src/test/bookingbugAPI/models/ClientTest.java | 65 +++++ src/test/bookingbugAPI/models/ModelTest.java | 19 ++ src/test/resources/json/answer.json | 57 +++++ src/test/resources/json/client.json | 45 ++++ 10 files changed, 671 insertions(+), 16 deletions(-) create mode 100644 src/main/bookingbugAPI/models/Answer.java create mode 100644 src/test/bookingbugAPI/models/AnswerTest.java create mode 100644 src/test/bookingbugAPI/models/ClientTest.java create mode 100644 src/test/resources/json/answer.json create mode 100644 src/test/resources/json/client.json diff --git a/src/main/bookingbugAPI/models/Answer.java b/src/main/bookingbugAPI/models/Answer.java new file mode 100644 index 0000000..6a1e197 --- /dev/null +++ b/src/main/bookingbugAPI/models/Answer.java @@ -0,0 +1,117 @@ +package bookingbugAPI.models; + +import helpers.HttpServiceResponse; + +public class Answer extends BBRoot{ + + public Answer(HttpServiceResponse httpServiceResponse) { + super(httpServiceResponse); + } + + public Answer(HttpServiceResponse httpServiceResponse, String auth_token) { + super(httpServiceResponse, auth_token); + } + + public Answer() { + } + + /** + * Returns the answer's id. + * + * @return The id associated with the current Answer object. + */ + public Integer getId() { + return getInteger("id", INTEGER_DEFAULT_VALUE); + } + + /** + * Returns the answer's value. + * + * @return The value associated with the current Answer object. + */ + public String getValue() { + return get("value"); + } + + /** + * Returns the answer's price. + * + * @return The price associated with the current Answer object. + */ + public Double getPrice() { + return getDouble("price", INTEGER_DEFAULT_VALUE); + } + + /** + * Returns the question id. + * + * @return The question id associated with the current Answer object. + */ + public Integer getQuestionId() { + return getInteger("question_id", INTEGER_DEFAULT_VALUE); + } + + + /** + * Returns the admin only attribute. + * + * @return The admin only attribute associated with the current Answer object. + */ + public Boolean getAdminOnly() { + return getBoolean("admin_only", BOOLEAN_DEFAULT_VALUE); + } + + /** + * Returns the important attribute. + * + * @return The important attribute associated with the current Answer object. + */ + public Boolean getImportant() { + return getBoolean("important", BOOLEAN_DEFAULT_VALUE); + } + + /** + * Returns the question. + * + * @return The question associated with the current Answer object. + */ + public Question getQuestion() { + return new Question(new HttpServiceResponse(getResource("question"))); + } + + /** + * Returns the question text . + * + * @return The question text associated with the current Answer object. + */ + public String getQuestionText() { + return get("question_text"); + } + + /** + * Returns the outcome. + * + * @return The outcome associated with the current Answer object. + */ + public Boolean getOutcome() { + return getBoolean("outcome", BOOLEAN_DEFAULT_VALUE); + } + + /** + * Returns the company id. + * + * @return The company id associated with the current Answer object. + */ + public Integer getCompanyId() { + return getInteger("company_id", INTEGER_DEFAULT_VALUE); + } + + /** + * Returns the question link . + * + * @return The question link associated with the current Answer object. + */ + public String getQuestionLink() { + return getLink("question"); + } +} diff --git a/src/main/bookingbugAPI/models/BBRoot.java b/src/main/bookingbugAPI/models/BBRoot.java index 6c1cb9b..1b5733a 100644 --- a/src/main/bookingbugAPI/models/BBRoot.java +++ b/src/main/bookingbugAPI/models/BBRoot.java @@ -3,20 +3,28 @@ import bookingbugAPI.services.HttpService; import com.damnhandy.uri.template.UriTemplate; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; import com.theoryinpractise.halbuilder.api.ContentRepresentation; import com.theoryinpractise.halbuilder.api.Link; +import com.theoryinpractise.halbuilder.api.ReadableRepresentation; import com.theoryinpractise.halbuilder.api.RepresentationException; +import com.theoryinpractise.halbuilder.impl.representations.ContentBasedRepresentation; import com.theoryinpractise.halbuilder.json.JsonRepresentationFactory; import helpers.Config; import helpers.HttpServiceResponse; +import helpers.Utils; +import helpers.hal_addon.CustomJsonDeserializer; import org.joda.time.DateTime; +import org.json.simple.JSONObject; import java.io.*; import java.net.URL; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.logging.Logger; import static com.theoryinpractise.halbuilder.api.RepresentationFactory.HAL_JSON; @@ -37,6 +45,8 @@ public class BBRoot { protected String auth_token = null; public String id; public Map data; + public int INTEGER_DEFAULT_VALUE = 0; + public boolean BOOLEAN_DEFAULT_VALUE = false; protected String curl = "N/A"; @@ -123,10 +133,68 @@ public int getInteger(String key, int defaultValue) { return defaultValue; } + public double getDouble(String key, int defaultValue) { + String val = this.get(key); + if (val != null) return Double.parseDouble(val); + return defaultValue; + } + public DateTime getDate(String key) { return new DateTime(get(key)); } + public List getArray(String key) { + List val = null; + try { + val = (List) (response.getRep().getValue(key)); + } catch (RepresentationException e) { + e.printStackTrace(); + } + return val; + } + + //TODO: improve this + public T getObject(String key, Class type) { + + try { + ObjectMapper mapper = CustomJsonDeserializer.getMapper(); + String json_obj = mapper.writeValueAsString(response.getRep().getValue(key)); + return mapper.readValue(json_obj, type); + } catch (RepresentationException | IOException e) { + e.printStackTrace(); + } + return null; + } + + public List getObjects(String key, Class type) { + List val = null; + + try { + ObjectMapper mapper = CustomJsonDeserializer.getMapper(); + String json_obj = mapper.writeValueAsString(response.getRep().getValue(key)); + val = mapper.readValue(json_obj, new TypeReference>(){}); + } catch (IOException e) { + e.printStackTrace(); + } + + return val; + } + + //TODO: fix this + public ContentRepresentation getResource(String key) { + try { + List entries = response.getRep().getResourcesByRel(key); + + for (ReadableRepresentation item : entries) { + if(item instanceof ContentBasedRepresentation) + return (ContentRepresentation) item; + } + } catch (RepresentationException e) { + e.printStackTrace(); + } + return null; + } + public String getAuth_token() { return auth_token; } diff --git a/src/main/bookingbugAPI/models/Client.java b/src/main/bookingbugAPI/models/Client.java index 5d163cf..4ebdba1 100644 --- a/src/main/bookingbugAPI/models/Client.java +++ b/src/main/bookingbugAPI/models/Client.java @@ -1,23 +1,247 @@ package bookingbugAPI.models; +import com.fasterxml.jackson.annotation.JsonProperty; import helpers.HttpServiceResponse; -public class Client extends BBRoot { +import java.util.List; +import java.util.Map; - public String first_name; - public String last_name; - public String email; - public String phone; +public class Client extends BBRoot { - public Client(HttpServiceResponse httpServiceResponse){ + public Client(HttpServiceResponse httpServiceResponse) { super(httpServiceResponse); } - - public Client(HttpServiceResponse httpServiceResponse, String auth_token){ + public Client(HttpServiceResponse httpServiceResponse, String auth_token) { super(httpServiceResponse, auth_token); } - public Client() {} + public Client() { + } + + /** + * Returns the client's first name. + * + * @return The first name associated with the current Client object. + */ + public String getFirstName() { + return get("first_name"); + } + + /** + * Returns the client's last name. + * + * @return The last name associated with the current Client object. + */ + public String getLastName() { + return get("last_name"); + } + + /** + * Returns the client's email. + * + * @return The last name associated with the current Client object. + */ + public String getEmail() { + return get("email"); + } + + /** + * Returns the first address, if exists. + * + * @return The first address associated with the current Client object. + */ + public String getAddress1() { + return get("address1"); + } + + /** + * Returns the second address, if exists. + * + * @return The second address associated with the current Client object. + */ + public String getAddress2() { + return get("address2"); + } + + /** + * Returns the third address, if exists. + * + * @return The third address associated with the current Client object. + */ + public String getAddress3() { + return get("address3"); + } + + /** + * Returns the fourth address, if exists. + * + * @return The fourth address associated with the current Client object. + */ + public String getAddress4() { + return get("address4"); + } + + /** + * Returns the fifth address, if exists. + * + * @return The fifth address associated with the current Client object. + */ + public String getAddress5() { + return get("address5"); + } + + /** + * Returns the post code. + * + * @return The post code associated with the current Client object. + */ + public String getPostcode() { + return get("postcode"); + } + + /** + * Returns the country. + * + * @return The country associated with the current Client object. + */ + public String getCountry() { + return get("country"); + } + + /** + * Returns the client's phone. + * + * @return The phone associated with the current Client object. + */ + public String getPhone() { + return get("phone"); + } + + /** + * Returns the client's mobile. + * + * @return The mobile associated with the current Client object. + */ + public String getMobile() { + return get("mobile"); + } + + + /** + * Returns the client's id. + * + * @return The id associated with the current Client object. + */ + public Integer getId() { + return getInteger("id", INTEGER_DEFAULT_VALUE); + } + + /** + * Returns the client's member type. + * + * @return The member type associated with the current Client object. + */ + public Integer getMemberType() { + return getInteger("member_type", INTEGER_DEFAULT_VALUE); + } + + /** + * Returns the reference. + * + * @return The reference associated with the current Client object. + */ + public String getReference() { + return get("reference"); + } + + /** + * Returns the files. + * + * @return The files associated with the current Client object. + */ + public List getFiles() { + return getArray("files"); + } + + /** + * Returns the answers. + * + * @return The answers associated with the current Client object. + */ + public List getAnswers() { + return getObjects("answers", Answer.class); + } + + /** + * Returns the client if it's deleted attribute. + * + * @return True if the client is deleted, false otherwise. + */ + public Boolean getDeleted() { + return getBoolean("deleted", BOOLEAN_DEFAULT_VALUE); + } + /** + * Returns the client's phone prefix. + * + * @return The phone prefix associated with the current Client object. + */ + public String getPhonePrefix() { + return get("phone_prefix"); + } + + /** + * Returns the client's mobile prefix. + * + * @return The mobile prefix associated with the current Client object. + */ + public String getMobilePrefix() { + return get("mobile_prefix"); + } + + /** + * Returns the client's . + * + * @return The associated with the current Client object. + */ + public Map getQ() { + return getObject("q", Map.class); + } + + /** + * Returns the bookings link. + * + * @return The bookings link associated with the current Client object. + */ + public String getBookingsLink() { + return getLink("bookings"); + } + + /** + * Returns the pre paid bookings link. + * + * @return The pre paid bookings link associated with the current Client object. + */ + public String getPrePaidBookingsLink() { + return getLink("pre_paid_bookings"); + } + + /** + * Returns the questions link. + * + * @return The questions link associated with the current Client object. + */ + public String getQuestionsLink() { + return getLink("questions"); + } + + /** + * Returns the edit link. + * + * @return The edit link associated with the current Client object. + */ + public String getEditLink() { + return getLink("edit"); + } } diff --git a/src/main/helpers/hal_addon/CustomJsonDeserializer.java b/src/main/helpers/hal_addon/CustomJsonDeserializer.java index dfc65d2..348f58a 100644 --- a/src/main/helpers/hal_addon/CustomJsonDeserializer.java +++ b/src/main/helpers/hal_addon/CustomJsonDeserializer.java @@ -9,6 +9,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer; import com.fasterxml.jackson.databind.jsontype.TypeDeserializer; +import com.fasterxml.jackson.databind.module.SimpleModule; import java.io.IOException; import java.util.HashMap; @@ -38,4 +39,13 @@ public Object deserializeWithType(JsonParser jsonParser, DeserializationContext public Object getNullValue() { return ""; } + + public static ObjectMapper getMapper() { + ObjectMapper mapper = new ObjectMapper(); + + SimpleModule simpleModule = new SimpleModule(); + simpleModule.addDeserializer(Object.class, new CustomJsonDeserializer()); + mapper.registerModule(simpleModule); + return mapper; + } } diff --git a/src/main/helpers/hal_addon/CustomJsonRepresentationReader.java b/src/main/helpers/hal_addon/CustomJsonRepresentationReader.java index c8aa67e..3d5e693 100644 --- a/src/main/helpers/hal_addon/CustomJsonRepresentationReader.java +++ b/src/main/helpers/hal_addon/CustomJsonRepresentationReader.java @@ -30,11 +30,7 @@ public class CustomJsonRepresentationReader implements RepresentationReader { public CustomJsonRepresentationReader(AbstractRepresentationFactory representationFactory) { this.representationFactory = representationFactory; - this.mapper = new ObjectMapper(); - - SimpleModule simpleModule = new SimpleModule(); - simpleModule.addDeserializer(Object.class, new CustomJsonDeserializer()); - this.mapper.registerModule(simpleModule); + this.mapper = CustomJsonDeserializer.getMapper(); } public ContentRepresentation read(Reader reader) { diff --git a/src/test/bookingbugAPI/models/AnswerTest.java b/src/test/bookingbugAPI/models/AnswerTest.java new file mode 100644 index 0000000..7f575ac --- /dev/null +++ b/src/test/bookingbugAPI/models/AnswerTest.java @@ -0,0 +1,54 @@ +package bookingbugAPI.models; + +import com.fasterxml.jackson.core.JsonProcessingException; +import helpers.HttpServiceResponse; +import helpers.Utils; +import helpers.hal_addon.CustomJsonDeserializer; +import org.json.simple.JSONObject; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.text.ParseException; + +import static org.junit.Assert.assertTrue; + + +public class AnswerTest extends ModelTest { + private JSONObject jsonObject; + + @Override + @Before + public void setUp() { + jsonObject = getJSON("json/answer.json"); + } + + @Override + @Test + public void modelInit() throws ParseException { + Answer answer = new Answer(new HttpServiceResponse(Utils.stringToContentRep(jsonObject.toString()))); + JSONObject jsonLinks = (JSONObject) jsonObject.get("_links"); + JSONObject jsonEmbedded = (JSONObject) jsonObject.get("_embedded"); + CustomJsonDeserializer jsonDeserializer = new CustomJsonDeserializer(); + + assertTrue(answer.getId().toString().equals(jsonObject.get("id").toString())); + assertTrue(answer.getValue().equals(jsonObject.get("value"))); + assertTrue(answer.getPrice().toString().equals(jsonObject.get("price").toString())); + assertTrue(answer.getQuestionId().toString().equals(jsonObject.get("question_id").toString())); + assertTrue(answer.getAdminOnly().toString().equals(jsonObject.get("admin_only").toString())); + assertTrue(answer.getImportant().toString().equals(jsonObject.get("important").toString())); + + assertTrue(answer.getQuestion().id.equals("15571")); + + assertTrue(answer.getQuestionText().equals(jsonObject.get("question_text"))); + assertTrue(answer.getOutcome().toString().equals(jsonObject.get("outcome").toString())); + assertTrue(answer.getCompanyId().toString().equals(jsonObject.get("company_id").toString())); + assertTrue(answer.getQuestionLink().equals(((JSONObject) jsonLinks.get("question")).get("href"))); + } + + @Override + @After + public void tearDown() { + jsonObject = null; + } +} diff --git a/src/test/bookingbugAPI/models/ClientTest.java b/src/test/bookingbugAPI/models/ClientTest.java new file mode 100644 index 0000000..c09b3a6 --- /dev/null +++ b/src/test/bookingbugAPI/models/ClientTest.java @@ -0,0 +1,65 @@ +package bookingbugAPI.models; + +import helpers.HttpServiceResponse; +import helpers.Utils; +import helpers.hal_addon.CustomJsonDeserializer; +import org.json.simple.JSONObject; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.text.ParseException; + +import static org.junit.Assert.assertTrue; + + +public class ClientTest extends ModelTest{ + private JSONObject jsonObject; + + @Override + @Before + public void setUp() { + jsonObject = getJSON("json/client.json"); + } + + @Override + @Test + public void modelInit() throws ParseException { + Client client =new Client(new HttpServiceResponse(Utils.stringToContentRep(jsonObject.toString()))); + JSONObject jsonLinks = (JSONObject) jsonObject.get("_links"); + CustomJsonDeserializer jsonDeserializer = new CustomJsonDeserializer(); + + assertTrue(client.getFirstName().equals(jsonObject.get("first_name"))); + assertTrue(client.getLastName().equals(jsonObject.get("last_name"))); + assertTrue(client.getEmail().equals(jsonObject.get("email"))); + assertTrue(client.getAddress1().equals(jsonObject.get("address1"))); + assertTrue(client.getAddress2().equals(jsonObject.get("address2"))); + assertTrue(client.getAddress3().equals(jsonObject.get("address3"))); + assertTrue(client.getAddress4().equals(jsonObject.get("address4"))); + assertTrue(client.getCountry().equals(jsonObject.get("country"))); + assertTrue(client.getId().toString().equals(jsonObject.get("id").toString())); + assertTrue(client.getMemberType().toString().equals(jsonObject.get("member_type").toString())); + assertTrue(client.getReference().equals(jsonObject.get("reference"))); + assertTrue(client.getFiles().equals(jsonObject.get("files"))); + assertTrue(client.getDeleted().toString().equals(jsonObject.get("deleted").toString())); + assertTrue(client.getPhonePrefix().equals(jsonObject.get("phone_prefix"))); + assertTrue(client.getMobilePrefix().equals(jsonObject.get("mobile_prefix"))); + assertTrue(client.getBookingsLink().equals(((JSONObject) jsonLinks.get("bookings")).get("href"))); + assertTrue(client.getPrePaidBookingsLink().equals(((JSONObject) jsonLinks.get("pre_paid_bookings")).get("href"))); + assertTrue(client.getQuestionsLink().equals(((JSONObject) jsonLinks.get("questions")).get("href"))); + assertTrue(client.getEditLink().equals(((JSONObject) jsonLinks.get("edit")).get("href"))); +/* + try { + assertTrue((jsonDeserializer.getMapper().writeValueAsString(client.getAnswers())).equals(jsonObject.get("answers").toString())); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } +*/ + } + + @Override + @After + public void tearDown() { + jsonObject = null; + } +} diff --git a/src/test/bookingbugAPI/models/ModelTest.java b/src/test/bookingbugAPI/models/ModelTest.java index f3cb906..1766a6f 100644 --- a/src/test/bookingbugAPI/models/ModelTest.java +++ b/src/test/bookingbugAPI/models/ModelTest.java @@ -1,10 +1,14 @@ package bookingbugAPI.models; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; import org.junit.After; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; +import java.io.FileReader; +import java.io.IOException; import java.text.ParseException; /** @@ -22,4 +26,19 @@ public abstract class ModelTest { @After public abstract void tearDown(); + + public JSONObject getJSON(String jsonFile) { + ClassLoader classLoader = getClass().getClassLoader(); + String fileName; + try { + fileName = classLoader.getResource(jsonFile).getFile(); + + JSONParser parser = new JSONParser(); + return (JSONObject) parser.parse(new FileReader(fileName)); + } catch (org.json.simple.parser.ParseException | IOException | NullPointerException e) { + e.printStackTrace(); + } + + return null; + } } diff --git a/src/test/resources/json/answer.json b/src/test/resources/json/answer.json new file mode 100644 index 0000000..14decf2 --- /dev/null +++ b/src/test/resources/json/answer.json @@ -0,0 +1,57 @@ +{ + "id": 4868338, + "value": "", + "price": 0.0, + "question_id": 15571, + "admin_only": false, + "important": false, + "_embedded": { + "question": { + "id": 15571, + "name": "What type of pet?", + "required": true, + "important": false, + "admin_only": false, + "applies_to": 0, + "ask_member": true, + "detail_type": "select-price", + "options": [{ + "name": "Dog", + "price": -1000, + "is_default": false, + "id": 27946 + }, { + "name": "Cat", + "price": 0, + "is_default": false, + "id": 27947 + }, { + "name": "Rabbit", + "price": 0, + "is_default": false, + "id": 27948 + }], + "settings": {}, + "price": 0, + "price_per_booking": false, + "outcome": false, + "_links": { + "self": { + "href": "https://uk.bookingbug.com/api/v1/37901/questions/15571" + } + } + } + }, + "question_text": "What type of pet?", + "outcome": false, + "company_id": 37901, + "_links": { + "self": { + "href": "https://uk.bookingbug.com/api/v1/37901/answers/4868338" + }, + "question": { + "title": "What type of pet?", + "href": "https://uk.bookingbug.com/api/v1/37901/questions/15571" + } + } +} diff --git a/src/test/resources/json/client.json b/src/test/resources/json/client.json new file mode 100644 index 0000000..72e139a --- /dev/null +++ b/src/test/resources/json/client.json @@ -0,0 +1,45 @@ +{ + "first_name": "Conor", + "last_name": "McCafferson", + "email": "conor.cafferkey@gmail.com", + "address1": "", + "address2": "", + "address3": "", + "address4": "", + "postcode": "", + "country": "United Kingdom", + "phone": "", + "mobile": "7472391991", + "id": 900649, + "member_type": 1, + "reference": "", + "files": [], + "answers": [{ + "question_id": 17353, + "name": "Private Notes", + "answer": "123" + }], + "deleted": false, + "phone_prefix": "44", + "mobile_prefix": "44", + "q": {}, + "_links": { + "self": { + "href": "https://uk.bookingbug.com/api/v1/admin/37901/client/900649" + }, + "bookings": { + "href": "https://uk.bookingbug.com/api/v1/admin/37901/bookings{/id}?client_id=900649{&start_date,end_date,page,per_page,include_cancelled,modified_since,slot_id,event_id,resource_id,service_id,person_id}", + "templated": true + }, + "pre_paid_bookings": { + "href": "https://uk.bookingbug.com/api/v1/37901/members/900649/pre_paid_bookings{?include_invalid,event_id}", + "templated": true + }, + "questions": { + "href": "https://uk.bookingbug.com/api/v1/37901/client_details" + }, + "edit": { + "href": "https://uk.bookingbug.com/api/v1/admin/37901/client/900649/edit" + } + } +} From ae14d6f0bc6dff5aa51802bbe4bf911b28b622dd Mon Sep 17 00:00:00 2001 From: Macarescu Sebastian Date: Fri, 27 May 2016 11:51:26 +0300 Subject: [PATCH 11/22] Admin model: getters, unittesting, javadoc --- .../bookingbugAPI/models/Administrator.java | 126 +++++++++++++++--- src/test/bookingbugAPI/models/AdminTest.java | 48 +++++++ src/test/resources/json/admin.json | 28 ++++ 3 files changed, 185 insertions(+), 17 deletions(-) create mode 100644 src/test/bookingbugAPI/models/AdminTest.java create mode 100644 src/test/resources/json/admin.json diff --git a/src/main/bookingbugAPI/models/Administrator.java b/src/main/bookingbugAPI/models/Administrator.java index ad07a1c..9bb8875 100644 --- a/src/main/bookingbugAPI/models/Administrator.java +++ b/src/main/bookingbugAPI/models/Administrator.java @@ -11,37 +11,129 @@ public class Administrator extends BBRoot { - private Company company; - private BBRoot schema; - - public Administrator(HttpServiceResponse httpServiceResponse, String auth_token) { super(httpServiceResponse); this.auth_token = auth_token; } + public Administrator(HttpServiceResponse httpServiceResponse) { + super(httpServiceResponse); + } public Company getCompany() throws IOException { - if(company == null){ - String link = response.getRep().getLinkByRel("company").getHref(); - URL url = new URL(UriTemplate.fromTemplate(link).expand()); - company = new Company(HttpService.api_GET(url, auth_token), auth_token); - } - return company; + String link = response.getRep().getLinkByRel("company").getHref(); + URL url = new URL(UriTemplate.fromTemplate(link).expand()); + return new Company(HttpService.api_GET(url, auth_token), auth_token); } public BBRoot getEditSchema() throws IOException { - if(schema == null) { - String link = response.getRep().getLinkByRel("edit").getHref(); - URL url = new URL(UriTemplate.fromTemplate(link).expand()); - schema = new BBRoot(HttpService.api_GET(url, auth_token), auth_token); - } - return schema; + String link = response.getRep().getLinkByRel("edit").getHref(); + URL url = new URL(UriTemplate.fromTemplate(link).expand()); + return new BBRoot(HttpService.api_GET(url, auth_token), auth_token); } - public Login login(Map params) throws IOException { + public Login login(Map params) throws IOException { return auth(params, response.getRep().getLinkByRel("login")); } + + /** + * Returns the name of the admin. + * + * @return the name associated with the current Administrator object + */ + public String getName() { + return get("name"); + } + + /** + * Returns the email of the admin. + * + * @return the email associated with the current Administrator object + */ + public String getEmail() { + return get("email"); + } + + /** + * Returns the role of the admin. + * + * @return the associated with the current administrator object + */ + public String getRole() { + return get("role"); + } + + /** + * Returns the company id. + * + * @return the company id associated with the current administrator object + */ + public Integer getCompanyId() { + return getInteger("company_id", INTEGER_DEFAULT_VALUE); + } + + /** + * Returns the company name. + * + * @return the company name associated with the current administrator object + */ + public String getCompanyName() { + return get("company_name"); + } + + /** + * Returns the person id. + * + * @return the person id associated with the current administrator object + */ + public Integer getPersonId() { + return getInteger("person_id", INTEGER_DEFAULT_VALUE); + } + + /** + * Returns the edit link. + * + * @return the edit link associated with the current administrator object + */ + public String getEditLink() { + return getLink("edit"); + } + + /** + * Returns the company link. + * + * @return the company link associated with the current administrator object + */ + public String getCompanyLink() { + return getLink("company"); + } + + /** + * Returns the person link. + * + * @return the person link associated with the current administrator object + */ + public String getPersonLink() { + return getLink("person"); + } + + /** + * Returns the login link. + * + * @return the login link associated with the current administrator object + */ + public String getLoginLink() { + return getLink("login"); + } + + /** + * Returns the base_login. + * + * @return the base_login associated with the current administrator object + */ + public String getBaseLoginLink() { + return getLink("base_login"); + } } diff --git a/src/test/bookingbugAPI/models/AdminTest.java b/src/test/bookingbugAPI/models/AdminTest.java new file mode 100644 index 0000000..5a7918d --- /dev/null +++ b/src/test/bookingbugAPI/models/AdminTest.java @@ -0,0 +1,48 @@ +package bookingbugAPI.models; + +import helpers.HttpServiceResponse; +import helpers.Utils; +import org.json.simple.JSONObject; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.text.ParseException; + +import static org.junit.Assert.assertTrue; + + +public class AdminTest extends ModelTest{ + private JSONObject jsonObject; + + @Override + @Before + public void setUp() { + jsonObject = getJSON("json/admin.json"); + } + + @Override + @Test + public void modelInit() throws ParseException { + Administrator admin = new Administrator(new HttpServiceResponse(Utils.stringToContentRep(jsonObject.toString()))); + JSONObject jsonLinks = (JSONObject) jsonObject.get("_links"); + + assertTrue(admin.getName().equals(jsonObject.get("name"))); + assertTrue(admin.getEmail().equals(jsonObject.get("email"))); + assertTrue(admin.getRole().equals(jsonObject.get("role"))); + assertTrue(admin.getCompanyName().equals(jsonObject.get("company_name"))); + assertTrue(admin.getCompanyId().toString().equals(jsonObject.get("company_id").toString())); + assertTrue(admin.getPersonId().toString().equals(jsonObject.get("person_id").toString())); + assertTrue(admin.getEditLink().equals(((JSONObject) jsonLinks.get("edit")).get("href"))); + assertTrue(admin.getCompanyLink().equals(((JSONObject) jsonLinks.get("company")).get("href"))); + assertTrue(admin.getPersonLink().equals(((JSONObject) jsonLinks.get("person")).get("href"))); + assertTrue(admin.getLoginLink().equals(((JSONObject) jsonLinks.get("login")).get("href"))); + assertTrue(admin.getBaseLoginLink().equals(((JSONObject) jsonLinks.get("base_login")).get("href"))); + } + + @Override + @After + public void tearDown() { + jsonObject = null; + } +} diff --git a/src/test/resources/json/admin.json b/src/test/resources/json/admin.json new file mode 100644 index 0000000..05d0422 --- /dev/null +++ b/src/test/resources/json/admin.json @@ -0,0 +1,28 @@ +{ + "name": "Conor", + "email": "conor+user@bookingbug.com", + "role": "user", + "company_id": 37901, + "company_name": "Conor's Pet Store", + "person_id": 16246, + "_links": { + "self": { + "href": "https://uk.bookingbug.com/api/v1/admin/37901/administrators/25928" + }, + "edit": { + "href": "https://uk.bookingbug.com/api/v1/admin/37901/administrators/25928/edit" + }, + "company": { + "href": "https://uk.bookingbug.com/api/v1/admin/37901/company" + }, + "person": { + "href": "https://uk.bookingbug.com/api/v1/admin/37901/people/16246" + }, + "login": { + "href": "https://uk.bookingbug.com/api/v1/login/admin/37901" + }, + "base_login": { + "href": "https://uk.bookingbug.com/api/v1/login/admin" + } + } +} From 14c4eeb2bcf5ff09edf434dcadd208b942628248 Mon Sep 17 00:00:00 2001 From: Macarescu Sebastian Date: Fri, 27 May 2016 11:58:44 +0300 Subject: [PATCH 12/22] Question model: getters, unittesting, javadoc. Added test.db on gitignore --- .gitignore | 2 +- src/main/bookingbugAPI/models/Option.java | 42 ++++++ src/main/bookingbugAPI/models/Question.java | 128 +++++++++++++++++- .../bookingbugAPI/models/QuestionTest.java | 57 ++++++++ src/test/resources/json/question.json | 40 ++++++ 5 files changed, 263 insertions(+), 6 deletions(-) create mode 100644 src/main/bookingbugAPI/models/Option.java create mode 100644 src/test/bookingbugAPI/models/QuestionTest.java create mode 100644 src/test/resources/json/question.json diff --git a/.gitignore b/.gitignore index 2c1cc35..ba08868 100644 --- a/.gitignore +++ b/.gitignore @@ -13,5 +13,5 @@ dist /.project /RUNNING_PID /.settings - +test.db \ No newline at end of file diff --git a/src/main/bookingbugAPI/models/Option.java b/src/main/bookingbugAPI/models/Option.java new file mode 100644 index 0000000..db68ccd --- /dev/null +++ b/src/main/bookingbugAPI/models/Option.java @@ -0,0 +1,42 @@ +package bookingbugAPI.models; + + + +public class Option extends BBRoot{ + + /** + * Returns the option name. + * + * @return The option name associated with the current Option object. + */ + public String getName() { + return get("name"); + } + + /** + * Returns the price. + * + * @return The price associated with the current Option object. + */ + public Integer getPrice() { + return getInteger("price", INTEGER_DEFAULT_VALUE); + } + + /** + * Returns the is default attribute. + * + * @return The is default attribute associated with the current Option object. + */ + public Boolean getIs_default() { + return getBoolean("is_default", BOOLEAN_DEFAULT_VALUE); + } + + /** + * Returns the option id. + * + * @return The option id associated with the current Option object. + */ + public Integer getId() { + return getInteger("id", INTEGER_DEFAULT_VALUE); + } +} diff --git a/src/main/bookingbugAPI/models/Question.java b/src/main/bookingbugAPI/models/Question.java index b77de8b..a801e78 100644 --- a/src/main/bookingbugAPI/models/Question.java +++ b/src/main/bookingbugAPI/models/Question.java @@ -1,22 +1,140 @@ package bookingbugAPI.models; -import bookingbugAPI.models.BBRoot; +import com.fasterxml.jackson.annotation.JsonProperty; import helpers.HttpServiceResponse; +import java.util.List; +import java.util.Map; -public class Question extends BBRoot{ +public class Question extends BBRoot { - public Question(HttpServiceResponse httpServiceResponse){ + public Question(HttpServiceResponse httpServiceResponse) { super(httpServiceResponse); } - public Question(HttpServiceResponse httpServiceResponse, String auth_token){ + public Question(HttpServiceResponse httpServiceResponse, String auth_token) { super(httpServiceResponse, auth_token); } + public Question() { + } + + /** + * Returns the question's id. + * + * @return The id associated with the current Question object. + */ + public Integer getId() { + return getInteger("id", INTEGER_DEFAULT_VALUE); + } - public Question() {} + /** + * Returns the question's name. + * + * @return The name associated with the current Question object. + */ + public String getName() { + return get("name"); + } + /** + * Returns the question's required attribute. + * + * @return The required attribute associated with the current Question object. + */ + public Boolean getRequired() { + return getBoolean("required", BOOLEAN_DEFAULT_VALUE); + } + + /** + * Returns the question's important attribute. + * + * @return The important attribute associated with the current Question object. + */ + public Boolean getImportant() { + return getBoolean("important", BOOLEAN_DEFAULT_VALUE); + } + + /** + * Returns the question's admin only attribute. + * + * @return The admin only attribute associated with the current Question object. + */ + public Boolean getAdminOnly() { + return getBoolean("admin_only", BOOLEAN_DEFAULT_VALUE); + } + + /** + * Returns the question's apllies to attribute. + * + * @return The apllies to attribute associated with the current Question object. + */ + public Integer getAppliesTo() { + return getInteger("applies_to", INTEGER_DEFAULT_VALUE); + } + + /** + * Returns the question's ask member attribute. + * + * @return The ask member attribute associated with the current Question object. + */ + public Boolean getAskMember() { + return getBoolean("ask_member", BOOLEAN_DEFAULT_VALUE); + } + + /** + * Returns the question's detail type. + * + * @return The detail type associated with the current Question object. + */ + public String getDetailType() { + return get("detail_type"); + } + + /** + * Returns the question's option. + * + * @return The option associated with the current Question object. + */ + public List