package au.gov.amsa.ihs.reader;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.log4j.Logger;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import com.google.common.base.Optional;
import rx.Observable.Operator;
import rx.Subscriber;
public class OperatorIhsReader implements Operator<Map<String, String>, InputStream> {
private static final Logger log = Logger.getLogger(OperatorIhsReader.class);
private final String parentElementName;
public OperatorIhsReader(String parentElementName) {
this.parentElementName = parentElementName;
}
@Override
public Subscriber<? super InputStream> call(
final Subscriber<? super Map<String, String>> child) {
return new Subscriber<InputStream>() {
@Override
public void onCompleted() {
child.onCompleted();
}
@Override
public void onError(Throwable e) {
child.onError(e);
}
@Override
public void onNext(InputStream is) {
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
DefaultHandler handler = createHandler(child, parentElementName);
parser.parse(is, handler);
} catch (UnsubscribedSAXException e) {
child.onCompleted();
} catch (Exception e) {
onError(e);
} finally {
try {
is.close();
} catch (IOException e) {
// ignore
}
}
}
};
}
public static class UnsubscribedSAXException extends SAXException {
private static final long serialVersionUID = 1L;
}
public static class MyDefaultHandler extends DefaultHandler {
private int count = 0;
private final Map<String, String> values = new HashMap<String, String>();
private Optional<String> currentElement = Optional.absent();
private final Subscriber<? super Map<String, String>> subscriber;
private final String parentElementName;
public MyDefaultHandler(Subscriber<? super Map<String, String>> subscriber,
String parentElementName) {
this.subscriber = subscriber;
this.parentElementName = parentElementName;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
checkSubscription(subscriber);
if (parentElementName.equals(qName)) {
values.clear();
count++;
if (count % 1000 == 0)
log.info(count + " records read");
}
currentElement = Optional.of(qName);
}
private void checkSubscription(final Subscriber<? super Map<String, String>> subscriber)
throws UnsubscribedSAXException {
if (subscriber.isUnsubscribed())
throw new UnsubscribedSAXException();
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
checkSubscription(subscriber);
String val = new String(ch, start, length).trim();
if (val.length() > 0) {
String currentValue = values.get(currentElement.get());
if (currentValue == null)
values.put(currentElement.get(), val);
else
values.put(currentElement.get(), currentValue + val);
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
checkSubscription(subscriber);
if (parentElementName.equals(qName)) {
try {
subscriber.onNext(new HashMap<>(values));
} catch (RuntimeException e) {
throw new RuntimeException("error building Ship from " + values, e);
}
}
}
}
private static DefaultHandler createHandler(
final Subscriber<? super Map<String, String>> subscriber, String parentElementName) {
return new MyDefaultHandler(subscriber, parentElementName);
}
}