/* 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.layer; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.logging.Level; import java.util.logging.Logger; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import org.geoserver.catalog.KeywordInfo; import org.geoserver.catalog.LayerGroupInfo; import org.geoserver.catalog.LayerInfo; import org.geoserver.catalog.MetadataMap; import org.geoserver.catalog.ResourceInfo; import org.geoserver.catalog.StyleInfo; import org.geoserver.gwc.GWC; import org.geoserver.gwc.config.GWCConfig; import org.geoserver.wms.GetMapRequest; import org.geoserver.wms.WMS; import org.geoserver.wms.WebMap; import org.geoserver.wms.map.RenderedImageMap; import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.referencing.CRS; import org.geotools.util.CanonicalSet; import org.geotools.util.logging.Logging; import org.geowebcache.GeoWebCacheException; import org.geowebcache.config.ConfigurationException; import org.geowebcache.conveyor.ConveyorTile; import org.geowebcache.filter.parameters.ParameterException; import org.geowebcache.filter.parameters.ParameterFilter; import org.geowebcache.filter.parameters.StringParameterFilter; import org.geowebcache.filter.request.RequestFilter; import org.geowebcache.grid.BoundingBox; import org.geowebcache.grid.GridSet; import org.geowebcache.grid.GridSetBroker; import org.geowebcache.grid.GridSubset; import org.geowebcache.grid.GridSubsetFactory; import org.geowebcache.grid.OutsideCoverageException; import org.geowebcache.grid.SRS; import org.geowebcache.io.Resource; import org.geowebcache.layer.GridLocObj; import org.geowebcache.layer.LayerListenerList; import org.geowebcache.layer.MetaTile; import org.geowebcache.layer.TileLayer; import org.geowebcache.layer.TileLayerListener; import org.geowebcache.layer.meta.ContactInformation; import org.geowebcache.layer.meta.LayerMetaInformation; import org.geowebcache.layer.updatesource.UpdateSourceDefinition; import org.geowebcache.mime.FormatModifier; import org.geowebcache.mime.MimeException; import org.geowebcache.mime.MimeType; import org.geowebcache.util.GWCVars; import org.geowebcache.util.ServletUtils; import org.opengis.referencing.FactoryException; import org.opengis.referencing.NoSuchAuthorityCodeException; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.TransformException; import org.springframework.util.Assert; public class GeoServerTileLayer extends TileLayer { private static final Logger LOGGER = Logging.getLogger(GeoServerTileLayer.class); private final GeoServerTileLayerInfo info; public static final String GWC_SEED_INTERCEPT_TOKEN = "GWC_SEED_INTERCEPT"; public static final ThreadLocal<WebMap> WEB_MAP = new ThreadLocal<WebMap>(); private CatalogConfiguration mediator; private final String layerId; private final String layerGroupId; private String configErrorMessage; private List<ParameterFilter> parameterFilters; private Map<String, GridSubset> subSets; private static LayerListenerList listeners = new LayerListenerList(); public GeoServerTileLayer(final CatalogConfiguration mediator, final LayerGroupInfo layerGroup) { this.mediator = mediator; this.layerId = null; this.layerGroupId = layerGroup.getId(); GWCConfig configDefaults = mediator.getConfig(); this.info = GeoServerTileLayerInfo.create(layerGroup, configDefaults); } public GeoServerTileLayer(final CatalogConfiguration mediator, final LayerInfo layerInfo) { this.mediator = mediator; this.layerId = layerInfo.getId(); this.layerGroupId = null; GWCConfig configDefaults = mediator.getConfig(); this.info = GeoServerTileLayerInfo.create(layerInfo, configDefaults); } @Override public String getName() { if (layerGroupId != null) { LayerGroupInfo layerGroupInfo = getLayerGroupInfo(); return layerGroupInfo.getName(); } LayerInfo layerInfo = getLayerInfo(); ResourceInfo resource = layerInfo.getResource(); return resource.getPrefixedName(); } void setConfigErrorMessage(String configErrorMessage) { this.configErrorMessage = configErrorMessage; } public String getConfigErrorMessage() { return configErrorMessage; } @Override public List<ParameterFilter> getParameterFilters() { if (parameterFilters == null) { Set<String> cachedStyles = info.getCachedStyles(); if (cachedStyles.size() > 0) { String defaultStyle = getStyles(); if (defaultStyle == null) { // may be null if backed by a LayerGroupInfo, but in that case // cachedStyles.size() can't be > 0 throw new IllegalStateException( "TileLayer backed by a LayerGroup should not have alternate styles!"); } ParameterFilter stylesParameterFilter; stylesParameterFilter = createStylesParameterFilters(defaultStyle, cachedStyles); if (stylesParameterFilter != null) { LOGGER.fine("Created STYLES parameter filter for layer " + getName() + " and styles " + stylesParameterFilter.getLegalValues()); List<ParameterFilter> paramFilters = Arrays.asList(stylesParameterFilter); this.parameterFilters = paramFilters; } } } return parameterFilters; } public void resetParameterFilters() { super.defaultParameterFilterValues = null;// reset default values this.parameterFilters = null; } /** * Returns whether this tile layer is enabled. * <p> * The layer is enabled if the following conditions apply: * <ul> * <li>Caching for this layer is enabled by configuration * <li>Its backing {@link LayerInfo} or {@link LayerGroupInfo} is enabled and not errored (as * per {@link LayerInfo#enabled()} {@link LayerGroupInfo#} * <li>The layer is not errored ({@link #getConfigErrorMessage() == null} * </ul> * The layer is enabled by configuration if: the {@code GWC.enabled} metadata property is set to * {@code true} in it's corresponding {@link LayerInfo} or {@link LayerGroupInfo} * {@link MetadataMap}, or there's no {@code GWC.enabled} property set at all but the global * {@link GWCConfig#isCacheLayersByDefault()} is {@code true}. * </p> * * @see org.geowebcache.layer.TileLayer#isEnabled() */ @Override public boolean isEnabled() { final boolean tileLayerInfoEnabled = info.isEnabled(); if (!tileLayerInfoEnabled) { return false; } if (getConfigErrorMessage() != null) { if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("Layer " + getName() + "is not enabled due to config error: " + getConfigErrorMessage()); } return false; } boolean geoserverLayerEnabled; LayerInfo layerInfo = getLayerInfo(); if (layerInfo != null) { geoserverLayerEnabled = layerInfo.enabled(); } else { // LayerGroupInfo has no enabled property, so assume true geoserverLayerEnabled = true; } return tileLayerInfoEnabled && geoserverLayerEnabled; } @Override public void setEnabled(final boolean enabled) { boolean oldVal = info.isEnabled(); info.setEnabled(enabled); if (oldVal != enabled) { mediator.save(this); } } /** * * @see org.geowebcache.layer.TileLayer#isQueryable() * @see WMS#isQueryable(LayerGroupInfo) * @see WMS#isQueryable(LayerInfo) */ @Override public boolean isQueryable() { return mediator.isQueryable(this); } private ReferencedEnvelope getLatLonBbox() throws IllegalStateException { final CoordinateReferenceSystem wgs84LonFirst; try { final boolean longitudeFirst = true; wgs84LonFirst = CRS.decode("EPSG:4326", longitudeFirst); } catch (Exception e) { throw new RuntimeException(e); } ReferencedEnvelope latLongBbox; if (getLayerInfo() == null) { LayerGroupInfo groupInfo = getLayerGroupInfo(); try { ReferencedEnvelope bounds = groupInfo.getBounds(); boolean lenient = true; latLongBbox = bounds.transform(wgs84LonFirst, lenient); } catch (Exception e) { String msg = "Can't get lat long bounds for layer group " + groupInfo.getName(); LOGGER.log(Level.WARNING, msg, e); throw new IllegalStateException(msg, e); } } else { ResourceInfo resourceInfo = getResourceInfo(); latLongBbox = resourceInfo.getLatLonBoundingBox(); if (null == latLongBbox) { latLongBbox = new ReferencedEnvelope(wgs84LonFirst); } if (null == latLongBbox.getCoordinateReferenceSystem()) { ReferencedEnvelope tmp = new ReferencedEnvelope(wgs84LonFirst); tmp.init(latLongBbox.getMinX(), latLongBbox.getMaxX(), latLongBbox.getMinY(), latLongBbox.getMaxY()); latLongBbox = tmp; } } return latLongBbox; } /** * Creates parameter filters for each additional layer style * * @return */ public static StringParameterFilter createStylesParameterFilters(final String defaultStyle, final Set<String> styleNames) { Assert.notNull(defaultStyle, "defaultStyle"); Assert.notNull(defaultStyle, "alternate styles"); if (styleNames.size() == 0) { return null; } Set<String> possibleValues = new TreeSet<String>(); possibleValues.add(defaultStyle); possibleValues.addAll(styleNames); StringParameterFilter styleParamFilter = new StringParameterFilter(); styleParamFilter.key = "STYLES"; styleParamFilter.defaultValue = defaultStyle; styleParamFilter.values = new ArrayList<String>(possibleValues); return styleParamFilter; } /** * @return the {@link LayerInfo} for this layer, or {@code null} if it's backed by a * {@link LayerGroupInfo} instead */ public LayerInfo getLayerInfo() { if (layerId == null) { return null; } LayerInfo layerInfo = mediator.getLayerInfoById(layerId); return layerInfo; } /** * @return the {@link LayerGroupInfo} for this layer, or {@code null} if it's backed by a * {@link LayerInfo} instead */ public LayerGroupInfo getLayerGroupInfo() { if (layerGroupId == null) { return null; } LayerGroupInfo layerGroupInfo = mediator.getLayerGroupById(layerGroupId); return layerGroupInfo; } private ResourceInfo getResourceInfo() { LayerInfo layerInfo = getLayerInfo(); return layerInfo == null ? null : layerInfo.getResource(); } /** * Overrides to return a dynamic view of the backing {@link LayerInfo} or {@link LayerGroupInfo} * metadata adapted to GWC * * @see org.geowebcache.layer.TileLayer#getMetaInformation() */ @Override public LayerMetaInformation getMetaInformation() { LayerMetaInformation meta = null; String title = getName(); String description = ""; List<String> keywords = Collections.emptyList(); List<ContactInformation> contacts = Collections.emptyList(); ResourceInfo resourceInfo = getResourceInfo(); if (resourceInfo != null) { title = resourceInfo.getTitle(); description = resourceInfo.getAbstract(); keywords = new ArrayList<String>(); for (KeywordInfo kw : resourceInfo.getKeywords()) { keywords.add(kw.getValue()); } } meta = new LayerMetaInformation(title, description, keywords, contacts); return meta; } /** * The default style name for the layer, as advertised by its backing * {@link LayerInfo#getDefaultStyle()}, or {@code null} if this tile layer is backed by a * {@link LayerGroupInfo}. * <p> * As the default style is always cached, its name is not stored as part of this tile layer's * {@link GeoServerTileLayerInfo}. Instead it's 'live' and retrieved from the current * {@link LayerInfo} every time this method is invoked. * </p> * * @see org.geowebcache.layer.TileLayer#getStyles() * @see GeoServerTileLayerInfo#getDefaultStyle() */ @Override public String getStyles() { if (layerGroupId != null) { // there's no such thing as default style for a layer group return null; } LayerInfo layerInfo = getLayerInfo(); StyleInfo defaultStyle = layerInfo.getDefaultStyle(); if (defaultStyle == null) { setConfigErrorMessage("Underlying GeoSever Layer has no default style"); return null; } return defaultStyle.getName(); } /** * @see org.geowebcache.layer.TileLayer#getFeatureInfo * @see GWC#dispatchOwsRequest */ @Override public Resource getFeatureInfo(ConveyorTile convTile, BoundingBox bbox, int height, int width, int x, int y) throws GeoWebCacheException { Map<String, String> params = buildGetFeatureInfo(convTile, bbox, height, width, x, y); Resource response; try { response = mediator.dispatchOwsRequest(params, (Cookie[]) null); } catch (Exception e) { throw new GeoWebCacheException(e); } return response; } private Map<String, String> buildGetFeatureInfo(ConveyorTile convTile, BoundingBox bbox, int height, int width, int x, int y) { Map<String, String> wmsParams = new HashMap<String, String>(); wmsParams.put("SERVICE", "WMS"); wmsParams.put("VERSION", "1.1.1"); wmsParams.put("REQUEST", "GetFeatureInfo"); wmsParams.put("LAYERS", getName()); wmsParams.put("STYLES", ""); wmsParams.put("QUERY_LAYERS", getName()); MimeType mimeType = convTile.getMimeType(); if (mimeType == null) { mimeType = getMimeTypes().get(0); } wmsParams.put("FORMAT", mimeType.getFormat()); wmsParams.put("EXCEPTIONS", GetMapRequest.SE_XML); wmsParams.put("INFO_FORMAT", convTile.getMimeType().getFormat()); GridSubset gridSubset = convTile.getGridSubset(); wmsParams.put("SRS", gridSubset.getSRS().toString()); wmsParams.put("HEIGHT", String.valueOf(height)); wmsParams.put("WIDTH", String.valueOf(width)); wmsParams.put("BBOX", bbox.toString()); wmsParams.put("X", String.valueOf(x)); wmsParams.put("Y", String.valueOf(y)); String featureCount; { Map<String, String> values = ServletUtils.selectedStringsFromMap( convTile.servletReq.getParameterMap(), convTile.servletReq.getCharacterEncoding(), "feature_count"); featureCount = values.get("feature_count"); } if(featureCount != null){ wmsParams.put("FEATURE_COUNT", featureCount); } Map<String, String> fullParameters = convTile.getFullParameters(); if (fullParameters.isEmpty()) { fullParameters = getDefaultParameterFilters(); } wmsParams.putAll(fullParameters); return wmsParams; } @Override public ConveyorTile getTile(ConveyorTile tile) throws GeoWebCacheException, IOException, OutsideCoverageException { MimeType mime = tile.getMimeType(); final List<MimeType> formats = getMimeTypes(); if (mime == null) { mime = formats.get(0); } else { if (!formats.contains(mime)) { throw new IllegalArgumentException(mime.getFormat() + " is not a supported format for " + getName()); } } final String tileGridSetId = tile.getGridSetId(); final GridSubset gridSubset = getGridSubset(tileGridSetId); if (gridSubset == null) { throw new IllegalArgumentException("Requested gridset not found: " + tileGridSetId); } final long[] gridLoc = tile.getTileIndex(); Assert.notNull(gridLoc); // Final preflight check, throws OutsideCoverageException if necessary gridSubset.checkCoverage(gridLoc); ConveyorTile returnTile; int metaX; int metaY; if (mime.supportsTiling()) { metaX = info.getMetaTilingX(); metaY = info.getMetaTilingY(); } else { metaX = metaY = 1; } returnTile = getMetatilingReponse(tile, true, metaX, metaY); sendTileRequestedEvent(returnTile); return returnTile; } @Override public void addLayerListener(final TileLayerListener listener) { listeners.addListener(listener); } @Override public boolean removeLayerListener(final TileLayerListener listener) { listeners.removeListener(listener); return true; } protected final void sendTileRequestedEvent(ConveyorTile tile) { if (listeners != null) { listeners.sendTileRequested(this, tile); } } private static final CanonicalSet<GridLocObj> META_GRID_LOCKS = CanonicalSet .newInstance(GridLocObj.class); private ConveyorTile getMetatilingReponse(ConveyorTile tile, final boolean tryCache, final int metaX, final int metaY) throws GeoWebCacheException, IOException { // Acquire lock if (tryCache && tryCacheFetch(tile)) { return finalizeTile(tile); } final GeoServerMetaTile metaTile = createMetaTile(tile, metaX, metaY); final GridLocObj metaGridLoc; metaGridLoc = META_GRID_LOCKS.unique(new GridLocObj(metaTile.getMetaGridPos(), 32)); synchronized (metaGridLoc) { // got the lock on the meta tile, try again if (tryCache && tryCacheFetch(tile)) { LOGGER.finest("--> " + Thread.currentThread().getName() + " returns cache hit for " + Arrays.toString(metaTile.getMetaGridPos())); } else { LOGGER.finer("--> " + Thread.currentThread().getName() + " submitting getMap request for meta grid location " + Arrays.toString(metaTile.getMetaGridPos()) + " on " + metaTile); RenderedImageMap map; try { map = dispatchGetMap(tile, metaTile); Assert.notNull(map, "Did not obtain a WebMap from GeoServer's Dispatcher"); metaTile.setWebMap(map); saveTiles(metaTile, tile); } catch (Exception e) { e.printStackTrace(); throw new GeoWebCacheException("Problem communicating with GeoServer", e); } finally { META_GRID_LOCKS.remove(metaGridLoc); metaTile.dispose(); } } } return finalizeTile(tile); } private RenderedImageMap dispatchGetMap(final ConveyorTile tile, final MetaTile metaTile) throws Exception { Map<String, String> params = buildGetMap(tile, metaTile); WebMap map; try { HttpServletRequest actualRequest = tile.servletReq; Cookie[] cookies = actualRequest == null ? null : actualRequest.getCookies(); mediator.dispatchOwsRequest(params, cookies); map = WEB_MAP.get(); if (!(map instanceof RenderedImageMap)) { throw new IllegalStateException("Expected: RenderedImageMap, got " + map); } } finally { WEB_MAP.remove(); } return (RenderedImageMap) map; } private GeoServerMetaTile createMetaTile(ConveyorTile tile, final int metaX, final int metaY) { GeoServerMetaTile metaTile; String tileGridSetId = tile.getGridSetId(); GridSubset gridSubset = getGridSubset(tileGridSetId); MimeType responseFormat = tile.getMimeType(); FormatModifier formatModifier = null; long[] tileGridPosition = tile.getTileIndex(); int gutter = info.getGutter(); String layerName = this.getName(); metaTile = new GeoServerMetaTile(layerName, gridSubset, responseFormat, formatModifier, tileGridPosition, metaX, metaY, gutter, mediator); return metaTile; } private Map<String, String> buildGetMap(final ConveyorTile tile, final MetaTile metaTile) throws ParameterException { Map<String, String> params = new HashMap<String, String>(); final MimeType mimeType = tile.getMimeType(); final String gridSetId = tile.getGridSetId(); final GridSubset gridSubset = getGridSubset(gridSetId); int width = metaTile.getMetaTileWidth(); int height = metaTile.getMetaTileHeight(); String srs = gridSubset.getSRS().toString(); String format = mimeType.getFormat(); BoundingBox bbox = metaTile.getMetaTileBounds(); params.put("SERVICE", "WMS"); params.put("VERSION", "1.1.1"); params.put("REQUEST", "GetMap"); params.put("LAYERS", getName()); params.put("SRS", srs); params.put("FORMAT", format); params.put("WIDTH", String.valueOf(width)); params.put("HEIGHT", String.valueOf(height)); params.put("BBOX", bbox.toString()); params.put("EXCEPTIONS", GetMapRequest.SE_XML); params.put("STYLES", ""); params.put("TRANSPARENT", "true"); params.put(GWC_SEED_INTERCEPT_TOKEN, "true"); Map<String, String> filteredParams = tile.getFullParameters(); if (filteredParams.isEmpty()) { filteredParams = getDefaultParameterFilters(); } params.putAll(filteredParams); return params; } private boolean tryCacheFetch(ConveyorTile tile) { int expireCache = this.getExpireCache((int) tile.getTileIndex()[2]); if (expireCache != GWCVars.CACHE_DISABLE_CACHE) { try { return tile.retrieve(expireCache * 1000L); } catch (GeoWebCacheException gwce) { LOGGER.info(gwce.getMessage()); tile.setErrorMsg(gwce.getMessage()); return false; } } return false; } private ConveyorTile finalizeTile(ConveyorTile tile) { if (tile.getStatus() == 0 && !tile.getError()) { tile.setStatus(200); } if (tile.servletResp != null) { setExpirationHeader(tile.servletResp, (int) tile.getTileIndex()[2]); setTileIndexHeader(tile); } return tile; } /** * @param tile */ private void setTileIndexHeader(ConveyorTile tile) { tile.servletResp.addHeader("geowebcache-tile-index", Arrays.toString(tile.getTileIndex())); } @Override public ConveyorTile getNoncachedTile(ConveyorTile tile) throws GeoWebCacheException { try { return getMetatilingReponse(tile, false, 1, 1); } catch (IOException e) { throw new GeoWebCacheException(e); } } @Override public ConveyorTile doNonMetatilingRequest(ConveyorTile tile) throws GeoWebCacheException { try { return getMetatilingReponse(tile, true, 1, 1); } catch (IOException e) { throw new GeoWebCacheException(e); } } @Override public void seedTile(ConveyorTile tile, boolean tryCache) throws GeoWebCacheException, IOException { int metaX = info.getMetaTilingX(); int metaY = info.getMetaTilingY(); if (!tile.getMimeType().supportsTiling()) { metaX = metaY = 1; } getMetatilingReponse(tile, tryCache, metaX, metaY); } @Override public void acquireLayerLock() { throw new UnsupportedOperationException("not implemented yet"); } @Override public void releaseLayerLock() { throw new UnsupportedOperationException("not implemented yet"); } private Map<String, GridSubset> getGrids(final ReferencedEnvelope latLonBbox, final GridSetBroker gridSetBroker) throws ConfigurationException { Set<String> cachedGridSetIds = info.getCachedGridSetIds(); if (cachedGridSetIds.size() == 0) { throw new IllegalStateException("TileLayer " + getName() + " has no gridsets configured"); } Map<String, GridSubset> grids = new HashMap<String, GridSubset>(2); for (String gridSetId : cachedGridSetIds) { GridSet gridSet = gridSetBroker.get(gridSetId); if (gridSet == null) { throw new ConfigurationException("No GWC GridSet named '" + gridSetId + "' exists."); } BoundingBox extent = getBoundsFromWGS84Bounds(latLonBbox, gridSet.getSrs()); Integer zoomStart = 0; Integer zoomStop = gridSet.getGrids().length - 1; GridSubset gridSubSet; gridSubSet = GridSubsetFactory.createGridSubSet(gridSet, extent, zoomStart, zoomStop); grids.put(gridSetId, gridSubSet); } return grids; } private BoundingBox getBoundsFromWGS84Bounds(final ReferencedEnvelope latLonBbox, final SRS srs) { Assert.notNull(latLonBbox); Assert.notNull(latLonBbox.getCoordinateReferenceSystem()); Assert.notNull(srs); final double minX = latLonBbox.getMinX(); final double minY = latLonBbox.getMinY(); final double maxX = latLonBbox.getMaxX(); final double maxY = latLonBbox.getMaxY(); final String epsgCode = srs.toString(); final boolean longitudeFirst = true; ReferencedEnvelope transformedBounds; BoundingBox bounds; if ("EPSG:900913".equals(epsgCode) || "EPSG:3857".equals(epsgCode)) { bounds = new BoundingBox(longToSphericalMercatorX(minX), latToSphericalMercatorY(minY), longToSphericalMercatorX(maxX), latToSphericalMercatorY(maxY)); } else { try { CoordinateReferenceSystem crs; crs = CRS.decode(epsgCode, longitudeFirst); Assert.notNull(crs); transformedBounds = latLonBbox.transform(crs, true, 20); } catch (NoSuchAuthorityCodeException e) { throw new RuntimeException(e); } catch (FactoryException e) { throw new RuntimeException(e); } catch (TransformException e) { throw new RuntimeException(e); } bounds = new BoundingBox(transformedBounds.getMinX(), transformedBounds.getMinY(), transformedBounds.getMaxX(), transformedBounds.getMaxY()); } // BoundingBox bounds4326 = new BoundingBox(minX, minY, maxX, maxY); return bounds; } private double longToSphericalMercatorX(double x) { return (x / 180.0) * 20037508.34; } private double latToSphericalMercatorY(double y) { if (y > 85.05112) { y = 85.05112; } if (y < -85.05112) { y = -85.05112; } y = (Math.PI / 180.0) * y; double tmp = Math.PI / 4.0 + y / 2.0; return 20037508.34 * Math.log(Math.tan(tmp)) / Math.PI; } public GeoServerTileLayerInfo getInfo() { return info; } @Override public synchronized Map<String, GridSubset> getGridSubsets() { if (this.subSets == null) { ReferencedEnvelope latLongBbox = getLatLonBbox(); try { GridSetBroker gridSetBroker = mediator.getGridSetBroker(); this.subSets = getGrids(latLongBbox, gridSetBroker); } catch (ConfigurationException e) { String msg = "Can't create grids for '" + getName() + "': " + e.getMessage(); LOGGER.log(Level.WARNING, msg, e); setConfigErrorMessage(msg); return Collections.emptyMap(); } } return this.subSets; } /** * @see org.geowebcache.layer.TileLayer#getUpdateSources() */ @Override public List<UpdateSourceDefinition> getUpdateSources() { return Collections.emptyList(); } /** * @see org.geowebcache.layer.TileLayer#useETags() */ @Override public boolean useETags() { return false; } /** * @see org.geowebcache.layer.TileLayer#getFormatModifiers() */ @Override public List<FormatModifier> getFormatModifiers() { return Collections.emptyList(); } /** * @see org.geowebcache.layer.TileLayer#setFormatModifiers(java.util.List) */ @Override public void setFormatModifiers(List<FormatModifier> formatModifiers) { throw new UnsupportedOperationException(); } /** * @see org.geowebcache.layer.TileLayer#getMetaTilingFactors() */ @Override public int[] getMetaTilingFactors() { return new int[] { info.getMetaTilingX(), info.getMetaTilingY() }; } /** * @return {@code true} * @see #getNoncachedTile(ConveyorTile) * @see org.geowebcache.layer.TileLayer#isCacheBypassAllowed() */ @Override public Boolean isCacheBypassAllowed() { return true; } /** * @throws UnsupportedOperationException * @see org.geowebcache.layer.TileLayer#setCacheBypassAllowed(boolean) */ @Override public void setCacheBypassAllowed(boolean allowed) { throw new UnsupportedOperationException(); } /** * @return {@code 0} * @see org.geowebcache.layer.TileLayer#getBackendTimeout() */ @Override public Integer getBackendTimeout() { return Integer.valueOf(0); } /** * @throws UnsupportedOperationException * @see org.geowebcache.layer.TileLayer#setBackendTimeout(int) */ @Override public void setBackendTimeout(int seconds) { throw new UnsupportedOperationException(); } /** * @see org.geowebcache.layer.TileLayer#getMimeTypes() */ @Override public List<MimeType> getMimeTypes() { Set<String> mimeFormats = info.getMimeFormats(); List<MimeType> mimeTypes = new ArrayList<MimeType>(mimeFormats.size()); for (String format : mimeFormats) { try { mimeTypes.add(MimeType.createFromFormat(format)); } catch (MimeException e) { LOGGER.log(Level.WARNING, "Can't create MimeType from format " + format, e); } } return mimeTypes; } /** * @see org.geowebcache.layer.TileLayer#getExpireClients(int) */ @Override public int getExpireClients(int zoomLevel) { // TODO: make configurable return 0; } /** * @see org.geowebcache.layer.TileLayer#getExpireCache(int) */ @Override public int getExpireCache(int zoomLevel) { // TODO: make configurable return 0; } /** * @return {@code null}, no request filters supported so far * @see org.geowebcache.layer.TileLayer#getRequestFilters() */ @Override public List<RequestFilter> getRequestFilters() { return null; } /** * Empty method that returns {@code true} * * @see org.geowebcache.layer.TileLayer#initialize(org.geowebcache.grid.GridSetBroker) */ @Override public boolean initialize(GridSetBroker gridSetBroker) { return true; } }