Initial commit of sample java rest server
diff --git a/README.md b/README.md new file mode 100644 index 0000000..6f3d5f2 --- /dev/null +++ b/README.md
@@ -0,0 +1,125 @@ +# Booking Server (REST) Skeleton for Java + +This ia a reference implementation for API v3 Booking server based on: + +* [google-protobuf](https://developers.google.com/protocol-buffers/docs/overview) +* [Jersey RESTful Web Services](https://jersey.github.io/) + +### Prerequisites + +Require installations of + +* [Apache Maven](https://maven.apache.org/) +* [Protocol compiler for java](https://github.com/google/protobuf) +* [Apache Tomcat](http://tomcat.apache.org/) + +### Get Started + +1. Copy the [Proto + Interface](https://developers.google.com/maps-booking/reference/rest-api-v3/proto-bundle) + into a proto file (api_v3.proto). Modify the package to match your project + (com.partner.mapsbooking.v3.model). + +2. Create a web application project in your IDE named booking_server_v3, add + Maven support to this project. + +3. Place your proto file under the **src/main/resources,** add dependencies for + Jersey and protocol buffers runtime to the Maven **pom.xml** file: + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.glassfish.jersey</groupId> + <artifactId>jersey-bom</artifactId> + <version>${jersey.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>org.glassfish.jersey.containers</groupId> + <artifactId>jersey-container-servlet-core</artifactId> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.media</groupId> + <artifactId>jersey-media-json-jackson</artifactId> + <version>2.27</version> + </dependency> + <dependency> + <groupId>com.google.protobuf</groupId> + <artifactId>protobuf-java</artifactId> + <version>3.5.1</version> + </dependency> + <dependency> + <groupId>io.grpc</groupId> + <artifactId>grpc-protobuf</artifactId> + <version>1.11.0</version> + </dependency> + </dependencies> + + <properties> + <java.version>1.8</java.version> + <jersey.version>2.23.2</jersey.version> + </properties> + +4. Execute the following command under **src/main** to auto-generate a source + file for the classes defined in the proto file: + + protoc --java_out=java resources/api_v3.proto + +5. Inside of the **src/main/java,** create a new package matching your groupId + (com.partner.mapsbooking). Retrieve the sample code from the repo, place the + files under your package, follow the **TODOs** to complete your + implementation. + +6. Configure your servlet by modifying the **web.xml** file: + + <?xml version="1.0" encoding="UTF-8"?> + <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" + version="4.0"> + + <servlet> + <servlet-name>Booking Rest Server</servlet-name> + <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> + <init-param> + <param-name>jersey.config.server.provider.packages</param-name> + <param-value>com.partner.mapsbooking</param-value> + </init-param> + <load-on-startup>1</load-on-startup> + </servlet> + + <servlet-mapping> + <servlet-name>Booking Rest Server</servlet-name> + <url-pattern>/mapsbooking/*</url-pattern> + </servlet-mapping> + </web-app> + +7. In the Run Configurations, set up a Tomcat server configuration. Add all the + jars to the /WEB_INF/lib directory (project structure -> artifacts -> After + selecting all jars right click and choose "Put into /WEB-INF/lib"). + +8. Run Tomcat to start your server. + +### Final Directory Structure + + src + |---main + |---java + |---com.partner.mapsbooking + |---rest + |---BookingService.java + |---BookingExceptionMapper.java + |---Error.java + |---authentication + |---AuthenticationService.java + |---RestAuthenticationFilter.java + |---v3.model + |---ApiV3.java + |---resources + |---api_v3.proto + |---test
diff --git a/authentication/AuthenticationService.java b/authentication/AuthenticationService.java new file mode 100644 index 0000000..745a882 --- /dev/null +++ b/authentication/AuthenticationService.java
@@ -0,0 +1,65 @@ +/* + * 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. + */ + +package com.partner.mapsbooking.authentication; + +import java.io.IOException; +import java.util.StringTokenizer; +import sun.misc.BASE64Decoder; + +/** Check the credentials by validates the data included in authorization headers. */ +public class AuthenticationService { + // TODO(partner): set your user name and password + private static String USERNAME = "admin"; + private static String PASSWORD = "password"; + + public boolean authenticate(String credential) { + if (null == credential) { + return false; + } + // header value format will be "Basic encoded string" for Basic + // authentication. Example "Basic YWRtaW46YWRtaW4=" + final String encodedUserPassword = credential.replaceFirst("Basic" + " ", ""); + String usernameAndPassword = null; + try { + byte[] decodedBytes = new BASE64Decoder().decodeBuffer(encodedUserPassword); + usernameAndPassword = new String(decodedBytes, "UTF-8"); + } catch (IOException e) { + e.printStackTrace(); + } + final StringTokenizer tokenizer = new StringTokenizer(usernameAndPassword, ":"); + final String username = tokenizer.nextToken(); + final String password = tokenizer.nextToken(); + + boolean authenticationStatus = USERNAME.equals(username) && PASSWORD.equals(password); + return authenticationStatus; + } +}
diff --git a/authentication/RestAuthenticationFilter.java b/authentication/RestAuthenticationFilter.java new file mode 100644 index 0000000..0ecfc20 --- /dev/null +++ b/authentication/RestAuthenticationFilter.java
@@ -0,0 +1,57 @@ +/* + * 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. + */ + +package com.partner.mapsbooking.authentication; + +import javax.ws.rs.NotAuthorizedException; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.ext.Provider; + +/** Do the authentication by inspecting the authorization headers. */ +@Provider +public class RestAuthenticationFilter implements ContainerRequestFilter { + + public void filter(ContainerRequestContext containerRequest) throws WebApplicationException { + + String authCredentials = containerRequest.getHeaderString(HttpHeaders.AUTHORIZATION); + + AuthenticationService authenticationService = new AuthenticationService(); + + boolean authStatus = authenticationService.authenticate(authCredentials); + + if (!authStatus) { + throw new NotAuthorizedException("Wrong username/password!"); + } + } +}
diff --git a/rest/BookingExceptionMapper.java b/rest/BookingExceptionMapper.java new file mode 100644 index 0000000..be6e361 --- /dev/null +++ b/rest/BookingExceptionMapper.java
@@ -0,0 +1,71 @@ +/* + * 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. + */ + +package com.partner.mapsbooking.rest; + +import com.google.protobuf.InvalidProtocolBufferException; +import javax.ws.rs.NotAuthorizedException; +import javax.ws.rs.NotFoundException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +/** Map exceptions to responses by implementing the ExceptionMapper interface, + * which handles unexpected errors. + */ +@Provider +public class BookingExceptionMapper implements ExceptionMapper<Throwable> { + + public Response toResponse(Throwable ex) { + javax.ws.rs.core.Response.StatusType type = getStatusType(ex); + Error error = new Error(type.getStatusCode(), type.getReasonPhrase(), ex.getMessage()); + + return javax.ws.rs.core.Response.status(type.getStatusCode()) + .entity(error) + .type(MediaType.APPLICATION_JSON) + .build(); + } + + private javax.ws.rs.core.Response.StatusType getStatusType(Throwable ex) { + if (ex instanceof InvalidProtocolBufferException) { + return javax.ws.rs.core.Response.Status.BAD_REQUEST; + } else if (ex instanceof NotAuthorizedException) { + return javax.ws.rs.core.Response.Status.UNAUTHORIZED; + } else if (ex instanceof NotFoundException) { + return javax.ws.rs.core.Response.Status.NOT_FOUND; + } else if (ex instanceof UnsupportedOperationException) { + return javax.ws.rs.core.Response.Status.NOT_IMPLEMENTED; + } + // TODO(partner): implement handlers for other exception you throw + return javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; + } +}
diff --git a/rest/BookingService.java b/rest/BookingService.java new file mode 100644 index 0000000..9c46024 --- /dev/null +++ b/rest/BookingService.java
@@ -0,0 +1,449 @@ +/* + * 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. + */ + +package com.partner.mapsbooking.rest; + +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.util.JsonFormat; +import com.partner.mapsbooking.v3.model.ApiV3; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +/** Booking REST Server for API v3 with authentication. */ +@Path("/v3") +public class BookingService { + + private JsonFormat.Printer jsonPrinter() { + return JsonFormat.printer().preservingProtoFieldNames(); + } + + @GET + @Produces(MediaType.TEXT_PLAIN) + public String checkServer() { + // method for testing + return "Got it!"; + } + + @Path("/CheckAvailability") + @POST + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + public String checkAvailability(String request) throws InvalidProtocolBufferException { + + // use JsonFormat.Parser to convert Json String to protocol buffer + ApiV3.CheckAvailabilityRequest.Builder requestBuilder = + ApiV3.CheckAvailabilityRequest.newBuilder(); + JsonFormat.Parser jsonParser = JsonFormat.parser(); + jsonParser.merge(request, requestBuilder); + ApiV3.CheckAvailabilityRequest checkAvailabilityRequest = requestBuilder.build(); + + // Unexpected error: throw exception and handle it in BookingExceptionMapper class, + // return corresponding response and HTTP code + // + // Normal path: get response object from the helper function + ApiV3.CheckAvailabilityResponse response = performCheckAvailability(checkAvailabilityRequest); + + // use JsonFormat to convert protocol buffer to Json + String jsonResponse = jsonPrinter().print(response); + return jsonResponse; + } + + // TODO(partner): Implement this method to perform availability check + private ApiV3.CheckAvailabilityResponse performCheckAvailability( + ApiV3.CheckAvailabilityRequest request) { + + // Check availability business logic: + // e.g. + // ApiV3.Slot requestedSlot = request.getSlot(); + // int available_spots = ...; + // ApiV3.CheckAvailabilityResponse response = + // ApiV3.CheckAvailabilityResponse.newBuilder() + // .setSlot(requestedSlot) + // .setCountAvailable(available_spots) + // .build(); + // return response; + + throw new UnsupportedOperationException("Not implemented yet"); + } + + @Path("/CreateBooking") + @POST + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + public String createBooking(String request) throws InvalidProtocolBufferException { + + // use JsonFormat.Parser to convert Json String into protocol buffer + ApiV3.CreateBookingRequest.Builder requestBuilder = ApiV3.CreateBookingRequest.newBuilder(); + JsonFormat.Parser jsonParser = JsonFormat.parser(); + jsonParser.merge(request, requestBuilder); + ApiV3.CreateBookingRequest createBookingRequest = requestBuilder.build(); + + // Unexpected error: throw exception and handle it in BookingExceptionMapper class, + // return corresponding response and HTTP code + // + // Normal path: get response object from the helper function + ApiV3.CreateBookingResponse response = performCreateBooking(createBookingRequest); + + // use JsonFormat to convert protocol buffer to Json + String jsonResponse = jsonPrinter().print(response); + return jsonResponse; + } + + // TODO(partner): Implement this method to create a booking based on the request + private ApiV3.CreateBookingResponse performCreateBooking(ApiV3.CreateBookingRequest request) { + + // Create booking business logic: + // e.g. + // ApiV3.Booking createdBooking = ApiV3.Booking.newBuilder() + // .setBookingId("sampleBooking1") + // .setSlot(request.getSlot()) + // .setUserInformation(request.getUserInformation()) + // .setStatus(ApiV3.BookingStatus.CONFIRMED) + // .build(); + // + // ApiV3.CreateBookingResponse response = ApiV3.CreateBookingResponse.newBuilder() + // .setBooking(createdBooking) + // .build(); + // + // Business logic error -> set the BookingFailure in the response + // e.g. + // BookingServerModel.BookingFailure bookingFailure = + // BookingServerModel.BookingFailure.newBuilder() + // .setCause(BookingServerModel.BookingFailure.Cause.SLOT_UNAVAILABLE) + // .setDescription("slot is not available now") + // .build(); + // BookingServerModel.CreateBookingResponse response = + // BookingServerModel.CreateBookingResponse.newBuilder() + // .setBookingFailure(bookingFailure).build(); + // + // return response; + + throw new UnsupportedOperationException("Not implemented yet"); + } + + @Path("/UpdateBooking") + @POST + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + public String updateBooking(String request) throws InvalidProtocolBufferException { + + // use JsonFormat.Parser to convert Json String into protocol buffer + ApiV3.UpdateBookingRequest.Builder requestBuilder = ApiV3.UpdateBookingRequest.newBuilder(); + JsonFormat.Parser jsonParser = JsonFormat.parser(); + jsonParser.merge(request, requestBuilder); + ApiV3.UpdateBookingRequest updateBookingRequest = requestBuilder.build(); + + // Unexpected error: throw exception and handle it in BookingExceptionMapper class, + // return corresponding response and HTTP code + // + // Normal path: get response object from the helper function + ApiV3.UpdateBookingResponse response = performUpdateBooking(updateBookingRequest); + + // use JsonFormat to convert protocol buffer to Json + String jsonResponse = jsonPrinter().print(response); + return jsonResponse; + } + + // TODO(partner): Implement this method to update the booking based on the request + private ApiV3.UpdateBookingResponse performUpdateBooking(ApiV3.UpdateBookingRequest request) { + + // Update booking business logic: + // e.g. + // ApiV3.Booking booking = request.getBooking(); + // ApiV3.Booking updatedBooking = ... + // ApiV3.UpdateBookingResponse response = ApiV3.UpdateBookingResponse.newBuilder() + // .setBooking(updatedBooking) + // .build(); + // + // Business logic error -> set the BookingFailure in the response + // e.g. + // BookingServerModel.BookingFailure bookingFailure = + // BookingServerModel.BookingFailure.newBuilder() + // .setCause(BookingServerModel.BookingFailure.Cause.BOOKING_NOT_CANCELLABLE) + // .setDescription("this booking is not cancellable") + // .build(); + // BookingServerModel.CreateBookingResponse response = + // BookingServerModel.CreateBookingResponse.newBuilder() + // .setBookingFailure(bookingFailure).build(); + // + // return response; + + throw new UnsupportedOperationException("Not implemented yet"); + } + + @Path("/GetBookingStatus") + @POST + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + public String getBookingStatus(String request) throws InvalidProtocolBufferException { + + // use JsonFormat.Parser to convert Json String into protocol buffer + ApiV3.GetBookingStatusRequest.Builder requestBuilder = + ApiV3.GetBookingStatusRequest.newBuilder(); + JsonFormat.Parser jsonParser = JsonFormat.parser(); + jsonParser.merge(request, requestBuilder); + ApiV3.GetBookingStatusRequest getBookingStatusRequest = requestBuilder.build(); + + // Unexpected error: throw exception and handle it in BookingExceptionMapper class, + // return corresponding response and HTTP code + // + // Normal path: get response object from the helper function + ApiV3.GetBookingStatusResponse response = performGetBookingStatus(getBookingStatusRequest); + + // use JsonFormat to convert protocol buffer to Json + String jsonResponse = jsonPrinter().print(response); + return jsonResponse; + } + + // TODO(partner): Implement this method to get the booking status and prepayment status based on + // the request + private ApiV3.GetBookingStatusResponse performGetBookingStatus( + ApiV3.GetBookingStatusRequest request) { + + // Get booking status business logic: + // e.g. + // String bookingId = request.getBookingId(); + // ... + // ApiV3.GetBookingStatusResponse response = ApiV3.GetBookingStatusResponse.newBuilder() + // .setBookingId(bookingId) + // .setBookingStatus(ApiV3.BookingStatus.CONFIRMED) + // .setPrepaymentStatus(ApiV3.PrepaymentStatus.PREPAYMENT_NOT_PROVIDED) + // .build(); + // + // If booking id is not found -> throw new NotFoundException("Booking id not found"); + // + // return response; + + throw new UnsupportedOperationException("Not implemented yet"); + } + + @Path("/ListBookings") + @POST + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + public String getListBooking(String request) throws InvalidProtocolBufferException { + + // use JsonFormat.Parser to convert Json String into protocol buffer + ApiV3.ListBookingsRequest.Builder requestBuilder = ApiV3.ListBookingsRequest.newBuilder(); + JsonFormat.Parser jsonParser = JsonFormat.parser(); + jsonParser.merge(request, requestBuilder); + ApiV3.ListBookingsRequest listBookingsRequest = requestBuilder.build(); + + // Unexpected error: throw exception and handle it in BookingExceptionMapper class, + // return corresponding response and HTTP code + // + // Normal path: get response object from the helper function + ApiV3.ListBookingsResponse response = performGetListBooking(listBookingsRequest); + + // use JsonFormat to convert protocol buffer to Json + String jsonResponse = jsonPrinter().print(response); + return jsonResponse; + } + + // TODO(partner): Implement this method to look up all bookings with the given userId + private ApiV3.ListBookingsResponse performGetListBooking(ApiV3.ListBookingsRequest request) { + + // List bookings business logic: + // e.g. + // String userId = request.getUserId(); + // List<ApiV3.Booking> bookings = ... + // + // ApiV3.ListBookingsResponse response = ApiV3.ListBookingsResponse.newBuilder() + // .addAllBookings(bookings) + // .build(); + // + // If user id not found -> throw new NotFoundException("User id not found"); + // + // return response; + + throw new UnsupportedOperationException("Not implemented yet"); + } + + @Path("/CheckOrderFulfillability") + @POST + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + public String checkOrderFulfillability(String request) throws InvalidProtocolBufferException { + + // use JsonFormat.Parser to convert Json String into protocol buffer + ApiV3.CheckOrderFulfillabilityRequest.Builder requestBuilder = + ApiV3.CheckOrderFulfillabilityRequest.newBuilder(); + JsonFormat.Parser jsonParser = JsonFormat.parser(); + jsonParser.merge(request, requestBuilder); + ApiV3.CheckOrderFulfillabilityRequest checkOrderFulfillabilityRequest = requestBuilder.build(); + + // For unexpected error: throw exception and handle it in BookingExceptionMapper class, + // return corresponding response and HTTP code + // + // Normal path: get response object from the helper function + ApiV3.CheckOrderFulfillabilityResponse response = + performCheckOrderFulfillability(checkOrderFulfillabilityRequest); + + // use JsonFormat to convert protocol buffer to Json + String jsonResponse = jsonPrinter().print(response); + return jsonResponse; + } + + // TODO(partner): Implement this method to perform order fulfillability check + private ApiV3.CheckOrderFulfillabilityResponse performCheckOrderFulfillability( + ApiV3.CheckOrderFulfillabilityRequest request) { + + // Check order fulfillability business logic: + // e.g. + // String merchantId = request.getMerchantId(); + // List<ApiV3.LineItem> lineItems = request.getItemList(); + // + // List<ApiV3.LineItemFulfillability> itemFulfillabilities = + // getLineItemFulfillability(merchantId,lineItems); + // ApiV3.OrderFulfillability.OrderFulfillabilityResult result = + // getOrderFulfillabilityResult(itemFulfillabilities); + // + // ApiV3.OrderFulfillability.Builder orderFulfillability = + // ApiV3.OrderFulfillability.newBuilder() + // .setResult(result); + // for (int i = 0; i < itemFulfillabilities.size(); i++) { + // orderFulfillability.setItemFulfillability(i, itemFulfillabilities.get(i)); + // } + // ApiV3.Price total = ... // total processing fees & taxes for this order + // ApiV3.CheckOrderFulfillabilityResponse response = + // ApiV3.CheckOrderFulfillabilityResponse.newBuilder() + // .setFulfillability(orderFulfillability.build()) + // .setFeesAndTaxes(total) + // .build(); + // + // return response; + + throw new UnsupportedOperationException("Not implemented yet"); + } + + @Path("/CreateOrder") + @POST + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + public String createOrder(String request) throws InvalidProtocolBufferException { + + // use JsonFormat.Parser to convert Json String into protocol buffer + ApiV3.CreateOrderRequest.Builder requestBuilder = ApiV3.CreateOrderRequest.newBuilder(); + JsonFormat.Parser jsonParser = JsonFormat.parser(); + jsonParser.merge(request, requestBuilder); + ApiV3.CreateOrderRequest createOrderRequest = requestBuilder.build(); + + // For unexpected error: throw exception and handle it in BookingExceptionMapper class, + // return corresponding response and HTTP code + // + // Normal path: get response object from the helper function + ApiV3.CreateOrderResponse response = performCreateOrder(createOrderRequest); + + // use JsonFormat to convert protocol buffer to Json + String jsonResponse = jsonPrinter().print(response); + return jsonResponse; + } + + // TODO(partner): Implement this method to create the order based on the request + private ApiV3.CreateOrderResponse performCreateOrder(ApiV3.CreateOrderRequest request) { + + // Create order business logic: + // e.g. + // ApiV3.Order order = request.getOrder(); + + // normal case -> create this order in the backend, return response: + // ApiV3.CreateOrderResponse response = ApiV3.CreateOrderResponse.newBuilder() + // .setOrder(order) + // .build(); + // + // Business logic error -> set the BookingFailure in the response + // e.g. + // ApiV3.OrderFailure orderFailure = ApiV3.OrderFailure.newBuilder() + // .setCause(ApiV3.OrderFailure.Cause.ORDER_UNFULFILLABLE) + // .setFulfillability(orderFulfillability...) + // .build(); + // ApiV3.CreateOrderResponse response = ApiV3.CreateOrderResponse.newBuilder() + // .setOrderFailure(orderFailure) + // .build(); + // + // return response; + + throw new UnsupportedOperationException("Not implemented yet"); + } + + @Path("/ListOrders") + @POST + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + public String listOrders(String request) throws InvalidProtocolBufferException { + + // use JsonFormat.Parser to convert Json String into protocol buffer + ApiV3.ListOrdersRequest.Builder requestBuilder = ApiV3.ListOrdersRequest.newBuilder(); + JsonFormat.Parser jsonParser = JsonFormat.parser(); + jsonParser.merge(request, requestBuilder); + ApiV3.ListOrdersRequest listOrdersRequest = requestBuilder.build(); + + // For unexpected error: throw exception and handle it in BookingExceptionMapper class, + // return corresponding response and HTTP code + // + // Normal path: get response object from the helper function + ApiV3.ListOrdersResponse response = getListOrders(listOrdersRequest); + + // use JsonFormat to convert protocol buffer to Json + String jsonResponse = jsonPrinter().print(response); + return jsonResponse; + } + + // TODO(partner): Implement this method to list orders based on user id or order ids + private ApiV3.ListOrdersResponse getListOrders(ApiV3.ListOrdersRequest request) { + + // List orders business logic: + // e.g. + // String userId = request.getUserId(); + // ApiV3.ListOrdersRequest.OrderIds orderIds = request.getOrderIds(); + // List<ApiV3.Order> orders = new ArrayList<ApiV3.Order>(); + // if (userId != null) { + // orders = findOrdersByUserId(userId); + // } else if (orderIds != null) { + // List<String> orderId = orderIds.getOrderIdList(); + // orders = getOrders(orderId); + // } else { + // throw new NotFoundException("No userId or orderId matched"); + // } + // ApiV3.ListOrdersResponse.Builder response = ApiV3.ListOrdersResponse.newBuilder(); + // for (int i = 0; i < orders.size(); i++) { + // response.setOrder(i, orders.get(i)); + // } + // + // return response.build(); + + throw new UnsupportedOperationException("Not implemented yet"); + } +}
diff --git a/rest/Error.java b/rest/Error.java new file mode 100644 index 0000000..d344c4f --- /dev/null +++ b/rest/Error.java
@@ -0,0 +1,72 @@ +/* + * 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. + */ + +package com.partner.mapsbooking.rest; + +import com.fasterxml.jackson.annotation.JsonRootName; + +/** The JSON object we use to return error message. */ +@JsonRootName(value = "error") +public class Error { + private int statusCode; + private String statusDescription; + private String errorMessage; + + public Error(int statusCode, String statusDescription, String errorMessage) { + this.statusCode = statusCode; + this.statusDescription = statusDescription; + this.errorMessage = errorMessage; + } + + public int getStatusCode() { + return statusCode; + } + + public void setStatusCode(int statusCode) { + this.statusCode = statusCode; + } + + public String getStatusDescription() { + return statusDescription; + } + + public void setStatusDescription(String statusDescription) { + this.statusDescription = statusDescription; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } +}