package com.limegroup.gnutella.updates;
import java.io.IOException;
import java.io.StringReader;
import org.apache.xerces.parsers.DOMParser;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import com.limegroup.gnutella.Assert;
import com.limegroup.gnutella.settings.ApplicationSettings;
import com.limegroup.gnutella.xml.LimeXMLUtils;
public class UpdateFileParser {
//initilaize this once per class.
private static DOMParser parser = new DOMParser();
/**
* For the first release the only value we need is the new version.
* As we add more data to the update file, we can have the structure be a
* hashmap, and add getter and setter methods.
*/
private String newVersion=null;
private String updateMessage=null;
private boolean usingLocale = true;
private long timestamp;
public UpdateFileParser(String xml) throws SAXException, IOException {
if(xml==null || xml.equals(""))
throw new SAXException("xml is null or empty string");
timestamp = -1l;
InputSource inputSource = new InputSource(new StringReader(xml));
Document d = null;
synchronized(this.parser) {
parser.parse(inputSource);
d = parser.getDocument();
}
if(d==null)//problems parsing?
throw new SAXException("document is null");
populateValues(d);
}
private void populateValues(Document doc) throws IOException {
Element docElement = doc.getDocumentElement();
//Note: We are assuming that the XML structure will have no attributes.
//only child elements. We can make this assumption because we are the
//XML is generated right here in house at LimeWire.
NodeList children = docElement.getChildNodes();
int len = children.getLength();
for(int i=0; i<len; i++) { //parse the nodes.
Node node = children.item(i);
String name = node.getNodeName().toLowerCase().trim();
if(name.equals("version"))
newVersion = LimeXMLUtils.getText(node.getChildNodes());
else if(name.equals("message"))
updateMessage = getLocaleSpecificMessage(node);
else if(name.equals("timestamp")) {
try {
timestamp =
Long.parseLong(LimeXMLUtils.getText(node.getChildNodes()));
} catch (NumberFormatException nfx) {
throw new IOException();
}
}
}
}
/**
* Looks at the child nodes of node, and tries to find the value of the
* message based on the language specified in limewire.props
* If there is no string for the message in that langauge, returns the
* string in English.
* <p>
* If we were not able to find the string as per the language preference,
* we set the value of usingLocale to false.
*/
private String getLocaleSpecificMessage(Node node) {
String locale = ApplicationSettings.LANGUAGE.getValue().toLowerCase();
String defaultMessage=null;
String localeMessage=null;
NodeList children = node.getChildNodes();
int len = children.getLength();
for(int i=0 ; i<len ; i++) {
Node n = children.item(i);
String name = n.getNodeName().toLowerCase().trim();
if(name.equals("en"))
defaultMessage = LimeXMLUtils.getText(n.getChildNodes());
else if(name.equals(locale))
localeMessage = LimeXMLUtils.getText(n.getChildNodes());
}
Assert.that(defaultMessage!=null,"bad xml file signed by LimeWire");
//check if we should send back en or locale
if(locale.equals("en"))
return defaultMessage;
if(localeMessage!=null) //we have a proper string to return
return localeMessage;
usingLocale = false;
return defaultMessage;
}
/**
* @return the value of new version we parsed out of XML. Can return null.
*/
public String getVersion() {
return newVersion;
}
public long getTimestamp() {
return timestamp;
}
/**
* @return true if the message was picked up as per the locale, else false
*/
public boolean usesLocale() {
return usingLocale;
}
/**
* @return the message to show the user.
*/
public String getMessage() {
return updateMessage;
}
}