/* Copyright (c) 2001 - 2011 TOPP - www.openplans.org. All rights reserved. * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.gwc.wms; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import org.geoserver.gwc.GWC; import org.geoserver.wms.ExtendedCapabilitiesProvider; import org.geoserver.wms.GetCapabilitiesRequest; import org.geoserver.wms.WMS; import org.geoserver.wms.WMSInfo; import org.geotools.util.Version; import org.geowebcache.grid.BoundingBox; import org.geowebcache.grid.GridSubset; import org.geowebcache.layer.TileLayer; import org.geowebcache.mime.MimeType; import org.xml.sax.helpers.AttributesImpl; import org.xml.sax.helpers.NamespaceSupport; /** * Implementation of the {@link ExtendedCapabilitiesProvider} extension point to contribute WMS-C * DTD elements and TileSet definitions to the capabilities document of the regular GeoServer WMS. * * <p> * A {@code TileSet} is added at {@link #encode} for each GWC {@link TileLayer}, but respecting the * {@link GetCapabilitiesRequest#getNamespace() namespace} filter if set. * </p> * * @author Gabriel Roldan * */ public class CachingExtendedCapabilitiesProvider implements ExtendedCapabilitiesProvider { private final GWC gwc; public CachingExtendedCapabilitiesProvider(final GWC gwc) { this.gwc = gwc; } /** * @see org.geoserver.wms.ExtendedCapabilitiesProvider#getSchemaLocations() */ public String[] getSchemaLocations(String schemaBaseURL) { return new String[0]; } /** * @return {@code TileSet*} * @see org.geoserver.wms.ExtendedCapabilitiesProvider#getVendorSpecificCapabilitiesRoots */ public List<String> getVendorSpecificCapabilitiesRoots(final GetCapabilitiesRequest request) { if (isTiled(request)) { return Collections.singletonList("TileSet*"); } return Collections.emptyList(); } private boolean isTiled(GetCapabilitiesRequest request) { return Boolean.valueOf(request.getRawKvp().get("TILED")).booleanValue(); } /** * @see org.geoserver.wms.ExtendedCapabilitiesProvider#getVendorSpecificCapabilitiesChildDecls() */ public List<String> getVendorSpecificCapabilitiesChildDecls(final GetCapabilitiesRequest request) { if (isTiled(request)) { List<String> wmscElements = new ArrayList<String>(); wmscElements .add("<!ELEMENT TileSet (SRS, BoundingBox?, Resolutions, Width, Height, Format, Layers*, Styles*) >"); wmscElements.add("<!ELEMENT Resolutions (#PCDATA) >"); wmscElements.add("<!ELEMENT Width (#PCDATA) >"); wmscElements.add("<!ELEMENT Height (#PCDATA) >"); wmscElements.add("<!ELEMENT Layers (#PCDATA) >"); wmscElements.add("<!ELEMENT Styles (#PCDATA) >"); return wmscElements; } return Collections.emptyList(); } /** * Empty implementation, no namespaces to add until we support the WMS-C 1.3 profile * * @see org.geoserver.wms.ExtendedCapabilitiesProvider#registerNamespaces(org.xml.sax.helpers.NamespaceSupport) */ public void registerNamespaces(NamespaceSupport namespaces) { // nothing to do } /** * @see org.geoserver.wms.ExtendedCapabilitiesProvider#encode(org.geoserver.wms.ExtendedCapabilitiesProvider.Translator, * org.geoserver.wms.WMSInfo, org.geotools.util.Version) */ public void encode(final Translator tx, final WMSInfo wms, final GetCapabilitiesRequest request) throws IOException { Version version = WMS.version(request.getVersion(), true); if (!WMS.VERSION_1_1_1.equals(version) || !isTiled(request)) { return; } String namespacePrefixFilter = request.getNamespace(); Iterable<TileLayer> tileLayers = gwc.getTileLayersByNamespacePrefix(namespacePrefixFilter); for (TileLayer layer : tileLayers) { Map<String, GridSubset> gridSubsets = layer.getGridSubsets(); Collection<GridSubset> layerGrids = gridSubsets.values(); for (GridSubset grid : layerGrids) { for (MimeType mime : layer.getMimeTypes()) { vendorSpecificTileset(tx, layer, grid, mime.getFormat()); } } } } private void vendorSpecificTileset(final Translator tx, final TileLayer layer, final GridSubset grid, final String format) { String srsStr = grid.getSRS().toString(); StringBuilder resolutionsStr = new StringBuilder(); double[] res = grid.getResolutions(); for (int i = 0; i < res.length; i++) { resolutionsStr.append(Double.toString(res[i]) + " "); } String[] bs = boundsPrep(grid.getCoverageBestFitBounds()); tx.start("TileSet"); tx.start("SRS"); tx.chars(srsStr); tx.end("SRS"); AttributesImpl atts; atts = new AttributesImpl(); atts.addAttribute("", "SRS", "SRS", "", srsStr); atts.addAttribute("", "minx", "minx", "", bs[0]); atts.addAttribute("", "miny", "miny", "", bs[1]); atts.addAttribute("", "maxx", "maxx", "", bs[2]); atts.addAttribute("", "maxy", "maxy", "", bs[3]); tx.start("BoundingBox", atts); tx.end("BoundingBox"); tx.start("Resolutions"); tx.chars(resolutionsStr.toString()); tx.end("Resolutions"); tx.start("Width"); tx.chars(String.valueOf(grid.getTileWidth())); tx.end("Width"); tx.start("Height"); tx.chars(String.valueOf(grid.getTileHeight())); tx.end("Height"); tx.start("Format"); tx.chars(format); tx.end("Format"); tx.start("Layers"); tx.chars(layer.getName()); tx.end("Layers"); // TODO ignoring styles for now tx.start("Styles"); tx.end("Styles"); tx.end("TileSet"); } String[] boundsPrep(BoundingBox bbox) { String[] bs = { Double.toString(bbox.getMinX()), Double.toString(bbox.getMinY()), Double.toString(bbox.getMaxX()), Double.toString(bbox.getMaxY()) }; return bs; } }