/* Copyright (c) 2010 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;
import static org.geowebcache.seed.GWCTask.TYPE.TRUNCATE;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.XMLConstants;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.catalog.LayerGroupInfo;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.catalog.NamespaceInfo;
import org.geoserver.catalog.ResourceInfo;
import org.geoserver.gwc.config.GWCConfig;
import org.geoserver.gwc.config.GWCConfigPersister;
import org.geoserver.gwc.layer.CatalogLayerEventListener;
import org.geoserver.gwc.layer.CatalogStyleChangeListener;
import org.geoserver.gwc.layer.GeoServerTileLayer;
import org.geoserver.ows.Dispatcher;
import org.geoserver.platform.GeoServerExtensions;
import org.geoserver.wms.GetMapRequest;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.CRS;
import org.geotools.util.logging.Logging;
import org.geowebcache.GeoWebCacheException;
import org.geowebcache.conveyor.ConveyorTile;
import org.geowebcache.diskquota.DiskQuotaConfig;
import org.geowebcache.diskquota.DiskQuotaMonitor;
import org.geowebcache.diskquota.storage.BDBQuotaStore;
import org.geowebcache.diskquota.storage.LayerQuota;
import org.geowebcache.diskquota.storage.Quota;
import org.geowebcache.filter.parameters.ParameterFilter;
import org.geowebcache.grid.BoundingBox;
import org.geowebcache.grid.GridMismatchException;
import org.geowebcache.grid.GridSet;
import org.geowebcache.grid.GridSetBroker;
import org.geowebcache.grid.GridSubset;
import org.geowebcache.grid.SRS;
import org.geowebcache.io.ByteArrayResource;
import org.geowebcache.io.Resource;
import org.geowebcache.layer.TileLayer;
import org.geowebcache.layer.TileLayerDispatcher;
import org.geowebcache.mime.MimeException;
import org.geowebcache.mime.MimeType;
import org.geowebcache.seed.GWCTask;
import org.geowebcache.seed.GWCTask.TYPE;
import org.geowebcache.seed.SeedRequest;
import org.geowebcache.seed.TileBreeder;
import org.geowebcache.service.Service;
import org.geowebcache.storage.StorageBroker;
import org.geowebcache.storage.StorageException;
import org.geowebcache.storage.TileRange;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import com.vividsolutions.jts.geom.Envelope;
/**
* Spring bean acting as a mediator between GWC and GeoServer for the GWC integration classes so
* that they don't need to worry about complexities nor API changes in either.
*
* @author Gabriel Roldan
* @version $Id$
*
*/
public class GWC implements DisposableBean, InitializingBean {
/**
* @see #get()
*/
private static GWC INSTANCE;
private static Logger log = Logging.getLogger(GWC.class);
private final TileLayerDispatcher tld;
private final StorageBroker storageBroker;
private final TileBreeder tileBreeder;
private final BDBQuotaStore quotaStore;
private final GWCConfigPersister gwcConfigPersister;
private final Dispatcher owsDispatcher;
private final GridSetBroker gridSetBroker;
private DiskQuotaMonitor monitor;
private CatalogLayerEventListener catalogLayerEventListener;
private CatalogStyleChangeListener catalogStyleChangeListener;
private final Catalog rawCatalog;
public GWC(final GWCConfigPersister gwcConfigPersister, final StorageBroker sb,
final TileLayerDispatcher tld, final GridSetBroker gridSetBroker,
final TileBreeder tileBreeder, final BDBQuotaStore quotaStore,
final DiskQuotaMonitor monitor, final Dispatcher owsDispatcher, final Catalog rawCatalog) {
this.gwcConfigPersister = gwcConfigPersister;
this.tld = tld;
this.storageBroker = sb;
this.gridSetBroker = gridSetBroker;
this.tileBreeder = tileBreeder;
this.monitor = monitor;
this.owsDispatcher = owsDispatcher;
this.quotaStore = quotaStore;
this.rawCatalog = rawCatalog;
}
public synchronized static GWC get() {
if (GWC.INSTANCE == null) {
GWC.INSTANCE = GeoServerExtensions.bean(GWC.class);
if (GWC.INSTANCE == null) {
throw new IllegalStateException("No bean of type " + GWC.class.getName()
+ " found by GeoServerExtensions");
}
}
return GWC.INSTANCE;
}
/**
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
* @see #initialize()
*/
public void afterPropertiesSet() throws Exception {
initialize();
}
public void initialize() {
// this.embeddedConfig = new CatalogConfiguration(this);
// tld.addConfiguration(embeddedConfig);
// List<GeoServerTileLayer> tileLayers;
// tileLayers = embeddedConfig.getTileLayers();
// for (GeoServerTileLayer layer : tileLayers) {
// addOrReplaceLayer(layer);
// }
}
/**
*
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/
public void destroy() throws Exception {
Catalog catalog = getCatalog();
if (this.catalogLayerEventListener != null) {
catalog.removeListener(this.catalogLayerEventListener);
}
if (this.catalogStyleChangeListener != null) {
catalog.removeListener(this.catalogStyleChangeListener);
}
}
private Catalog getCatalog() {
return rawCatalog;
}
public GWCConfig getConfig() {
return gwcConfigPersister.getConfig();
}
/**
* Fully truncates the given layer, including any ParameterFilter
*
* @param layerName
*/
public void truncate(final String layerName) {
String styleName = null;// all of them
String gridSetId = null; // all of them
BoundingBox bounds = null;// whole layer
String format = null;// all of them
truncate(layerName, styleName, gridSetId, bounds, format);
}
/**
* Truncates the cache for the given layer/style combination
*
* @param layerName
* @param styleName
*/
public void truncate(final String layerName, final String styleName) {
// check if the given style is actually cached
if (log.isLoggable(Level.FINE)) {
log.fine("Truncate for layer/style called. Checking if style '" + styleName
+ "' is cached for layer '" + layerName + "'");
}
if (!isStyleCached(layerName, styleName)) {
log.fine("Style '" + styleName + "' is not cached for layer " + layerName
+ "'. No need to truncate.");
return;
}
log.fine("truncating '" + layerName + "' for style '" + styleName + "'");
String gridSetId = null; // all of them
BoundingBox bounds = null;// all of them
String format = null;// all of them
truncate(layerName, styleName, gridSetId, bounds, format);
}
public void truncate(final String layerName, final ReferencedEnvelope bounds)
throws GeoWebCacheException {
final TileLayer tileLayer = tld.getTileLayer(layerName);
final Collection<GridSubset> gridSubSets = tileLayer.getGridSubsets().values();
/*
* Create a truncate task for each gridSubset (CRS), format and style
*/
for (GridSubset layerGrid : gridSubSets) {
BoundingBox intersectingBounds = getIntersectingBounds(layerName, layerGrid, bounds);
if (intersectingBounds == null) {
continue;
}
String gridSetId = layerGrid.getName();
String styleName = null;// all of them
String format = null;// all of them
truncate(layerName, styleName, gridSetId, intersectingBounds, format);
}
}
private BoundingBox getIntersectingBounds(String layerName, GridSubset layerGrid,
ReferencedEnvelope bounds) {
final GridSet gridSet = layerGrid.getGridSet();
final String gridSetId = gridSet.getName();
final SRS srs = gridSet.getSrs();
final CoordinateReferenceSystem gridSetCrs;
try {
gridSetCrs = CRS.decode("EPSG:" + srs.getNumber(), true);
} catch (Exception e) {
throw new RuntimeException("Can't decode SRS for layer '" + layerName + "': ESPG:"
+ srs.getNumber());
}
ReferencedEnvelope truncateBoundsInGridsetCrs;
try {
truncateBoundsInGridsetCrs = bounds.transform(gridSetCrs, true);
} catch (Exception e) {
log.warning("Can't truncate layer " + layerName
+ ": error transforming requested bounds to layer gridset " + gridSetId + ": "
+ e.getMessage());
return null;
}
final double minx = truncateBoundsInGridsetCrs.getMinX();
final double miny = truncateBoundsInGridsetCrs.getMinY();
final double maxx = truncateBoundsInGridsetCrs.getMaxX();
final double maxy = truncateBoundsInGridsetCrs.getMaxY();
final BoundingBox reqBounds = new BoundingBox(minx, miny, maxx, maxy);
/*
* layerGrid.getCoverageIntersections is not too robust, so we better check the requested
* bounds intersect the layer bounds
*/
final BoundingBox layerBounds = layerGrid.getCoverageBestFitBounds();
if (!layerBounds.intersects(reqBounds)) {
log.fine("Requested truncation bounds do not intersect cached layer bounds, ignoring truncate request");
return null;
}
final BoundingBox intersectingBounds = BoundingBox.intersection(layerBounds, reqBounds);
return intersectingBounds;
}
/**
* @param layerName
* name of the layer to truncate, non {@code null}
* @param styleName
* style to truncate, or {@code null} for all
* @param gridSetName
* grid set to truncate, non {@code null}
* @param bounds
* bounds to truncate based on, or {@code null} for whole layer
* @param format
* {@link MimeType#getFormat() format} to truncate, or {@code null} for all
*/
private void truncate(final String layerName, final String styleName, final String gridSetName,
final BoundingBox bounds, final String format) {
final TileLayer layer = getTileLayerByName(layerName);
final Set<String> styleNames;
final Set<String> gridSetIds;
final List<MimeType> mimeTypes;
if (styleName == null) {
styleNames = getCachedStyles(layerName);
if (styleNames.size() == 0) {
styleNames.add("");
}
} else {
styleNames = Collections.singleton(styleName);
}
if (gridSetName == null) {
gridSetIds = layer.getGridSubsets().keySet();
} else {
gridSetIds = Collections.singleton(gridSetName);
}
if (format == null) {
mimeTypes = layer.getMimeTypes();
} else {
try {
mimeTypes = Collections.singletonList(MimeType.createFromFormat(format));
} catch (MimeException e) {
throw new RuntimeException();
}
}
final String defaultStyle = layer.getStyles();
for (String gridSetId : gridSetIds) {
final GridSubset gridSubset = layer.getGridSubset(gridSetId);
for (String style : styleNames) {
Map<String, String> parameters;
if (style.length() == 0 || style.equals(defaultStyle)) {
log.finer("'" + style + "' is the layer's default style, "
+ "not adding a parameter filter");
parameters = null;
} else {
parameters = Collections.singletonMap("STYLES", style);
}
for (MimeType mime : mimeTypes) {
String formatName = mime.getFormat();
truncate(layer, bounds, gridSubset, formatName, parameters);
}
}
}
}
private void truncate(final TileLayer layer, final BoundingBox bounds,
final GridSubset gridSubset, String formatName, Map<String, String> parameters) {
final int threadCount = 1;
int zoomStart;
int zoomStop;
zoomStart = gridSubset.getZoomStart();
zoomStop = gridSubset.getZoomStop();
final TYPE taskType = TRUNCATE;
SeedRequest req = new SeedRequest(layer.getName(), bounds, gridSubset.getName(),
threadCount, zoomStart, zoomStop, formatName, taskType, parameters);
try {
TileRange tr = TileBreeder.createTileRange(req, layer);
boolean filterUpdate = false;
GWCTask[] tasks = tileBreeder.createTasks(tr, taskType, threadCount, filterUpdate);
tileBreeder.dispatchTasks(tasks);
} catch (GeoWebCacheException e) {
throw new RuntimeException(e);
}
}
private boolean isStyleCached(final String layerName, final String styleName) {
Set<String> cachedStyles = getCachedStyles(layerName);
boolean styleIsCached = cachedStyles.contains(styleName);
return styleIsCached;
}
/**
* Returns the names of the styles for the layer, including the default style
*
* @param layerName
* @return
*/
private Set<String> getCachedStyles(final String layerName) {
final TileLayer l = getTileLayerByName(layerName);
Set<String> cachedStyles = new HashSet<String>();
String defaultStyle = l.getStyles();
if (defaultStyle != null) {
cachedStyles.add(defaultStyle);
}
List<ParameterFilter> parameterFilters = l.getParameterFilters();
if (parameterFilters != null) {
for (ParameterFilter pf : parameterFilters) {
if (!"STYLES".equalsIgnoreCase(pf.getKey())) {
continue;
}
cachedStyles.add(pf.getDefaultValue());
cachedStyles.addAll(pf.getLegalValues());
break;
}
}
return cachedStyles;
}
/**
* Completely eliminates a {@link GeoServerTileLayer} from GWC.
* <p>
* This method is intended to be called whenever a layer is removed from GeoServer, and besides
* eliminating the {@link GeoServerTileLayer} matching it, it also deletes the cache for it.
* </p>
*
* @param prefixedName
* the name of the layer to remove.
*/
public synchronized void layerRemoved(final String prefixedName) {
try {
storageBroker.delete(prefixedName);
} catch (StorageException e) {
throw new RuntimeException(e);
}
}
public void reload() {
try {
tld.reInit();
} catch (Exception gwce) {
log.log(Level.WARNING, "Unable to reinit TileLayerDispatcher", gwce);
}
}
/**
* Tries to dispatch a tile request represented by a GeoServer WMS {@link GetMapRequest} through
* GeoWebCache, and returns the {@link ConveyorTile} if succeeded or {@code null} if it wasn't
* possible.
* <p>
* Preconditions:
* <ul>
* <li><code>{@link GetMapRequest#isTiled() request.isTiled()} == true</code>
* </ul>
* </p>
*
* @param request
* @return
*/
public final ConveyorTile dispatch(final GetMapRequest request) {
final String layerName = request.getRawKvp().get("LAYERS");
/*
* This is a quick way of checking if the request was for a single layer. We can't really
* use request.getLayers() because in the event that a layerGroup was requested, the request
* parser turned it into a list of actual Layers
*/
if (layerName.indexOf(',') != -1) {
return null;
}
final TileLayer tileLayer;
try {
tileLayer = this.tld.getTileLayer(layerName);
} catch (GeoWebCacheException e) {
return null;
}
if (!tileLayer.isEnabled()) {
return null;
}
if (!isCachingPossible(tileLayer, request)) {
return null;
}
GridSubset gridSubset;
try {
String srs = request.getSRS();
int epsgId = Integer.parseInt(srs.substring(srs.indexOf(':') + 1));
SRS srs2 = SRS.getSRS(epsgId);
gridSubset = tileLayer.getGridSubsetForSRS(srs2);
if (gridSubset == null) {
return null;
}
} catch (Exception e) {
return null;
}
if (request.getWidth() != gridSubset.getTileWidth()
|| request.getHeight() != gridSubset.getTileHeight()) {
return null;
}
final MimeType mimeType;
try {
mimeType = MimeType.createFromFormat(request.getFormat());
List<MimeType> tileLayerFormats = tileLayer.getMimeTypes();
if (!tileLayerFormats.contains(mimeType)) {
return null;
}
} catch (MimeException me) {
// not a GWC supported format
return null;
}
ConveyorTile tileResp = null;
try {
HttpServletRequest servletReq = null;
HttpServletResponse servletResp = null;
final String gridSetId;
long[] tileIndex;
gridSetId = gridSubset.getName();
Envelope bbox = request.getBbox();
BoundingBox tileBounds = new BoundingBox(bbox.getMinX(), bbox.getMinY(),
bbox.getMaxX(), bbox.getMaxY());
try {
tileIndex = gridSubset.closestIndex(tileBounds);
if (!gridSubset.covers(tileIndex)) {
return null;
}
} catch (GridMismatchException e) {
return null;
}
Map<String, String> fullParameters;
{
Map<String, String> requestParameterMap = request.getRawKvp();
fullParameters = tileLayer.getModifiableParameters(requestParameterMap, "UTF-8");
}
ConveyorTile tileReq;
tileReq = new ConveyorTile(storageBroker, layerName, gridSetId, tileIndex, mimeType,
fullParameters, servletReq, servletResp);
tileResp = tileLayer.getTile(tileReq);
} catch (Exception e) {
e.printStackTrace();
}
return tileResp;
}
/**
* Determines whether the given {@link GetMapRequest} is a candidate to match a GWC tile or not.
*
* @param layer
*
* @param request
* @return {@code true} if {@code request} <b>might</b>
*/
private boolean isCachingPossible(TileLayer layer, GetMapRequest request) {
if (null != request.getRemoteOwsType() || null != request.getRemoteOwsURL()) {
return false;
}
if (request.getEnv() != null && !request.getEnv().isEmpty()) {
return false;
}
Map<String, ParameterFilter> filters;
{
List<ParameterFilter> parameterFilters = layer.getParameterFilters();
if (null != parameterFilters && parameterFilters.size() > 0) {
filters = new HashMap<String, ParameterFilter>();
for (ParameterFilter pf : parameterFilters) {
filters.put(pf.getKey().toUpperCase(), pf);
}
} else {
filters = Collections.emptyMap();
}
}
// if (request.isTransparent()) {
// if (!filterApplies(filters, request, "TRANSPARENT")) {
// return false;
// }
// }
if (request.getFormatOptions() != null && !request.getFormatOptions().isEmpty()) {
if (!filterApplies(filters, request, "FORMAT_OPTIONS")) {
return false;
}
}
if (0.0 != request.getAngle()) {
if (!filterApplies(filters, request, "ANGLE")) {
return false;
}
}
if (null != request.getRawKvp().get("BGCOLOR")) {
if (!filterApplies(filters, request, "BGCOLOR")) {
return false;
}
}
if (0 != request.getBuffer()) {
if (!filterApplies(filters, request, "BUFFER")) {
return false;
}
}
if (null != request.getCQLFilter() && !request.getCQLFilter().isEmpty()) {
if (!filterApplies(filters, request, "CQL_FILTER")) {
return false;
}
}
if (request.getElevation() != null && !request.getElevation().isEmpty()) {
if (!filterApplies(filters, request, "ELEVATION")) {
return false;
}
}
if (null != request.getFeatureId() && !request.getFeatureId().isEmpty()) {
if (!filterApplies(filters, request, "FEATUREID")) {
return false;
}
}
if (null != request.getFilter() && !request.getFilter().isEmpty()) {
if (!filterApplies(filters, request, "FILTER")) {
return false;
}
}
if (null != request.getPalette()) {
if (!filterApplies(filters, request, "PALETTE")) {
return false;
}
}
if (null != request.getSld()) {
if (!filterApplies(filters, request, "SLD")) {
return false;
}
}
if (null != request.getSldBody()) {
if (!filterApplies(filters, request, "SLD_BODY")) {
return false;
}
}
if (null != request.getStartIndex()) {
if (!filterApplies(filters, request, "STARTINDEX")) {
return false;
}
}
if (null != request.getMaxFeatures()) {
if (!filterApplies(filters, request, "MAXFEATURES")) {
return false;
}
}
if (null != request.getTime() && !request.getTime().isEmpty()) {
if (!filterApplies(filters, request, "TIME")) {
return false;
}
}
if (null != request.getViewParams() && !request.getViewParams().isEmpty()) {
if (!filterApplies(filters, request, "VIEWPARAMS")) {
return false;
}
}
if (null != request.getFeatureVersion()) {
if (!filterApplies(filters, request, "FEATUREVERSION")) {
return false;
}
}
return true;
}
private boolean filterApplies(Map<String, ParameterFilter> filters, GetMapRequest request,
String key) {
ParameterFilter parameterFilter = filters.get(key);
if (parameterFilter == null) {
return false;
}
String parameter = request.getRawKvp().get(key);
boolean applies = parameterFilter.applies(parameter);
return applies;
}
/**
* @param layerName
* @return the tile layer named {@code layerName}
* @throws IllegalArgumentException
* if no {@link TileLayer} named {@code layeName} is found
*/
public TileLayer getTileLayerByName(String layerName) throws IllegalArgumentException {
TileLayer tileLayer;
try {
tileLayer = tld.getTileLayer(layerName);
} catch (GeoWebCacheException e) {
throw new IllegalArgumentException(e.getMessage());
}
return tileLayer;
}
public Set<String> getTileLayerNames() {
return tld.getLayerNames();
}
public Iterable<TileLayer> getTileLayers() {
return tld.getLayerList();
}
/**
* @param nsPrefix
* the namespace prefix to filter upon, or {@code null} to return all layers
* @return the tile layers that belong to a layer(group)info in the given prefix, or all the
* {@link TileLayer}s in the {@link TileLayerDispatcher} if {@code nsPrefix == null}
*/
public Iterable<TileLayer> getTileLayersByNamespacePrefix(final String nsPrefix) {
if (nsPrefix == null) {
return getTileLayers();
}
final Catalog catalog = getCatalog();
final NamespaceInfo namespaceFilter = catalog.getNamespaceByPrefix(nsPrefix);
if (namespaceFilter == null) {
return getTileLayers();
}
List<TileLayer> filteredLayers = new ArrayList<TileLayer>();
NamespaceInfo layerNamespace;
String layerName;
for (TileLayer tileLayer : getTileLayers()) {
layerName = tileLayer.getName();
LayerInfo layerInfo = catalog.getLayerByName(layerName);
if (layerInfo != null) {
layerNamespace = layerInfo.getResource().getNamespace();
if (namespaceFilter.equals(layerNamespace)) {
filteredLayers.add(tileLayer);
}
}
}
return filteredLayers;
}
/**
* Returns whether the disk quota module is available at all.
* <p>
* If not, none of the other diskquota related methods should be even called. The disk quota
* module may have been completely disabled through the {@code GWC_DISKQUOTA_DISABLED=true}
* environment variable
* </p>
*
* @return whether the disk quota module is available at all.
*/
public boolean isDiskQuotaAvailable() {
DiskQuotaMonitor diskQuotaMonitor = getDiskQuotaMonitor();
return diskQuotaMonitor.isEnabled();
}
/**
* @return the current DiskQuota configuration or {@code null} if the disk quota module has been
* disabled (i.e. through the {@code GWC_DISKQUOTA_DISABLED=true} environment variable)
*/
public DiskQuotaConfig getDiskQuotaConfig() {
if (!isDiskQuotaAvailable()) {
return null;
}
DiskQuotaMonitor monitor = getDiskQuotaMonitor();
return monitor.getConfig();
}
private DiskQuotaMonitor getDiskQuotaMonitor() {
return monitor;
}
public void saveConfig(GWCConfig gwcConfig) throws IOException {
gwcConfigPersister.save(gwcConfig);
}
public void saveDiskQuotaConfig(DiskQuotaConfig config) {
Assert.isTrue(isDiskQuotaAvailable());
DiskQuotaMonitor monitor = getDiskQuotaMonitor();
monitor.saveConfig(config);
}
public Quota getGlobalQuota() {
Assert.isTrue(isDiskQuotaAvailable());
return getDiskQuotaConfig().getGlobalQuota();
}
/**
* Precondition: {@link #getDiskQuotaConfig() != null}
*
* @return the globally used quota
*/
public Quota getGlobalUsedQuota() {
Assert.isTrue(isDiskQuotaAvailable());
try {
return quotaStore.getGloballyUsedQuota();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
/**
* Precondition: {@link #isDiskQuotaAvailable()}
*
* @return the Quota limit for the given layer, or {@code null} if no specific limit has been
* set for that layer
*/
public Quota getQuotaLimit(final String layerName) {
Assert.isTrue(isDiskQuotaAvailable());
DiskQuotaConfig disQuotaConfig = getDiskQuotaConfig();
List<LayerQuota> layerQuotas = disQuotaConfig.getLayerQuotas();
if (layerQuotas == null) {
return null;
}
for (LayerQuota lq : layerQuotas) {
if (layerName.equals(lq.getLayer())) {
return new Quota(lq.getQuota());
}
}
return null;
}
/**
* Precondition: {@link #isDiskQuotaAvailable()}
*
* @return the currently used disk quota for the layer or {@code null} if can't be determined
*/
public Quota getUsedQuota(final String layerName) {
Assert.isTrue(isDiskQuotaAvailable());
try {
Quota usedQuotaByLayerName = quotaStore.getUsedQuotaByLayerName(layerName);
return usedQuotaByLayerName;
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
/**
* Dispatches a request to the GeoServer OWS {@link Dispatcher}
*
* @param params
* the KVP map of OWS parameters
* @param cookies
* @return an http response wrapper where to grab the raw dispatcher response from
* @throws Exception
*/
public Resource dispatchOwsRequest(final Map<String, String> params, Cookie[] cookies)
throws Exception {
FakeHttpServletRequest req = new FakeHttpServletRequest(params, cookies);
FakeHttpServletResponse resp = new FakeHttpServletResponse();
owsDispatcher.handleRequest(req, resp);
return new ByteArrayResource(resp.getBytes());
}
public GridSetBroker getGridSetBroker() {
return gridSetBroker;
}
// public GeoServerTileLayer getTileLayerById(final String id) {
// return embeddedConfig.getLayerById(id);
// }
public List<LayerInfo> getLayerInfos() {
return getCatalog().getLayers();
}
public List<LayerGroupInfo> getLayerGroups() {
return getCatalog().getLayerGroups();
}
public LayerInfo getLayerInfoByName(String layerName) {
return getCatalog().getLayerByName(layerName);
}
public LayerGroupInfo getLayerGroupByName(String layerName) {
return getCatalog().getLayerGroupByName(layerName);
}
public void layerAdded(GeoServerTileLayer layer) {
String layerName = layer.getName();
if (isDiskQuotaAvailable()) {
try {
quotaStore.createLayer(layerName);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public void layerRenamed(String oldLayerName, String newLayerName) {
try {
log.info("Renaming GWC TileLayer '" + oldLayerName + "' as '" + newLayerName + "'");
// /embeddedConfig.rename(oldLayerName, newLayerName);
storageBroker.rename(oldLayerName, newLayerName);
} catch (StorageException e) {
log.log(Level.WARNING, e.getMessage(), e);
}
}
public boolean isServiceEnabled(final Service service) {
return getConfig().isEnabled(service.getPathName());
}
/**
* @return {@code true} if there's a TileLayer named {@code layerName}
*/
public boolean tileLayerExists(final String layerName) {
return tld.layerExists(layerName);
}
/**
* @param namespaceURI
* the feature type namespace
* @param typeName
* the feature type name
* @return the set of TileLayer names (from LayerInfos and LayerGroupInfos) affected by the
* feature type, may be empty
*/
public Set<String> getTileLayersByFeatureType(final String namespaceURI, final String typeName) {
NamespaceInfo namespace;
if (namespaceURI == null || XMLConstants.DEFAULT_NS_PREFIX.equals(namespaceURI)) {
namespace = getCatalog().getDefaultNamespace();
} else {
namespace = getCatalog().getNamespaceByURI(namespaceURI);
}
final FeatureTypeInfo typeInfo = getCatalog().getFeatureTypeByName(namespace, typeName);
final List<LayerInfo> layers = getCatalog().getLayers(typeInfo);
Set<String> affectedLayers = new HashSet<String>();
for (LayerInfo layer : layers) {
// this is redundant now but I'm still hoping for the infamous resource/publish split
if (tileLayerExists(layer.getResource().getPrefixedName())) {
affectedLayers.add(layer.getResource().getPrefixedName());
}
}
for (LayerGroupInfo lgi : getLayerGroups()) {
if (!tileLayerExists(lgi.getName())) {
continue;
}
for (LayerInfo li : lgi.getLayers()) {
ResourceInfo resource = li.getResource();
if (typeInfo.equals(resource)) {
affectedLayers.add(lgi.getName());
}
}
}
return affectedLayers;
}
}