All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.methvin.better.files.RecursiveFileMonitor.scala Maven / Gradle / Ivy

The newest version!
/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.methvin.better.files

import java.nio.file.Path
import java.nio.file.WatchEvent
import java.util.Collections

import better.files._
import io.methvin.watcher.DirectoryChangeEvent
import io.methvin.watcher.DirectoryChangeEvent.EventType
import io.methvin.watcher.DirectoryChangeListener
import io.methvin.watcher.DirectoryWatcher
import io.methvin.watcher.hashing.FileHasher
import org.slf4j.Logger
import org.slf4j.helpers.NOPLogger

import scala.concurrent.ExecutionContext

/** An implementation of the better-files `File.Monitor` interface using directory-watcher.
  *
  * @param root
  *   the root directory to watch
  * @param fileHasher
  *   a hasher implementation used to hash files to prevent duplicate events. `None` to disable
  *   hashing.
  * @param logger
  *   the logger used by `DirectoryWatcher`. Useful to see debug output. Defaults to nop logger.
  */
abstract class RecursiveFileMonitor(
  val root: File,
  val fileHasher: Option[FileHasher] = Some(FileHasher.DEFAULT_FILE_HASHER),
  val logger: Logger = NOPLogger.NOP_LOGGER
) extends File.Monitor {

  protected[this] val pathToWatch: Option[Path] =
    if (root.exists) Some(if (root.isDirectory) root.path else root.parent.path) else None

  protected[this] def reactTo(path: Path): Boolean =
    path == null || root.isDirectory || root.isSamePathAs(path)

  protected[this] val watcher: DirectoryWatcher = DirectoryWatcher.builder
    .paths(pathToWatch.fold(Collections.emptyList[Path]())(Collections.singletonList))
    .listener(new DirectoryChangeListener {
      override def onEvent(event: DirectoryChangeEvent): Unit = {
        if (reactTo(event.path)) {
          val et = event.eventType
          et match {
            case EventType.OVERFLOW =>
              onUnknownEvent(new WatchEvent[AnyRef] {
                override def kind = et.getWatchEventKind.asInstanceOf[WatchEvent.Kind[AnyRef]]
                override def count = event.count
                override def context = null
              })
            case _ =>
              RecursiveFileMonitor.this.onEvent(
                et.getWatchEventKind.asInstanceOf[WatchEvent.Kind[Path]],
                File(event.path),
                event.count
              )
          }
        }
      }

      override def onException(e: Exception): Unit = {
        RecursiveFileMonitor.this.onException(e)
      }
    })
    .fileHasher(fileHasher.orNull)
    .logger(logger)
    .build()

  override def start()(implicit executionContext: ExecutionContext): Unit = {
    executionContext.execute(() => watcher.watch())
  }

  override def close(): Unit = {
    watcher.close()
  }

  // override these so it works like the better-files monitor
  override def onCreate(file: File, count: Int): Unit = {}
  override def onModify(file: File, count: Int): Unit = {}
  override def onDelete(file: File, count: Int): Unit = {}
  override def onUnknownEvent(event: WatchEvent[_]): Unit = {}
  override def onException(exception: Throwable): Unit = {}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy