IMPROVE: better url querying management (IVY-138) (thanks to Bernard Niset)

git-svn-id: https://svn.apache.org/repos/asf/incubator/ivy/trunk@484106 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Xavier Hanin 2006-01-18 16:48:14 +00:00
parent 469a603599
commit af59bab18e
7 changed files with 322 additions and 64 deletions

View File

@ -8,6 +8,8 @@
- NEW: it is now possible to reference existing resolver in resolver containers (IVY-35)
- NEW: overwrite attribute in the publish task now let force overwrite of read only files (IVY-83)
- NEW: add a conflict manager ("strict") making build fail when a diamond conflict is found (thanks to Christer Jonsson) (IVY-118)
- IMPROVE: better url querying management (IVY-138) (thanks to Bernard Niset)
- IMPROVE: do not add resolver info in ivy files in cache so that they can be safely used as usual ivy files in a repository (IVY-137)
- IMPROVE: review default conf mapping management (IVY-134)
- IMPROVE: add possibility for a chain to behave like a dual chain (IVY-131)
@ -24,6 +26,7 @@
- IMPROVE: string identifying a module is now clearly different from a path
- IMPROVE: better error message when publish fails due to readonly destination (IVY-83)
- IMPROVE: some javadoc improvements (IVY-136 IVY-129) (thanks to Stephen Nesbitt)
- FIX: no variable replacement during the deliver step (IVY-133)
- FIX: conflict badly solved in some complex cases (IVY-130)
- FIX: mapping on conf * now only takes public configurations (IVY-126)

View File

