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 */
}
}