/* Copyright (c) 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.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.CatalogException;
import org.geoserver.catalog.CatalogInfo;
import org.geoserver.catalog.LayerGroupInfo;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.catalog.StyleInfo;
import org.geoserver.catalog.event.CatalogAddEvent;
import org.geoserver.catalog.event.CatalogListener;
import org.geoserver.catalog.event.CatalogModifyEvent;
import org.geoserver.catalog.event.CatalogPostModifyEvent;
import org.geoserver.catalog.event.CatalogRemoveEvent;
import org.geotools.util.logging.Logging;
import org.geowebcache.filter.parameters.ParameterFilter;
/**
* Listens to changes in {@link StyleInfo styles} for the GeoServer {@link Catalog} and applies the
* needed {@link ParameterFilter} changes to the corresponding {@link GeoServerTileLayer}.
*
* @author Arne Kepp
* @author Gabriel Roldan
*/
public class CatalogStyleChangeListener implements CatalogListener {
private static Logger log = Logging.getLogger(CatalogStyleChangeListener.class);
private final CatalogConfiguration catalogConfig;
public CatalogStyleChangeListener(final CatalogConfiguration catalogConfiguration) {
this.catalogConfig = catalogConfiguration;
}
/**
* @see org.geoserver.catalog.event.CatalogListener#handleAddEvent(org.geoserver.catalog.event.CatalogAddEvent)
*/
public void handleAddEvent(CatalogAddEvent event) throws CatalogException {
// no need to handle style additions, they are added before being attached to a layerinfo
}
/**
* Handles the rename of a style, truncating the cache for any layer that has it as a cached
* alternate style; modifications to the actual style are handled at
* {@link #handlePostModifyEvent(CatalogPostModifyEvent)}.
* <p>
* When a style is renamed, the {@link LayerInfo} and {@link LayerGroupInfo} that refer to it
* are not modified, since they refer to the {@link StyleInfo} by id, so they don't really care
* about the name of the style. For the tiled layer its different, because styles are referred
* to by {@link GeoServerTileLayerInfo#getCachedStyles() name} in order to create the
* appropriate "STYLES" {@link ParameterFilter parameter filter}. This method will look for any
* tile layer backed by a {@link LayerInfo} that has a cache for the renamed style as an
* alternate style (i.e. through a parameter filter) and will truncate the cache for that
* layer/style. This is so because there's no way in GWC to just rename a style (that would
* imply getting to the parameter filters that refer to that style in the meta-store and change
* it's value preserving the parametersId)
* <p>
*
* @see org.geoserver.catalog.event.CatalogListener#handleModifyEvent(org.geoserver.catalog.event.CatalogModifyEvent)
*/
public void handleModifyEvent(CatalogModifyEvent event) throws CatalogException {
CatalogInfo source = event.getSource();
if (!(source instanceof StyleInfo)) {
return;
}
final List<String> propertyNames = event.getPropertyNames();
if (!propertyNames.contains("name")) {
return;
}
final int index = propertyNames.indexOf("name");
final String oldStyleName = (String) event.getOldValues().get(index);
final String newStyleName = (String) event.getNewValues().get(index);
if (oldStyleName.equals(newStyleName)) {
return;
}
List<GeoServerTileLayer> affectedLayers;
affectedLayers = catalogConfig.getTileLayersForStyle(oldStyleName);
for (GeoServerTileLayer tl : affectedLayers) {
GeoServerTileLayerInfo info = tl.getInfo();
Set<String> styleNames = new HashSet<String>(info.getCachedStyles());
if (styleNames.contains(oldStyleName)) {
tl.resetParameterFilters();
// pity, we don't have a way to just rename a style in GWC
catalogConfig.truncate(tl.getName(), oldStyleName);
styleNames.remove(oldStyleName);
styleNames.add(newStyleName);
info.setCachedStyles(styleNames);
catalogConfig.save(tl);
}
}
}
/**
* Truncates all tile sets referring the modified {@link StyleInfo}
*
* @see org.geoserver.catalog.event.CatalogListener#handlePostModifyEvent
*/
public void handlePostModifyEvent(CatalogPostModifyEvent event) throws CatalogException {
Object obj = event.getSource();
if (obj instanceof StyleInfo) {
StyleInfo si = (StyleInfo) obj;
handleStyleChange(si);
}
}
/**
* Options are:
* <ul>
* <li>A {@link LayerInfo} has {@code modifiedStyle} as either its default or style or as one of
* its alternate styles
* <li>A {@link LayerGroupInfo} contains a layer using {@code modifiedStyle}
* <li>{@code modifiedStyle} is explicitly assigned to a {@link LayerGroupInfo}
* </ul>
*
* @param modifiedStyle
*/
private void handleStyleChange(final StyleInfo modifiedStyle) {
final String styleName = modifiedStyle.getName();
log.finer("Handling style modification: " + styleName);
// First we collect all the layers that use this style
for (LayerInfo affectedLayer : catalogConfig.getLayerInfosFor(modifiedStyle)) {
// If the style name changes, we need to update the layer's parameter filter
String prefixedName = affectedLayer.getResource().getPrefixedName();
log.info("Truncating layer '" + prefixedName + "' due to a change in style '"
+ styleName + "'");
catalogConfig.truncate(prefixedName, styleName);
}
// Now we check for layer groups that are affected
for (LayerGroupInfo layerGroup : catalogConfig.getLayerGroupsFor(modifiedStyle)) {
String layerGroupName = layerGroup.getName();
log.info("Truncating layer group '" + layerGroupName + "' due to a change in style '"
+ styleName + "'");
catalogConfig.truncate(layerGroupName);
}
}
/**
* No need to do anything here, when a style is removed all the layers that reference it are
* updated first
*
* @see org.geoserver.catalog.event.CatalogListener#handleRemoveEvent
*/
public void handleRemoveEvent(CatalogRemoveEvent event) throws CatalogException {
//
}
/**
*
*/
public void reloaded() {
//
}
}