package com.limegroup.gnutella.archive;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.PostMethod;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
class ArchiveRequest {
private final String _url;
private final NameValuePair[] _parameters;
private PostMethod _post;
private ArchiveResponse _response;
/* no default constructor */
private ArchiveRequest() {
_url = null;
_parameters = null;
}
ArchiveRequest( String url, NameValuePair[] parameters ) {
_url = url;
_parameters = parameters;
}
/**
*
* @throws BadResponseException
* @throws HttpException
* @throws IOException
*
* @throws IllegalStateException
* If java's xml parser is broken
*/
void execute() throws BadResponseException, HttpException,
IOException {
final PostMethod post = new PostMethod( _url );
post.addRequestHeader("Content-type","application/x-www-form-urlencoded");
post.addRequestHeader("Accept","text/plain");
post.addParameters( _parameters );
final HttpClient client = new HttpClient();
synchronized(this) {
_post = post;
}
client.executeMethod( post );
final String responseString = post.getResponseBodyAsString();
final InputStream responseStream = post.getResponseBodyAsStream();
synchronized(this) {
_post = null;
}
post.releaseConnection();
/*
* kinds of responses we might get back:
*
* <result type="..."> <url>...</url></result>
*
* <result type="..." code="..."><message>...</message></result>
* (result's code attribute is optional)
*
* <result type="..."> <message>...</message> </result> <url> ... </url>
*
* url element can be inside or outside result element
*
*/
final String RESULT_ELEMENT = "result";
final String TYPE_ATTR = "type";
final String CODE_ATTR = "code";
final String URL_ELEMENT = "url";
final String MESSAGE_ELEMENT = "message";
final DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
factory.setIgnoringComments( true );
factory.setCoalescing( true );
final DocumentBuilder parser;
final Document document;
try {
parser = factory.newDocumentBuilder();
document = parser.parse( responseStream );
} catch (final ParserConfigurationException e) {
final IllegalStateException ise = new IllegalStateException();
ise.initCause(e);
throw ise;
} catch (final SAXException e) {
throw new BadResponseException(e);
} catch (final IOException e) {
throw (e);
} finally {
responseStream.close();
}
final Element resultElement = _findChildElement( document, RESULT_ELEMENT );
if ( resultElement == null ) {
throw new BadResponseException( "No top level element <" +
RESULT_ELEMENT + ">\n" + responseString );
}
final String type = resultElement.getAttribute( TYPE_ATTR );
if ( type.equals( "" ) ) {
throw new BadResponseException( "<" + RESULT_ELEMENT +
"> element does not have a \"" + TYPE_ATTR + "" +
"\" attribute\n" + responseString );
}
final String code = resultElement.getAttribute( CODE_ATTR );
final String message = _findChildElementsText( resultElement, MESSAGE_ELEMENT );
String url = _findChildElementsText( resultElement, URL_ELEMENT );
if ( url.equals( "" ) ) {
// ok, look for it outside the <result> element
url = _findChildElementsText( document, URL_ELEMENT );
}
_response = new ArchiveResponse( type, code, message, url );
}
synchronized void cancel() {
if ( _post != null ) {
_post.abort();
_post = null;
}
}
/**
* @throws IllegalStateException
* if you didn't (successfully) call execute() before calling getResponse()
* @return
*/
ArchiveResponse getResponse() {
if ( _response == null ) {
throw new IllegalStateException( "call execute() before calling getResponse()" );
}
return _response;
}
/** helper function */
private static Element _findChildElement( Node parent, String name ) {
Node n = parent.getFirstChild();
for ( ; n != null; n = n.getNextSibling() ) {
if ( n.getNodeType() == Node.ELEMENT_NODE
&& n.getNodeName().equals( name )) {
return (Element) n;
}
}
return null;
}
private static String _findText( Node parent ) {
for ( Node n = parent.getFirstChild();
n != null; n = n.getNextSibling()) {
if (n.getNodeType() == Node.TEXT_NODE ) {
return n.getNodeValue();
}
}
return "";
}
private static String _findChildElementsText( Node parent, String name ) {
final Element e = _findChildElement( parent, name );
if ( e == null ) {
return "";
} else {
return _findText( e );
}
}
}