/*
 * Copyright 2014, 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 io.grpc;

import com.google.common.base.Preconditions;

import io.grpc.ForwardingServerCall.SimpleForwardingServerCall;
import io.grpc.ForwardingServerCallListener.SimpleForwardingServerCallListener;

import java.util.Arrays;
import java.util.List;

/**
 * Utility methods for working with {@link ServerInterceptor}s.
 */
public class ServerInterceptors {
  // Prevent instantiation
  private ServerInterceptors() {}

  /**
   * Create a new {@code ServerServiceDefinition} whose {@link ServerCallHandler}s will call
   * {@code interceptors} before calling the pre-existing {@code ServerCallHandler}. The last
   * interceptor will have its {@link ServerInterceptor#interceptCall} called first.
   *
   * @param serviceDef the service definition for which to intercept all its methods.
   * @param interceptors array of interceptors to apply to the service.
   * @return a wrapped version of {@code serviceDef} with the interceptors applied.
   */
  public static ServerServiceDefinition intercept(ServerServiceDefinition serviceDef,
                                                  ServerInterceptor... interceptors) {
    return intercept(serviceDef, Arrays.asList(interceptors));
  }

  /**
   * Create a new {@code ServerServiceDefinition} whose {@link ServerCallHandler}s will call
   * {@code interceptors} before calling the pre-existing {@code ServerCallHandler}. The last
   * interceptor will have its {@link ServerInterceptor#interceptCall} called first.
   *
   * @param serviceDef the service definition for which to intercept all its methods.
   * @param interceptors list of interceptors to apply to the service.
   * @return a wrapped version of {@code serviceDef} with the interceptors applied.
   */
  public static ServerServiceDefinition intercept(ServerServiceDefinition serviceDef,
      List<? extends ServerInterceptor> interceptors) {
    Preconditions.checkNotNull(serviceDef);
    if (interceptors.isEmpty()) {
      return serviceDef;
    }
    ServerServiceDefinition.Builder serviceDefBuilder
        = ServerServiceDefinition.builder(serviceDef.getName());
    for (ServerMethodDefinition<?, ?> method : serviceDef.getMethods()) {
      wrapAndAddMethod(serviceDefBuilder, method, interceptors);
    }
    return serviceDefBuilder.build();
  }

  private static <ReqT, RespT> void wrapAndAddMethod(
      ServerServiceDefinition.Builder serviceDefBuilder, ServerMethodDefinition<ReqT, RespT> method,
      List<? extends ServerInterceptor> interceptors) {
    ServerCallHandler<ReqT, RespT> callHandler = method.getServerCallHandler();
    for (ServerInterceptor interceptor : interceptors) {
      callHandler = InterceptCallHandler.create(interceptor, callHandler);
    }
    serviceDefBuilder.addMethod(method.withServerCallHandler(callHandler));
  }

  private static class InterceptCallHandler<ReqT, RespT> implements ServerCallHandler<ReqT, RespT> {
    public static <ReqT, RespT> InterceptCallHandler<ReqT, RespT> create(
        ServerInterceptor interceptor, ServerCallHandler<ReqT, RespT> callHandler) {
      return new InterceptCallHandler<ReqT, RespT>(interceptor, callHandler);
    }

    private final ServerInterceptor interceptor;
    private final ServerCallHandler<ReqT, RespT> callHandler;

    private InterceptCallHandler(ServerInterceptor interceptor,
        ServerCallHandler<ReqT, RespT> callHandler) {
      this.interceptor = Preconditions.checkNotNull(interceptor, "interceptor");
      this.callHandler = callHandler;
    }

    @Override
    public ServerCall.Listener<ReqT> startCall(
        MethodDescriptor<ReqT, RespT> method,
        ServerCall<RespT> call,
        Metadata.Headers headers) {
      return interceptor.interceptCall(method, call, headers, callHandler);
    }
  }

  /**
   * Utility base class for decorating {@link ServerCall} instances.
   *
   * @deprecated Use {@link SimpleForwardingServerCall}
   */
  @Deprecated
  public static class ForwardingServerCall<RespT> extends SimpleForwardingServerCall<RespT> {
    public ForwardingServerCall(ServerCall<RespT> delegate) {
      super(delegate);
    }
  }

  /**
   * Utility base class for decorating {@link ServerCall.Listener} instances.
   *
   * @deprecated Use {@link SimpleForwardingServerCallListener}
   */
  @Deprecated
  public static class ForwardingListener<ReqT> extends SimpleForwardingServerCallListener<ReqT> {
    public ForwardingListener(ServerCall.Listener<ReqT> delegate) {
      super(delegate);
    }
  }
}

@@ -1622,153 +1622,8 @@
 s;%0A%0A
-import io.grpc.ForwardingServerCall.SimpleForwardingServerCall;%0Aimport io.grpc.ForwardingServerCallListener.SimpleForwardingServerCallListener;%0A%0A
 impo
@@ -5171,726 +5171,7 @@
 %0A  %7D
-%0A%0A  /**%0A   * Utility base class for decorating %7B@link ServerCall%7D instances.%0A   *%0A   * @deprecated Use %7B@link SimpleForwardingServerCall%7D%0A   */%0A  @Deprecated%0A  public static class ForwardingServerCall%3CRespT%3E extends SimpleForwardingServerCall%3CRespT%3E %7B%0A    public ForwardingServerCall(ServerCall%3CRespT%3E delegate) %7B%0A      super(delegate);%0A    %7D%0A  %7D%0A%0A  /**%0A   * Utility base class for decorating %7B@link ServerCall.Listener%7D instances.%0A   *%0A   * @deprecated Use %7B@link SimpleForwardingServerCallListener%7D%0A   */%0A  @Deprecated%0A  public static class ForwardingListener%3CReqT%3E extends SimpleForwardingServerCallListener%3CReqT%3E %7B%0A    public ForwardingListener(ServerCall.Listener%3CReqT%3E delegate) %7B%0A      super(delegate);%0A    %7D%0A  %7D
 %0A%7D%0A

Remove deprecated classes from ServerInterceptors