package de.uni_passau.fim.pkjab.model.xmpp; import java.io.IOException; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.Locator; import org.xml.sax.SAXException; import de.uni_passau.fim.pkjab.model.InvalidXMLException; import de.uni_passau.fim.pkjab.model.RestartStreamException; import de.uni_passau.fim.pkjab.model.UnknownXMLException; import de.uni_passau.fim.pkjab.model.ConnectionCallback; import de.uni_passau.fim.pkjab.model.tags.AbstractXMLTag; import de.uni_passau.fim.pkjab.model.tags.XMLTag; import de.uni_passau.fim.pkjab.util.Stack; abstract class XMPPReaderAdapter implements ContentHandler { protected static final String JABBER_URI = "jabber:client"; protected final ConnectionCallback connection; final Stack xmlStack; // <AbstractXMLTag> private final int offset; private final String namespace; private StringBuffer contentCharacters = null; protected XMPPReaderAdapter(final ConnectionCallback connection, final Stack xmlStack, final String namespace) { this.connection = connection; this.xmlStack = xmlStack; this.offset = Math.max(0, xmlStack.size()-1); this.namespace = namespace; } public void characters(char[] ch, int start, int length) throws SAXException { if (contentCharacters == null) { contentCharacters = new StringBuffer(); } contentCharacters.append(ch, start, length); } public void startDocument() throws SAXException { xmlStack.clear(); } public void endDocument() throws SAXException { System.err.println("XML ended!"); throw new RestartStreamException(); } public final void startElement(String uri, String localName, String name, Attributes atts) throws SAXException { AbstractXMLTag lastTag = xmlStack.peek(); XMLTag thisTag = new XMLTag(localName, uri); xmlStack.add(thisTag); System.out.println("startElement: " + thisTag); // switch over xml tree depth and handle tags // if unsuccessful, an exception is thrown if (!startElement(xmlStack, thisTag, lastTag, atts)) { // during Development, ignore unknown tags: System.out.println("Defaulting to ignore for unhandled tag " + thisTag); XMPPReaderAdapter newHandler = new XMPPReaderIgnore(this, null); connection.setXMPPReader(newHandler); newHandler.startElement(xmlStack, thisTag, null, atts); // throw new UnknownXMLException(xmlStack); } } protected final boolean startElement(Stack xmlStack, AbstractXMLTag thisTag, AbstractXMLTag lastTag, Attributes atts) throws SAXException { boolean result; int oldStackSize = xmlStack.size(); if ((namespace == null) || namespace.equals(thisTag.uri) || (thisTag.uri == null)) { switch (oldStackSize-offset) { case 1: result = startTopLevel(xmlStack, thisTag, atts); break; case 2: result = startChild(xmlStack, thisTag, atts); break; case 3: result = startGrandchild(xmlStack, thisTag, atts); break; default: result = startFurtherChild(xmlStack, thisTag, lastTag, atts); } } else { System.out.println("Defaulting to ignore for other namespace " + thisTag.uri); XMPPReaderAdapter newHandler = new XMPPReaderIgnore(this, null); connection.setXMPPReader(newHandler); result = newHandler.startElement(xmlStack, thisTag, null, atts); } if (oldStackSize != xmlStack.size()) { throw new Error(); } return result; } protected abstract boolean startTopLevel(Stack xmlStack, AbstractXMLTag thisTag, Attributes atts) throws SAXException; protected abstract boolean startChild(Stack xmlStack, AbstractXMLTag thisTag, Attributes atts) throws SAXException; protected abstract boolean startGrandchild(Stack xmlStack, AbstractXMLTag thisTag, Attributes atts) throws SAXException; protected abstract boolean startFurtherChild(Stack xmlStack, AbstractXMLTag thisTag, AbstractXMLTag lastTag, Attributes atts) throws SAXException; public final void endElement(String uri, String localName, String name) throws SAXException { System.out.println("endElement: " + localName + "(" + uri + ")"); AbstractXMLTag thisTag = xmlStack.pop(); if (!(uri.equals(thisTag.uri) && localName.equals(thisTag.getName()))) { // XML error, a tag is closed that was not opened xmlStack.add(thisTag); throw new InvalidXMLException(xmlStack, new XMLTag(localName, uri)); } AbstractXMLTag lastTag = xmlStack.peek(); String content = contentCharacters != null ? contentCharacters.toString() : null; contentCharacters = null; try { boolean result; int oldStackSize = xmlStack.size(); switch (oldStackSize-offset) { case 0: result = endTopLevel(thisTag, content); break; case 1: result = endChild(xmlStack, thisTag, content); break; case 2: result = endGrandchild(xmlStack, thisTag, content); break; default: result = endFurtherChild(xmlStack, thisTag, lastTag, content); } if (oldStackSize != xmlStack.size()) { throw new Error(); } if (!result) { // TODO: what to do here? // assert false : "Only happens if we forgot to handle a tag here that was handled in startElement()"; xmlStack.add(thisTag); throw new UnknownXMLException(xmlStack); } } catch (IOException e) { throw new SAXException(e); } } protected abstract boolean endTopLevel(AbstractXMLTag thisTag, String content) throws IOException, SAXException; protected abstract boolean endChild(Stack xmlStack, AbstractXMLTag thisTag, String content) throws IOException, SAXException; protected abstract boolean endGrandchild(Stack xmlStack, AbstractXMLTag thisTag, String content) throws IOException, SAXException; protected abstract boolean endFurtherChild(Stack xmlStack, AbstractXMLTag thisTag, AbstractXMLTag lastTag, String content) throws IOException, SAXException; public void endPrefixMapping(String prefix) throws SAXException { /* ignore */ } public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { /* ignore */ } public void processingInstruction(String target, String data) throws SAXException { /* ignore */ } public void setDocumentLocator(Locator locator) { /* ignore */ } public void skippedEntity(String name) throws SAXException { /* ignore */ } public void startPrefixMapping(String prefix, String uri) throws SAXException { /* ignore */ } }