/*
* citygml4j - The Open Source Java API for CityGML
* https://github.com/citygml4j
*
* Copyright 2013-2017 Claus Nagel <claus.nagel@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.citygml4j.builder.jaxb.xml.io.reader;
import java.io.InputStream;
import java.net.URI;
import java.util.NoSuchElementException;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.UnmarshallerHandler;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.sax.SAXResult;
import org.citygml4j.builder.jaxb.xml.io.reader.XMLElementChecker.ElementInfo;
import org.citygml4j.model.citygml.CityGML;
import org.citygml4j.model.common.base.ModelObject;
import org.citygml4j.model.common.base.ModelType;
import org.citygml4j.model.gml.feature.AbstractFeature;
import org.citygml4j.util.internal.xml.TransformerChain;
import org.citygml4j.util.xml.SAXEventBuffer;
import org.citygml4j.util.xml.StAXStream2SAX;
import org.citygml4j.xml.io.reader.CityGMLReadException;
import org.citygml4j.xml.io.reader.CityGMLReader;
import org.citygml4j.xml.io.reader.MissingADESchemaException;
import org.citygml4j.xml.io.reader.ParentInfo;
import org.citygml4j.xml.io.reader.XMLChunk;
import org.xml.sax.SAXException;
public class JAXBSimpleReader extends AbstractJAXBReader implements CityGMLReader {
private boolean iterator;
private ElementInfo elementInfo;
public JAXBSimpleReader(XMLStreamReader reader, InputStream in, JAXBInputFactory factory, URI baseURI) throws CityGMLReadException {
super(reader, in, factory, baseURI);
jaxbUnmarshaller.setParseSchema(parseSchema);
}
public void close() throws CityGMLReadException {
super.close();
elementInfo = null;
}
public synchronized boolean hasNext() throws CityGMLReadException {
iterator = false;
elementInfo = null;
try {
while (reader.hasNext()) {
if (reader.getEventType() == XMLStreamConstants.START_ELEMENT) {
// keep track of schema documents
if (parseSchema) {
for (int i = 0; i < reader.getAttributeCount(); i++) {
if (reader.getAttributeLocalName(i).equals("schemaLocation"))
parseSchema(reader.getAttributeValue(i));
else if (reader.getAttributeLocalName(i).equals("noNamespaceSchemaLocation"))
schemaHandler.parseSchema("", reader.getAttributeValue(i));
}
}
elementInfo = elementChecker.getCityGMLFeature(reader.getName(), isFilteredReader());
if (elementInfo != null && elementInfo.isFeature()) {
if (!isFilteredReader() || filter.accept(elementInfo.getType())) {
iterator = true;
break;
}
else {
// consume events until corresponding end element
for (int depth = 1; depth > 0; ) {
reader.next();
if (reader.getEventType() == XMLStreamConstants.START_ELEMENT)
depth++;
else if (reader.getEventType() == XMLStreamConstants.END_ELEMENT)
depth--;
}
}
}
}
reader.next();
}
} catch (XMLStreamException e) {
throw new CityGMLReadException("Caused by: ", e);
} catch (SAXException e) {
throw new CityGMLReadException("Caused by: ", e);
}
return iterator;
}
public synchronized CityGML nextFeature() throws CityGMLReadException {
CityGML next = null;
if (iterator || hasNext()) {
try {
Unmarshaller unmarshaller = factory.builder.getJAXBContext().createUnmarshaller();
// validate input
if (useValidation) {
unmarshaller.setSchema(validationSchemaHandler.getSchema());
if (validationEventHandler != null)
unmarshaller.setEventHandler(validationEventHandler);
}
// unmarshal input
Object result = null;
if (transformerChainFactory == null)
result = unmarshaller.unmarshal(reader);
else {
// create a unmarshaller handler and make it the target of the transformer chain
UnmarshallerHandler handler = unmarshaller.getUnmarshallerHandler();
TransformerChain chain = transformerChainFactory.buildChain();
chain.tail().setResult(new SAXResult(handler));
// the entire document has to be copied to a sax buffer
SAXEventBuffer buffer = new SAXEventBuffer();
StAXStream2SAX mapper = new StAXStream2SAX(buffer);
// map all stax events to the sax buffer
mapper.bridgeEvent(reader);
for (int depth = 1; depth > 0; ) {
reader.next();
mapper.bridgeEvent(reader);
if (reader.getEventType() == XMLStreamConstants.START_ELEMENT)
depth++;
else if (reader.getEventType() == XMLStreamConstants.END_ELEMENT)
depth--;
}
// send the sax buffer to the first template in the chain
chain.head().startDocument();
buffer.send(chain.head(), true);
chain.head().endDocument();
result = handler.getResult();
}
// release memory
unmarshaller = null;
if (result instanceof JAXBElement<?>) {
ModelObject citygml = jaxbUnmarshaller.unmarshal((JAXBElement<?>)result);
if (citygml.getModelType() == ModelType.CITYGML && citygml instanceof AbstractFeature)
next = (CityGML)citygml;
}
} catch (JAXBException e) {
throw new CityGMLReadException("Caused by: ", e);
} catch (SAXException e) {
throw new CityGMLReadException("Caused by: ", e);
} catch (MissingADESchemaException e) {
throw new CityGMLReadException("Caused by: ", e);
} catch (TransformerConfigurationException e) {
throw new CityGMLReadException("Caused by: ", e);
} catch (XMLStreamException e) {
throw new CityGMLReadException("Caused by: ", e);
}
}
if (next == null)
throw new NoSuchElementException();
else {
iterator = false;
return next;
}
}
public synchronized XMLChunk nextChunk() throws CityGMLReadException {
XMLChunkImpl next = null;
if (iterator || hasNext()) {
try {
next = new XMLChunkImpl(this, null, elementInfo != null ? elementInfo.getType() : null);
while (reader.hasNext()) {
next.addEvent(reader);
if (next.isComplete())
break;
reader.next();
}
} catch (XMLStreamException e) {
throw new CityGMLReadException("Caused by: ", e);
}
}
if (next == null)
throw new NoSuchElementException();
else {
iterator = false;
return next;
}
}
public boolean isSetParentInfo() {
return false;
}
public ParentInfo getParentInfo() {
return null;
}
}