/**
  * LayerInfo has been created, add a matching {@link GeoServerTileLayer}
  *
  * @see CatalogLayerEventListener#handleAddEvent
  * @see GWC#add(GeoServerTileLayer)
  */
 void createTileLayer(final LayerInfo layerInfo) {
   GWCConfig defaults = mediator.getConfig();
   if (defaults.isSane() && defaults.isCacheLayersByDefault()) {
     GridSetBroker gridSetBroker = mediator.getGridSetBroker();
     GeoServerTileLayer tileLayer = new GeoServerTileLayer(layerInfo, defaults, gridSetBroker);
     mediator.add(tileLayer);
   }
 }
    @Override
    public void validate(IValidatable<Set<XMLGridSubset>> validatable) {
      if (!validate) {
        return;
      }
      Set<XMLGridSubset> gridSubsets = validatable.getValue();
      if (gridSubsets == null || gridSubsets.size() == 0) {
        error(validatable, "GridSubsetsEditor.validation.empty");
        return;
      }

      final GWC gwc = GWC.get();
      for (XMLGridSubset subset : gridSubsets) {
        final String gridSetName = subset.getGridSetName();
        final Integer zoomStart = subset.getZoomStart();
        final Integer zoomStop = subset.getZoomStop();
        final BoundingBox extent = subset.getExtent();

        if (gridSetName == null) {
          throw new IllegalStateException("GridSet name is null");
        }

        if (zoomStart != null && zoomStop != null) {
          if (zoomStart.intValue() > zoomStop.intValue()) {
            error(validatable, "GridSubsetsEditor.validation.zoomLevelsError");
            return;
          }
        }

        final GridSetBroker gridSetBroker = gwc.getGridSetBroker();
        final GridSet gridSet = gridSetBroker.get(gridSetName);

        if (null == gridSet) {
          error(validatable, "GridSubsetsEditor.validation.gridSetNotFound", gridSetName);
          return;
        }

        if (extent != null) {
          if (extent.isNull() || !extent.isSane()) {
            error(validatable, "GridSubsetsEditor.validation.invalidBounds");
          }
          final BoundingBox fullBounds = gridSet.getOriginalExtent();
          final boolean intersects = fullBounds.intersects(extent);
          if (!intersects) {
            error(validatable, "GridSubsetsEditor.validation.boundsOutsideCoverage");
          }
        }
      }
    }
  private void handleRename(
      final GeoServerTileLayerInfo tileLayerInfo,
      final CatalogInfo source,
      final List<String> changedProperties,
      final List<Object> oldValues,
      final List<Object> newValues) {

    final int nameIndex = changedProperties.indexOf("name");
    final int namespaceIndex = changedProperties.indexOf("namespace");

    String oldLayerName;
    String newLayerName;
    if (source instanceof ResourceInfo) { // covers LayerInfo, CoverageInfo, and WMSLayerInfo
      // must cover prefix:name
      final ResourceInfo resourceInfo = (ResourceInfo) source;
      final NamespaceInfo currNamespace = resourceInfo.getNamespace();
      final NamespaceInfo oldNamespace;
      if (namespaceIndex > -1) {
        // namespace changed
        oldNamespace = (NamespaceInfo) oldValues.get(namespaceIndex);
      } else {
        oldNamespace = currNamespace;
      }

      newLayerName = resourceInfo.prefixedName();
      if (nameIndex > -1) {
        oldLayerName = (String) oldValues.get(nameIndex);
      } else {
        oldLayerName = resourceInfo.getName();
      }
      oldLayerName = oldNamespace.getPrefix() + ":" + oldLayerName;
    } else {
      // it's a layer group, no need to worry about namespace
      oldLayerName = tileLayerInfo.getName();
      newLayerName = tileLayerName((LayerGroupInfo) source);
    }

    if (!oldLayerName.equals(newLayerName)) {
      tileLayerInfo.setName(newLayerName);

      // notify the mediator of the rename so it changes the name of the layer in GWC without
      // affecting its caches
      GridSetBroker gridSetBroker = mediator.getGridSetBroker();

      final GeoServerTileLayer oldTileLayer =
          (GeoServerTileLayer) mediator.getTileLayerByName(oldLayerName);

      checkState(
          null != oldTileLayer,
          "hanldeRename: old tile layer not found: '"
              + oldLayerName
              + "'. New name: '"
              + newLayerName
              + "'");

      final GeoServerTileLayer modifiedTileLayer;

      if (oldTileLayer.getLayerInfo() != null) {
        LayerInfo layerInfo = oldTileLayer.getLayerInfo();
        modifiedTileLayer = new GeoServerTileLayer(layerInfo, gridSetBroker, tileLayerInfo);
      } else {
        LayerGroupInfo layerGroup = oldTileLayer.getLayerGroupInfo();
        modifiedTileLayer = new GeoServerTileLayer(layerGroup, gridSetBroker, tileLayerInfo);
      }
      mediator.save(modifiedTileLayer);
    }
  }
  /**
   * Handles changes of interest to GWC on a {@link LayerInfo}.
   *
   * <ul>
   *   <li>If the name of the default style changed, then the layer's cache for the default style is
   *       truncated. This method doesn't check if the contents of the styles are equal. That is
   *       handled by {@link CatalogStyleChangeListener} whenever a style is modified.
   *   <li>If the tile layer is {@link GeoServerTileLayerInfo#isAutoCacheStyles() auto caching
   *       styles} and the layerinfo's "styles" list changed, the tile layer's STYLE parameter
   *       filter is updated to match the actual list of layer styles and any removed style is
   *       truncated.
   * </ul>
   *
   * @param changedProperties
   * @param oldValues
   * @param newValues
   * @param li
   * @param tileLayerInfo
   */
  private void handleLayerInfoChange(
      final List<String> changedProperties,
      final List<Object> oldValues,
      final List<Object> newValues,
      final LayerInfo li,
      final GeoServerTileLayerInfo tileLayerInfo) {

    checkNotNull(tileLayerInfo);

    final String layerName = tileLayerName(li);

    boolean save = false;

    final String defaultStyle;

    /*
     * If default style name changed
     */
    if (changedProperties.contains("defaultStyle")) {
      final int propIndex = changedProperties.indexOf("defaultStyle");
      final StyleInfo oldStyle = (StyleInfo) oldValues.get(propIndex);
      final StyleInfo newStyle = (StyleInfo) newValues.get(propIndex);

      final String oldStyleName = oldStyle.getName();
      defaultStyle = newStyle.getName();
      if (!Objects.equal(oldStyleName, defaultStyle)) {
        save = true;
        log.info(
            "Truncating default style for layer "
                + layerName
                + ", as it changed from "
                + oldStyleName
                + " to "
                + defaultStyle);
        mediator.truncateByLayerAndStyle(layerName, oldStyleName);
      }
    } else {
      StyleInfo styleInfo = li.getDefaultStyle();
      defaultStyle = styleInfo == null ? null : styleInfo.getName();
    }

    if (tileLayerInfo.isAutoCacheStyles()) {
      Set<String> styles = new HashSet<String>();
      for (StyleInfo s : li.getStyles()) {
        styles.add(s.getName());
      }
      ImmutableSet<String> cachedStyles = tileLayerInfo.cachedStyles();
      if (!styles.equals(cachedStyles)) {
        // truncate no longer existing cached styles
        Set<String> notCachedAnyMore = Sets.difference(cachedStyles, styles);
        for (String oldCachedStyle : notCachedAnyMore) {
          log.info(
              "Truncating cached style "
                  + oldCachedStyle
                  + " of layer "
                  + layerName
                  + " as it's no longer one of the layer's styles");
          mediator.truncateByLayerAndStyle(layerName, oldCachedStyle);
        }
        // reset STYLES parameter filter
        final boolean createParamIfNotExists = true;
        TileLayerInfoUtil.updateStringParameterFilter(
            tileLayerInfo, "STYLES", createParamIfNotExists, defaultStyle, styles);
        save = true;
      }
    }

    if (save) {
      GridSetBroker gridSetBroker = mediator.getGridSetBroker();
      GeoServerTileLayer tileLayer = new GeoServerTileLayer(li, gridSetBroker, tileLayerInfo);
      mediator.save(tileLayer);
    }
  }
 /**
  * LayerGroupInfo has been created, add a matching {@link GeoServerTileLayer}
  *
  * @see CatalogLayerEventListener#handleAddEvent
  * @see GWC#add(GeoServerTileLayer)
  */
 public void createTileLayer(LayerGroupInfo lgi) {
   GWCConfig defaults = mediator.getConfig();
   GridSetBroker gridSetBroker = mediator.getGridSetBroker();
   GeoServerTileLayer tileLayer = new GeoServerTileLayer(lgi, defaults, gridSetBroker);
   mediator.add(tileLayer);
 }
  GridSubset findBestGridSubset(WMSMapContent map) {
    GetMapRequest req = map.getRequest();
    Map formatOpts = req.getFormatOptions();

    GridSetBroker gridSetBroker = gwc.getGridSetBroker();
    GridSet gridSet = null;

    // first check format options to see if explicitly specified
    if (formatOpts.containsKey("gridset")) {
      gridSet = gridSetBroker.get(formatOpts.get("gridset").toString());
    }

    // next check srs
    if (gridSet == null) {
      gridSet = gridSetBroker.get(req.getSRS().toUpperCase());
    }

    if (gridSet != null) {
      return GridSubsetFactory.createGridSubSet(gridSet);
    }

    CoordinateReferenceSystem crs = map.getCoordinateReferenceSystem();

    // look up epsg code
    Integer epsgCode = null;
    try {
      epsgCode = CRS.lookupEpsgCode(crs, false);
    } catch (Exception e) {
      throw new ServiceException("Unable to determine epsg code for " + crs, e);
    }
    if (epsgCode == null) {
      throw new ServiceException("Unable to determine epsg code for " + crs);
    }

    SRS srs = SRS.getSRS(epsgCode);

    // figure out the appropriate grid sub set
    Set<GridSubset> gridSubsets = new LinkedHashSet<GridSubset>();
    for (MapLayerInfo l : req.getLayers()) {
      TileLayer tl = gwc.getTileLayerByName(l.getName());
      if (tl == null) {
        throw new ServiceException("No tile layer for " + l.getName());
      }

      List<GridSubset> theseGridSubsets = tl.getGridSubsetsForSRS(srs);
      if (gridSubsets.isEmpty()) {
        gridSubsets.addAll(theseGridSubsets);
      } else {
        gridSubsets.retainAll(theseGridSubsets);
      }

      if (gridSubsets.isEmpty()) {
        throw new ServiceException(
            "No suitable " + epsgCode + " grid subset for " + req.getLayers());
      }
    }

    if (gridSubsets.size() > 1) {
      if (LOGGER.isLoggable(Level.WARNING)) {
        StringBuilder msg = new StringBuilder("Found multiple grid subsets: ");
        for (GridSubset gs : gridSubsets) {
          msg.append(gs.getName()).append(", ");
        }
        msg.setLength(msg.length() - 2);
        msg.append(". Choosing first.");
        LOGGER.warning(msg.toString());
      }
    }

    return gridSubsets.iterator().next();
  }