Initial commit of sample java grpc server
diff --git a/BookingService.java b/BookingService.java
new file mode 100644
index 0000000..5124027
--- /dev/null
+++ b/BookingService.java
@@ -0,0 +1,472 @@
+/*
+ * 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 ext.maps.booking.partner.v2;
+
+import ext.maps.booking.partner.v2.ApitemplateV2BookingService.AvailabilityUpdate;
+import ext.maps.booking.partner.v2.ApitemplateV2BookingService.Booking;
+import ext.maps.booking.partner.v2.ApitemplateV2BookingService.BookingStatus;
+import ext.maps.booking.partner.v2.ApitemplateV2BookingService.CheckAvailabilityRequest;
+import ext.maps.booking.partner.v2.ApitemplateV2BookingService.CheckAvailabilityResponse;
+import ext.maps.booking.partner.v2.ApitemplateV2BookingService.CheckAvailabilityResponse.DurationRequirement;
+import ext.maps.booking.partner.v2.ApitemplateV2BookingService.CreateBookingRequest;
+import ext.maps.booking.partner.v2.ApitemplateV2BookingService.CreateBookingResponse;
+import ext.maps.booking.partner.v2.ApitemplateV2BookingService.GetBookingStatusRequest;
+import ext.maps.booking.partner.v2.ApitemplateV2BookingService.GetBookingStatusResponse;
+import ext.maps.booking.partner.v2.ApitemplateV2BookingService.ListBookingsRequest;
+import ext.maps.booking.partner.v2.ApitemplateV2BookingService.ListBookingsResponse;
+import ext.maps.booking.partner.v2.ApitemplateV2BookingService.PrepaymentStatus;
+import ext.maps.booking.partner.v2.ApitemplateV2BookingService.Slot;
+import ext.maps.booking.partner.v2.ApitemplateV2BookingService.UpdateBookingRequest;
+import ext.maps.booking.partner.v2.ApitemplateV2BookingService.UpdateBookingResponse;
+import ext.maps.booking.partner.v2.ApitemplateV2BookingService.UserPaymentOption;
+import grpc.health.v1.Health.HealthImpl;
+import io.grpc.Grpc;
+import io.grpc.Metadata;
+import io.grpc.Server;
+import io.grpc.ServerCall;
+import io.grpc.ServerCallHandler;
+import io.grpc.ServerInterceptor;
+import io.grpc.ServerInterceptors;
+import io.grpc.Status;
+import io.grpc.netty.GrpcSslContexts;
+import io.grpc.netty.NettyServerBuilder;
+import io.grpc.stub.StreamObserver;
+import io.netty.handler.ssl.ClientAuth;
+import io.netty.handler.ssl.SslContextBuilder;
+import io.netty.handler.ssl.SslProvider;
+import java.io.File;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Logger;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import org.bouncycastle.asn1.x500.RDN;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x500.style.BCStyle;
+import org.bouncycastle.asn1.x500.style.IETFUtils;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
+
+/** Booking Server with TLS enabled */
+public class BookingService {
+  private static final Logger logger = Logger.getLogger(BookingService.class.getName());
+
+  private Server server;
+
+  private final String host;
+  private final int port;
+  private final String certChainFilePath;
+  private final String privateKeyFilePath;
+  private final String trustedrootsFilePath;
+  private final Set<String> acceptedCNs;
+
+  public BookingService(
+      String host,
+      int port,
+      String certChainFilePath,
+      String privateKeyFilePath,
+      String trustedrootsFilePath,
+      Set<String> acceptedCNs) {
+    this.host = host;
+    this.port = port;
+    this.certChainFilePath = certChainFilePath;
+    this.privateKeyFilePath = privateKeyFilePath;
+    this.trustedrootsFilePath = trustedrootsFilePath;
+    this.acceptedCNs = acceptedCNs;
+  }
+
+  private SslContextBuilder getSslContextBuilder() {
+    SslContextBuilder sslClientContextBuilder =
+        SslContextBuilder.forServer(new File(certChainFilePath), new File(privateKeyFilePath));
+    if (trustedrootsFilePath != null) {
+      sslClientContextBuilder.trustManager(new File(trustedrootsFilePath));
+      sslClientContextBuilder.clientAuth(ClientAuth.OPTIONAL);
+    }
+    return GrpcSslContexts.configure(sslClientContextBuilder, SslProvider.OPENSSL);
+  }
+
+  private void start() throws IOException {
+
+    server =
+        NettyServerBuilder.forAddress(new InetSocketAddress(host, port))
+            .addService(ServerInterceptors.intercept(new BookingServiceImpl(), new MyInterceptor()))
+            .addService(new HealthImpl())
+            .sslContext(getSslContextBuilder().build())
+            .build()
+            .start();
+
+    logger.info("Booking Server started, listening on " + port);
+    Runtime.getRuntime()
+        .addShutdownHook(
+            new Thread() {
+              @Override
+              public void run() {
+                // Use stderr here since the logger may have been reset by its JVM shutdown hook.
+                System.err.println("*** shutting down gRPC server since JVM is shutting down");
+                BookingService.this.stop();
+                System.err.println("*** server shut down");
+              }
+            });
+  }
+
+  private void stop() {
+    if (server != null) {
+      server.shutdown();
+    }
+  }
+
+  /** Await termination on the main thread since the grpc library uses daemon threads. */
+  private void blockUntilShutdown() throws InterruptedException {
+    if (server != null) {
+      server.awaitTermination();
+    }
+  }
+
+  /** Main launches the server. */
+  public static void main(String[] args) throws IOException, InterruptedException {
+    // Set the accepted cns of the server
+    Set<String> acceptedCNs = new HashSet<String>();
+    acceptedCNs.add("mapsbooking.businesslink-3.net");
+
+    // TODO(partner): override your host name, port, server_cert_chain file path,
+    // private_key file path and trusted_client_roots file path here to build the server
+    final BookingService server =
+        new BookingService(
+            "localhost",
+            8443,
+            "src/main/certificates/server_cert_chain.pem",
+            "src/main/certificates/server_private_key.pem",
+            "src/main/certificates/trusted_client_roots.pem",
+            acceptedCNs);
+    server.start();
+    server.blockUntilShutdown();
+  }
+
+  /**
+   * Implement the server interceptor to do peer certificate validation that checks for a specific
+   * CN in the subject name, if the CN check fails, the connection will be closed with
+   * "PERMISSION_DENIED" status message.
+   */
+  private class MyInterceptor implements ServerInterceptor {
+    @Override
+    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
+        ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
+      SSLSession sslSession = call.getAttributes().get(Grpc.TRANSPORT_ATTR_SSL_SESSION);
+      try {
+        Certificate[] peerCerts = sslSession.getPeerCertificates();
+        if (peerCerts[0] instanceof java.security.cert.X509Certificate) {
+          X509Certificate peerCert = (X509Certificate) peerCerts[0];
+          X500Name x500Name = new JcaX509CertificateHolder(peerCert).getSubject();
+          RDN cn = x500Name.getRDNs(BCStyle.CN)[0];
+          String peerCN = IETFUtils.valueToString(cn.getFirst().getValue());
+          if (!acceptedCNs.contains(peerCN)) {
+            throw new SSLPeerUnverifiedException("Invalid CN");
+          }
+        } else {
+          throw new SSLPeerUnverifiedException("Invalid certificate type");
+        }
+      } catch (SSLPeerUnverifiedException se) {
+        System.err.println(se.getMessage());
+        call.close(Status.PERMISSION_DENIED, headers);
+        return new ServerCall.Listener<ReqT>() {};
+      } catch (CertificateEncodingException ce) {
+        System.err.println(ce.getMessage());
+        call.close(Status.PERMISSION_DENIED, headers);
+        return new ServerCall.Listener<ReqT>() {};
+      }
+      return next.startCall(call, headers);
+    }
+  }
+
+  /** The implementation of Booking Service. */
+  static class BookingServiceImpl extends BookingServiceGrpc.BookingServiceImplBase {
+    @Override
+    public void checkAvailability(
+        CheckAvailabilityRequest request,
+        StreamObserver<CheckAvailabilityResponse> responseObserver) {
+
+      Slot requestedSlot = request.getSlot();
+
+      // TODO(partner): perform availability check
+      //
+      // Error conditions: response with corresponding canonical gRPC error code
+      // example:
+      //  responseObserver.onError(
+      //      new StatusException(
+      //          io.grpc.Status.INVALID_ARGUMENT.withDescription("Invalid merchant id")
+      //      )
+      //  );
+      //
+      // Happy path: implement the helper functions, populate the response
+
+      CheckAvailabilityResponse response =
+          CheckAvailabilityResponse.newBuilder()
+              .setSlot(requestedSlot)
+              .setCountAvailable(getAvailableSpots(requestedSlot))
+              .setDurationRequirement(getDurationRequirement(requestedSlot)) // optional
+              .setAvailabilityUpdate(getAvailabilityUpdate(requestedSlot)) // optional
+              .build();
+
+      responseObserver.onNext(response);
+      responseObserver.onCompleted();
+    }
+
+    private int getAvailableSpots(Slot slot) {
+      // TODO(partner): get the available spots for the given slot
+      //
+      // int available_spots = ...
+      // return available_spots;
+
+      throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    private DurationRequirement getDurationRequirement(Slot slot) {
+      // TODO(partner): optional, get the duration requirment for the given slot
+      //
+      // DurationRequirement durationRequirement = ...
+      // return durationRequirement;
+
+      throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    private AvailabilityUpdate getAvailabilityUpdate(Slot slot) {
+      // TODO(partner): optional, get the availability update for the given slot
+      //
+      // AvailabilityUpdate availabilityUpdate = ...
+      // return availabilityUpdate;
+
+      throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    @Override
+    public void createBooking(
+        CreateBookingRequest request, StreamObserver<CreateBookingResponse> responseObserver) {
+
+      // TODO(partner): create a booking based on the request
+      //
+      // Error conditions:
+      // unexpected error -> response with corresponding canonical gRPC error code
+      // example:
+      //  responseObserver.onError(
+      //      new StatusException(
+      //          io.grpc.Status.INVALID_ARGUMENT.withDescription("Invalid merchant id")
+      //      )
+      //  );
+      // business logic error -> set the BookingFailure in the response
+      // example:
+      // BookingFailure bookingFailure = BookingFailure.newBuilder()
+      //     .setCause(Cause.SLOT_UNAVAILABLE)
+      //     .setDescription("slot is not available now")
+      //     .build();
+      // CreateBookingResponse response = CreateBookingResponse.newBuilder()
+      //     .setBookingFailure(bookingFailure)...
+      //
+      // Happy path: implement the helper functions, populate the response
+
+      Booking booking = createSuccessfulBooking(request);
+
+      CreateBookingResponse response =
+          CreateBookingResponse.newBuilder()
+              .setBooking(booking)
+              .setUserPaymentOption(getUserPaymentOption(booking)) // optional
+              .build();
+
+      responseObserver.onNext(response);
+      responseObserver.onCompleted();
+    }
+
+    private Booking createSuccessfulBooking(CreateBookingRequest request) {
+      // TODO(partner): create a booking based on the create booking request and return the
+      // created booking instance
+      //
+      // Booking created = ...(e.g.
+      // Booking.newBuilder()
+      //     .setBookingId("sampleBooking1")
+      //     .setSlot(request.getSlot())
+      //     .setUserInformation(request.getUserInformation())
+      //     .setStatus(BookingStatus.CONFIRMED)
+      //     .setPaymentInformation(request.getPaymentInformation())
+      //     .build()
+      // )
+      // return created;
+
+      throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    private UserPaymentOption getUserPaymentOption(Booking booking) {
+      // TODO(partner): optional, get the user payment option for the given booking
+      //
+      // UserPaymentOption paymentOption = ...
+      // return paymentOption;
+
+      throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    @Override
+    public void updateBooking(
+        UpdateBookingRequest request, StreamObserver<UpdateBookingResponse> responseObserver) {
+
+      // TODO(partner): update the booking based on the request
+      //
+      // Error conditions:
+      // unexpected error -> response with corresponding canonical gRPC error code
+      // example:
+      //  responseObserver.onError(
+      //      new StatusException(
+      //          io.grpc.Status.NOT_FOUND.withDescription("Unknown booking id")
+      //      )
+      //  );
+      // business logic error -> set the BookingFailure in the response
+      // example:
+      // BookingFailure bookingFailure = BookingFailure.newBuilder()
+      //     .setCause(Cause.SLOT_UNAVAILABLE)
+      //     .setDescription("slot is not available now")
+      //     .build();
+      // CreateBookingResponse response = CreateBookingResponse.newBuilder()
+      //     .setBookingFailure(bookingFailure)...
+      //
+      // Happy path: implement the helper functions, populate the response
+
+      Booking booking = updateSuccessfulBooking(request);
+
+      UpdateBookingResponse response =
+          UpdateBookingResponse.newBuilder()
+              .setBooking(booking)
+              .setUserPaymentOption(getUserPaymentOption(booking)) // option
+              .build();
+
+      responseObserver.onNext(response);
+      responseObserver.onCompleted();
+    }
+
+    private Booking updateSuccessfulBooking(UpdateBookingRequest request) {
+      // TODO(partner): look up the booking with bookingId, update fields according to
+      // updateMask and return the updated booking instance
+      //
+      // String bookingId = request.getBooking().getBookingId();
+      // FieldMask updateMask = request.getUpdateMask();
+      // Booking updated = ...
+      // return updated;
+
+      throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    @Override
+    public void getBookingStatus(
+        GetBookingStatusRequest request,
+        StreamObserver<GetBookingStatusResponse> responseObserver) {
+
+      String bookingId = request.getBookingId();
+
+      // TODO(partner): look up the booking status and prepayment status with bookingId
+      //
+      // Error conditions:
+      // unexpected error -> response with corresponding canonical gRPC error code
+      // example:
+      //  responseObserver.onError(
+      //      new StatusException(
+      //          io.grpc.Status.NOT_FOUND.withDescription("Unknown booking id")
+      //      )
+      //  );
+      //
+      // Happy path: implement the helper functions, populate the response
+
+      GetBookingStatusResponse response =
+          GetBookingStatusResponse.newBuilder()
+              .setBookingId(bookingId)
+              .setBookingStatus(getBookingStatus(bookingId))
+              .setPrepaymentStatus(getPrepaymentStatus(bookingId))
+              .build();
+
+      responseObserver.onNext(response);
+      responseObserver.onCompleted();
+    }
+
+    private BookingStatus getBookingStatus(String bookingId) {
+      // TODO(partner): get the booking status for the given bookingId
+      //
+      // BookingStatus bookingStatus = ...
+      // return bookingStatus;
+
+      throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    private PrepaymentStatus getPrepaymentStatus(String bookingId) {
+      // TODO(partner): get the prepayment status for the given bookingId
+      //
+      // Prepayment prepaymentStatus = ...
+      // return prepaymentStatus;
+
+      throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    @Override
+    public void listBookings(
+        ListBookingsRequest request, StreamObserver<ListBookingsResponse> responseObserver) {
+
+      String userId = request.getUserId();
+
+      // TODO(partner): look up all bookings with the given userId
+      //
+      // Error conditions:
+      // unexpected error -> response with corresponding canonical gRPC error code
+      // example:
+      //  responseObserver.onError(
+      //      new StatusException(
+      //          io.grpc.Status.NOT_FOUND.withDescription("Unknown user id")
+      //      )
+      //  );
+      //
+      // Happy path: implement the helper function, populate the response
+
+      ListBookingsResponse response =
+          ListBookingsResponse.newBuilder().addAllBookings(getListBooking(userId)).build();
+
+      responseObserver.onNext(response);
+      responseObserver.onCompleted();
+    }
+
+    private List<Booking> getListBooking(String userId) {
+      // TODO(partner): get the bookings list for the given userId
+      //
+      // List<Booking> bookings = ...
+      // return bookings;
+
+      throw new UnsupportedOperationException("Not implemented yet");
+    }
+  }
+}
diff --git a/Health.java b/Health.java
new file mode 100644
index 0000000..81788b6
--- /dev/null
+++ b/Health.java
@@ -0,0 +1,73 @@
+/*
+ * 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 grpc.health.v1;
+
+import grpc.health.v1.HealthOuterClass.HealthCheckRequest;
+import grpc.health.v1.HealthOuterClass.HealthCheckResponse;
+import grpc.health.v1.HealthOuterClass.HealthCheckResponse.ServingStatus;
+import io.grpc.Status;
+import io.grpc.StatusException;
+import io.grpc.stub.StreamObserver;
+import java.util.logging.Logger;
+
+/** gRPC Health Checking Protocol */
+public class Health {
+  private static final Logger logger = Logger.getLogger(Health.class.getName());
+  private static final String ACCEPTED_SERVICE = "ext.maps.booking.partner.v2.BookingService";
+
+  /** The implementation of Health Checking Service. */
+  public static class HealthImpl extends HealthGrpc.HealthImplBase {
+    @Override
+    public void check(
+        HealthCheckRequest request, StreamObserver<HealthCheckResponse> responseObserver) {
+      String service = request.getService();
+      if (!service.equals(ACCEPTED_SERVICE)) {
+        responseObserver.onError(
+            new StatusException(Status.NOT_FOUND.withDescription("Unknown service")));
+      } else {
+        HealthCheckResponse response =
+            HealthCheckResponse.newBuilder().setStatus(getServingStatus()).build();
+        responseObserver.onNext(response);
+        responseObserver.onCompleted();
+      }
+    }
+
+    private ServingStatus getServingStatus() {
+      // TODO(partner): check the health status of the service
+      //
+      // ServingStatus status = ... (e.g. ServingStatus.SERVING)
+      // return status;
+
+      throw new UnsupportedOperationException("Not implemented yet");
+    }
+  }
+}
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..6fefbd1
--- /dev/null
+++ b/README.md
@@ -0,0 +1,163 @@
+# gRPC Server Skeleton for Java
+
+### Get Started
+
+1.  Create a java gradle project (grpc-booking-service), under the src/main,
+    create a 'proto' directory.
+
+2.  Download the [booking service
+    definition](https://developers.google.com/maps-booking/download/apitemplate.v2.booking_service.proto)
+    and [health checking
+    protocol](https://github.com/grpc/grpc/blob/master/src/proto/grpc/health/v1/health.proto),
+    place them under src/main/proto. These files define the gRPC methods and
+    messages for the Reserve with Google API and Health Check.
+
+3.  Update the ***build.gradle*** file, add dependencies and the protobuf plugin
+    for Gradle. The introduction and guide for protobuf-gradle-plugin can be
+    found [here](https://github.com/google/protobuf-gradle-plugin).
+
+            apply plugin: 'java'
+            apply plugin: 'com.google.protobuf'
+
+            repositories {
+                mavenCentral()
+            }
+
+            // updating the version in our release process.
+            def grpcVersion = '1.8.0' // CURRENT_GRPC_VERSION
+            def nettyTcNativeVersion = '2.0.7.Final'
+
+            dependencies {
+                compile "com.google.api.grpc:proto-google-common-protos:0.1.9"
+                compile "io.grpc:grpc-netty:${grpcVersion}"
+                compile "io.grpc:grpc-protobuf:${grpcVersion}"
+                compile "io.grpc:grpc-stub:${grpcVersion}"
+                compile "io.netty:netty-tcnative-boringssl-static:${nettyTcNativeVersion}"
+                compile "org.bouncycastle:bcmail-jdk15:1.46"
+
+                testCompile "io.grpc:grpc-testing:${grpcVersion}"
+                testCompile "junit:junit:4.12"
+                testCompile "org.mockito:mockito-core:1.9.5"
+            }
+
+            buildscript {
+                repositories {
+                    mavenCentral()
+                }
+                dependencies {
+                    // ASSUMES GRADLE 2.12 OR HIGHER. Use plugin version 0.7.5 with earlier
+                    // gradle versions
+                    classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.1'
+                }
+            }
+
+            protobuf {
+                protoc {
+                    artifact = 'com.google.protobuf:protoc:3.4.0'
+                }
+                plugins {
+                    grpc {
+                        artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}"
+                    }
+                }
+                generateProtoTasks {
+                    all()*.plugins {
+                        grpc {}
+                    }
+                }
+            }
+
+            // Inform IDEs like IntelliJ IDEA, Eclipse or NetBeans about the generated code.
+            sourceSets {
+                main {
+                    java {
+                        srcDirs 'build/generated/source/proto/main/grpc'
+                        srcDirs 'build/generated/source/proto/main/java'
+                    }
+                }
+            }
+
+            // Generate IntelliJ IDEA's .idea & .iml project files
+            apply plugin: 'idea'
+
+            // Provide convenience executables for trying out the examples.
+            apply plugin: 'application'
+
+            startScripts.enabled = false
+
+4.  Run the following command to build the library and auto-generate code from
+    protoc build plugin:
+
+          ./gradlew build
+
+5.  To enable TLS on the server, under ***src/main/certificates/*** the
+    following files are required:
+
+    *   ***server_cert_chain.pem*** your server certificate chain in PEM format
+    *   ***server_private_key.pem*** your private key for the server certificate
+        chain, needs to be the PKCS#8 private key
+    *   ***trusted_client_roots.pem*** the root certificates that are trusted
+        when authenticating clients, you can choose to obtain this set of
+        trusted roots from an authority like
+        [Mozilla](https://wiki.mozilla.org/CA:IncludedCAs), or install the [set
+        of roots currently recommended by the Google Internet Authority
+        G2](https://pki.google.com/roots.pem). In the latter case, you may have
+        to manually update the root certificate at times
+
+6.  Retrieve the sample code, place the **BookingService.java** under
+    *src/main/java/ext/maps/booking/partner/v2*, place **Health.java** under
+    *src/main/java/grpc/health/v1*. In both files, follow the ***TODOs*** to
+    complete your implementations.
+
+7.  Update the gradle.build file to specify the generation of server executable
+    by adding the following code:
+
+        task bookingService(type: CreateStartScripts) {
+            mainClassName = 'ext.maps.booking.partner.v2.BookingService'
+            applicationName = 'booking-service'
+            outputDir = new File(project.buildDir, 'tmp')
+            classpath = jar.outputs.files + project.configurations.runtime
+        }
+
+        applicationDistribution.into('bin') {
+            from(bookingService)
+            fileMode = 0755
+        }
+
+8.  Compile the server:
+
+        ./gradlew installDist
+
+9.  Run the booking server:
+
+        ./build/install/grpc-booking-service/bin/booking-service
+
+### Final Directory Structure
+
+    src
+    |---main
+        |---certificates
+            |---server_cert_chain.pem
+            |---server_private_key.pem
+            |---trusted_client_roots.pem
+        |---java
+            |---ext.maps.booking.partner.v2.BookingService.java
+            |---grpc.health.v1.Health.java
+        |---proto
+            |---booking_service.proto
+            |---health.proto
+    |---test
+
+### Other Reference
+
+*   For other building tools, visit the
+    [gRPC-java](https://grpc.io/docs/quickstart/java.html) and download the
+    example, check grpc-java/examples.
+
+         git clone -b v1.9.0 https://github.com/grpc/grpc-java
+
+*   [gRPC java Transport Security
+    (TLS)](https://github.com/grpc/grpc-java/blob/master/SECURITY.md).
+
+*   [gRPC API
+    V2](https://developers.google.com/maps-booking/reference/grpc-api-v2/slot-specification).