package com.limegroup.gnutella.licenses;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.io.StringReader;
import java.net.URI;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.util.EntityUtils;
import org.limewire.http.httpclient.LimeHttpClient;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import com.limegroup.gnutella.util.LimeWireUtils;
/**
* A base license class, implementing common functionality.
*/
public abstract class AbstractLicense implements MutableLicense, Serializable, Cloneable {
private static final Log LOG = LogFactory.getLog(AbstractLicense.class);
private static final long serialVersionUID = 6508972367931096578L;
/** Whether or not this license has been verified. */
protected transient int verified = UNVERIFIED;
/** The URI where verification will be performed. */
protected transient URI licenseLocation;
/** The license name. */
private transient String licenseName;
/** The last time this license was verified. */
private long lastVerifiedTime;
/** Constructs a new AbstractLicense. */
AbstractLicense(URI uri) {
this.licenseLocation = uri;
}
public void setLicenseName(String name) { this.licenseName = name; }
public boolean isVerifying() { return verified == VERIFYING; }
public boolean isVerified() { return verified == VERIFIED; }
public String getLicenseName() { return licenseName; }
public URI getLicenseURI() { return licenseLocation; }
public long getLastVerifiedTime() { return lastVerifiedTime; }
void setVerified(int verified) {
this.verified = verified;
}
void setLastVerifiedTime(long lastVerifiedTime) {
this.lastVerifiedTime = lastVerifiedTime;
}
/**
* Assume that all serialized licenses were verified.
* (Otherwise they wouldn't have been serialized.
*/
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
verified = VERIFIED;
}
/**
* Clears all internal state that could be set while verifying.
*/
protected abstract void clear();
/**
* Retrieves the body of a URL from a webserver.
*
* Returns null if the page could not be found.
*/
protected String getBody(String url, LimeHttpClient httpClient) {
return getBodyFromURL(url, httpClient);
}
/**
* Contacts the given URL and downloads returns the body of the
* HTTP request.
*/
protected String getBodyFromURL(String url, LimeHttpClient httpClient) {
if (LOG.isTraceEnabled())
LOG.trace("Contacting: " + url);
HttpResponse response = null;
try {
HttpGet get = new HttpGet(url);
get.addHeader("User-Agent", LimeWireUtils.getHttpServer());
response = httpClient.execute(get);
String result;
if (response.getEntity() != null) {
result = EntityUtils.toString(response.getEntity());
} else {
result = null;
}
return result;
} catch (IOException e) {
LOG.warn("Can't contact license server: " + url, e);
} finally {
httpClient.releaseConnection(response);
}
return null;
}
/**
* Parses the document node of the XML.
*/
protected abstract void parseDocumentNode(Node node, LicenseCache licenseCache, LimeHttpClient httpClient);
/**
* Attempts to parse the given XML.
* The actual handling of the XML is sent to parseDocumentNode,
* which subclasses can implement as they see fit.
*
* If this is a request directly from our Verifier, 'liveData' is true.
* Subclasses may use this to know where the XML data is coming from.
*/
protected void parseXML(String xml, LicenseCache licenseCache, LimeHttpClient httpClient) {
if(xml == null)
return;
if(LOG.isTraceEnabled())
LOG.trace("Attempting to parse: " + xml);
// TODO propagate exceptions and handle in LicenseVerifier
Document d;
try {
DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
InputSource is = new InputSource(new StringReader(xml));
d = parser.parse(is);
} catch (IOException ioe) {
LOG.debug("IOX parsing XML\n" + xml, ioe);
return;
} catch (SAXException saxe) {
LOG.debug("SAX parsing XML\n" + xml, saxe);
return;
} catch (ParserConfigurationException bad) {
LOG.debug("couldn't instantiate parser", bad);
return;
}
parseDocumentNode(d.getDocumentElement(), licenseCache, httpClient);
}
public void verify(LicenseCache licenseCache, LimeHttpClient httpClient) {
setVerified(AbstractLicense.VERIFYING);
clear();
String body = getBody(getLicenseURI().toString(), httpClient);
parseXML(body, licenseCache, httpClient);
setLastVerifiedTime(System.currentTimeMillis());
setVerified(AbstractLicense.VERIFIED);
licenseCache.addVerifiedLicense(this);
}
}