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

Scala example source code file (CachedFileStorage.scala)

This example Scala source code file (CachedFileStorage.scala) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Scala tags/keywords

cachedfilestorage, file, file, fileoutputstream, io, iterator, iterator, logged, nio, node, node, thread, unit, unit

The Scala CachedFileStorage.scala source code

/*                     __                                               *\
**     ________ ___   / /  ___     Scala API                            **
**    / __/ __// _ | / /  / _ |    (c) 2002-2011, LAMP/EPFL             **
**  __\ \/ /__/ __ |/ /__/ __ |    http://scala-lang.org/               **
** /____/\___/_/ |_/____/_/ | |                                         **
**                          |/                                          **
\*                                                                      */


package scala.xml
package persistent

import java.io.{ File, FileOutputStream } 
import java.nio.ByteBuffer
import java.nio.channels.Channels 
import java.lang.Thread
import scala.util.logging.Logged
import scala.collection.Iterator

/** <p>
 *    Mutable storage of immutable xml trees. Everything is kept in memory,
 *    with a thread periodically checking for changes and writing to file.
 *    To ensure atomicity, two files are used, filename1 and '$'+filename1.
 *    The implementation switches between the two, deleting the older one
 *    after a complete dump of the database has been written.
 *  </p>
 *
 *  @author Burak Emir
 */
abstract class CachedFileStorage(private val file1: File) extends Thread with Logged {

  private val file2 = new File(file1.getParent, file1.getName+"$")
    
  /**  either equals file1 or file2, references the next file in which updates will be stored
   */
  private var theFile: File = null

  private def switch() = { theFile = if (theFile == file1) file2 else file1; }

  /** this storage modified since last modification check */
  protected var dirty = false

  /** period between modification checks, in milliseconds */
  protected val interval = 1000

  /** finds and loads the storage file. subclasses should call this method 
   *  prior to any other, but only once, to obtain the initial sequence of nodes.
   */
  protected def initialNodes: Iterator[Node] = (file1.exists, file2.exists) match {
    case (false,false) => 
      theFile = file1
      Iterator.empty
    case (true, true ) if (file1.lastModified < file2.lastModified) => 
      theFile = file2
      load
    case (true, _ ) =>
      theFile = file1
      load
    case _ =>
      theFile = file2
      load
  }

  /** returns an iterator over the nodes in this storage */
  def nodes: Iterator[Node]  

  /** adds a node, setting this.dirty to true as a side effect */
  def += (e: Node): Unit 

  /** removes a tree, setting this.dirty to true as a side effect */
  def -= (e: Node): Unit 

  /* loads and parses XML from file */
  private def load: Iterator[Node] = {
    import scala.io.Source
    import scala.xml.parsing.ConstructingParser
    log("[load]\nloading "+theFile)
    val src = Source.fromFile(theFile)
    log("parsing "+theFile)
    val res = ConstructingParser.fromSource(src,false).document.docElem(0)
    switch
    log("[load done]")
    res.child.iterator
  }
  
  /** saves the XML to file */
  private def save() = if (this.dirty) {
    log("[save]\ndeleting "+theFile);
    theFile.delete();
    log("creating new "+theFile);
    theFile.createNewFile();
    val fos = new FileOutputStream(theFile)
    val c   = fos.getChannel()
    
    // @todo: optimize
    val storageNode = <nodes>{ nodes.toList }
    val w = Channels.newWriter(c, "utf-8")
    XML.write(w, storageNode, "utf-8", true, null)
    
    log("writing to "+theFile);
    
    w.close
    c.close
    fos.close
    dirty = false
    switch
    log("[save done]")
  }
  
  /** run method of the thread. remember to use start() to start a thread, not run. */
  override def run = {
    log("[run]\nstarting storage thread, checking every "+interval+" ms");
    while(true) { 
      Thread.sleep( this.interval ); 
      save 
    }
  }
  
  /** forces writing of contents to the file, even if there has not been any update. */
  def flush() = {
    this.dirty = true; 
    save
  }
}

Other Scala examples (source code examples)

Here is a short list of links related to this Scala CachedFileStorage.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.