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

libretto.examples.libraryOfAlexandria.vendor.ConnectorImpl.scala Maven / Gradle / Ivy

The newest version!
package libretto.examples.libraryOfAlexandria.vendor

private[vendor] class ConnectorImpl extends Connector {
  private var openConnections: Int = 0
  private var closed: Boolean = false

  override def connect(): Connection =
    ConnectorImpl.this.synchronized {
      if (closed) {
        throw IllegalStateException("Already closed")
      } else {
        openConnections += 1
        new ConnectionImpl()
      }
    }

  override def close(): Unit =
    ConnectorImpl.this.synchronized {
      if (openConnections > 0)
        throw IllegalStateException(s"There are $openConnections open connections")
      else
        closed = true
    }

  class ConnectionImpl() extends Connection {
    private var closed = false
    private var inUseBy: Option[Job[?]] = None

    override def fetchScroll(id: ScrollId): Option[ResultSet[Page]] = {
      val job: Option[ScrollDigitization] =
        ConnectionImpl.this.synchronized {
          if (closed) {
            throw IllegalStateException("Connection already closed.")
          } else if (inUseBy.nonEmpty) {
            throw IllegalStateException("Connection already in use.")
          } else {
            val job: Option[ScrollDigitization] =
              ScrollDatabase.get(id).map(ScrollDigitization(id, _))
            inUseBy = job
            job
          }
        }
      job.map(_.start())
    }

    override def close(): Unit = {
      val currentJob: Option[Job[?]] =
        ConnectionImpl.this.synchronized {
          if (!closed) {
            val currentJob = inUseBy
            inUseBy = None
            closed = true
            ConnectorImpl.this.synchronized {
              openConnections -= 1
            }
            currentJob
          } else {
            None
          }
        }
      currentJob.foreach(_.cancel())
    }

    sealed trait Job[A] {
      def start(): A
      def cancel(): Unit
    }

    class ScrollDigitization(id: ScrollId, scroll: Scroll) extends Job[ResultSet[Page]] {
      private var started = false
      private var closed  = false

      override def start(): ResultSet[Page] =
        ScrollDigitization.this.synchronized {
          if (started)
            throw IllegalStateException("Job already started")
          else {
            started = true
            Thread.sleep(10) // scanning the scroll takes some time
            new ResultSetImpl(id, scroll.paginate())
          }
        }

      override def cancel(): Unit =
        ScrollDigitization.this.synchronized {
          if (!closed) {
            closed = true
            ConnectionImpl.this.synchronized {
              ConnectionImpl.this.inUseBy match {
                case None =>
                  // do nothing
                case Some(job) =>
                  assert(job eq ScrollDigitization.this)
                  ConnectionImpl.this.inUseBy = None
              }
            }
          }
        }

      class ResultSetImpl(
        scrollId: ScrollId,
        pages: Iterator[(Int, String)],
      ) extends ResultSet[Page] {
        override def earlyClose(): Unit =
          ScrollDigitization.this.cancel()

        override def next(): Option[Page] =
          if (pages.hasNext) {
            val (number, content) = pages.next()
            Some(Page(scrollId, number, content))
          } else {
            ScrollDigitization.this.cancel()
            None
          }
      }
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy