Java tutorial
package org.apache.maven.wagon.shared.http; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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. */ import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HostConfiguration; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpConnectionManager; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; import org.apache.commons.httpclient.NTCredentials; import org.apache.commons.httpclient.UsernamePasswordCredentials; import org.apache.commons.httpclient.auth.AuthScope; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.HeadMethod; import org.apache.commons.httpclient.methods.PutMethod; import org.apache.commons.httpclient.methods.RequestEntity; import org.apache.commons.httpclient.params.HttpMethodParams; import org.apache.commons.httpclient.util.DateParseException; import org.apache.commons.httpclient.util.DateUtil; import org.apache.maven.wagon.InputData; import org.apache.maven.wagon.OutputData; import org.apache.maven.wagon.PathUtils; import org.apache.maven.wagon.ResourceDoesNotExistException; import org.apache.maven.wagon.StreamWagon; import org.apache.maven.wagon.TransferFailedException; import org.apache.maven.wagon.Wagon; import org.apache.maven.wagon.authorization.AuthorizationException; import org.apache.maven.wagon.events.TransferEvent; import org.apache.maven.wagon.proxy.ProxyInfo; import org.apache.maven.wagon.repository.Repository; import org.apache.maven.wagon.resource.Resource; import org.codehaus.plexus.util.IOUtil; import org.codehaus.plexus.util.StringUtils; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Iterator; import java.util.Locale; import java.util.Properties; import java.util.TimeZone; import java.util.zip.GZIPInputStream; /** * @author <a href="michal.maczka@dimatics.com">Michal Maczka</a> * @author <a href="mailto:james@atlassian.com">James William Dumay</a> */ public abstract class AbstractHttpClientWagon extends StreamWagon { private final class RequestEntityImplementation implements RequestEntity { private final Resource resource; private final Wagon wagon; private final File source; private RequestEntityImplementation(final InputStream stream, final Resource resource, final Wagon wagon, final File source) throws TransferFailedException { if (source != null) { this.source = source; } else { FileOutputStream fos = null; try { this.source = File.createTempFile("http-wagon.", ".tmp"); this.source.deleteOnExit(); fos = new FileOutputStream(this.source); IOUtil.copy(stream, fos); } catch (IOException e) { fireTransferError(resource, e, TransferEvent.REQUEST_PUT); throw new TransferFailedException("Failed to buffer stream contents to temp file for upload.", e); } finally { IOUtil.close(fos); } } this.resource = resource; this.wagon = wagon; } public long getContentLength() { return resource.getContentLength(); } public String getContentType() { return null; } public boolean isRepeatable() { return true; } public void writeRequest(OutputStream output) throws IOException { byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; TransferEvent transferEvent = new TransferEvent(wagon, resource, TransferEvent.TRANSFER_PROGRESS, TransferEvent.REQUEST_PUT); transferEvent.setTimestamp(System.currentTimeMillis()); FileInputStream fin = null; try { fin = new FileInputStream(source); int remaining = Integer.MAX_VALUE; while (remaining > 0) { int n = fin.read(buffer, 0, Math.min(buffer.length, remaining)); if (n == -1) { break; } fireTransferProgress(transferEvent, buffer, n); output.write(buffer, 0, n); remaining -= n; } } finally { IOUtil.close(fin); } output.flush(); } } protected static final int SC_NULL = -1; protected static final TimeZone GMT_TIME_ZONE = TimeZone.getTimeZone("GMT"); private HttpClient client; protected HttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager(); /** * @deprecated Use httpConfiguration instead. */ private Properties httpHeaders; /** * @since 1.0-beta-6 */ private HttpConfiguration httpConfiguration; private HttpMethod getMethod; public void openConnectionInternal() { repository.setUrl(getURL(repository)); client = new HttpClient(connectionManager); String username = null; String password = null; if (authenticationInfo != null) { username = authenticationInfo.getUserName(); password = authenticationInfo.getPassword(); } String host = getRepository().getHost(); if (StringUtils.isNotEmpty(username) && StringUtils.isNotEmpty(password)) { Credentials creds = new UsernamePasswordCredentials(username, password); int port = getRepository().getPort() > -1 ? getRepository().getPort() : AuthScope.ANY_PORT; AuthScope scope = new AuthScope(host, port); client.getState().setCredentials(scope, creds); } HostConfiguration hc = new HostConfiguration(); ProxyInfo proxyInfo = getProxyInfo(getRepository().getProtocol(), getRepository().getHost()); if (proxyInfo != null) { String proxyUsername = proxyInfo.getUserName(); String proxyPassword = proxyInfo.getPassword(); String proxyHost = proxyInfo.getHost(); int proxyPort = proxyInfo.getPort(); String proxyNtlmHost = proxyInfo.getNtlmHost(); String proxyNtlmDomain = proxyInfo.getNtlmDomain(); if (proxyHost != null) { hc.setProxy(proxyHost, proxyPort); if (proxyUsername != null && proxyPassword != null) { Credentials creds; if (proxyNtlmHost != null || proxyNtlmDomain != null) { creds = new NTCredentials(proxyUsername, proxyPassword, proxyNtlmHost, proxyNtlmDomain); } else { creds = new UsernamePasswordCredentials(proxyUsername, proxyPassword); } int port = proxyInfo.getPort() > -1 ? proxyInfo.getPort() : AuthScope.ANY_PORT; AuthScope scope = new AuthScope(proxyHost, port); client.getState().setProxyCredentials(scope, creds); } } } hc.setHost(host); //start a session with the webserver client.setHostConfiguration(hc); } public void closeConnection() { if (connectionManager instanceof MultiThreadedHttpConnectionManager) { ((MultiThreadedHttpConnectionManager) connectionManager).shutdown(); } } public void put(File source, String resourceName) throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException { Resource resource = new Resource(resourceName); firePutInitiated(resource, source); resource.setContentLength(source.length()); resource.setLastModified(source.lastModified()); put(null, resource, source); } public void putFromStream(final InputStream stream, String destination, long contentLength, long lastModified) throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException { Resource resource = new Resource(destination); firePutInitiated(resource, null); resource.setContentLength(contentLength); resource.setLastModified(lastModified); put(stream, resource, null); } private void put(final InputStream stream, Resource resource, File source) throws TransferFailedException, AuthorizationException, ResourceDoesNotExistException { String url = getRepository().getUrl(); String[] parts = StringUtils.split(resource.getName(), "/"); for (int i = 0; i < parts.length; i++) { // TODO: Fix encoding... // url += "/" + URLEncoder.encode( parts[i], System.getProperty("file.encoding") ); url += "/" + URLEncoder.encode(parts[i]); } //Parent directories need to be created before posting try { mkdirs(PathUtils.dirname(resource.getName())); } catch (IOException e) { fireTransferError(resource, e, TransferEvent.REQUEST_GET); } PutMethod putMethod = new PutMethod(url); firePutStarted(resource, source); try { putMethod.setRequestEntity(new RequestEntityImplementation(stream, resource, this, source)); int statusCode; try { statusCode = execute(putMethod); } catch (IOException e) { fireTransferError(resource, e, TransferEvent.REQUEST_PUT); throw new TransferFailedException(e.getMessage(), e); } fireTransferDebug(url + " - Status code: " + statusCode); // Check that we didn't run out of retries. switch (statusCode) { // Success Codes case HttpStatus.SC_OK: // 200 case HttpStatus.SC_CREATED: // 201 case HttpStatus.SC_ACCEPTED: // 202 case HttpStatus.SC_NO_CONTENT: // 204 break; case SC_NULL: { TransferFailedException e = new TransferFailedException("Failed to transfer file: " + url); fireTransferError(resource, e, TransferEvent.REQUEST_PUT); throw e; } case HttpStatus.SC_FORBIDDEN: fireSessionConnectionRefused(); throw new AuthorizationException("Access denied to: " + url); case HttpStatus.SC_NOT_FOUND: throw new ResourceDoesNotExistException("File: " + url + " does not exist"); //add more entries here default: { TransferFailedException e = new TransferFailedException( "Failed to transfer file: " + url + ". Return code is: " + statusCode); fireTransferError(resource, e, TransferEvent.REQUEST_PUT); throw e; } } firePutCompleted(resource, source); } finally { putMethod.releaseConnection(); } } protected void mkdirs(String dirname) throws HttpException, IOException { } public boolean resourceExists(String resourceName) throws TransferFailedException, AuthorizationException { String url = getRepository().getUrl() + "/" + resourceName; HeadMethod headMethod = new HeadMethod(url); int statusCode; try { statusCode = execute(headMethod); } catch (IOException e) { throw new TransferFailedException(e.getMessage(), e); } try { switch (statusCode) { case HttpStatus.SC_OK: return true; case HttpStatus.SC_NOT_MODIFIED: return true; case SC_NULL: throw new TransferFailedException("Failed to transfer file: " + url); case HttpStatus.SC_FORBIDDEN: throw new AuthorizationException("Access denied to: " + url); case HttpStatus.SC_UNAUTHORIZED: throw new AuthorizationException("Not authorized."); case HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED: throw new AuthorizationException("Not authorized by proxy."); case HttpStatus.SC_NOT_FOUND: return false; //add more entries here default: throw new TransferFailedException( "Failed to transfer file: " + url + ". Return code is: " + statusCode); } } finally { headMethod.releaseConnection(); } } protected int execute(HttpMethod httpMethod) throws HttpException, IOException { int statusCode = SC_NULL; setParameters(httpMethod); setHeaders(httpMethod); statusCode = client.executeMethod(httpMethod); return statusCode; } protected void setParameters(HttpMethod method) { HttpMethodConfiguration config = httpConfiguration == null ? null : httpConfiguration.getMethodConfiguration(method); if (config != null) { HttpMethodParams params = config.asMethodParams(method.getParams()); if (params != null) { method.setParams(params); } } if (config == null || config.getConnectionTimeout() == HttpMethodConfiguration.DEFAULT_CONNECTION_TIMEOUT) { method.getParams().setSoTimeout(getTimeout()); } } protected void setHeaders(HttpMethod method) { HttpMethodConfiguration config = httpConfiguration == null ? null : httpConfiguration.getMethodConfiguration(method); if (config == null || config.isUseDefaultHeaders()) { // TODO: merge with the other headers and have some better defaults, unify with lightweight headers method.addRequestHeader("Cache-control", "no-cache"); method.addRequestHeader("Cache-store", "no-store"); method.addRequestHeader("Pragma", "no-cache"); method.addRequestHeader("Expires", "0"); method.addRequestHeader("Accept-Encoding", "gzip"); } if (httpHeaders != null) { for (Iterator i = httpHeaders.keySet().iterator(); i.hasNext();) { String header = (String) i.next(); method.addRequestHeader(header, httpHeaders.getProperty(header)); } } Header[] headers = config == null ? null : config.asRequestHeaders(); if (headers != null) { for (int i = 0; i < headers.length; i++) { method.addRequestHeader(headers[i]); } } } /** * getUrl * Implementors can override this to remove unwanted parts of the url such as role-hints * @param repository * @return */ protected String getURL(Repository repository) { return repository.getUrl(); } protected HttpClient getClient() { return client; } public void setConnectionManager(HttpConnectionManager connectionManager) { this.connectionManager = connectionManager; } public Properties getHttpHeaders() { return httpHeaders; } public void setHttpHeaders(Properties httpHeaders) { this.httpHeaders = httpHeaders; } public HttpConfiguration getHttpConfiguration() { return httpConfiguration; } public void setHttpConfiguration(HttpConfiguration httpConfiguration) { this.httpConfiguration = httpConfiguration; } public void fillInputData(InputData inputData) throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException { Resource resource = inputData.getResource(); String url = getRepository().getUrl() + "/" + resource.getName(); getMethod = new GetMethod(url); long timestamp = resource.getLastModified(); if (timestamp > 0) { SimpleDateFormat fmt = new SimpleDateFormat("EEE, dd-MMM-yy HH:mm:ss zzz", Locale.US); fmt.setTimeZone(GMT_TIME_ZONE); Header hdr = new Header("If-Modified-Since", fmt.format(new Date(timestamp))); fireTransferDebug("sending ==> " + hdr + "(" + timestamp + ")"); getMethod.addRequestHeader(hdr); } int statusCode; try { statusCode = execute(getMethod); } catch (IOException e) { fireTransferError(resource, e, TransferEvent.REQUEST_GET); throw new TransferFailedException(e.getMessage(), e); } fireTransferDebug(url + " - Status code: " + statusCode); // TODO [BP]: according to httpclient docs, really should swallow the output on error. verify if that is // required switch (statusCode) { case HttpStatus.SC_OK: break; case HttpStatus.SC_NOT_MODIFIED: // return, leaving last modified set to original value so getIfNewer should return unmodified return; case SC_NULL: { TransferFailedException e = new TransferFailedException("Failed to transfer file: " + url); fireTransferError(resource, e, TransferEvent.REQUEST_GET); throw e; } case HttpStatus.SC_FORBIDDEN: fireSessionConnectionRefused(); throw new AuthorizationException("Access denied to: " + url); case HttpStatus.SC_UNAUTHORIZED: fireSessionConnectionRefused(); throw new AuthorizationException("Not authorized."); case HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED: fireSessionConnectionRefused(); throw new AuthorizationException("Not authorized by proxy."); case HttpStatus.SC_NOT_FOUND: throw new ResourceDoesNotExistException("File: " + url + " does not exist"); // add more entries here default: { cleanupGetTransfer(resource); TransferFailedException e = new TransferFailedException( "Failed to transfer file: " + url + ". Return code is: " + statusCode); fireTransferError(resource, e, TransferEvent.REQUEST_GET); throw e; } } InputStream is = null; Header contentLengthHeader = getMethod.getResponseHeader("Content-Length"); if (contentLengthHeader != null) { try { long contentLength = Integer.valueOf(contentLengthHeader.getValue()).intValue(); resource.setContentLength(contentLength); } catch (NumberFormatException e) { fireTransferDebug( "error parsing content length header '" + contentLengthHeader.getValue() + "' " + e); } } Header lastModifiedHeader = getMethod.getResponseHeader("Last-Modified"); long lastModified = 0; if (lastModifiedHeader != null) { try { lastModified = DateUtil.parseDate(lastModifiedHeader.getValue()).getTime(); resource.setLastModified(lastModified); } catch (DateParseException e) { fireTransferDebug("Unable to parse last modified header"); } fireTransferDebug("last-modified = " + lastModifiedHeader.getValue() + " (" + lastModified + ")"); } Header contentEncoding = getMethod.getResponseHeader("Content-Encoding"); boolean isGZipped = contentEncoding == null ? false : "gzip".equalsIgnoreCase(contentEncoding.getValue()); try { is = getMethod.getResponseBodyAsStream(); if (isGZipped) { is = new GZIPInputStream(is); } } catch (IOException e) { fireTransferError(resource, e, TransferEvent.REQUEST_GET); String msg = "Error occurred while retrieving from remote repository:" + getRepository() + ": " + e.getMessage(); throw new TransferFailedException(msg, e); } inputData.setInputStream(is); } protected void cleanupGetTransfer(Resource resource) { if (getMethod != null) { getMethod.releaseConnection(); } } public void fillOutputData(OutputData outputData) throws TransferFailedException { throw new IllegalStateException("Should not be using the streaming wagon for HTTP PUT"); } }