@ -6,14 +6,11 @@
*/
package fr.jayasoft.ivy.repository.url;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import fr.jayasoft.ivy.repository.Resource;
import fr.jayasoft.ivy.url.URLHandlerRegistry;
import fr.jayasoft.ivy.util.Message;
import fr.jayasoft.ivy.url.URLHandler.URLInfo;
public class URLResource implements Resource {
private URL _url;
@ -38,24 +35,10 @@ public class URLResource implements Resource {
}
private void init() {
URLConnection con = null;
try {
_lastModified = 0;
_contentLength = 0;
_exists = URLHandlerRegistry.getDefault().isReachable(_url);
if (_exists) {
con = _url.openConnection();
_lastModified = con.getLastModified();
_contentLength = con.getContentLength();
}
} catch (IOException e) {
Message.verbose("impossible to open connection to "+_url+":"+e.getMessage());
_exists = false;
} finally {
if (con instanceof HttpURLConnection) {
((HttpURLConnection)con).disconnect();
}
}
URLInfo info = URLHandlerRegistry.getDefault().getURLInfo(_url);
_contentLength = info.getContentLength();
_lastModified = info.getLastModified();
_exists = info.isReachable();
_init = true;
}

View File

@ -0,0 +1,31 @@
/*
* This file is subject to the licence found in LICENCE.TXT in the root directory of the project.
* Copyright Jayasoft 2005 - All rights reserved
*
* #SNAPSHOT#
*/
package fr.jayasoft.ivy.url;
import java.net.URL;
public abstract class AbstractURLHandler implements URLHandler {
public boolean isReachable(URL url) {
return getURLInfo(url).isReachable();
}
public boolean isReachable(URL url, int timeout) {
return getURLInfo(url, timeout).isReachable();
}
public long getContentLength(URL url) {
return getURLInfo(url).getContentLength();
}
public long getContentLength(URL url, int timeout) {
return getURLInfo(url, timeout).getContentLength();
}
public long getLastModified(URL url) {
return getURLInfo(url).getLastModified();
}
public long getLastModified(URL url, int timeout) {
return getURLInfo(url, timeout).getLastModified();
}
}

View File

@ -25,18 +25,22 @@ import fr.jayasoft.ivy.util.Message;
* @author Xavier Hanin
*
*/
public class BasicURLHandler implements URLHandler {
public boolean isReachable(URL url) {
return isReachable(url, 0);
public class BasicURLHandler extends AbstractURLHandler {
public URLInfo getURLInfo(URL url) {
return getURLInfo(url, 0);
}
public boolean isReachable(URL url, int timeout) {
public URLInfo getURLInfo(URL url, int timeout) {
URLConnection con = null;
try {
con = url.openConnection();
if (con instanceof HttpURLConnection) {
int status = ((HttpURLConnection)con).getResponseCode();
if (status == HttpStatus.SC_OK) {
return true;
return new URLInfo(
true,
((HttpURLConnection)con).getContentLength(),
con.getLastModified()
);
}
if (status == HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED) {
Message.warn("Your proxy requires authentication.");
@ -48,7 +52,15 @@ public class BasicURLHandler implements URLHandler {
Message.debug("HTTP response status: "+status+" url="+url);
} else {
int contentLength = con.getContentLength();
return contentLength > 0;
if (contentLength <= 0) {
return UNAVAILABLE;
} else {
return new URLInfo(
true,
contentLength,
con.getLastModified()
);
}
}
} catch (UnknownHostException e) {
Message.warn("Host " + e.getMessage() +" not found. url="+url);
@ -60,7 +72,7 @@ public class BasicURLHandler implements URLHandler {
((HttpURLConnection)con).disconnect();
}
}
return false;
return UNAVAILABLE;
}
public InputStream openStream(URL url) throws IOException {

View File

@ -5,15 +5,20 @@
*/
package fr.jayasoft.ivy.url;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.UnknownHostException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Locale;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethodBase;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.methods.GetMethod;
@ -27,7 +32,8 @@ import fr.jayasoft.ivy.util.Message;
* @author Xavier Hanin
*
*/
public class HttpClientHandler implements URLHandler {
public class HttpClientHandler extends AbstractURLHandler {
private static final SimpleDateFormat LAST_MODIFIED_FORMAT = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z", Locale.US);
private String _realm = null;
private String _host = null;
private String _userName = null;
@ -41,6 +47,9 @@ public class HttpClientHandler implements URLHandler {
private String _proxyUserName = null;
private String _proxyPasswd = null;
private HttpClient _client;
private HttpClientHelper _httpClientHelper;
public HttpClientHandler() {
configureProxy();
}
@ -85,10 +94,8 @@ public class HttpClientHandler implements URLHandler {
public InputStream openStream(URL url) throws IOException {
GetMethod get = doGet(url);
byte[] response = get.getResponseBody();
get.releaseConnection();
return new ByteArrayInputStream(response);
final InputStream is = get.getResponseBodyAsStream();
return new GETInputStream(get);
}
public void download(URL src, File dest, CopyProgressListener l) throws IOException {
@ -97,17 +104,18 @@ public class HttpClientHandler implements URLHandler {
get.releaseConnection();
}
public boolean isReachable(URL url) {
return isReachable(url, 0);
public URLInfo getURLInfo(URL url) {
return getURLInfo(url, 0);
}
public boolean isReachable(URL url, int timeout) {
public URLInfo getURLInfo(URL url, int timeout) {
HeadMethod head = null;
try {
HeadMethod head = doHead(url, timeout);
head = doHead(url, timeout);
int status = head.getStatusCode();
head.releaseConnection();
if (status == HttpStatus.SC_OK) {
return true;
return new URLInfo(true, getResponseContentLength(head), getLastModified(head));
}
if (status == HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED) {
Message.error("Your proxy requires authentication.");
@ -124,9 +132,56 @@ public class HttpClientHandler implements URLHandler {
Message.info("You probably access the destination server through a proxy server that is not well configured.");
}catch (IOException e) {
Message.error("HttpClientHandler: "+e.getMessage()+" url="+url);
} finally{
if(head != null) {
head.releaseConnection();
}
}
return false;
}
return UNAVAILABLE;
}
private long getLastModified(HeadMethod head) {
Header header = head.getResponseHeader("last-modified");
if (header != null) {
String lastModified = header.getValue();
try {
return LAST_MODIFIED_FORMAT.parse(lastModified).getTime();
} catch (ParseException e) {
}
return System.currentTimeMillis();
} else {
return System.currentTimeMillis();
}
}
private long getResponseContentLength(HeadMethod head) {
return getHttpClientHelper().getResponseContentLength(head);
}
private HttpClientHelper getHttpClientHelper() {
if (_httpClientHelper == null) {
// use commons httpclient 3.0 if available
try {
Method method = HttpMethodBase.class.getMethod("getResponseContentLength", new Class[0]);
if (method.isAccessible()) {
_httpClientHelper = new HttpClientHelper3x();
Message.verbose("using commons httpclient 3.x helper");
} else {
_httpClientHelper = new HttpClientHelper2x();
Message.verbose("using commons httpclient 2.x helper");
}
} catch (SecurityException e) {
Message.verbose("unable to get access to getResponseContentLength of commons-httpclient HeadMethod. Please use commons-httpclient 3.0 or use ivy with sufficient security permissions.");
Message.verbose("exception: "+e.getMessage());
_httpClientHelper = new HttpClientHelper2x();
Message.verbose("using commons httpclient 2.x helper");
} catch (NoSuchMethodException e) {
_httpClientHelper = new HttpClientHelper2x();
Message.verbose("using commons httpclient 2.x helper");
}
}
return _httpClientHelper;
}
private GetMethod doGet(URL url) throws IOException, HttpException {
HttpClient client = getClient();
@ -148,22 +203,24 @@ public class HttpClientHandler implements URLHandler {
}
private HttpClient getClient() {
HttpClient client = new HttpClient();
if (useProxy()) {
client.getHostConfiguration().setProxy(_proxyHost, _proxyPort);
if (useProxyAuthentication()) {
client.getState().setProxyCredentials(_proxyRealm, _proxyHost,
new UsernamePasswordCredentials(_proxyUserName, _proxyPasswd));
}
if(_client == null){
_client = new HttpClient();
if (useProxy()) {
_client.getHostConfiguration().setProxy(_proxyHost, _proxyPort);
if (useProxyAuthentication()) {
_client.getState().setProxyCredentials(_proxyRealm, _proxyHost,
new UsernamePasswordCredentials(_proxyUserName, _proxyPasswd));
}
}
if (useAuthentication()) {
_client.getState().setCredentials(
_realm,
_host,
new UsernamePasswordCredentials(_userName, _passwd)
);
}
}
if (useAuthentication()) {
client.getState().setCredentials(
_realm,
_host,
new UsernamePasswordCredentials(_userName, _passwd)
);
}
return client;
return _client;
}
private boolean useProxy() {
@ -175,4 +232,90 @@ public class HttpClientHandler implements URLHandler {
private boolean useProxyAuthentication() {
return (_proxyUserName != null && _proxyUserName.trim().length() > 0);
}
private static final class GETInputStream extends InputStream {
private InputStream _is;
private GetMethod _get;
private GETInputStream(GetMethod get) throws IOException {
_get = get;
_is = get.getResponseBodyAsStream();
}
public int available() throws IOException {
return _is.available();
}
public void close() throws IOException {
_is.close();
_get.releaseConnection();
}
public boolean equals(Object obj) {
return _is.equals(obj);
}
public int hashCode() {
return _is.hashCode();
}
public void mark(int readlimit) {
_is.mark(readlimit);
}
public boolean markSupported() {
return _is.markSupported();
}
public int read() throws IOException {
return _is.read();
}
public int read(byte[] b, int off, int len) throws IOException {
return _is.read(b, off, len);
}
public int read(byte[] b) throws IOException {
return _is.read(b);
}
public void reset() throws IOException {
_is.reset();
}
public long skip(long n) throws IOException {
return _is.skip(n);
}
public String toString() {
return _is.toString();
}
}
private static final class HttpClientHelper3x implements HttpClientHelper {
private HttpClientHelper3x() {
}
public long getResponseContentLength(HeadMethod head) {
return head.getResponseContentLength();
}
}
private static final class HttpClientHelper2x implements HttpClientHelper {
private HttpClientHelper2x() {
}
public long getResponseContentLength(HeadMethod head) {
Header header = head.getResponseHeader("Content-Length");
if (header != null) {
try {
return Integer.parseInt(header.getValue());
} catch (NumberFormatException e) {
Message.verbose("Invalid content-length value: " + e.getMessage());
}
}
return 0;
}
}
public interface HttpClientHelper {
long getResponseContentLength(HeadMethod head);
}
}

View File

@ -20,22 +20,84 @@ import fr.jayasoft.ivy.util.CopyProgressListener;
*
*/
public interface URLHandler {
public static class URLInfo {
private long _contentLength;
private long _lastModified;
private boolean _available;
protected URLInfo(boolean available, long contentLength, long lastModified) {
_available = available;
_contentLength = contentLength;
_lastModified = lastModified;
}
public boolean isReachable() {
return _available;
}
public long getContentLength() {
return _contentLength;
}
public long getLastModified() {
return _lastModified;
}
}
public static final URLInfo UNAVAILABLE = new URLInfo(false, 0,0);
/**
* Returns true if the given url is reachable, and without
* error code in case of http urls.
* Please prefer getURLInfo when several infos are needed.
* @param url the url to check
* @return true if the given url is reachable
* @return true if the target is reachable
*/
public boolean isReachable(URL url);
/**
* Returns true if the given url is reachable, and without
* Please prefer getURLInfo when several infos are needed.
* @param url the url to check
* @return true if the target is reachable
*/
public boolean isReachable(URL url, int timeout);
/**
* Returns the length of the target if the given url is reachable, and without
* error code in case of http urls.
* Please prefer getURLInfo when several infos are needed.
* @param url the url to check
* @return the length of the target if available, 0 if not reachable
*/
public long getContentLength(URL url);
/**
* Returns the length of the target if the given url is reachable, and without
* error code in case of http urls.
* @param url the url to check
* @param timeout the maximum time before considering an url is not reachable
* a timeout of zero indicates no timeout
* @return true if the given url is reachable
* @return the length of the target if available, 0 if not reachable
*/
public boolean isReachable(URL url, int timeout);
public long getContentLength(URL url, int timeout);
/**
* Please prefer getURLInfo when several infos are needed.
* @param url the url to check
* @return last modified timestamp of the given url
*/
public long getLastModified(URL url);
/**
* Please prefer getURLInfo when several infos are needed.
* @param url the url to check
* @return last modified timestamp of the given url
*/
public long getLastModified(URL url, int timeout);
/**
* never returns null, return UNAVAILABLE when url is not reachable
* @param url
* @return
*/
public URLInfo getURLInfo(URL url);
/**
* never returns null, return UNAVAILABLE when url is not reachable
* @param url
* @return
*/
public URLInfo getURLInfo(URL url, int timeout);
public InputStream openStream(URL url) throws IOException;
public void download(URL src, File dest, CopyProgressListener l) throws IOException;
}

View File

@ -35,6 +35,30 @@ public class URLHandlerDispatcher implements URLHandler {
return getHandler(url.getProtocol()).isReachable(url, timeout);
}
public long getContentLength(URL url) {
return getHandler(url.getProtocol()).getContentLength(url);
}
public long getContentLength(URL url, int timeout) {
return getHandler(url.getProtocol()).getContentLength(url, timeout);
}
public long getLastModified(URL url) {
return getHandler(url.getProtocol()).getLastModified(url);
}
public long getLastModified(URL url, int timeout) {
return getHandler(url.getProtocol()).getLastModified(url, timeout);
}
public URLInfo getURLInfo(URL url) {
return getHandler(url.getProtocol()).getURLInfo(url);
}
public URLInfo getURLInfo(URL url, int timeout) {
return getHandler(url.getProtocol()).getURLInfo(url, timeout);
}
public InputStream openStream(URL url) throws IOException {
return getHandler(url.getProtocol()).openStream(url);
}