uri-resolver/src/main/java/org/gcube/datatransfer/resolver/gis/geonetwork/HTTPCallsUtils.java

635 lines
21 KiB
Java

/**
*
*/
package org.gcube.datatransfer.resolver.gis.geonetwork;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.DeleteMethod;
import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
import org.apache.commons.httpclient.methods.FileRequestEntity;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.jdom2.Document;
import org.jdom2.input.SAXBuilder;
/**
* The Class HTTPCallsUtils.
* copied by Geosolution
*
* @author Francesco Mangiacrapa francesco.mangiacrapa@isti.cnr.it
* Apr 5, 2016
*/
public class HTTPCallsUtils {
private static final Logger logger = Logger.getLogger(HTTPCallsUtils.class);
private final String username;
private final String pw;
/**
* This instance is shared among the various calls, so that the
* state (mainly cookies) will be preserved.
*/
private HttpClient client = new HttpClient();
/**
* Some apps may require application/xml, so you can set it to whatever is needed.
*/
private String xmlContentType = "text/xml";
private int lastHttpStatus;
private boolean ignoreResponseContentOnSuccess = false;
/**
* Instantiates a new HTTP utils.
*/
public HTTPCallsUtils() {
this(null, null);
}
/**
* Instantiates a new HTTP utils.
*
* @param userName the user name
* @param password the password
*/
public HTTPCallsUtils(String userName, String password) {
this.username = userName;
this.pw = password;
}
/**
* Sets the xml content type.
*
* @param xmlContentType the new xml content type
*/
public void setXmlContentType(String xmlContentType) {
this.xmlContentType = xmlContentType;
}
/**
* Gets the last http status.
*
* @return the last http status
*/
public int getLastHttpStatus() {
return lastHttpStatus;
}
/**
* Checks if is ignore response content on success.
*
* @return true, if is ignore response content on success
*/
public boolean isIgnoreResponseContentOnSuccess() {
return ignoreResponseContentOnSuccess;
}
/**
* Sets the ignore response content on success.
*
* @param ignoreResponseContentOnSuccess the new ignore response content on success
*/
public void setIgnoreResponseContentOnSuccess(boolean ignoreResponseContentOnSuccess) {
this.ignoreResponseContentOnSuccess = ignoreResponseContentOnSuccess;
}
/**
* Performs an HTTP GET on the given URL.
*
* @param url The URL where to connect to.
* @return The HTTP response as a String if the HTTP response code was 200 (OK).
* @throws MalformedURLException the malformed url exception
*/
public String get(String url) throws MalformedURLException {
GetMethod httpMethod = null;
try {
setAuth(client, url, username, pw);
httpMethod = new GetMethod(url);
client.getHttpConnectionManager().getParams().setConnectionTimeout(5000);
lastHttpStatus = client.executeMethod(httpMethod);
if(lastHttpStatus == HttpStatus.SC_OK) {
InputStream is = httpMethod.getResponseBodyAsStream();
String response = IOUtils.toString(is);
if(response.trim().length()==0) { // sometime gs rest fails
logger.warn("ResponseBody is empty");
return null;
} else {
return response;
}
} else {
logger.info("("+lastHttpStatus+") " + HttpStatus.getStatusText(lastHttpStatus) + " -- " + url );
}
} catch (ConnectException e) {
logger.info("Couldn't connect to ["+url+"]");
} catch (IOException e) {
logger.info("Error talking to ["+url+"]", e);
} finally {
if(httpMethod != null)
httpMethod.releaseConnection();
}
return null;
}
/**
* Performs an HTTP GET on the given URL and return reponse body.
*
* @param url The URL where to connect to.
* @return The HTTP response as a String if the HTTP response code was 200 (OK).
* @throws MalformedURLException the malformed url exception
*/
public InputStream getBody(String url) throws MalformedURLException {
GetMethod httpMethod = null;
try {
setAuth(client, url, username, pw);
httpMethod = new GetMethod(url);
client.getHttpConnectionManager().getParams().setConnectionTimeout(5000);
lastHttpStatus = client.executeMethod(httpMethod);
if(lastHttpStatus == HttpStatus.SC_OK) {
return httpMethod.getResponseBodyAsStream();
} else {
logger.info("("+lastHttpStatus+") " + HttpStatus.getStatusText(lastHttpStatus) + " -- " + url );
}
} catch (ConnectException e) {
logger.info("Couldn't connect to ["+url+"]");
} catch (IOException e) {
logger.info("Error talking to ["+url+"]", e);
} finally {
if(httpMethod != null)
httpMethod.releaseConnection();
}
return null;
}
//==========================================================================
//=== PUT
//==========================================================================
/**
* Gets the client.
*
* @return the client
*/
public HttpClient getClient() {
return client;
}
/**
* PUTs a String representing an XML document to the given URL.
*
* @param url The URL where to connect to.
* @param content The XML content to be sent as a String.
* @return The HTTP response as a String if the HTTP response code was 200 (OK).
* the HTTP response or <TT>null</TT> on errors.
*/
public String putXml(String url, String content) {
return put(url, content, xmlContentType);
}
/**
* PUTs a File to the given URL.
*
* @param url The URL where to connect to.
* @param file The File to be sent.
* @param contentType The content-type to advert in the PUT.
* @return The HTTP response as a String if the HTTP response code was 200 (OK).
* the HTTP response or <TT>null</TT> on errors.
*/
public String put(String url, File file, String contentType) {
return put(url, new FileRequestEntity(file, contentType));
}
/**
* PUTs a String to the given URL.
*
* @param url The URL where to connect to.
* @param content The content to be sent as a String.
* @param contentType The content-type to advert in the PUT.
* @return The HTTP response as a String if the HTTP response code was 200 (OK).
* the HTTP response or <TT>null</TT> on errors.
*/
public String put(String url, String content, String contentType) {
try {
return put(url, new StringRequestEntity(content, contentType, null));
} catch (UnsupportedEncodingException ex) {
logger.error("Cannot PUT " + url, ex);
return null;
}
}
/**
* Performs a PUT to the given URL.
*
* @param url The URL where to connect to.
* @param requestEntity The request to be sent.
* @return The HTTP response as a String if the HTTP response code was 200 (OK).
* the HTTP response or <TT>null</TT> on errors.
*/
public String put(String url, RequestEntity requestEntity) {
return send(new PutMethod(url), url, requestEntity);
}
//==========================================================================
//=== POST
//==========================================================================
/**
* POSTs a String representing an XML document to the given URL.
*
* @param url The URL where to connect to.
* @param content The XML content to be sent as a String.
* @return The HTTP response as a String if the HTTP response code was 200 (OK).
* the HTTP response or <TT>null</TT> on errors.
*/
public String postXml(String url, String content) {
return post(url, content, xmlContentType);
}
/**
* POSTs a Stream content representing an XML document to the given URL.
*
* @param url The URL where to connect to.
* @param content The content to be sent as an InputStream.
* @return The HTTP response as a String if the HTTP response code was 200 (OK).
* the HTTP response or <TT>null</TT> on errors.
*/
public String postXml(String url, InputStream content) {
return post(url, content, xmlContentType);
}
/**
* POSTs a File to the given URL.
*
* @param url The URL where to connect to.
* @param file The File to be sent.
* @param contentType The content-type to advert in the POST.
* @return The HTTP response as a String if the HTTP response code was 200 (OK).
* the HTTP response or <TT>null</TT> on errors.
*/
public String post(String url, File file, String contentType) {
return post(url, new FileRequestEntity(file, contentType));
}
/**
* POSTs a String to the given URL.
*
* @param url The URL where to connect to.
* @param content The content to be sent as a String.
* @param contentType The content-type to advert in the POST.
* @return The HTTP response as a String if the HTTP response code was 200 (OK).
* the HTTP response or <TT>null</TT> on errors.
*/
public String post(String url, String content, String contentType) {
try {
return post(url, new StringRequestEntity(content, contentType, null));
} catch (UnsupportedEncodingException ex) {
logger.error("Cannot POST " + url, ex);
return null;
}
}
/**
* POSTs a Stream content to the given URL.
*
* @param url The URL where to connect to.
* @param content The content to be sent as an InputStream.
* @param contentType The content-type to advert in the POST.
* @return The HTTP response as a String if the HTTP response code was 200 (OK).
* the HTTP response or <TT>null</TT> on errors.
*/
public String post(String url, InputStream content, String contentType) {
return post(url, new InputStreamRequestEntity(content, contentType));
}
/**
* Performs a POST to the given URL.
* <BR>Basic auth is used if both username and pw are not null.
*
* @param url The URL where to connect to.
* @param requestEntity The request to be sent.
* @return The HTTP response as a String if the HTTP response code was 200 (OK).
* the HTTP response or <TT>null</TT> on errors.
*/
public String post(String url, RequestEntity requestEntity) {
return send(new PostMethod(url), url, requestEntity);
}
//==========================================================================
//=== HTTP requests
//==========================================================================
/**
* Send an HTTP request (PUT or POST) to a server.
* <BR>Basic auth is used if both username and pw are not null.
* <P>
* Only <UL>
* <LI>200: OK</LI>
* <LI>201: ACCEPTED</LI>
* <LI>202: CREATED</LI>
* </UL> are accepted as successful codes; in these cases the response string will be returned.
*
* @param httpMethod the http method
* @param url the url
* @param requestEntity the request entity
* @return the HTTP response or <TT>null</TT> on errors.
*/
protected String send(final EntityEnclosingMethod httpMethod, String url, RequestEntity requestEntity) {
try {
setAuth(client, url, username, pw);
client.getHttpConnectionManager().getParams().setConnectionTimeout(5000);
if(requestEntity != null)
httpMethod.setRequestEntity(requestEntity);
lastHttpStatus = client.executeMethod(httpMethod);
switch(lastHttpStatus) {
case HttpURLConnection.HTTP_OK:
case HttpURLConnection.HTTP_CREATED:
case HttpURLConnection.HTTP_ACCEPTED:
if(logger.isDebugEnabled())
logger.debug("HTTP "+ httpMethod.getStatusText() + " <-- " + url);
if(ignoreResponseContentOnSuccess)
return "";
String response = IOUtils.toString(httpMethod.getResponseBodyAsStream());
return response;
default:
String badresponse = IOUtils.toString(httpMethod.getResponseBodyAsStream());
String message = getGeoNetworkErrorMessage(badresponse);
logger.warn("Bad response: "+lastHttpStatus
+ " " + httpMethod.getStatusText()
+ " -- " + httpMethod.getName()
+ " " +url
+ " : "
+ message
);
if(logger.isDebugEnabled())
logger.debug("GeoNetwork response:\n"+badresponse);
return null;
}
} catch (ConnectException e) {
logger.info("Couldn't connect to ["+url+"]");
return null;
} catch (IOException e) {
logger.error("Error talking to " + url + " : " + e.getLocalizedMessage());
return null;
} finally {
if(httpMethod != null)
httpMethod.releaseConnection();
}
}
/**
* Send an HTTP request (PUT or POST) to a server.
* <BR>Basic auth is used if both username and pw are not null.
* <P>
* Only <UL>
* <LI>200: OK</LI>
* <LI>201: ACCEPTED</LI>
* <LI>202: CREATED</LI>
* </UL> are accepted as successful codes; in these cases the response string will be returned.
*
* @param httpMethod the http method
* @param url the url
* @param requestEntity the request entity
* @return the HTTP response or <TT>null</TT> on errors.
*/
protected InputStream sendPost(final EntityEnclosingMethod httpMethod, String url, RequestEntity requestEntity) {
try {
setAuth(client, url, username, pw);
client.getHttpConnectionManager().getParams().setConnectionTimeout(5000);
if(requestEntity != null)
httpMethod.setRequestEntity(requestEntity);
lastHttpStatus = client.executeMethod(httpMethod);
switch(lastHttpStatus) {
case HttpURLConnection.HTTP_OK:
case HttpURLConnection.HTTP_CREATED:
case HttpURLConnection.HTTP_ACCEPTED:
if(logger.isDebugEnabled())
logger.debug("HTTP "+ httpMethod.getStatusText() + " <-- " + url);
return httpMethod.getResponseBodyAsStream();
default:
logger.warn("Bad response: "+lastHttpStatus
+ " " + httpMethod.getStatusText()
+ " -- " + httpMethod.getName()
+ " " +url
);
return httpMethod.getResponseBodyAsStream();
}
} catch (ConnectException e) {
logger.info("Couldn't connect to ["+url+"]");
return null;
} catch (IOException e) {
logger.error("Error talking to " + url + " : " + e.getLocalizedMessage());
return null;
} finally {
if(httpMethod != null)
httpMethod.releaseConnection();
}
}
/**
* Delete.
*
* @param url the url
* @return true, if successful
*/
public boolean delete(String url) {
DeleteMethod httpMethod = null;
try {
// HttpClient client = new HttpClient();
setAuth(client, url, username, pw);
httpMethod = new DeleteMethod(url);
client.getHttpConnectionManager().getParams().setConnectionTimeout(5000);
lastHttpStatus = client.executeMethod(httpMethod);
String response = "";
if(lastHttpStatus == HttpStatus.SC_OK) {
if(logger.isDebugEnabled())
logger.debug("("+lastHttpStatus+") " + httpMethod.getStatusText() + " -- " + url );
if( ! ignoreResponseContentOnSuccess) {
InputStream is = httpMethod.getResponseBodyAsStream();
response = IOUtils.toString(is);
if(response.trim().equals("")) {
if(logger.isDebugEnabled())
logger.debug("ResponseBody is empty (this may be not an error since we just performed a DELETE call)");
}
}
return true;
} else {
logger.info("("+lastHttpStatus+") " + httpMethod.getStatusText() + " -- " + url );
logger.info("Response: '"+response+"'" );
}
} catch (ConnectException e) {
logger.info("Couldn't connect to ["+url+"]");
} catch (IOException e) {
logger.info("Error talking to ["+url+"]", e);
} finally {
if(httpMethod != null)
httpMethod.releaseConnection();
}
return false;
}
/**
* Http ping.
*
* @param url the url
* @return true if the server response was an HTTP_OK
*/
public boolean httpPing(String url) {
GetMethod httpMethod = null;
try {
// HttpClient client = new HttpClient();
setAuth(client, url, username, pw);
httpMethod = new GetMethod(url);
client.getHttpConnectionManager().getParams().setConnectionTimeout(2000);
lastHttpStatus = client.executeMethod(httpMethod);
if(lastHttpStatus != HttpStatus.SC_OK) {
logger.warn("PING failed at '"+url+"': ("+lastHttpStatus+") " + httpMethod.getStatusText());
return false;
} else {
return true;
}
} catch (ConnectException e) {
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
} finally {
if(httpMethod != null)
httpMethod.releaseConnection();
}
}
/**
* Used to query for REST resources.
*
* @param url The URL of the REST resource to query about.
* @return true on 200, false on 404.
*/
public boolean exists(String url) {
GetMethod httpMethod = null;
try {
// HttpClient client = new HttpClient();
setAuth(client, url, username, pw);
httpMethod = new GetMethod(url);
client.getHttpConnectionManager().getParams().setConnectionTimeout(2000);
lastHttpStatus = client.executeMethod(httpMethod);
switch(lastHttpStatus) {
case HttpStatus.SC_OK:
return true;
case HttpStatus.SC_NOT_FOUND:
return false;
default:
throw new RuntimeException("Unhandled response status at '"+url+"': ("+lastHttpStatus+") " + httpMethod.getStatusText());
}
} catch (ConnectException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if(httpMethod != null)
httpMethod.releaseConnection();
}
}
/**
* Sets the auth.
*
* @param client the client
* @param url the url
* @param username the username
* @param pw the pw
* @throws MalformedURLException the malformed url exception
*/
private static void setAuth(HttpClient client, String url, String username, String pw) throws MalformedURLException {
URL u = new URL(url);
if(username != null && pw != null) {
Credentials defaultcreds = new UsernamePasswordCredentials(username, pw);
client.getState().setCredentials(new AuthScope(u.getHost(), u.getPort()), defaultcreds);
client.getParams().setAuthenticationPreemptive(true); // GS2 by default always requires authentication
} else {
if(logger.isTraceEnabled()) {
logger.trace("Not setting credentials to access to " + url);
}
}
}
/**
* Gets the geo network error message.
*
* @param msg the msg
* @return the geo network error message
*/
protected static String getGeoNetworkErrorMessage(String msg) {
try {
SAXBuilder builder = new SAXBuilder();
Document error = builder.build(new StringReader(msg));
return error.getRootElement().getChildText("message");
} catch (Exception ex) {
return "-";
}
}
/**
* Gets the geo network error message.
*
* @param msg the msg
* @return the geo network error message
*/
protected static String getGeoNetworkErrorMessage(InputStream msg) {
try {
SAXBuilder builder = new SAXBuilder();
Document error = builder.build(msg);
return error.getRootElement().getChildText("message");
} catch (Exception ex) {
return "-";
}
}
}