public MediaFileDescriptor buildMediaDescriptor(File f) {
   MediaFileDescriptor id = new MediaFileDescriptor();
   int[] data;
   String md5;
   try {
     id.setPath(f.getCanonicalPath());
     id.setMtime(f.lastModified());
     id.setSize(f.length());
     // generate thumbnails only for images, not video
     if (Utils.isValideImageName(f.getName())) {
       MetaDataFinder mdf = new MetaDataFinder(f);
       double[] latLon = mdf.getLatLong();
       if (latLon != null) {
         id.setLat(latLon[0]);
         id.setLon(latLon[1]);
       }
       // bufferize images in memory, read directly from file for others
       ByteArrayInputStream fbi = this.readFileToMemory(f);
       id.setHash(new ImageHash().generateSignature(fbi));
       fbi.reset();
       md5 = generateMD5(fbi);
       id.setMd5Digest(md5);
     } else {
       md5 = generateMD5(f);
       id.setMd5Digest(md5);
     }
   } catch (FileNotFoundException e) {
     e.printStackTrace();
   } catch (IOException e) {
     System.err.println("Error processing  file " + f.getName());
     e.printStackTrace();
   }
   return id;
 }
  public void generateAndSave(File f) {
    System.out.print(".");
    currentProgressSize += f.length() / 1024;
    try {
      MediaFileDescriptor mf = ts.getMediaFileDescriptor(f.getCanonicalPath());
      Logger.getLogger().err("MediaIndexer.generateAndSave " + f + " descriptor: " + mf);

      if ((mf != null) && (f.lastModified() == mf.getMtime())) {
        // Descriptor exists with same mtime
        Logger.getLogger()
            .err("MediaIndexer.generateImageDescriptor() Already in DB, ignoring with same mtime");
        Logger.getLogger().err("MediaIndexer.generateImageDescriptor() In   DB : " + mf.getMtime());
        Logger.getLogger()
            .err("MediaIndexer.generateImageDescriptor() On Disk : " + f.lastModified());
        boolean update = false;

        if (forceGPSUpdate) {
          //  MediaFileDescriptor mfd = ts.getMediaFileDescriptor(f.getCanonicalPath());
          MetaDataFinder mdf = new MetaDataFinder(f);
          double latLon[] = mdf.getLatLong();
          Logger.getLogger().err("MediaIndexer.generateAndSave working on " + f);
          if (latLon != null) {
            mf.setLat(latLon[0]);
            mf.setLon(latLon[1]);
            Logger.getLogger().err("MediaIndexer : forced update for GPS data for " + f);
            updateToDB(mf);
            update = true;
          }
        }
        if (forceHashUpdate || (mf.getHash() == null)) {
          if (Utils.isValideImageName(f.getName())) {
            mf.setHash(new ImageHash().generateSignature(f.getCanonicalPath()));
            updateToDB(mf);
            update = true;
          }
        }
        // if (update) {
        this.fileCreatedUpdated(false, update);
        // }
      } else {
        Logger.getLogger().err("MediaIndexer.generateAndSave building descriptor");
        MediaFileDescriptor id = this.buildMediaDescriptor(f);
        if (id != null) {
          if ((mf != null) && (f.lastModified() != mf.getMtime())) {
            // we need to update it
            updateToDB(id);
            this.fileCreatedUpdated(false, true);
          } else {
            saveToDB(id);
            this.fileCreatedUpdated(true, false);
          }
          if (log.isEnabled()) {
            log.log(
                f.getCanonicalPath()
                    + " ..... size  "
                    + (f.length() / 1024)
                    + " KiB OK "
                    + executorService.getActiveCount()
                    + " threads running");
          }
        } else {
          this.fileCreatedUpdated(false, false);
        }
      }
    } catch (IOException e) {
      System.err.println("Error processing  file " + f.getName());
      e.printStackTrace();
    }
  }
  //
  // обработка исходящего каталога АБС
  //
  public boolean processOutDirectory() {
    boolean result = true;
    try {

      //
      // читаем control.xml
      //
      File controlFile = new File(ABS_OUTPUT_DIR + "/control.xml");
      if (!controlFile.exists()) {
        logger.error("Нет файла " + controlFile.getName());
        if (new File(ABS_OUTPUT_DIR + "/control.zip").exists()) {
          logger.info("Обнаружен архив " + ABS_OUTPUT_DIR + "/control.zip");
          return true;
        }
        return false;
      }
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      DocumentBuilder builder = factory.newDocumentBuilder();
      Document controlDoc = builder.parse(controlFile);
      // готовимся изменять файл
      XPath searchPath = XPathFactory.newInstance().newXPath();

      // ищем каталоги с контейнерами
      File[] directoryList = (new File(ABS_OUTPUT_DIR)).listFiles(p -> p.isDirectory());

      //
      // просматриваем каталоги типа FILES/out/....
      //
      for (int i = 0; i < directoryList.length; i++) {
        //
        // в каталоге должен быть файл data.zip и файлы-вложения
        // файл data.zip нужно подписать и зазиповать
        //
        logger.info("Обрабатываем каталог " + directoryList[i].getAbsolutePath());
        //
        // просматриваем содержимое каталога с контейнером
        //
        File[] currentDir = (directoryList[i]).listFiles(p -> p.isFile());
        //
        // создаем zip-file
        //
        File zip = new File(directoryList[i].getAbsolutePath() + "/data_" + i + ".zip");
        logger.info("Создаем архив " + zip.getAbsolutePath());
        FileOutputStream zipStream = new FileOutputStream(zip);
        ZipOutputStream dataZip = new ZipOutputStream(zipStream);
        for (File curFile : currentDir) {
          if ("data.xml.sig".equals(curFile.getName())) continue;
          appendZipFile(dataZip, curFile);
          //
          // для файла data.zip создаем цифровую подпись и записываем файл с подписью в архив
          //
          if ("data.xml".equals(curFile.getName())) {
            fileSigner.cades(curFile.getAbsolutePath());
            String fName = curFile.getAbsolutePath();
            File signFile = new File(fName.substring(0, fName.length() - 3) + "sign");
            appendZipFile(dataZip, signFile);
            signFile.delete();
          }
          //
          // удаляем файл после включения в архив
          //
          curFile.delete();
        }
        //
        // закрываем архив и его поток
        //
        dataZip.close();
        zipStream.close();
        logger.info("Запись в архив " + zip.getAbsolutePath() + " завершена");
        //
        // вычисляем crc32
        //
        long crc32 = Utils.calculateCRC32(zip);
        long zipSize = zip.length();
        //
        // в файле control.xml ищем соответствующий узел контейнера и меняем его атрибуты
        //
        String xpathQuery = "//Containers[@ReqUID='" + directoryList[i].getName() + "']";
        Node containerNode =
            (Node) searchPath.evaluate(xpathQuery, controlDoc, XPathConstants.NODE);
        if (containerNode == null) {
          logger.error(
              "В файле control.xml  не найдено описание для контейнера "
                  + directoryList[i].getName());
          System.exit(1);
        }
        Element containerElement = (Element) containerNode;
        containerElement.setAttribute("name", zip.getName());
        containerElement.setAttribute("size", zipSize + "");
        containerElement.setAttribute("CRC", crc32 + "");
      }
      // сохраняем control.xml
      DOMSource domSource = new DOMSource(controlDoc);
      StreamResult streamResult = new StreamResult(controlFile);
      Transformer transformer = TransformerFactory.newInstance().newTransformer();
      transformer.transform(domSource, streamResult);
      transformer.reset();
      //
      // подписываем файл
      //
      fileSigner.cades(controlFile.getAbsolutePath());
      //
      // записываем файл control.xml и подпись в архив
      //
      File zip = new File(ABS_OUTPUT_DIR + "/control.zip");
      logger.info("Создаем архив " + zip.getAbsolutePath());
      FileOutputStream zipStream = new FileOutputStream(zip);
      ZipOutputStream dataZip = new ZipOutputStream(zipStream);
      //
      // дописываем управляющий файл
      //
      File cFile = new File(ABS_OUTPUT_DIR + "/control.xml");
      appendZipFile(dataZip, cFile);
      cFile.delete();
      //
      // дописываем подпись
      //
      cFile = new File(ABS_OUTPUT_DIR + "/control.sign");
      appendZipFile(dataZip, cFile);
      cFile.delete();
      logger.info("Запись в архив " + zip.getAbsolutePath() + " завершена");
      //
      // закрываем архив и его поток
      //
      dataZip.close();
      zipStream.close();
    } catch (Exception e) {
      logger.error(e.getMessage());
      e.printStackTrace();
    }

    return result;
  }