/*******************************************************************************
* Copyright (c) 2010-2014 SAP AG and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* SAP AG - initial API and implementation
*******************************************************************************/
package org.eclipse.skalli.model.ext.maven.internal;
import static org.apache.http.HttpStatus.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.MessageFormat;
import java.util.UUID;
import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.params.HttpParams;
import org.eclipse.skalli.commons.HttpUtils;
import org.eclipse.skalli.model.ValidationException;
import org.eclipse.skalli.services.destination.Destinations;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class HttpMavenPomResolverBase extends MavenPomResolverBase {
private static final Logger LOG = LoggerFactory.getLogger(HttpMavenPomResolverBase.class);
/**
* Calculates the <code>URL</code> corresponding to the parameters <code>scmLocation</code> and <code>relativePath</code>.
* @throws MalformedURLException in case the <code>URL</code> could not be created
*/
protected abstract URL resolvePath(String scmLocation, String relativePath) throws MalformedURLException;
/**
* Returns an input stream, from which one can directly read the content of the POM.
* @param entity the HTTP entity to convert to a stream.
* @param relativePath the path of the POM relative to the root of the project's source code.
* @return an input stream for the content of the POM.
* @throws IOException if an i/o problem occured.
*/
protected abstract InputStream asPomInputStream(HttpEntity entity, String relativePath) throws IOException;
@Override
public MavenPom getMavenPom(UUID project, String scmLocation, String relativePath) throws IOException {
URL url = resolvePath(scmLocation, relativePath);
if (url == null) {
throw new IOException(MessageFormat.format(
"Failed to calculate an URL for downloading of a POM based on SCM location \"{0}\" and relative path \"{1}\"",
scmLocation, relativePath));
}
try {
return parse(url, relativePath, false);
} catch (Exception e) {
try {
parse(url, relativePath, true);
} catch (Exception e1) {
LOG.error(MessageFormat.format(
"Unexpected error occured while logging the response from {0}",
url.toExternalForm()), e);
}
throw new IOException(MessageFormat.format(
"Failed to download POM from {0} (scmLocation=\"{1}\", relativePath =\"{2}\")",
url.toExternalForm(), scmLocation, relativePath), e);
}
}
/**
* @param logResponse = true will return an default empty MavenPom and log the content read from the
* url with level Error to LOG; if set to false the method parse is called.
*/
private MavenPom parse(URL url, String relativePath, boolean logResponse) throws IOException,
HttpException, ValidationException {
HttpClient client = Destinations.getClient(url);
if (client == null) {
return null;
}
HttpParams params = client.getParams();
HttpClientParams.setRedirecting(params, false); // we want to find 301 MOVED PERMANTENTLY
HttpResponse response = null;
try {
LOG.info("GET " + url); //$NON-NLS-1$
HttpGet method = new HttpGet(url.toExternalForm());
response = client.execute(method);
int status = response.getStatusLine().getStatusCode();
LOG.info(status + " " + response.getStatusLine().getReasonPhrase()); //$NON-NLS-1$
if (status == HttpStatus.SC_OK) {
HttpEntity entity = response.getEntity();
if (entity == null) {
return null;
}
if (!logResponse) {
return parse(asPomInputStream(entity, relativePath));
} else {
logResponse(url, entity);
return new MavenPom();
}
}
else {
String statusText = response.getStatusLine().getReasonPhrase();
switch (status) {
case SC_NOT_FOUND:
throw new HttpException(MessageFormat.format("{0} not found", url));
case SC_UNAUTHORIZED:
throw new HttpException(MessageFormat.format("{0} found but authentication required: {1} {2}", url,
status, statusText));
case SC_INTERNAL_SERVER_ERROR:
case SC_SERVICE_UNAVAILABLE:
case SC_GATEWAY_TIMEOUT:
case SC_INSUFFICIENT_STORAGE:
throw new HttpException(MessageFormat.format(
"{0} not found. Host reports a temporary problem: {1} {2}", url, status, statusText));
case SC_MOVED_PERMANENTLY:
throw new HttpException(MessageFormat.format(
"{0} not found. Resource has been moved permanently to {1}",
url, response.getFirstHeader("Location")));
default:
throw new HttpException(MessageFormat.format("{0} not found. Host responded with {1} {2}", url,
status, statusText));
}
}
} finally {
HttpUtils.consumeQuietly(response);
}
}
private void logResponse(URL url, HttpEntity entity) throws IOException {
try {
StringWriter writer = new StringWriter();
String encoding = null;
if (entity.getContentEncoding() != null) {
encoding = entity.getContentEncoding().getValue();
}
IOUtils.copy(entity.getContent(), writer, encoding);
String content = writer.toString();
StringBuilder sb = new StringBuilder();
sb.append("Response from ").append(url.toExternalForm()).append(":\n");
Header contentType = entity.getContentType();
sb.append("Content-Type: ")
.append(contentType == null ? "<not available>" : entity.getContentType().getValue())
.append("\n");
sb.append("Content-Encoding: ").append(encoding == null? "<not available>" : encoding).append("\n");
sb.append("\n").append(content);
LOG.error(sb.toString());
} catch (IOException e) {
throw new IOException(MessageFormat.format(
"Unexpected exception while trying to consume the response from {0}",
url.toExternalForm()), e);
}
}
}