/*
* Copyright (c) 2015 EMC Corporation
* All Rights Reserved
*/
package com.emc.vipr.client.impl.jaxb;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.SAXParser;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.sax.SAXSource;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.XMLFilterImpl;
import com.emc.vipr.client.util.ItemProcessor;
public class ListProcessor<T> {
private SAXParser saxParser;
private DocumentBuilder documentBuilder;
private Transformer transformer;
private Unmarshaller unmarshaller;
private ItemProcessor<T> itemProcessor;
protected ListProcessor() {
}
public ListProcessor(Unmarshaller unmarshaller, ItemProcessor<T> itemProcessor) {
this.unmarshaller = unmarshaller;
this.itemProcessor = itemProcessor;
}
public ListProcessor(Class<T> itemClass, ItemProcessor<T> itemProcessor) {
this.unmarshaller = XmlUtils.createUnmarshaller(itemClass);
this.itemProcessor = itemProcessor;
}
public SAXParser getSAXParser() {
if (saxParser == null) {
saxParser = XmlUtils.createSAXParser();
}
return saxParser;
}
public void setSAXParser(SAXParser saxParser) {
this.saxParser = saxParser;
}
public DocumentBuilder getDocumentBuilder() {
if (documentBuilder == null) {
documentBuilder = XmlUtils.createDocumentBuilder();
}
return documentBuilder;
}
public void setDocumentBuilder(DocumentBuilder documentBuilder) {
this.documentBuilder = documentBuilder;
}
public Transformer getTransformer() {
if (transformer == null) {
transformer = XmlUtils.createTransformer();
}
return transformer;
}
public void setTransformer(Transformer transformer) {
this.transformer = transformer;
}
public void process(InputStream in) throws IOException, SAXException, TransformerException {
try {
ItemFilter filter = new ItemFilter();
SAXSource source = filter.createSource(in);
DOMResult result = filter.createResult();
getTransformer().transform(source, result);
} finally {
in.close();
}
}
protected void startItems() throws Exception {
itemProcessor.startItems();
}
protected void endItems() throws Exception {
itemProcessor.endItems();
}
protected void processItem(Element e) throws Exception {
@SuppressWarnings("unchecked")
T item = (T) unmarshaller.unmarshal(e);
itemProcessor.processItem(item);
}
protected class ItemFilter extends XMLFilterImpl {
private int depth;
private Document itemDocument;
public SAXSource createSource(InputStream in) throws SAXException {
setParent(getSAXParser().getXMLReader());
return new SAXSource(this, new InputSource(in));
}
public DOMResult createResult() {
itemDocument = getDocumentBuilder().newDocument();
return new DOMResult(itemDocument);
}
@Override
public void startDocument() throws SAXException {
super.startDocument();
try {
startItems();
} catch (Exception e) {
throw new SAXException(e);
}
}
@Override
public void endDocument() throws SAXException {
super.endDocument();
try {
endItems();
} catch (Exception e) {
throw new SAXException(e);
}
}
@Override
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
super.startElement(uri, localName, qName, atts);
depth++;
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
depth--;
if (depth == 1) {
Element item = getLastChildElement(itemDocument.getDocumentElement());
try {
processItem(item);
} catch (Exception e) {
throw new SAXException(e);
}
clear(itemDocument.getDocumentElement());
}
}
/**
* Get the last element of the parent. This will be the most recently added element.
*
* @param parent the parent element.
* @return the last element.
*/
private Element getLastChildElement(Element parent) {
NodeList children = parent.getChildNodes();
for (int i = children.getLength() - 1; i >= 0; i--) {
Node child = children.item(i);
if (child.getNodeType() == Node.ELEMENT_NODE) {
return (Element) child;
}
}
return null;
}
/**
* Clears all children of the given element.
*
* @param parent the parent element.
*/
private void clear(Element parent) {
NodeList children = parent.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
parent.removeChild(child);
}
}
}
}