Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
Copyright 2012 Google Inc. All Rights Reserved. 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 http://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.apphosting.vmruntime;
 
 import  com.google.appengine.repackaged.com.google.common.collect.Lists;
 import  com.google.apphosting.api.ApiProxy;
 import  com.google.apphosting.api.ApiProxy.ApiConfig;
 import  com.google.apphosting.api.ApiProxy.ApiProxyException;
 import  com.google.apphosting.api.ApiProxy.LogRecord;
 import  com.google.apphosting.api.ApiProxy.RPCFailedException;
 import  com.google.apphosting.utils.remoteapi.RemoteApiPb;
 
 import java.util.List;
Delegates AppEngine API calls to a local http API proxy when running inside a VM.

Instances should be registered using ApiProxy.setDelegate(ApiProxy.Delegate).

 
 public class VmApiProxyDelegate implements ApiProxy.Delegate<LazyApiProxyEnvironment> {
 
     private static final Logger logger = Logger.getLogger(VmApiProxyDelegate.class.getName());
 
     public static final String RPC_DEADLINE_HEADER = "X-Google-RPC-Service-Deadline";
     public static final String RPC_STUB_ID_HEADER = "X-Google-RPC-Service-Endpoint";
     public static final String RPC_METHOD_HEADER = "X-Google-RPC-Service-Method";
 
     public static final String REQUEST_ENDPOINT = "/rpc_http";
     public static final String REQUEST_STUB_ID = "app-engine-apis";
     public static final String REQUEST_STUB_METHOD = "/VMRemoteAPI.CallRemoteAPI";
 
     protected static final String API_DEADLINE_KEY =
             "com.google.apphosting.api.ApiProxy.api_deadline_key";
 
     static final int ADDITIONAL_HTTP_TIMEOUT_BUFFER_MS = 1000;
 
     protected int defaultTimeoutMs;
     protected final ExecutorService executor;
 
     protected final HttpClient httpclient;
 
 
     private static ClientConnectionManager createConnectionManager() {
         PoolingClientConnectionManager connectionManager = new PoolingClientConnectionManager();
         connectionManager.setMaxTotal(.);
         return connectionManager;
     }
 
     public VmApiProxyDelegate() {
         this(new DefaultHttpClient(createConnectionManager()));
     }
 
 
     VmApiProxyDelegate(HttpClient httpclient) {
         this. = 5 * 60 * 1000;
         this. = Executors.newCachedThreadPool();
         this. = httpclient;
         this. = new IdleConnectionMonitorThread(httpclient.getConnectionManager());
         this..start();
     }
 
     @Override
     public byte[] makeSyncCall(
             LazyApiProxyEnvironment environment,
            String packageName,
            String methodName,
            byte[] requestData)
            throws ApiProxyException {
        return makeSyncCallWithTimeout(environmentpackageNamemethodNamerequestData,
                );
    }
    private byte[] makeSyncCallWithTimeout(
            LazyApiProxyEnvironment environment,
            String packageName,
            String methodName,
            byte[] requestData,
            int timeoutMs)
            throws ApiProxyException {
        return makeApiCall(environmentpackageNamemethodNamerequestDatatimeoutMsfalse);
    }
    private byte[] makeApiCall(LazyApiProxyEnvironment environment,
                               String packageName,
                               String methodName,
                               byte[] requestData,
                               int timeoutMs,
                               boolean wasAsync) {
        environment.apiCallStarted(.wasAsync);
        try {
            return runSyncCall(environmentpackageNamemethodNamerequestDatatimeoutMs);
        } finally {
            environment.apiCallCompleted();
        }
    }
    protected byte[] runSyncCall(LazyApiProxyEnvironment environmentString packageName,
                                 String methodNamebyte[] requestDataint timeoutMs) {
        HttpPost request = createRequest(environmentpackageNamemethodNamerequestDatatimeoutMs);
        try {
            BasicHttpContext context = new BasicHttpContext();
            HttpResponse response = .execute(requestcontext);
            if (response.getStatusLine().getStatusCode() != .) {
                try (Scanner errorStreamScanner =
                             new Scanner(new BufferedInputStream(response.getEntity().getContent()));) {
                    .info("Error body: " + errorStreamScanner.useDelimiter("\\Z").next());
                    throw new RPCFailedException(packageNamemethodName);
                }
            }
            try (BufferedInputStream bis = new BufferedInputStream(response.getEntity().getContent())) {
                RemoteApiPb.Response remoteResponse = new RemoteApiPb.Response();
                if (!remoteResponse.parseFrom(bis)) {
                    .info(
                            "HTTP ApiProxy unable to parse response for " + packageName + "." + methodName);
                    throw new RPCFailedException(packageNamemethodName);
                }
                if (remoteResponse.hasRpcError() || remoteResponse.hasApplicationError()) {
                    throw convertRemoteError(remoteResponsepackageNamemethodName);
                }
                return remoteResponse.getResponseAsBytes();
            }
        } catch (IOException e) {
            .info(
                    "HTTP ApiProxy I/O error for " + packageName + "." + methodName + ": " + e.getMessage());
            throw new RPCFailedException(packageNamemethodName);
        } finally {
            request.releaseConnection();
        }
    }

    
Create an HTTP post request suitable for sending to the API server.

Parameters:
environment The current VMApiProxyEnvironment
packageName The API call package
methodName The API call method
requestData The POST payload.
timeoutMs The timeout for this request
Returns:
an HttpPost object to send to the API.
    static HttpPost createRequest(LazyApiProxyEnvironment environmentString packageName,
                                  String methodNamebyte[] requestDataint timeoutMs) {
        RemoteApiPb.Request remoteRequest = new RemoteApiPb.Request();
        remoteRequest.setServiceName(packageName);
        remoteRequest.setMethod(methodName);
        remoteRequest.setRequestId(environment.getTicket());
        remoteRequest.setRequestAsBytes(requestData);
        HttpPost request = new HttpPost("http://" + environment.getServer() + );
        request.setHeader();
        HttpParams params = new BasicHttpParams();
                timeoutMs + );
                timeoutMs + );
                timeoutMs + );
        request.setParams(params);
        Double deadline = (Double) (environment.getAttributes().get());
        if (deadline == null) {
            request.setHeader(,
                    Double.toString(..convert(timeoutMs.)));
        } else {
            request.setHeader(, Double.toString(deadline));
        }
        Object dapperHeader = environment.getAttributes()
        if (dapperHeader instanceof String) {
            request.setHeader(
                    ..., (StringdapperHeader);
        }
        ByteArrayEntity postPayload = new ByteArrayEntity(remoteRequest.toByteArray(),
                .);
        postPayload.setChunked(false);
        request.setEntity(postPayload);
        return request;
    }

    
