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

resource.AbstractManagedResource.scala Maven / Gradle / Ivy

There is a newer version: 2.0-RC1
Show newest version
// -----------------------------------------------------------------------------
//
//  scala.arm - The Scala Incubator Project
//  Copyright (c) 2009 The Scala Incubator Project. All rights reserved.
//
//  The primary distribution site is http://jsuereth.github.com/scala-arm
//
//  This software is released under the terms of the Revised BSD License.
//  There is NO WARRANTY.  See the file LICENSE for the full text.
//
// -----------------------------------------------------------------------------


package resource

import _root_.scala.collection.Seq
import _root_.scala.util.control.Exception
import _root_.scala.util.control.ControlThrowable

/**
 * An implementation of an ExtractableManagedResource that defers all processing until the user pulls out information using
 * either or opt functions.
 */
private[resource] class DeferredExtractableManagedResource[+A,R](val resource: ManagedResource[R], val translate: R => A)
  extends ExtractableManagedResource[A] with ManagedResourceOperations[A] { self =>

  override def acquireFor[B](f: A => B) : ExtractedEither[List[Throwable], B] = resource acquireFor (translate andThen f)

  override def either = ExtractedEither(resource acquireFor translate)

  override def opt = either.either.right.toOption

  override def tried = scala.util.Try(resource apply translate)

  override def equals(that: Any) = that match {
    case x : DeferredExtractableManagedResource[A,R] => (x.resource == resource) && (x.translate == translate)
    case _ => false
  }
  override def hashCode(): Int = (resource.hashCode << 7) + translate.hashCode + 13

  override def toString = "DeferredExtractableManagedResource(" + resource + ", " + translate + ")"
}


/**
 * Abstract class implementing most of the managed resource features in terms of an open and close method.   This
 * is a refinement over ManagedResourceOperations as it defines the acquireForMethod generically using the
 * scala.util.control.Exception API.
 */
abstract class AbstractManagedResource[R] extends ManagedResource[R] with ManagedResourceOperations[R] {

  /** 
   * Opens a given resource, returning a handle to execute against during the "session" of the resource being open.
   */
  protected def open: R

  /**
   * Closes a resource using the handle. This method will throw any exceptions normally occurring during the closing of
   * a resource.
   */
  protected def unsafeClose(handle: R, errors: Option[Throwable]): Unit

  /** These are a list of exceptions we *have* to rethrow, regardless of
   *  a users desires to ensure that thread/return behavior in scala is accurate.
   */
  protected def isRethrown(t: Throwable): Boolean = t match {
    case _: ControlThrowable      => true
    case _: InterruptedException  => true
    case _                        => false    
  }
  
  /** This checks to see if an exception should not be caught, under any circumstances.
   * These usually denote fatal program flaws.
   */
  protected def isFatal(t: Throwable): Boolean = t match {
    case _: java.lang.VirtualMachineError => true
    // TODO - Others?
    case _                                => false
  }
  /** A catcher of exceptions that will ignore those we consider fatal. */
  private final val catchingNonFatal: Exception.Catch[Nothing] = 
    (new Exception.Catch(Exception.mkThrowableCatcher(e => !isFatal(e), throw _), None, _ => false) 
     withDesc "")

  override def acquireFor[B](f : R => B) : ExtractedEither[List[Throwable], B] = {
    import Exception._
    val handle = open
    val result = catchingNonFatal either (f(handle))
    val close  = catchingNonFatal either unsafeClose(handle, result.left.toOption)
    // Here we pattern match to make sure we get all the errors.
    val either = (result, close) match {
      case (Left(t1), _       ) if isRethrown(t1)       => throw t1
      case (Left(t1), Left(t2))                         => Left(t1 :: t2 :: Nil)
      case (Left(t1), _       )                         => Left(t1 :: Nil)
      case (Right(ExtractedEither(Left(ts))), Left(t2)) => Left(ts.asInstanceOf[List[Throwable]] :+ t2)
      case (_,        Left(t2))                         => Left(t2 :: Nil)
      case (Right(r), _       )                         => Right(r)
    }
    ExtractedEither(either)
  }
}

/**
 * This is the default implementation of a ManagedResource that makes use of the Resource type trait.
 */
final class DefaultManagedResource[R : Resource : OptManifest](r : => R) extends AbstractManagedResource[R] { self =>
  /** Stable reference to the Resource type trait.*/
  protected val typeTrait = implicitly[Resource[R]]
  override protected def open: R = {
    val resource = r
    typeTrait.open(resource)
    resource
  }
  override protected def unsafeClose(r: R, error: Option[Throwable]): Unit =
    error match {
      case None    => typeTrait.close(r)
      case Some(t) => typeTrait.closeAfterException(r, t)
    }
  override protected def isFatal(t: Throwable): Boolean =
    typeTrait isFatalException t
  override protected def isRethrown(t: Throwable): Boolean =
    typeTrait isRethrownException t
  /* You cannot serialize resource and send them, so referential equality should be sufficient. */
  override def hashCode(): Int = (typeTrait.hashCode << 7) + super.hashCode + 13
  // That's right, we use manifest solely for nicer toStrings!
  override def toString = "Default[" + implicitly[OptManifest[R]] + " : " + typeTrait + "](...)"
}

/**
  * ConstantManagedResource encapsulates a constant value with no associated resource management.
  */
final class ConstantManagedResource[V](value: V) extends AbstractManagedResource[V] {

  /**
   * Simply return the value given at construction.
   */
  override protected def open: V = {
    value
  }

  /**
   * Nothing needs to be done to close.
   */
  override protected def unsafeClose(handle: V, errors: Option[Throwable]): Unit = {}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy