/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.integration.tool.portfolio.xml;
import java.io.Reader;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.opengamma.OpenGammaRuntimeException;
/**
* Performs a parse of an XML document (via the provided Reader), in order to extract the
* schema version. A StAX parser {@see http://docs.oracle.com/javase/tutorial/jaxp/stax/login.html} is
* used so that the whole document is not read into memory when all the should be required is the
* first few lines of the document.
*/
public class SchemaVersionParser {
private static final String EXPECTED_ROOT_ELEMENT = "og-portfolio";
private static final Logger s_logger = LoggerFactory.getLogger(SchemaVersionParser.class);
private static final QName SCHEMA_VERSION_QNAME = new QName("schemaVersion");
private final Reader _reader;
/**
* Initialise the parser with a reader holding an XML document. The reader is
* expected to be managed by the client, and should be initialised to the start
* of the document.
*
* @param reader reader to read the XML document from
*/
public SchemaVersionParser(Reader reader) {
_reader = reader;
}
/**
* Attempt to read the schema version from the XML document. The root element
* is found, checked and the version number extracted. If any of these operations
* fail then an {@link OpenGammaRuntimeException} will be thrown.
*
* @return the schema version from the xml document
* @throws OpenGammaRuntimeException if parsing the schema version fails
*/
public SchemaVersion parseSchemaVersion() {
try {
StartElement element = findRootElement();
checkRootElement(element, EXPECTED_ROOT_ELEMENT);
return parseVersionFromElement(element);
} catch (XMLStreamException e) {
throw new OpenGammaRuntimeException("Exception whilst trying to parse XML file", e);
}
}
private StartElement findRootElement() throws XMLStreamException {
s_logger.debug("Attempting to find root element for document");
// Work through the elements in the document until we hit a start element
for (XMLEventReader eventReader = createXmlEventReader(); eventReader.hasNext(); ) {
XMLEvent event = eventReader.nextEvent();
if (event.isStartElement()) {
// We've found the first proper element in the document, it may be
// what we're looking for or it may be incorrect but either way we
// don't need to read any more of the file
s_logger.debug("Found root element: [{}]", event);
return (StartElement) event;
}
}
throw new OpenGammaRuntimeException("No root element was found - unable to parse file");
}
private void checkRootElement(StartElement element, String expectedName) {
String elementName = element.getName().getLocalPart();
if (!elementName.equals(expectedName)) {
throw new OpenGammaRuntimeException("Root element should have name [" + expectedName +
"] but instead found [" + elementName +
"] - unable to parse file");
}
}
private SchemaVersion parseVersionFromElement(StartElement element) {
Attribute schemaVersion = element.getAttributeByName(SCHEMA_VERSION_QNAME);
if (schemaVersion != null) {
return new SchemaVersion(schemaVersion.getValue());
} else {
throw new OpenGammaRuntimeException("No schema version was found - unable to parse file");
}
}
private XMLEventReader createXmlEventReader() throws XMLStreamException {
XMLInputFactory factory = XMLInputFactory.newFactory();
factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
factory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
return factory.createXMLEventReader(_reader);
}
}