org.jets3t.service.utils.signedurl.GatekeeperClientUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.jets3t.service.utils.signedurl.GatekeeperClientUtils.java

Source

/*
 * JetS3t : Java S3 Toolkit
 * Project hosted at http://bitbucket.org/jmurty/jets3t/
 *
 * Copyright 2007 James Murty
 *
 * 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 org.jets3t.service.utils.signedurl;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.zip.GZIPInputStream;

import org.apache.http.Header;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.util.EntityUtils;
import org.apache.commons.httpclient.contrib.proxy.PluginProxyUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jets3t.service.model.S3Object;
import org.jets3t.service.utils.RestUtils;
import org.jets3t.service.utils.ServiceUtils;
import org.jets3t.service.utils.gatekeeper.GatekeeperMessage;
import org.jets3t.service.utils.gatekeeper.SignatureRequest;

/**
 * Utility class to handle common operations performed by Gatekeeper client applications.
 *
 * @author James Murty
 */
public class GatekeeperClientUtils {

    private HttpClient httpClientGatekeeper = null;

    private static final Log log = LogFactory.getLog(GatekeeperClientUtils.class);

    /**
     * Variable to store application exceptions, so that client failure information can be
     * included in the information provided to the Gatekeeper when uploads are retried.
     */
    private Exception priorFailureException = null;

    private String gatekeeperUrl = null;

    private final String userAgentDescription;
    private final int maxRetryCount;
    private final int connectionTimeout;
    private CredentialsProvider credentialsProvider = null;

    /**
     * @param gatekeeperUrl
     * @param userAgentDescription
     * @param maxRetryCount
     * @param connectionTimeoutMS
     * @param credentialsProvider
     */
    public GatekeeperClientUtils(String gatekeeperUrl, String userAgentDescription, int maxRetryCount,
            int connectionTimeoutMS, CredentialsProvider credentialsProvider) {
        this.gatekeeperUrl = gatekeeperUrl;
        this.userAgentDescription = userAgentDescription;
        this.maxRetryCount = maxRetryCount;
        this.connectionTimeout = connectionTimeoutMS;
        this.credentialsProvider = credentialsProvider;
    }

    /**
     * Prepares objects for HTTP communications with the Gatekeeper servlet.
     * @return
     */
    private HttpClient initHttpConnection() {
        // Set client parameters.
        HttpParams params = RestUtils.createDefaultHttpParams();
        HttpProtocolParams.setUserAgent(params, ServiceUtils.getUserAgentDescription(userAgentDescription));

        // Set connection parameters.
        HttpConnectionParams.setConnectionTimeout(params, connectionTimeout);
        HttpConnectionParams.setSoTimeout(params, connectionTimeout);
        HttpConnectionParams.setStaleCheckingEnabled(params, false);

        DefaultHttpClient httpClient = new DefaultHttpClient(params);
        // Replace default error retry handler.
        httpClient.setHttpRequestRetryHandler(new RestUtils.JetS3tRetryHandler(maxRetryCount, null));

        // httpClient.getParams().setAuthenticationPreemptive(true);
        httpClient.setCredentialsProvider(credentialsProvider);

        return httpClient;
    }

