package com.limegroup.gnutella.xml; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; 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.limegroup.gnutella.Response; 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 constructor to ensure that this class can never be * instantiated. */ private LimeXMLDocumentHelper() {} /** * TO be used when a Query Reply comes with a chunk of meta-data * we want to get LimeXMLDocuments out of it */ public static List getDocuments(String aggregatedXML, int totalResponseCount) { if(aggregatedXML==null || aggregatedXML.equals("") || totalResponseCount <= 0) return Collections.EMPTY_LIST; List results = new ArrayList(); for(Iterator i = XMLParsingUtils.split(aggregatedXML).iterator(); i.hasNext(); ) { String xmlDocument = (String)i.next(); 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.EMPTY_LIST; // abort } final String indexKey = parsingResult.canonicalKeyPrefix + LimeXMLDocument.XML_INDEX_ATTRIBUTE; LimeXMLDocument[] documents = new LimeXMLDocument[totalResponseCount]; for(Iterator j = parsingResult.iterator(); j.hasNext(); ) { Map attributes = (Map)j.next(); String sindex = (String)attributes.remove(indexKey); if (sindex == null) return Collections.EMPTY_LIST; int index = -1; try { index = Integer.parseInt(sindex); } catch(NumberFormatException bad) { //invalid document LOG.warn("NFE while parsing", bad); return Collections.EMPTY_LIST; } if (index >= documents.length || index < 0) return Collections.EMPTY_LIST; // malicious document, can't trust it. if(!attributes.isEmpty()) { try { documents[index] = new LimeXMLDocument(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) { HashMap /* LimeXMLSchema -> StringBuffer */ allXML = new HashMap(); for(int i = 0; i < responses.length; i++) { LimeXMLDocument doc = responses[i].getDocument(); if(doc != null) { LimeXMLSchema schema = doc.getSchema(); StringBuffer built = (StringBuffer)allXML.get(schema); if(built == null) { built = new StringBuffer(); 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. StringBuffer fullXML = new StringBuffer(); for(Iterator i = allXML.entrySet().iterator(); i.hasNext(); ) { Map.Entry entry = (Map.Entry)i.next(); LimeXMLSchema schema = (LimeXMLSchema)entry.getKey(); StringBuffer buffer = (StringBuffer)entry.getValue(); buildXML(fullXML, schema, buffer.toString()); } return fullXML.toString(); } /** * Wraps the inner element around the root tags, with the correct * XML headers. */ public static void buildXML(StringBuffer 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(">"); } }