alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Play Framework/Scala example source code file (ClosableLazy.scala)

This example Play Framework source code file (ClosableLazy.scala) is included in my "Source Code Warehouse" project. The intent of this project is to help you more easily find Play Framework (and Scala) source code examples by using tags.

All credit for the original source code belongs to Play Framework; I'm just trying to make examples easier to find. (For my Scala work, see my Scala examples and tutorials.)

Play Framework tags/keywords

anyref, boolean, can't, closablelazy, closefunction, core, illegalstateexception, none, null, play, play framework, t, unit

The ClosableLazy.scala Play Framework example source code

/*
 * Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
 */
package play.core

/**
 * Provides functionality like Scala's builtin lazy values, except allows cleanup of
 * the lazily initialized value. The value is lazily initialized when the `get()` method
 * is first called. Later, if the value is no longer needed, it can be cleaned up by
 * calling the `close()` method.
 *
 * Calling `close()` on an uninitialized ClosableLazy will not initialize the value
 * if it is not initialized. A ClosableLazy can be closed multiple times.
 *
 * After being closed, the value cannot be initialized again. ClosableLazy is designed
 * to make it easier to clean up resources when shutting down Play. If resources were able
 * to be reinitialized after closing, then it would be easy to accidentally allocate resources
 * when shutting down. To prevert reinitialization, galling the `get()` method after `close()`
 * will result in an `IllegalStateException`.
 *
 * The performance of this class should be similar to Scala's lazy values. Once initialized,
 * a single read of a volatile value is all that is needed to get the value. If the value is not initialized,
 * then initialization occurs, Initialization is synchronized on the ClosableLazy object.
 *
 * This class exposes `T` as the type of value that is lazily created. Subclasses
 * should implement the `create()` method to create this value. The `create()` method
 * also returns a function that will be called when `close()` is called. This allows
 * any resources associated with the value to be closed.
 */
private[play] abstract class ClosableLazy[T >: Null <: AnyRef] {

  protected type CloseFunction = (() => Unit)

  @volatile
  private var value: T = null
  private var closeFunction: CloseFunction = null
  private var hasBeenClosed: Boolean = false

  /**
   * Get the value. Calling this method may allocate resources, such as a thread pool.
   *
   * Calling this method after the `close()` method has been called will result in an
   * IllegalStateException.
   */
  final def get(): T = {
    val currentValue = value
    if (currentValue != null) return currentValue
    synchronized {
      if (hasBeenClosed) throw new IllegalStateException("Can't get ClosableLazy value after it has been closed")
      if (value == null) {
        val (v, cf): (T, CloseFunction) = create()
        if (v == null) throw new IllegalStateException("Can't initialize ClosableLazy to a null value")
        if (cf == null) throw new IllegalStateException("Can't initialize ClosableLazy's close function to a null value")
        value = v
        closeFunction = cf
        v
      } else {
        // Value was initialized by another thread before we got the monitor
        value
      }
    }
  }

  /**
   * Close the value. Calling this method is safe, but does nothing, if the value
   * has not been initialized.
   */
  final def close(): Unit = {
    val optionalClose: Option[CloseFunction] = synchronized {
      if (hasBeenClosed) {
        // Already closed
        None
      } else if (value == null) {
        // Close before first call to get
        hasBeenClosed = true
        None
      } else {
        // Close and call the close function
        hasBeenClosed = true
        val prevCloseFunction = closeFunction
        value = null
        closeFunction = null
        Some(prevCloseFunction)
      }
    }
    // Perform actual close outside the synchronized block,
    // just in case the close function calls get or close
    // from another thread.
    optionalClose.foreach(_.apply())
  }

  /**
   * Called when the lazy value is first initialized. Returns the value and
   * a function to close the value when `close` is called.
   */
  protected def create(): (T, CloseFunction)
}

Other Play Framework source code examples

Here is a short list of links related to this Play Framework ClosableLazy.scala source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.