package com.limegroup.gnutella.xml;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.SAXException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.limegroup.gnutella.Response;
@Singleton
public final class LimeXMLDocumentHelper{
private static final Log LOG = LogFactory.getLog(LimeXMLDocumentHelper.class);
public static final String XML_HEADER = "<?xml version=\"1.0\"?>";
public static final String XML_NAMESPACE =
"xsi:noNamespaceSchemaLocation=\"";
private final LimeXMLDocumentFactory limeXMLDocumentFactory;
/**
* Private constructor to ensure that this class can never be instantiated.
*/
@Inject
public LimeXMLDocumentHelper(LimeXMLDocumentFactory limeXMLDocumentFactory) {
this.limeXMLDocumentFactory = limeXMLDocumentFactory;
}
/**
* To be used when a Query Reply comes with a chunk of meta-data
* we want to get LimeXMLDocuments out of it.
*/
public List<LimeXMLDocument[]> getDocuments(String aggregatedXML, int totalResponseCount) {
if(aggregatedXML==null || aggregatedXML.equals("") || totalResponseCount <= 0)
return Collections.emptyList();
List<LimeXMLDocument[]> results = new ArrayList<LimeXMLDocument[]>();
for(String xmlDocument : XMLParsingUtils.split(aggregatedXML)) {
XMLParsingUtils.ParseResult parsingResult;
try {
parsingResult = XMLParsingUtils.parse(xmlDocument,totalResponseCount);
} catch (SAXException sax) {
LOG.warn("SAX while parsing: " + xmlDocument, sax);
continue;// bad xml, ignore
} catch (IOException bad) {
LOG.warn("IOX while parsing: " + aggregatedXML, bad);
return Collections.emptyList(); // abort
}
final String indexKey = parsingResult.canonicalKeyPrefix +
LimeXMLDocumentFactoryImpl.XML_INDEX_ATTRIBUTE;
LimeXMLDocument[] documents = new LimeXMLDocument[totalResponseCount];
for(Map<String, String> attributes : parsingResult) {
String sindex = attributes.remove(indexKey);
if (sindex == null)
return Collections.emptyList();
int index = -1;
try {
index = Integer.parseInt(sindex);
} catch(NumberFormatException bad) { //invalid document
LOG.warn("NFE while parsing", bad);
return Collections.emptyList();
}
if (index >= documents.length || index < 0)
return Collections.emptyList(); // malicious document, can't trust it.
if(!attributes.isEmpty()) {
try {
documents[index] = limeXMLDocumentFactory.createLimeXMLDocument(
attributes, parsingResult.schemaURI, parsingResult.canonicalKeyPrefix);
} catch(IOException ignored) {
LOG.debug("",ignored);
}
}
}
results.add(documents);
}
return results;
}
/**
* Builds an XML string out of all the responses.
* If no responses have XML, an empty string is returned.
*/
public static String getAggregateString(Response... responses) {
Map<LimeXMLSchema, StringBuilder> allXML = new HashMap<LimeXMLSchema, StringBuilder>();
for(int i = 0; i < responses.length; i++) {
LimeXMLDocument doc = responses[i].getDocument();
if(doc != null) {
LimeXMLSchema schema = doc.getSchema();
StringBuilder built = allXML.get(schema);
if(built == null) {
built = new StringBuilder();
allXML.put(schema, built);
}
built.append(doc.getAttributeStringWithIndex(i));
}
}
// Iterate through each schema and build a string containing
// a bunch of XML docs, each beginning with XML_HEADER.
StringBuilder fullXML = new StringBuilder();
for(Map.Entry<LimeXMLSchema, StringBuilder> entry : allXML.entrySet())
buildXML(fullXML, entry.getKey(), entry.getValue().toString());
return fullXML.toString();
}
/**
* Wraps the inner element around the root tags, with the correct
* XML headers.
*/
public static void buildXML(StringBuilder buffer, LimeXMLSchema schema, String inner) {
buffer.append(XML_HEADER);
buffer.append("<");
buffer.append(schema.getRootXMLName());
buffer.append(" ");
buffer.append(XML_NAMESPACE);
buffer.append(schema.getSchemaURI());
buffer.append("\">");
buffer.append(inner);
buffer.append("</");
buffer.append(schema.getRootXMLName());
buffer.append(">");
}
}