/**
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @author Gabriel Roldan (OpenGeo) 2010
*
*/
package org.geowebcache.georss;
import static javax.xml.stream.XMLStreamConstants.END_DOCUMENT;
import static javax.xml.stream.XMLStreamConstants.END_ELEMENT;
import static javax.xml.stream.XMLStreamConstants.START_ELEMENT;
import static org.geowebcache.georss.GML31ParsingUtils.GML.GML_NS_URI;
import static org.geowebcache.georss.GeoRSSParsingUtils.consume;
import static org.geowebcache.georss.GeoRSSParsingUtils.nextTag;
import static org.geowebcache.georss.GeoRSSParsingUtils.text;
import java.io.IOException;
import java.io.Reader;
import java.net.URI;
import java.net.URISyntaxException;
import javax.xml.namespace.QName;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.geowebcache.georss.GML31ParsingUtils.GML;
import com.vividsolutions.jts.geom.Geometry;
class StaxGeoRSSReader implements GeoRSSReader {
private static final Log logger = LogFactory.getLog(StaxGeoRSSReader.class);
private static final class ATOM {
public static final String NSURI = "http://www.w3.org/2005/Atom";
public static final QName feed = new QName(NSURI, "feed");
public static final QName title = new QName(NSURI, "title");
public static final QName subtitle = new QName(NSURI, "subtitle");
public static final QName updated = new QName(NSURI, "updated");
public static final QName link = new QName(NSURI, "link");
public static final QName summary = new QName(NSURI, "summary");
public static final QName author = new QName(NSURI, "author");
public static final QName name = new QName(NSURI, "name");
public static final QName email = new QName(NSURI, "email");
public static final QName id = new QName(NSURI, "id");
public static final QName entry = new QName(NSURI, "entry");
}
private static final class GEORSS {
public static final String GEORSS_NSURI = "http://www.georss.org/georss";
public static final QName where = new QName(GEORSS_NSURI, "where");
}
private XMLStreamReader reader;
private final GML31ParsingUtils gmlParser;
public StaxGeoRSSReader(final Reader feed) throws XMLStreamException, FactoryConfigurationError {
XMLInputFactory factory = XMLInputFactory.newInstance();
reader = factory.createXMLStreamReader(feed);
reader.nextTag();
reader.require(START_ELEMENT, null, null);
QName name = reader.getName();
if (!(ATOM.NSURI.equals(name.getNamespaceURI()) || "feed".equals(name.getLocalPart()))) {
throw new IllegalArgumentException("Document is not a GeoRSS feed. Root element: "
+ name);
}
findFirstEntry();
gmlParser = new GML31ParsingUtils();
}
private void findFirstEntry() throws XMLStreamException {
int event;
while ((event = reader.next()) != END_DOCUMENT) {
if (event == START_ELEMENT && ATOM.entry.equals(reader.getName())) {
break;
}
}
if (event == END_DOCUMENT) {
reader.close();
reader = null;
}
}
/**
* @see org.geowebcache.georss.GeoRSSReader#nextEntry()
*/
public Entry nextEntry() throws IOException {
if (reader == null) {
// reached EOF
return null;
}
try {
return parseEntry();
} catch (XMLStreamException e) {
throw (IOException) new IOException(e.getMessage()).initCause(e);
}
}
private Entry parseEntry() throws XMLStreamException {
reader.require(START_ELEMENT, ATOM.NSURI, ATOM.entry.getLocalPart());
Entry entry = new Entry();
logger.trace("Parsing GeoRSS entry...");
while (true) {
reader.next();
if (reader.isStartElement()) {
QName name = reader.getName();
parseEntryMember(reader, name, entry);
} else if (reader.isEndElement()) {
if (ATOM.entry.equals(reader.getName())) {
break;
}
}
}
logger.trace("Done parsing GeoRSS entry.");
reader.require(END_ELEMENT, ATOM.NSURI, ATOM.entry.getLocalPart());
QName nextTag;
while ((nextTag = nextTag(reader)) != null) {
// position parser ready for next entry
if (reader.isStartElement() && nextTag.equals(ATOM.entry)) {
break;
}
}
if (END_DOCUMENT == reader.getEventType()) {
reader.close();
reader = null;
}
return entry;
}
private void parseEntryMember(final XMLStreamReader reader, final QName memberName,
final Entry entry) throws XMLStreamException {
reader.require(START_ELEMENT, memberName.getNamespaceURI(), memberName.getLocalPart());
if (ATOM.id.equals(memberName)) {
String id = text(reader);
entry.setId(id);
} else if (ATOM.link.equals(memberName)) {
String uri = text(reader);
URI link;
try {
link = new URI(uri);
entry.setLink(link);
} catch (URISyntaxException e) {
logger.info("Feed contains illegal 'link' element content:" + uri);
}
} else if (ATOM.title.equals(memberName)) {
String title = text(reader);
entry.setTitle(title);
} else if (ATOM.subtitle.equals(memberName)) {
String subtitle = text(reader);
entry.setSubtitle(subtitle);
} else if (ATOM.updated.equals(memberName)) {
String upd = text(reader);
if (upd != null && upd.length() > 0) {
entry.setUpdated(upd);
}
} else if (GEORSS.where.equals(memberName)) {
QName nextTag = nextTag(reader);
if (reader.isStartElement() && GML_NS_URI.equals(nextTag.getNamespaceURI())) {
Geometry where = geometry(reader);
if (logger.isTraceEnabled()) {
logger.trace("Got geometry from feed: " + where);
}
entry.setWhere(where);
}
}
consume(reader, memberName);
reader.require(END_ELEMENT, memberName.getNamespaceURI(), memberName.getLocalPart());
}
private Geometry geometry(final XMLStreamReader reader) throws XMLStreamException {
reader.require(START_ELEMENT, GML.GML_NS_URI, null);
QName name = reader.getName();
Geometry geometry = gmlParser.parseGeometry(reader);
reader.require(END_ELEMENT, name.getNamespaceURI(), name.getLocalPart());
return geometry;
}
}