Convert RemoteApiPb.Response errors to the appropriate exception.

The response must have exactly one of the RpcError and ApplicationError fields set.

Parameters:
remoteResponse the Response
packageName the name of the API package.
methodName the name of the method within the API package.
logger the Logger used to create log messages.
Returns:
ApiProxyException
    private static ApiProxyException convertRemoteError(RemoteApiPb.Response remoteResponse,
                                                        String packageNameString methodNameLogger logger) {
        if (remoteResponse.hasRpcError()) {
            return convertApiResponseRpcErrorToException(
                    remoteResponse.getRpcError(),
                    packageName,
                    methodName,
                    logger);
        }
        RemoteApiPb.ApplicationError error = remoteResponse.getApplicationError();
        return new ApiProxy.ApplicationException(error.getCode(), error.getDetail());
    }

    
Convert the RemoteApiPb.RpcError to the appropriate exception.

Parameters:
rpcError the RemoteApiPb.RpcError.
packageName the name of the API package.
methodName the name of the method within the API package.
logger the Logger used to create log messages.
Returns:
ApiProxyException
    private static ApiProxyException convertApiResponseRpcErrorToException(
            RemoteApiPb.RpcError rpcErrorString packageNameString methodNameLogger logger) {
        int rpcCode = rpcError.getCode();
        String errorDetail = rpcError.getDetail();
        if (rpcCode > RemoteApiPb.RpcError.ErrorCode.values().length) {
            logger.severe("Received unrecognized error code from server: " + rpcError.getCode() +
                    " details: " + errorDetail);
            return new ApiProxy.UnknownException(packageNamemethodName);
        }
        RemoteApiPb.RpcError.ErrorCode errorCode = RemoteApiPb.RpcError.ErrorCode.values()[
                rpcError.getCode()];
        logger.warning("RPC failed : " + errorCode + " : " + errorDetail);
        switch (errorCode) {
            case CALL_NOT_FOUND:
                return new ApiProxy.CallNotFoundException(packageNamemethodName);
            case PARSE_ERROR:
                return new ApiProxy.ArgumentException(packageNamemethodName);
            case SECURITY_VIOLATION:
                logger.severe("Security violation: invalid request id used!");
                return new ApiProxy.UnknownException(packageNamemethodName);
            case CAPABILITY_DISABLED:
                return new ApiProxy.CapabilityDisabledException(
                        errorDetailpackageNamemethodName);
            case OVER_QUOTA:
                return new ApiProxy.OverQuotaException(packageNamemethodName);
            case REQUEST_TOO_LARGE:
                return new ApiProxy.RequestTooLargeException(packageNamemethodName);
            case RESPONSE_TOO_LARGE:
                return new ApiProxy.ResponseTooLargeException(packageNamemethodName);
            case BAD_REQUEST:
                return new ApiProxy.ArgumentException(packageNamemethodName);
            case CANCELLED:
                return new ApiProxy.CancelledException(packageNamemethodName);
            case FEATURE_DISABLED:
                return new ApiProxy.FeatureNotEnabledException(
                        errorDetailpackageNamemethodName);
            case DEADLINE_EXCEEDED:
                return new ApiProxy.ApiDeadlineExceededException(packageNamemethodName);
            default:
                return new ApiProxy.UnknownException(packageNamemethodName);
        }
    }
    private class MakeSyncCall implements Callable<byte[]> {
        private final VmApiProxyDelegate delegate;
        private final LazyApiProxyEnvironment environment;
        private final String packageName;
        private final String methodName;
        private final byte[] requestData;
        private final int timeoutMs;
        public MakeSyncCall(VmApiProxyDelegate delegate,
                            LazyApiProxyEnvironment environment,
                            String packageName,
                            String methodName,
                            byte[] requestData,
                            int timeoutMs) {
            this. = delegate;
            this. = environment;
            this. = packageName;
            this. = methodName;
            this. = requestData;
            this. = timeoutMs;
        }
        @Override
        public byte[] call() throws Exception {
            return .makeApiCall(,
                    ,
                    ,
                    ,
                    ,
                    true);
        }
    }
    @Override
    public Future<byte[]> makeAsyncCall(
            LazyApiProxyEnvironment environment,
            String packageName,
            String methodName,
            byte[] request,
            ApiConfig apiConfig) {
        int timeoutMs = ;
        if (apiConfig != null && apiConfig.getDeadlineInSeconds() != null) {
            timeoutMs = (int) (apiConfig.getDeadlineInSeconds() * 1000);
        }
        return .submit(new MakeSyncCall(thisenvironmentpackageName,
                methodNamerequesttimeoutMs));
    }
    @Override
    public void log(LazyApiProxyEnvironment environment, LogRecord record) {
        if (environment != null) {
            environment.addLogRecord(record);
        }
    }
    @Override
    public void flushLogs(LazyApiProxyEnvironment environment) {
        if (environment != null) {
            environment.flushLogs();
        }
    }
    @Override
    public List<ThreadgetRequestThreads(LazyApiProxyEnvironment environment) {
        Object threadFactory =
                environment.getAttributes().get(.);
        if (threadFactory != null && threadFactory instanceof VmRequestThreadFactory) {
            return ((VmRequestThreadFactorythreadFactory).getRequestThreads();
        }
        .warning("Got a call to getRequestThreads() but no VmRequestThreadFactory is available");
        return Lists.newLinkedList();
    }

    
Simple connection watchdog verifying that our connections are alive. Any stale connections are cleared as well.
    class IdleConnectionMonitorThread extends Thread {
        private final ClientConnectionManager connectionManager;
        public IdleConnectionMonitorThread(ClientConnectionManager connectionManager) {
            super("IdleApiConnectionMontorThread");
            this. = connectionManager;
            this.setDaemon(false);
        }
        @Override
        public void run() {
            try {
                while (true) {
                    .closeExpiredConnections();
                    .closeIdleConnections(60, .);
                    Thread.sleep(5000);
                }
            } catch (InterruptedException ex) {
            }
        }
    }
New to GrepCode? Check out our FAQ X