Java tutorial
/* * 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; } }