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

scalax.file.ramfs.RamFileSystem.scala Maven / Gradle / Ivy

The newest version!
/*                      __                                               *\
**     ________ ___   / /  ___     Scala API                            **
**    / __/ __// _ | / /  / _ |    (c) 2009-2010, Jesse Eichar          **
**  __\ \/ /__/ __ |/ /__/ __ |    http://scala-lang.org/               **
** /____/\___/_/ |_/____/_/ | |                                         **
**                          |/                                          **
\*                                                                      */

package scalax.file
package ramfs

import java.net.{
  URI, URLStreamHandler
}
import java.util.UUID
import java.io.{IOException, FileNotFoundException}
import scalax.io.{ResourceContext, DefaultResourceContext}

object RamFileSystem {
  case class RamFsId(id:String = UUID.randomUUID.toString)
  val protocol = "ramfs"
  private val fileSystems = scala.collection.mutable.WeakHashMap[RamFsId,RamFileSystem]()
  def apply(separator:String = "/") : RamFileSystem = new RamFileSystem(separator = separator)
  def apply(fsId:RamFsId) : RamFileSystem = synchronized {
    fileSystems.get(fsId).getOrElse(new RamFileSystem(fsId))
  }
  def apply(uri:URI) : RamPath = {
    require(uri.toString contains '!', "Ramfile system URIs must be of form: ramfs://fsId!path, was: "+uri+" (did not contain a !)")
    require(uri.getScheme equalsIgnoreCase "ramfs", "Ramfile system URIs must start with ramfs, was: "+uri)

    val id = RamFsId(uri.getAuthority.takeWhile{_ != '!'})
    val fs = apply(id)
    val path = uri.getRawPath.replace("/", fs.separator)
    fs.fromString(path)
  }
  private def register(fsId:RamFsId, fs:RamFileSystem) = synchronized {
    fileSystems(fsId) = fs
  }
}

class RamFileSystem(val id : RamFileSystem.RamFsId = RamFileSystem.RamFsId(), val separator:String = "/", val context:ResourceContext = DefaultResourceContext) extends FileSystem {
  type PathType = RamPath
  private var fsTree = new DirNode(separator)

  RamFileSystem.register(id,this)

  val root = new RamPath("",fsTree.name, this)
  var pwd = root

  val name = "Ram ("+id+")"
  override lazy val urlStreamHandler : Option[URLStreamHandler] = Some(Handler)
  override def fromString(path: String): RamPath = {
    if(path startsWith separator) fromStrings("",path)
    else fromStrings(pwd.toAbsolute.path, path)
  }
  protected def doCreateFromSeq(segments: Seq[String]) = fromString(segments mkString separator)
  def apply(relativeTo:String, segments: Seq[String]): RamPath = fromStrings(relativeTo,segments.filterNot{_.isEmpty} mkString separator)

  protected[ramfs] def fromStrings(relativeTo:String , path: String): RamPath = {
    def process(path:String) = {
//      println("regex",java.util.regex.Pattern.quote(separator))
      import java.util.regex.Pattern.quote
      val p = path.replace(separator+separator, separator);
      if((p endsWith separator) && (p.length > 1)) p.drop(1)
      else p
    }
    val newpath = new RamPath(process(relativeTo), process(path), this)
    if(newpath == root) root
    else newpath
  }
  override def roots:Set[RamPath] = Set (root)
  def updateContext(newContext:ResourceContext):RamFileSystem = new RamFileSystem(id,separator,newContext)
  override def updateContext(f:ResourceContext => ResourceContext):RamFileSystem = updateContext(f(context))

  def createTempFile(prefix: String = randomPrefix,
                   suffix: String = null,
                   dir: String = null,
                   deleteOnExit : Boolean = true
                   /*attributes:List[FileAttributes] TODO */ ) : RamPath = apply(separator,"temp",UUID.randomUUID.toString)

  def createTempDirectory(prefix: String = randomPrefix,
                        suffix: String = null,
                        dir: String = null,
                        deleteOnExit : Boolean = true
                        /*attributes:List[FileAttributes] TODO */) : RamPath  = apply(separator,"temp",UUID.randomUUID.toString)

  def uri(path:RamPath = root):URI = new URI(RamFileSystem.protocol+"://"+id.id+"!"+path.path.replaceAll("\\\\","/"))
  override def toString = "Ram File System"

  private[ramfs] def lookup(path:RamPath) = {
    val absolutePath = path.toAbsolute.segments
    fsTree.lookup(absolutePath)
  }
  private[ramfs] def create(path:RamPath, fac:NodeFac, createParents:Boolean = true) : Boolean = {
    if (path == root) {
      true
    } else {
      val absolute = path.toAbsolute
      absolute.parent match {
        case Some(p) if p.nonExistent && !createParents =>
          throw new FileNotFoundException("Parent directory " + p + " does not exist")
        case _ => ()
      }

      val x = fsTree.create(absolute.segments.drop(1), fac)

      true
    }
  }
  private[ramfs] def delete(path:RamPath, force:Boolean) : Boolean = {
    if(path.exists) {
      def delete(p:Path) = force || (p.canWrite && p.parent.forall {_.canWrite})

      if(delete(path) && path != root) {
        val parentPath = path.toAbsolute.parent
        val deletions = for { parent <- path.toAbsolute.parent
              parentNode <- parent.node
              node <- path.node
            } yield {
              parentNode.asInstanceOf[DirNode].children -= node
              true
            }
        deletions.isDefined
      } else if(path == root) {
        fsTree = new DirNode(separator)
        true
      } else {
        false
      }
    } else {
      false
    }
  }

  private[ramfs] def move(src:RamPath, dest:RamPath) = {
    if(src == root) {
      throw new IOException("Root cannot be moved")
    }
    val parentNode =
      dest.parent match {
        case Some(`root`) | None =>
          fsTree
        case Some(parent) =>
          create(parent, DirNode, true) // TODO paramaterize NodeFactory
          parent.node.get.asInstanceOf[DirNode]
      }

    src.node foreach { node =>
      node.name = dest.name
      parentNode.children += node
    }

    delete(src,true)
  }

  /**
   * creates and copies the data of the src node to the destination.
   * Assumption is the destination does not exist
   */
   private[ramfs] def copyFile(src:RamPath, srcNode:FileNode, dest:RamPath) = {

     dest.fileSystem.create(dest, FileNode, true)
     val newNode = dest.node.collect{case newNode:FileNode =>
       newNode.data = srcNode.data
     }
   }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy