/**
  * Report on the features of a layer.
  *
  * @param reportName name of the report
  * @param format format for the report (eg "pdf")
  * @param layerId id of the layer
  * @param crs coordinate reference system
  * @param filter filter to apply on layer
  * @param request request object for report parameters
  * @param model mvc model
  * @return name of the view
  */
 @RequestMapping(
     value = "/reporting/f/{layerId}/{reportName}.{format}",
     method = RequestMethod.GET)
 public String reportFeatures(
     @PathVariable String reportName,
     @PathVariable String format,
     @PathVariable String layerId,
     @RequestParam(defaultValue = "EPSG:4326", required = false) String crs,
     @RequestParam(required = false) String filter,
     HttpServletRequest request,
     Model model) {
   List<InternalFeature> features;
   try {
     Filter filterObject = null;
     if (null != filter) {
       filterObject = filterService.parseFilter(filter);
     }
     features =
         vectorLayerService.getFeatures(
             layerId,
             geoService.getCrs2(crs),
             filterObject,
             null,
             VectorLayerService.FEATURE_INCLUDE_ALL);
     model.addAttribute(DATA_SOURCE, new InternalFeatureDataSource(features));
     addParameters(model, request);
   } catch (GeomajasException ge) {
     log.error(REPORT_DATA_PROBLEM, ge);
     model.addAttribute(
         DATA_SOURCE, new InternalFeatureDataSource(new ArrayList<InternalFeature>()));
   }
   model.addAttribute(JasperReportsMultiFormatView.DEFAULT_FORMAT_KEY, format);
   return getView(reportName);
 }
  @Override
  public void execute(UserMaximumExtentRequest request, UserMaximumExtentResponse response)
      throws Exception {
    String[] layers;
    ArrayList<String> tempLayers = new ArrayList<String>();
    String[] includeLayers = request.getLayerIds();
    boolean excludeRasterLayers = request.isExcludeRasterLayers();
    if (includeLayers != null && includeLayers.length > 0) {
      for (String layerId : includeLayers) {
        if (!securityContext.isLayerVisible(layerId)) {
          throw new GeomajasSecurityException(ExceptionCode.LAYER_NOT_VISIBLE, layerId);
        }
        Layer<?> l = configurationService.getLayer(layerId);
        if (null == l) {
          throw new GeomajasException(ExceptionCode.LAYER_NOT_FOUND, layerId);
        }
        if (!excludeRasterLayers || l.getLayerInfo().getLayerType() != LayerType.RASTER) {
          tempLayers.add(l.getId());
        }
      }
    }
    layers = tempLayers.toArray(new String[tempLayers.size()]);

    Layer<?> layer;
    Crs targetCrs = geoService.getCrs2(request.getCrs());

    if (layers.length == 0) {
      // return empty bbox
      response.setBounds(new Bbox());
    } else {
      Envelope extent = new Envelope();
      for (String layerId : layers) {
        layer = configurationService.getLayer(layerId);
        if (layer != null) {
          Envelope bounds;
          if (layer.getLayerInfo().getLayerType() == LayerType.RASTER) {
            bounds = securityContext.getVisibleArea(layerId).getEnvelopeInternal();
            CrsTransform transform = geoService.getCrsTransform(layer.getCrs(), targetCrs);
            bounds = geoService.transform(bounds, transform);
          } else {
            bounds = layerService.getBounds(layerId, targetCrs, null);
          }
          extent.expandToInclude(bounds);
        } else {
          log.warn("layer not found ?! " + layerId);
        }
      }
      response.setBounds(converterService.toDto(extent));
    }
  }