/* 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() { // } }