private void writeOutput(
      List<TemporalBin> temporalBins, ProductData.UTC startTime, ProductData.UTC stopTime)
      throws Exception {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();

    initMetadataProperties();

    if (outputBinnedData) {
      try {
        writeNetCDFBinFile(temporalBins, startTime, stopTime);
      } catch (Exception e) {
        getLogger()
            .log(Level.SEVERE, String.format("Failed to write binned data: %s", e.getMessage()), e);
      }
    }

    if (outputTargetProduct) {
      getLogger()
          .info(String.format("Writing mapped product '%s'...", formatterConfig.getOutputFile()));
      final MetadataElement processingGraphMetadata = getProcessingGraphMetadata();
      Formatter.format(
          binningContext.getPlanetaryGrid(),
          getTemporalBinSource(temporalBins),
          binningContext.getBinManager().getResultFeatureNames(),
          formatterConfig,
          region,
          startTime,
          stopTime,
          processingGraphMetadata);
      stopWatch.stop();

      String msgPattern = "Writing mapped product '%s' done, took %s";
      getLogger().info(String.format(msgPattern, formatterConfig.getOutputFile(), stopWatch));

      if (outputType.equalsIgnoreCase("Product")) {
        final File writtenProductFile = new File(outputFile);
        String format = Formatter.getOutputFormat(formatterConfig, writtenProductFile);
        writtenProduct = ProductIO.readProduct(writtenProductFile, format);
        this.targetProduct = copyProduct(writtenProduct);
      } else {
        this.targetProduct = new Product("Dummy", "t", 10, 10);
      }
    } else {
      this.targetProduct = new Product("Dummy", "t", 10, 10);
    }
  }
  private void initBinWriter(ProductData.UTC startTime, ProductData.UTC stopTime) {
    if (binWriter == null) {
      binWriter = new SeaDASLevel3BinWriter(region, startTime, stopTime);
    }

    binWriter.setBinningContext(binningContext);
    binWriter.setTargetFileTemplatePath(formatterConfig.getOutputFile());
    binWriter.setLogger(getLogger());
  }
 private void validateInput() {
   if (timeFilterMethod == null) {
     timeFilterMethod = TimeFilterMethod.NONE;
   }
   if (timeFilterMethod != TimeFilterMethod.NONE
       && (startDateTime == null || periodDuration == null)) {
     throw new OperatorException(
         "Using a time filer requires the parameters 'startDateTime' and 'periodDuration'");
   }
   if (periodDuration != null && periodDuration < 0.0) {
     throw new OperatorException("The parameter 'periodDuration' must be a positive value");
   }
   if (timeFilterMethod == TimeFilterMethod.SPATIOTEMPORAL_DATA_DAY && minDataHour == null) {
     throw new OperatorException(
         "If SPATIOTEMPORAL_DATADAY filtering is used the parameters 'minDataHour' must be given");
   }
   if (sourceProducts == null && (sourceProductPaths == null || sourceProductPaths.length == 0)) {
     String msg =
         "Either source products must be given or parameter 'sourceProductPaths' must be specified";
     throw new OperatorException(msg);
   }
   if (numRows < 2 || numRows % 2 != 0) {
     throw new OperatorException("Operator parameter 'numRows' must be greater than 0 and even");
   }
   if (aggregatorConfigs == null || aggregatorConfigs.length == 0) {
     throw new OperatorException("No aggregators have been defined");
   }
   if (formatterConfig.getOutputFile() == null) {
     throw new OperatorException("Missing operator parameter 'formatterConfig.outputFile'");
   }
   if (metadataTemplateDir == null || "".equals(metadataTemplateDir.getPath())) {
     metadataTemplateDir = new File(".");
   }
   if (!metadataTemplateDir.exists()) {
     String msgPattern = "Directory given by 'metadataTemplateDir' does not exist: %s";
     throw new OperatorException(String.format(msgPattern, metadataTemplateDir));
   }
   if (!outputBinnedData && !outputTargetProduct) {
     throw new OperatorException(
         "At least one of the parameters 'outputBinnedData' and 'outputTargetProduct' must be 'true'");
   }
 }
  /**
   * Processes all source products and writes the output file. The target product represents the
   * written output file
   *
   * @throws org.esa.snap.framework.gpf.OperatorException If a processing error occurs.
   */
  @Override
  public void initialize() throws OperatorException {
    formatterConfig = new FormatterConfig();
    formatterConfig.setBandConfigurations(bandConfigurations);
    formatterConfig.setOutputFile(outputFile);
    formatterConfig.setOutputFormat(outputFormat);
    formatterConfig.setOutputType(outputType);
    formatterConfig.setProductCustomizerConfig(productCustomizerConfig);

    validateInput();

    ProductData.UTC startDateUtc = null;
    ProductData.UTC endDateUtc = null;
    if (startDateTime != null) {
      startDateUtc = parseStartDateUtc(startDateTime);
      double startMJD = startDateUtc.getMJD();
      double endMJD = startMJD + periodDuration;
      endDateUtc = new ProductData.UTC(endMJD);
    }

    StopWatch stopWatch = new StopWatch();
    stopWatch.start();

    if (region == null) {
      // TODO use JTS directly (nf 2013-11-06)
      regionArea = new Area();
    }

    final BinningConfig binningConfig = createConfig();

    binningContext = binningConfig.createBinningContext(region, startDateUtc, periodDuration);

    BinningProductFilter productFilter =
        createSourceProductFilter(binningContext.getDataPeriod(), startDateUtc, endDateUtc, region);

    metadataAggregator = MetadataAggregatorFactory.create(metadataAggregatorName);
    numProductsAggregated = 0;

    try {
      // Step 1: Spatial binning - creates time-series of spatial bins for each bin ID ordered by
      // ID. The tree map structure is <ID, time-series>
      SpatialBinCollection spatialBinMap = doSpatialBinning(productFilter);
      if (!spatialBinMap.isEmpty()) {
        // update region
        if (region == null && regionArea != null) {
          region = JTS.shapeToGeometry(regionArea, new GeometryFactory());
        }
        // Step 2: Temporal binning - creates a list of temporal bins, sorted by bin ID
        TemporalBinList temporalBins = doTemporalBinning(spatialBinMap);
        // Step 3: Formatting
        try {
          if (startDateTime != null) {
            writeOutput(temporalBins, startDateUtc, endDateUtc);
          } else {
            writeOutput(temporalBins, minDateUtc, maxDateUtc);
          }
        } finally {
          temporalBins.close();
        }
      } else {
        getLogger().warning("No bins have been generated, no output has been written");
      }
    } catch (OperatorException e) {
      throw e;
    } catch (Exception e) {
      throw new OperatorException(e);
    } finally {
      cleanSourceProducts();
    }

    stopWatch.stopAndTrace(
        String.format("Total time for binning %d product(s)", numProductsAggregated));

    globalMetadata.processMetadataTemplates(metadataTemplateDir, this, targetProduct, getLogger());
  }