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;
+  }
+}