    /**
     * Request permission from the Gatekeeper for a particular operation.
     *
     * @param operationType
     * @param bucketName
     * @param objects
     * @param applicationPropertiesMap
     * @throws HttpException
     * @throws Exception
     */
    public GatekeeperMessage requestActionThroughGatekeeper(String operationType, String bucketName,
            S3Object[] objects, Map applicationPropertiesMap) throws HttpException, Exception {
        /*
         *  Build Gatekeeper request.
         */
        GatekeeperMessage gatekeeperMessage = new GatekeeperMessage();
        gatekeeperMessage.addApplicationProperties(applicationPropertiesMap);
        gatekeeperMessage.addApplicationProperty(GatekeeperMessage.PROPERTY_CLIENT_VERSION_ID,
                userAgentDescription);

        // If a prior failure has occurred, add information about this failure.
        if (priorFailureException != null) {
            gatekeeperMessage.addApplicationProperty(GatekeeperMessage.PROPERTY_PRIOR_FAILURE_MESSAGE,
                    priorFailureException.getMessage());
            // Now reset the prior failure variable.
            priorFailureException = null;
        }

        // Add all S3 objects as candiates for PUT signing.
        for (int i = 0; i < objects.length; i++) {
            SignatureRequest signatureRequest = new SignatureRequest(operationType, objects[i].getKey());
            signatureRequest.setObjectMetadata(objects[i].getMetadataMap());
            signatureRequest.setBucketName(bucketName);

            gatekeeperMessage.addSignatureRequest(signatureRequest);
        }

        /*
         *  Build HttpClient POST message.
         */

        // Add all properties/parameters to credentials POST request.
        HttpPost postMethod = new HttpPost(gatekeeperUrl);
        Properties properties = gatekeeperMessage.encodeToProperties();
        Iterator<Map.Entry<Object, Object>> propsIter = properties.entrySet().iterator();
        List<NameValuePair> parameters = new ArrayList<NameValuePair>(properties.size());
        while (propsIter.hasNext()) {
            Map.Entry<Object, Object> entry = propsIter.next();
            String fieldName = (String) entry.getKey();
            String fieldValue = (String) entry.getValue();
            parameters.add(new BasicNameValuePair(fieldName, fieldValue));
        }
        postMethod.setEntity(new UrlEncodedFormEntity(parameters));

        // Create Http Client if necessary, and include User Agent information.
        if (httpClientGatekeeper == null) {
            httpClientGatekeeper = initHttpConnection();
        }

        // Try to detect any necessary proxy configurations.
        try {
            HttpHost proxyHost = PluginProxyUtil.detectProxy(new URL(gatekeeperUrl));
            if (proxyHost != null) {
                httpClientGatekeeper.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxyHost);
            }
        } catch (Throwable t) {
            if (log.isDebugEnabled()) {
                log.debug("No proxy detected");
            }
        }

        // Perform Gateway request.
        if (log.isDebugEnabled()) {
            log.debug("Contacting Gatekeeper at: " + gatekeeperUrl);
        }
        HttpResponse response = null;
        try {
            response = httpClientGatekeeper.execute(postMethod);
            int responseCode = response.getStatusLine().getStatusCode();
            String contentType = response.getFirstHeader("Content-Type").getValue();
            if (responseCode == 200) {
                InputStream responseInputStream = null;

                Header encodingHeader = response.getFirstHeader("Content-Encoding");
                if (encodingHeader != null && "gzip".equalsIgnoreCase(encodingHeader.getValue())) {
                    if (log.isDebugEnabled()) {
                        log.debug("Inflating gzip-encoded response");
                    }
                    responseInputStream = new GZIPInputStream(response.getEntity().getContent());
                } else {
                    responseInputStream = response.getEntity().getContent();
                }

                if (responseInputStream == null) {
                    throw new IOException("No response input stream available from Gatekeeper");
                }

                Properties responseProperties = new Properties();
                try {
                    responseProperties.load(responseInputStream);
                } finally {
                    responseInputStream.close();
                }

                GatekeeperMessage gatekeeperResponseMessage = GatekeeperMessage
                        .decodeFromProperties(responseProperties);

                // Check for Gatekeeper Error Code in response.
                String gatekeeperErrorCode = gatekeeperResponseMessage.getApplicationProperties()
                        .getProperty(GatekeeperMessage.APP_PROPERTY_GATEKEEPER_ERROR_CODE);
                if (gatekeeperErrorCode != null) {
                    if (log.isWarnEnabled()) {
                        log.warn("Received Gatekeeper error code: " + gatekeeperErrorCode);
                    }
                }

                return gatekeeperResponseMessage;
            } else {
                if (log.isDebugEnabled()) {
                    log.debug("The Gatekeeper did not permit a request. Response code: " + responseCode
                            + ", Response content type: " + contentType);
                }
                throw new IOException("The Gatekeeper did not permit your request");
            }
        } catch (IOException e) {
            throw e;
        } catch (Exception e) {
            throw new Exception("Gatekeeper did not respond", e);
        } finally {
            try {
                EntityUtils.consume(response.getEntity());
            } catch (Exception ee) {
                // ignore
            }
        }
    }

    /**
     * Parse the data in a set of SignatureRequest objects and build the corresponding
     * S3Objects represented by that data.
     *
     * @param srs
     * signature requests that represent S3 objects.
     * @return
     * objects reconstructed from the provided signature requests.
     */
    public S3Object[] buildS3ObjectsFromSignatureRequests(SignatureRequest[] srs) {
        S3Object[] objects = new S3Object[srs.length];
        for (int i = 0; i < srs.length; i++) {
            objects[i] = new S3Object(srs[i].getObjectKey());
            objects[i].addAllMetadata(srs[i].getObjectMetadata());
        }
        return objects;
    }

    public String getGatekeeperUrl() {
        return gatekeeperUrl;
    }

}