com.google.ipc.invalidation.ticl.android.AndroidChannelBase.java Source code

Java tutorial

Introduction

Here is the source code for com.google.ipc.invalidation.ticl.android.AndroidChannelBase.java

Source

/*
 * Copyright 2011 Google Inc.
 *
 * 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.ipc.invalidation.ticl.android;

import com.google.common.base.Preconditions;
import com.google.ipc.invalidation.external.client.SystemResources.Logger;
import com.google.protos.ipc.invalidation.AndroidChannel.AddressedAndroidMessage;

import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.BasicResponseHandler;

import java.io.IOException;

/**
 * Implementation of the HTTP communication used by {@code AndroidChannel}. Factored into
 * a separate class that can be run outside the Android environment to improve testing.
 *
 */

public abstract class AndroidChannelBase {
    /** Http client to use when making requests to . */
    HttpClient httpClient;

    /** Authentication type for  frontends. */
    private final String authType;

    /** URL of the frontends. */
    private final String channelUrl;

    /** The token that will be echoed to the data center in the headers of all HTTP requests. */
    private String echoToken = null;

    /**
     * Creates an instance that uses {@code httpClient} to send requests to {@code channelUrl}
     * using an auth type of {@code authType}.
     */
    protected AndroidChannelBase(HttpClient httpClient, String authType, String channelUrl) {
        this.httpClient = httpClient;
        this.authType = authType;
        this.channelUrl = channelUrl;
    }

    /** Sends {@code outgoingMessage} to . */
    void deliverOutboundMessage(final byte[] outgoingMessage) {
        getLogger().fine("Delivering outbound message: %s bytes", outgoingMessage.length);
        StringBuilder target = new StringBuilder();

        // Build base URL that targets the inbound request service with the encoded network endpoint id
        target.append(channelUrl);
        target.append(AndroidHttpConstants.REQUEST_URL);
        target.append(getWebEncodedEndpointId());

        // Add query parameter indicating the service to authenticate against
        target.append('?');
        target.append(AndroidHttpConstants.SERVICE_PARAMETER);
        target.append('=');
        target.append(authType);

        // Construct entity containing the outbound protobuf msg
        ByteArrayEntity contentEntity = new ByteArrayEntity(outgoingMessage);
        contentEntity.setContentType(AndroidHttpConstants.PROTO_CONTENT_TYPE);

        // Construct POST request with the entity content and appropriate authorization
        HttpPost httpPost = new HttpPost(target.toString());
        httpPost.setEntity(contentEntity);
        setPostHeaders(httpPost);
        try {
            String response = httpClient.execute(httpPost, new BasicResponseHandler());
        } catch (ClientProtocolException exception) {
            // TODO: Distinguish between key HTTP error codes and handle more specifically
            // where appropriate.
            getLogger().warning("Error from server on request: %s", exception);
        } catch (IOException exception) {
            getLogger().warning("Error writing request: %s", exception);
        } catch (RuntimeException exception) {
            getLogger().warning("Runtime exception writing request: %s", exception);
        }
    }

    /** Sets the Authorization and echo headers on {@code httpPost}. */
    private void setPostHeaders(HttpPost httpPost) {
        httpPost.setHeader("Authorization", "GoogleLogin auth=" + getAuthToken());
        if (echoToken != null) {
            // If we have a token to echo to the server, echo it.
            httpPost.setHeader(AndroidHttpConstants.ECHO_HEADER, echoToken);
        }
    }

    /**
     * If {@code echoToken} is not {@code null}, updates the token that will be sent in the header
     * of all HTTP requests.
     */
    void updateEchoToken(String echoToken) {
        if (echoToken != null) {
            this.echoToken = echoToken;
        }
    }

    /** Returns the token that will be sent in the header of all HTTP requests. */
    String getEchoTokenForTest() {
        return this.echoToken;
    }

    /** Sets the HTTP client to {@code client}. */
    void setHttpClientForTest(HttpClient client) {
        this.httpClient = Preconditions.checkNotNull(client);
    }

    /** Returns the base-64-encoded network endpoint id for the client. */
    protected abstract String getWebEncodedEndpointId();

    /** Returns the current authentication token for the client for web requests to . */
    protected abstract String getAuthToken();

    /** Returns the logger to use. */
    protected abstract Logger getLogger();

    /** Attempts to deliver a {@code message} from  to the local client. */
    protected abstract void tryDeliverMessage(AddressedAndroidMessage message);
}