All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.appengine.api.memcache.MemcacheServiceApiHelper Maven / Gradle / Ivy

There is a newer version: 2.0.32
Show newest version
/*
 * Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.appengine.api.memcache;

import static com.google.common.base.Throwables.throwIfInstanceOf;
import static com.google.common.base.Throwables.throwIfUnchecked;

import com.google.appengine.api.utils.FutureWrapper;
import com.google.apphosting.api.ApiProxy;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Message;
import java.util.concurrent.Future;
import java.util.logging.Logger;

/**
 * Helper methods and constants shared by classes that implement the java api
 * of MemcacheService.
 *
 */
class MemcacheServiceApiHelper {

  //@VisibleForTesting
  static final String PACKAGE = "memcache";
  private static final Logger logger = Logger.getLogger(MemcacheServiceApiHelper.class.getName());

  private MemcacheServiceApiHelper() {
    // Utility class
  }

  public interface Provider {
    T get();
  }

  interface Transformer {
    T transform(F from);
  }

  /**
   * An RPC response handler to convert an ApiProxy rpc response
   * (byte[] or exceptions) to an API level response.
   */
  static class RpcResponseHandler {

    private final String errorText;
    private final Message.Builder builder;
    private final Transformer responseTransfomer;
    private final ErrorHandler errorHandler;

    RpcResponseHandler(M response, String errorText,
        Transformer responseTransfomer, ErrorHandler errorHandler) {
      this.builder = response.newBuilderForType();
      this.errorText = errorText;
      this.responseTransfomer = responseTransfomer;
      this.errorHandler = errorHandler;
    }

    T convertResponse(byte[] responseBytes) throws InvalidProtocolBufferException {
      @SuppressWarnings("unchecked")
      M response = (M) builder.mergeFrom(responseBytes).build();
      return responseTransfomer.transform(response);
    }

    void handleApiProxyException(Throwable cause) throws Exception {
      handleApiProxyException(cause, errorHandler);
    }

    void handleApiProxyException(Throwable cause, ErrorHandler errorHandler) throws Exception {
      try {
        throw cause;
      } catch (InvalidProtocolBufferException ex) {
        errorHandler.handleServiceError(
            new MemcacheServiceException("Could not decode response:", ex));
      } catch (ApiProxy.ApplicationException ex) {
        // We don't want to propagate the app exception outside the api layer
        // but we can at least log the details.  Make sure we log before
        // we delegate to the handler because the handler implementation might throw.
        logger.info(errorText + ": " + ex.getErrorDetail());
        errorHandler.handleServiceError(new MemcacheServiceException(errorText));
      } catch (ApiProxy.ApiProxyException ex) {
        errorHandler.handleServiceError(new MemcacheServiceException(errorText, ex));
      } catch (MemcacheServiceException ex) {
        if (errorHandler instanceof ConsistentErrorHandler) {
          errorHandler.handleServiceError(ex);
        } else {
          // MemcacheServiceException thrown by responseTransfomer will not
          // be delegated to errorHandlers which do not implement the
          // ConsistentErrorHandler to preserve backward compatibility
          throw ex;
        }
      } catch (Throwable ex) {
        throwIfInstanceOf(ex, Exception.class);
        throwIfUnchecked(ex);
        throw new RuntimeException(ex);
      }
    }

    Logger getLogger() {
      return logger;
    }

    ErrorHandler getErrorHandler() {
      return errorHandler;
    }
  }

  /**
   * Issue an async rpc against the memcache package with the given request and
   * response pbs as input and apply standard exception handling.  Do not
   * use this helper function if you need non-standard exception handling.
   */
  static  Future makeAsyncCall(String methodName, Message request,
      final RpcResponseHandler responseHandler, final Provider defaultValue) {
    Future asyncResp = ApiProxy.makeAsyncCall(PACKAGE, methodName, request.toByteArray());
    return new FutureWrapper(asyncResp) {

      @Override
      protected T wrap(byte[] bytes) throws Exception {
        try {
          // This null check is mainly for the benefit of unit tests
          // (specifically ones using EasyMock, where the default behavior is to return null).
          return bytes == null ? null : responseHandler.convertResponse(bytes);
        } catch (Exception ex) {
          return absorbParentException(ex);
        }
      }

      @Override
      protected T absorbParentException(Throwable cause) throws Exception {
        responseHandler.handleApiProxyException(cause);
        return defaultValue.get();
      }

      @Override
      protected Throwable convertException(Throwable cause) {
        return cause;
      }
    };
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy