/* Copyright (c) 2001 - 2011 TOPP - www.openplans.org. All rights reserved.
* This code is licensed under the GPL 2.0 license, availible at the root
* application directory.
*/
package org.geoserver.geosearch.rest;
import static org.geoserver.geosearch.rest.Properties.INDEXING_ENABLED;
import static org.geoserver.geosearch.rest.Properties.LAST_MODIFIED;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.LayerGroupInfo;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.catalog.MetadataMap;
import org.geoserver.ows.util.ResponseUtils;
import org.geoserver.rest.format.StreamDataFormat;
import org.restlet.data.MediaType;
import org.springframework.util.Assert;
/**
* REST format that produces the sitemap.xml document
*/
public class SiteMapXMLFormat extends StreamDataFormat {
private static final String GEO_NS = "http://www.google.com/geo/schemas/sitemap/1.0";
private static final String SITEMAP_NS = "http://www.sitemaps.org/schemas/sitemap/0.9";
private static final DateFormat LAST_MOD_FORMATTER = new SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ssZ");
private static final DateFormat LAST_MOD_FORMATTER_GMT = new SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ss'Z'");
static {
LAST_MOD_FORMATTER_GMT.setTimeZone(TimeZone.getTimeZone("GMT"));
}
/**
* {@code <http://localhost:8080/geoserver/geosearch>[/]} or whatever the base URL is, in order
* to append {@code [/]l<layer>.kml} to it for each layer
*/
private final String baseUrl;
public SiteMapXMLFormat(final String baseUrl) {
super(MediaType.TEXT_XML);
this.baseUrl = baseUrl;
}
/**
* Unsupported.
*
* @see org.geoserver.rest.format.StreamDataFormat#read(java.io.InputStream)
*/
@Override
protected Object read(InputStream in) throws IOException {
throw new UnsupportedOperationException();
}
/**
* Writes out the sitemap to the given output stream.
*
* @see org.geoserver.rest.format.StreamDataFormat#write(java.lang.Object, java.io.OutputStream)
*/
@Override
protected void write(final Object object, OutputStream out) throws IOException {
Assert.isTrue(object instanceof Catalog);
final Catalog catalog = (Catalog) object;
final XMLStreamWriter writer;
try {
XMLOutputFactory factory;
factory = XMLOutputFactory.newInstance();
writer = factory.createXMLStreamWriter(out, "UTF-8");
} catch (FactoryConfigurationError e) {
throw new RuntimeException(e);
} catch (XMLStreamException e) {
throw new RuntimeException(e);
}
try {
encode(catalog, writer);
writer.flush();
} catch (XMLStreamException e) {
throw (IOException) new IOException("Error encoding sitemap: " + e.getMessage())
.initCause(e);
}
}
/**
* @param catalog
* @param writer
* @throws XMLStreamException
* @throws IOException
*/
private void encode(Catalog catalog, XMLStreamWriter writer) throws XMLStreamException,
IOException {
writer.writeStartDocument();
writer.writeStartElement("urlset");
writer.writeDefaultNamespace(SITEMAP_NS);
writer.writeNamespace("geo", GEO_NS);
writer.setDefaultNamespace(SITEMAP_NS);
writer.setPrefix("geo", GEO_NS);
for (LayerInfo info : catalog.getLayers()) {
final MetadataMap metadata = info.getMetadata();
final Boolean indexingEnabled = metadata.get(INDEXING_ENABLED, Boolean.class);
if (null == indexingEnabled || Boolean.FALSE.equals(indexingEnabled)) {
continue;
}
final String layerName = info.getResource().getPrefixedName();
writeUrl(writer, metadata, layerName);
}
for (LayerGroupInfo info : catalog.getLayerGroups()) {
final MetadataMap metadata = info.getMetadata();
final Boolean indexingEnabled = metadata.get(INDEXING_ENABLED, Boolean.class);
if (null == indexingEnabled || Boolean.FALSE.equals(indexingEnabled)) {
continue;
}
final String layerName = info.getName();
writeUrl(writer, metadata, layerName);
}
writer.writeEndElement();
writer.writeEndDocument();
}
/**
* @param writer
* @param metadata
* @param layerName
* @throws XMLStreamException
*/
private void writeUrl(XMLStreamWriter writer, final MetadataMap metadata, final String layerName)
throws XMLStreamException {
writer.writeStartElement("url");
{
writer.writeStartElement("loc");
writer.writeCharacters(kmlMetadataUrl(layerName));
writer.writeEndElement();
Long lastMod = metadata.get(LAST_MODIFIED, Long.class);
if (lastMod != null) {
Date parsed;
try {
parsed = LAST_MOD_FORMATTER_GMT.parse(LAST_MOD_FORMATTER.format(new Date(
lastMod.longValue())));
} catch (ParseException e) {
parsed = new Date(lastMod.longValue());
}
writer.writeStartElement("lastmod");
writer.writeCharacters(LAST_MOD_FORMATTER_GMT.format(parsed));
writer.writeEndElement();
}
writer.writeStartElement(GEO_NS, "geo");
{
writer.writeStartElement(GEO_NS, "format");
writer.writeCharacters("kml");
writer.writeEndElement();
}
writer.writeEndElement();
}
writer.writeEndElement();
}
private String kmlMetadataUrl(final String prefixedName) {
final String encodedName = ResponseUtils.urlEncode(prefixedName) + ".kml";
String path = ResponseUtils.appendPath(baseUrl, encodedName);
return path;
}
}