Initial commit of java client example for maps booking api
diff --git a/BookingNotification.java b/BookingNotification.java new file mode 100644 index 0000000..3a4f523 --- /dev/null +++ b/BookingNotification.java
@@ -0,0 +1,128 @@ +/* + * Copyright 2018, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; +import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; +import com.google.api.client.http.HttpTransport; +import com.google.api.client.json.JsonFactory; +import com.google.api.client.json.jackson2.JacksonFactory; +import com.google.api.services.mapsbooking.v1alpha.GoogleMapsBookingAPI; +import com.google.api.services.mapsbooking.v1alpha.model.Booking; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Collections; + +/** + * Java client example using the Booking Notification API to notify Google of changes to an existing + * booking + */ +public class BookingNotification { + + private static final String MAPS_BOOKING_SCOPE = "https://www.googleapis.com/auth/mapsbooking"; + + private static HttpTransport httpTransport; + + private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance(); + + private static GoogleMapsBookingAPI googleMapsBookingAPI; + + // TODO(partner): step1. put your partner_id here + private static final String PARTNER_ID = "{your partner_id}"; + + public static void main(String[] args) { + try { + try { + // get Credential through your Service Account + // TODO(partner): step2. put the path&file of your private key (JSON format) that you + // obtained from your service account into 'FileInputStream' + GoogleCredential credential = + GoogleCredential.fromStream(new FileInputStream("src/your-private-key.json")) + .createScoped(Collections.singleton(MAPS_BOOKING_SCOPE)); + + // get the service object to make requests to the API service + httpTransport = GoogleNetHttpTransport.newTrustedTransport(); + + // TODO(partner): step3. put your application name into 'setApplicationName' + googleMapsBookingAPI = + new GoogleMapsBookingAPI.Builder(httpTransport, JSON_FACTORY, credential) + .setApplicationName("PartnerBookingNotificationExample") + .build(); + + // TODO(partner): step5. call the methods you implement below to make + // booking changes notificatons + updateBooking(); + } catch (IOException e) { + System.err.println(e.getMessage()); + } + } catch (Throwable t) { + t.printStackTrace(); + } + System.exit(1); + } + + // TODO(partner): step4. implement this method with your data to make the updateBooking call + public static void updateBooking() throws IOException { + // example -> cancel a booking: + Booking updatedBooking = new Booking() + .setName("partners/" + PARTNER_ID + "/bookings/" + "{your booking id}") + .setMerchantId("{your merchant Id}") + .setServiceId("{your service Id}") + .setStatus("CANCELED") + .setStartTime("2018-01-02T10:00:00Z") + .setDuration("3600s") + .setClientInformation(...); + + Booking testUpdatedBooking = updateBooking(updatedBooking, "status"); + + System.out.println("updated booking:"); + System.out.println(testUpdatedBooking); + } + + /** + * Updates an existing Booking. + * + * @param content The booking object contains the updated booking content. @Param updateMask The + * specific fields to update for the booking. + * @return the updated instance of Booking. + */ + private static Booking updateBooking(Booking content, String updateMask) throws IOException { + + String name = content.getName(); + + return googleMapsBookingAPI + .notification() + .partners() + .bookings() + .patch(name, content) + .setUpdateMask(updateMask) + .execute(); + } +}
diff --git a/InventoryUpdate.java b/InventoryUpdate.java new file mode 100644 index 0000000..42bd954 --- /dev/null +++ b/InventoryUpdate.java
@@ -0,0 +1,479 @@ +/* + * Copyright 2018, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; +import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; +import com.google.api.client.http.HttpTransport; +import com.google.api.client.json.JsonFactory; +import com.google.api.client.json.jackson2.JacksonFactory; +import com.google.api.services.mapsbooking.v1alpha.GoogleMapsBookingAPI; +import com.google.api.services.mapsbooking.v1alpha.model.BatchReplaceServiceAvailabilityRequest; +import com.google.api.services.mapsbooking.v1alpha.model.BatchReplaceServiceAvailabilityResponse; +import com.google.api.services.mapsbooking.v1alpha.model.Empty; +import com.google.api.services.mapsbooking.v1alpha.model.ExtendedServiceAvailability; +import com.google.api.services.mapsbooking.v1alpha.model.Merchant; +import com.google.api.services.mapsbooking.v1alpha.model.ReplaceServiceAvailabilityRequest; +import com.google.api.services.mapsbooking.v1alpha.model.Service; +import com.google.api.services.mapsbooking.v1alpha.model.ServiceAvailability; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +/** + * Java client example using the Inventory Update API to provide real-time updates for invenotry + * changes + */ +public class InventoryUpdate { + + private static final String MAPS_BOOKING_SCOPE = "https://www.googleapis.com/auth/mapsbooking"; + + private static HttpTransport httpTransport; + + private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance(); + + private static GoogleMapsBookingAPI googleMapsBookingAPI; + + // TODO(partner): step1. put your partner_id here + private static final String PARTNER_ID = "{your partner_id}"; + + public static void main(String[] args) { + try { + try { + // get Credential via your Service Account + + // TODO(partner): step2. put the path&file of your private key (JSON format) that you + // obtained from your service account into 'FileInputStream' + GoogleCredential credential = + GoogleCredential.fromStream(new FileInputStream("src/your-private-key.json")) + .createScoped(Collections.singleton(MAPS_BOOKING_SCOPE)); + + // get the service object to make requests to the API service + httpTransport = GoogleNetHttpTransport.newTrustedTransport(); + + // TODO(partner): step3. put your application name into 'setApplicationName' + googleMapsBookingAPI = + new GoogleMapsBookingAPI.Builder(httpTransport, JSON_FACTORY, credential) + .setApplicationName("PartnerInventoryUpdateExample") + .build(); + + // TODO(partner): step12. call the methods you implement below to make inventory updates + + createMerchant(); + createService(); + + updateMerchant(); + updateService(); + + updateAvailability(); + batchUpdateAvailability(); + + deleteService(); + deleteMerchant(); + + } catch (IOException e) { + System.err.println(e.getMessage()); + } + } catch (Throwable t) { + t.printStackTrace(); + } + System.exit(1); + } + + // TODO(partner): step4. implement this method with your data to make the createMerchant call + public static void createMerchant() throws IOException { + // for example + PostalAddress postalAddress = new PostalAddress() + .setAddressCountry("US") + .setAddressLocality("WA") + .setAddressRegion("Kirkland") + .setPostalCode("98XXX") + .setStreetAddress("1111 11th Ave NE"); + + GeoCoordinates geo = new GeoCoordinates() + .setLatitude(47.67) + .setLongitude(-122.21) + .setAddress(postalAddress); + + TaxRate taxRate = new TaxRate().setMicroPercent(0); + + String merchantId = "sampleMerchant1"; + + Merchant merchant = new Merchant() + .setName("partners/" + PARTNER_ID + "/merchants/" + merchantId) + .setMerchantName("Test Create Merchant") + .setTelephone("206-888-8888") + .setUrl("www.****.com") + .setGeo(geo) + .setCategory("Fitness") + .setNumBookings30d((long)1000.00) + .setTaxRate(taxRate); + + Merchant CreatedMerchant = createMerchant(merchant); + + System.out.println("created merchant:"); + System.out.println(CreatedMerchant); + } + + // TODO(partner): step5. implement this method with your data to make the updateMerchant call + public static void updateMerchant() throws IOException { + // for example + PostalAddress postalAddress = new PostalAddress() + .setAddressCountry("US") + .setAddressLocality("WA") + .setAddressRegion("Kirkland") + .setPostalCode("98XXX") + .setStreetAddress("1111 11th Ave NE"); + + GeoCoordinates geo = new GeoCoordinates() + .setLatitude(47.67) + .setLongitude(-122.21) + .setAddress(postalAddress); + + TaxRate taxRate = new TaxRate().setMicroPercent(0); + + String merchantId = "sampleMerchant1"; + + Merchant merchantUpdate = new Merchant() + .setName("partners/" + PARTNER_ID + "/merchants/" + merchantId) + .setMerchantName("Test Update Merchant") + .setTelephone("206-666-6666") + .setUrl("www.****.com") + .setGeo(geo) + .setCategory("Fitness") + .setNumBookings30d((long)1000.00) + .setTaxRate(taxRate); + + Merchant updatedMerchant = + updateMerchant(merchantUpdate, "merchantName,telephone"); + + System.out.println("updated merchant:"); + System.out.println(updatedMerchant); + } + + // TODO(partner): step6. implement this method with your data to make the deleteMerchant call + public static void deleteMerchant() throws IOException { + // for example + String merchantId = "sampleMerchant1"; + + Empty deletedMerchant = deleteMerchant(merchantId); + + System.out.println("deleted merchant:"); + System.out.println(deletedMerchant); + } + + // TODO(partner): step7. implement this method with your data to make the createService call + public static void createService() throws IOException { + //for example + String merchantId = "sampleMerchant1"; + String serviceId = "sampleService1"; + Service service = new Service() + .setName("partners/" + PARTNER_ID + "/merchants/" + merchantId + "/services/" + serviceId) + .setServiceName("Yoga 101") + .setDescription("The entry-level Yoga course"); + + Service CreatedService = createService(service); + + System.out.println("created service:"); + System.out.println(CreatedService); + } + + // TODO(partner): step8. implement this method with your data to make the updateService call + public static void updateService() throws IOException { + //for example + String merchantId = "sampleMerchant1"; + String serviceId = "sampleService1"; + Service service = new Service() + .setName("partners/" + PARTNER_ID + "/merchants/" + merchantId + "/services/" + serviceId) + .setServiceName("Yoga 201") + .setDescription("The mid-level Yoga course"); + + Service updatedService = updateService(service, ""); + + System.out.println("updated service:"); + System.out.println(updatedService); + } + + // TODO(partner): step9. implement this method with your data to make the deleteService call + public static void deleteService() throws IOException { + // for example + String merchantId = "sampleMerchant1"; + String serviceId = "sampleService1"; + + Empty deletedService = deleteService(merchantId, serviceId); + + System.out.println("deleted service:"); + System.out.println(deletedService); + } + + // TODO(partner): step10. implement this method with your data to make the + // replaceServiceAvailability call + public static void updateAvailability() throws IOException { + // for example + String merchantId = "sampleMerchant1"; + String serviceId = "sampleService1"; + + Availability availability1 = new Availability() + .setStartTime("2018-01-02T09:00:00Z") + .setDuration("3600s") + .setSpotsTotal((long) 30) + .setSpotsOpen((long) 20); + + Availability availability2 = new Availability() + .setStartTime("2018-01-02T13:00:00Z") + .setDuration("3600s") + .setSpotsTotal((long) 30) + .setSpotsOpen((long) 25); + + List<Availability> availabilities1 = new ArrayList<Availability>(); + + availabilities1.add(availability1); + availabilities1.add(availability2); + + ServiceAvailability serviceAvailability = new ServiceAvailability() + .setName("partners/" + PARTNER_ID + "/merchants/" + merchantId + "/services/" + serviceId) + .setAvailability(availabilities1) + .setStartTimeRestrict("2018-01-02T00:00:00Z") + .setEndTimeRestrict("2018-01-02T23:30:00Z"); + + ServiceAvailability updatedAvailability = replaceServiceAvailability(serviceAvailability); + + System.out.println("updated availability:"); + System.out.println(updatedAvailability); + } + + // TODO(partner): step11. implement this method with your data to make the + // batchReplaceServiceAvailability call + public static void batchUpdateAvailability() throws IOException { + // for example + String merchantId1 = "sampleMerchant1"; + String merchantId2 = "sampleMerchant2"; + String serviceId1 = "sampleService1"; + String serviceId2 = "sampleService2"; + + List<Availability> availabilities1 = // {your first batch of availabilities}; + List<Availability> availabilities2 = // {your second batch of availabilities}; + + ExtendedServiceAvailability extendedServiceAvailability1 = new ExtendedServiceAvailability() + .setMerchantId(merchantId1) + .setServiceId(serviceId1) + .setAvailability(availabilities1) + .setStartTimeRestrict("2018-01-02T00:00:00Z") + .setEndTimeRestrict("2018-01-03T23:30:00Z"); + + ExtendedServiceAvailability extendedServiceAvailability2 = new ExtendedServiceAvailability() + .setMerchantId(merchantId2) + .setServiceId(serviceId2) + .setAvailability(availabilities2) + .setStartTimeRestrict("2018-01-02T00:00:00Z"); + + List<ExtendedServiceAvailability> extendedServiceAvailabilities = + new ArrayList<ExtendedServiceAvailability>(); + extendedServiceAvailabilities.add(extendedServiceAvailability1); + extendedServiceAvailabilities.add(extendedServiceAvailability2); + + BatchReplaceServiceAvailabilityResponse batchUpdatedAvailability = + batchReplaceServiceAvailability(extendedServiceAvailabilities); + + System.out.println("batch updated availabilities:"); + System.out.println(batchUpdatedAvailability); + } + + /** + * Creates a new Merchant managed by the specified partner, and returns it. + * + * @param content The merchant object to create. + * @return the newly created instance of Merchant. + */ + private static Merchant createMerchant(Merchant content) throws IOException { + + String merchantId = content.getName().split("/")[3]; + + String parent = "partners/" + PARTNER_ID; + + return googleMapsBookingAPI + .inventory() + .partners() + .merchants() + .create(parent, content) + .setMerchantId(merchantId) + .execute(); + } + + /** + * Deletes an existing Merchant managed by the specified partner. All the merchant's services and + * availability will be disabled. + * + * @param merchantId The merchant_id of the merchant to delete. + * @return the empty object. + */ + private static Empty deleteMerchant(String merchantId) throws IOException { + + String name = "partners/" + PARTNER_ID + "/merchants/" + merchantId; + + return googleMapsBookingAPI.inventory().partners().merchants().delete(name).execute(); + } + + /** + * Updates an existing Merchant managed by the specified partner, and returns it. + * + * @param content The merchant object contains the updated merchant content. @Param updateMask The + * specific fields to update for the merchant. + * @return the updated instance of Merchant. + */ + private static Merchant updateMerchant(Merchant content, String updateMask) throws IOException { + + String name = content.getName(); + + return googleMapsBookingAPI + .inventory() + .partners() + .merchants() + .patch(name, content) + .setUpdateMask(updateMask) + .execute(); + } + + /** + * Creates a new Service of a merchant managed by the specified partner, and returns it. + * + * @param content The service object to create. + * @return the newly created instance of Service. + */ + private static Service createService(Service content) throws IOException { + + String[] name = content.getName().split("/"); + String merchantId = name[3]; + String serviceId = name[5]; + String parent = "partners/" + PARTNER_ID + "/merchants/" + merchantId; + + return googleMapsBookingAPI + .inventory() + .partners() + .merchants() + .services() + .create(parent, content) + .setServiceId(serviceId) + .execute(); + } + + /** + * Deletes an existing Service of a merchant managed by the specified partner. All the service's + * availablity will be disabled. + * + * @param merchantId The merchant_id of the merchant who provides the to be deleted service. + * @param serviceId The service_id of the service to delete. + * @return the empty object. + */ + private static Empty deleteService(String merchantId, String serviceId) throws IOException { + + String name = "partners/" + PARTNER_ID + "/merchants/" + merchantId + "/services/" + serviceId; + + return googleMapsBookingAPI + .inventory() + .partners() + .merchants() + .services() + .delete(name) + .execute(); + } + + /** + * Updates an existing Service of a merchant managed by the specified partner, and returns it. + * + * @param content The service object contains the updated service content. @Param updateMask The + * specific fields to update for the service. + * @return the updated instance of Service. + */ + private static Service updateService(Service content, String updateMask) throws IOException { + + String name = content.getName(); + + return googleMapsBookingAPI + .inventory() + .partners() + .merchants() + .services() + .patch(name, content) + .setUpdateMask(updateMask) + .execute(); + } + + /** + * Replaces the Availability of an existing Service of a merchant managed by the specified + * partner, and returns it. + * + * @param serviceAvailability The service availability that is used to replace the existing ones. + * @return the successfully updated ServiceAvailability. + */ + private static ServiceAvailability replaceServiceAvailability( + ServiceAvailability serviceAvailability) throws IOException { + + String name = serviceAvailability.getName(); + + ReplaceServiceAvailabilityRequest replaceServiceAvailabilityRequest = + new ReplaceServiceAvailabilityRequest().setServiceAvailability(serviceAvailability); + + return googleMapsBookingAPI + .inventory() + .partners() + .merchants() + .services() + .availability() + .replace(name, replaceServiceAvailabilityRequest) + .execute(); + } + + /** + * Replaces the Availability of existing Services. This batch call does not guarantee atomicity. + * Only successfully updated availability slots will be returned. + * + * @param extendedServiceAvailabilities The list of extended service availability that is used to + * replace the existing availability slots. + * @return response containing successfully updated availability slots. + */ + private static BatchReplaceServiceAvailabilityResponse batchReplaceServiceAvailability( + List<ExtendedServiceAvailability> extendedServiceAvailabilities) throws IOException { + + String parent = "partners/" + PARTNER_ID; + + BatchReplaceServiceAvailabilityRequest batchReplaceServiceAvailabilityRequest = + new BatchReplaceServiceAvailabilityRequest() + .setExtendedServiceAvailability(extendedServiceAvailabilities); + + return googleMapsBookingAPI + .inventory() + .partners() + .availability() + .replace(parent, batchReplaceServiceAvailabilityRequest) + .execute(); + } +}
diff --git a/README.md b/README.md new file mode 100644 index 0000000..904003c --- /dev/null +++ b/README.md
@@ -0,0 +1,57 @@ +# Java client example for real-time updates using RESTful calls + +### Prerequisite: + +Have your service account created, download your private key. + +### Get started: + +1. Download the [Java client + library](https://dl.google.com/mapsbooking/apiclients/v1alpha/mapsbooking_java_public.zip) + , unzip the file to get the 'mapsbooking' package. + +2. Create a java project in your IDE, download the sample codes + (InventoryUpdate.java & BookingNotification.java), import them into your + java project under src directory. + +3. Make a copy of your private key (JSON file) to the src directory. + +4. Add the Java Client Library to the dependencies of your project + +5. In both java files, follow the TODOs to complete your implementations + +More detail about the REST API can be found +[here.](https://developers.google.com/maps-booking/reference/maps-booking-api/rest/) + +### Troubleshooting: + +1. Create a merchant/service with existing merchantId/serviceId, your will get + following error message: 409 Conflict { "code" : 409, "errors" : \[ { + "domain" : "global", "message" : "Requested entity already exists", + "reason" : "alreadyExists", "debugInfo" : "detail: \"\[ORIGINAL ERROR\] + generic::already_exists: ..."\n" } \], "message" : "Requested entity already + exists", "status" : "ALREADY_EXISTS" } + +2. Update/Delete with wrong merchantId/serviceId (update with wrong bookingId), + your will get following error message: 404 Not Found { "code" : 404, + "errors" : \[ { "domain" : "global", "message" : "Requested entity was not + found.", "reason" : "notFound", "debugInfo" : "detail: \"\[ORIGINAL ERROR\] + spanner::Row not found:...\"\n" } \], "message" : "Requested entity was not + found.", "status" : "NOT_FOUND" } + +3. In all update functions, the parameter 'updateMask' must be in + [FieldMask](https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#fieldmask) + format to specify the fields to update. The API is required to only change + the values of the fields as specified in the mask and leave the others + untouched. If you pass the wrong updateMask string, the update will not take + effect. If a field mask is not present on update, the operation applies to + all fields (as if a field mask of all fields has been specified). So if you + want to update all fields, just set the updateMask empty. + +4. Since an Availability Slot is not associated with a merchant_id/service_id, + if you make the replace availability calls with invalid + merchant_id/service_id, you will be able to make the REST call without any + issue, but your request will not be served in the production due to the + invalid merchant_id/service_id. + +5. Any field that has a zero value is not shown in the response.