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

Lift Framework example source code file (Wiring.scala)

This example Lift Framework source code file (Wiring.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 - Lift Framework tags/keywords

a, a, b, c, cell, cell, d, long, long, t, unit, valuecell, z, z

The Lift Framework Wiring.scala source code

/*
 * Copyright 2011 WorldWide Conferencing, LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.liftweb
package util

import net.liftweb.common._
import java.lang.ref.WeakReference

/**
 * Something that depends on the values of other cells
 */
trait Dependent {
  /**
   * If the predicate cell changes, the Dependent will be notified
   */
  def predicateChanged(which: Cell[_]): Unit

  /**
   * The Cell notifies the Dependent of the dependency
   */
  def youDependOnMe(who: Cell[_]): Unit = synchronized {
    _iDependOn = new WeakReference(who.asInstanceOf[Object]) :: _iDependOn.filter(_.get match {
      case null => false
      case x => x ne who
    })
  }

  /**
   * The Cell notifies the Dependent of the removed dependency
   */
  def youDontDependOnMe(who: Cell[_]): Unit =  synchronized {
    val tList = _iDependOn.filter(_.get match {
      case null => false
      case x => x ne who
    })

    _iDependOn = tList
  }

  /**
   * Get a list of all the cells this Dependency depends on
   */
  protected def whoDoIDependOn: Seq[Cell[_]] = synchronized {
    _iDependOn.flatMap(_.get match {
      case null => Nil
      case x => List(x)
    }).asInstanceOf[List[Cell[_]]]
  }

  private var _iDependOn: List[WeakReference[Object]] = Nil

  /**
   * Remove from all dependencies
   */
  protected def unregisterFromAllDepenencies(): Unit = {
    whoDoIDependOn.foreach(_.removeDependent(this))
  }
}

/**
 * A wiring Cell.  A Cell can be a ValueCell which holds
 * a value which can be set (and thus update the dependencies),
 * a FuncCell (a cell that is a function that depends on other cells),
 * or a DynamicCell which has a value that updates each time the cell is
 * accessed.
 */
trait Cell[T] extends Dependent {
  /**
   * The cell's value and most recent change time
   */
  def currentValue: (T, Long)

  /**
   * Get the cell's value
   */
  def get: T = currentValue._1

  /**
   * Create a new Cell by applying the function to this cell
   */
  def lift[A](f: T => A): Cell[A] = FuncCell(this)(f)

  def lift[A,B](cell: Cell[B])(f: (T, B) => A): Cell[A] = 
    FuncCell(this, cell)(f)

  private var _dependentCells: List[WeakReference[Dependent]] = Nil

  /**
   * Add a Dependent to this cell.  The Dependent will
   * be notified when the Cell's value changes.  Dependents
   * are kept around as WeakReferences so they do not
   * have to be explicitly removed from the List
   */
  def addDependent[T <: Dependent](dep: T): T = {
    synchronized {
      val tList = _dependentCells.filter(_.get match {
        case null => false
        case x => x ne dep
      })
      
      
      _dependentCells = new WeakReference(dep: Dependent) :: tList
    }

    dep.youDependOnMe(this)

    dep
  }

  /**
   * Remove a Dependent to this cell.
   */
  def removeDependent[T <: Dependent](dep: T): T = {
    synchronized {
      _dependentCells = _dependentCells.filter(_.get match {
        case null => false
        case x => x ne dep
      })
    }

    dep.youDontDependOnMe(this)

    dep
  }

  /**
   * Notify dependents of a state change.  Note this
   * will be performed on a separate thread asynchronously
   */
  def notifyDependents(): Unit = {
    Schedule.schedule(() => dependents.foreach(_.predicateChanged(this)),
                      0)
  }

  /**
   * Get a List of the Dependents
   */
  def dependents: Seq[Dependent] = synchronized {
    _dependentCells.flatMap(_.get match {
      case null => Nil
      case x => List(x)
    })
  }

}

object Cell {
  def apply[T](v: T): ValueCell[T] = new ValueCell[T](v)
}

/**
 * A cell that changes value on each access.  This kind of cell
 * could be used to access an external resource.  <b>Warning
 * the function may be accessed many times during a single wiring
 * recalculation, so it's best to use this as a front to a value
 * that's memoized for some duration.
 */
final case class DynamicCell[T](f: () => T) extends Cell[T] {
  /**
   * The cell's value and most recent change time
   */
  def currentValue: (T, Long) = 
    f() -> System.nanoTime()

  /**
   * If the predicate cell changes, the Dependent will be notified.
   * This Cell has no predicates, so this is just Unit
   */
  def predicateChanged(which: Cell[_]): Unit = {}

}

/**
 * The companion object that has a helpful constructor
 */
object ValueCell {
  def apply[A](value: A): ValueCell[A] = new ValueCell(value)

  implicit def vcToT[T](in: ValueCell[T]): T = in.get
}

/**
 * A ValueCell holds a value that can be mutated.
 */
final class ValueCell[A](initialValue: A) extends Cell[A] with LiftValue[A] {
  private var value: A = initialValue
  private var ct: Long = System.nanoTime()

  /**
   * The cell's value and most recent change time
   */
  def currentValue: (A, Long) = synchronized {
    (value, ct)
  }

  /**
   * Get the cell's value
   */
  def set(v: A): A = synchronized {
    val changed = value != v
    value = v
    ct = System.nanoTime()

    if (changed) notifyDependents()

    value
  }

  /**
   * If the predicate cell changes, the Dependent will be notified.
   * A ValueCell cannot have predicates
   */
  def predicateChanged(which: Cell[_]): Unit = {}


  override def toString(): String = synchronized {
    "ValueCell("+value+")"
  }

  override def hashCode(): Int = synchronized {
    if (null.asInstanceOf[Object] eq value.asInstanceOf[Object]) 0
    else value.hashCode()
  }

  override def equals(other: Any): Boolean = synchronized {
    other match {
      case vc: ValueCell[_] => value == vc.get
      case _ => false
    }
  }
}

/**
* A collection of Cells og a given type
*/
final case class SeqCell[T](cells: Cell[T]*) extends Cell[Seq[T]] {

  cells.foreach(_.addDependent(this))

  /**
  * The cell's value and most recent change time
  */
  def currentValue: (Seq[T], Long) = {
    val tcv = cells.map(_.currentValue)
    tcv.map(_._1) -> tcv.foldLeft(0L)((max, c) => if (max > c._2) max else c._2)
  }

  /**
   * If the predicate cell changes, the Dependent will be notified
   */
  def predicateChanged(which: Cell[_]): Unit = notifyDependents()
}

/**
* The companion object for FuncCell (function cells)
*/
object FuncCell {
  /**
  * Construct a function cell based on a single parameter
  */
  def apply[A, Z](a: Cell[A])(f: A => Z): Cell[Z] = FuncCell1(a, f)

  /**
  * Construct a function cell based on two parameters
  */
  def apply[A, B, Z](a: Cell[A], b: Cell[B])(f: (A, B) => Z): Cell[Z] = FuncCell2(a, b, f)

  /**
  * Construct a function cell based on three parameters
  */
  def apply[A, B, C, Z](a: Cell[A], b: Cell[B], c: Cell[C])(f: (A, B, C) => Z): Cell[Z] = FuncCell3(a, b, c, f)

  /**
  * Construct a function cell based on four parameters
  */
  def apply[A, B, C, D, Z](a: Cell[A], b: Cell[B], c: Cell[C], d: Cell[D])(f: (A, B, C, D) => Z): Cell[Z] = FuncCell4(a, b, c, d, f)

  /**
  * Construct a function cell based on five parameters
  */
  def apply[A, B, C, D, E, Z](a: Cell[A], b: Cell[B], c: Cell[C], d: Cell[D], e: Cell[E])(f: (A, B, C, D, E) => Z): Cell[Z] = FuncCell5(a, b, c, d, e, f)
}

final case class FuncCell1[A, Z](a: Cell[A], f: A => Z) extends Cell[Z] {
  private var value: Z = _
  private var ct: Long = 0

  /**
   * If the predicate cell changes, the Dependent will be notified
   */
  def predicateChanged(which: Cell[_]): Unit = {
    notifyDependents()
  }

  a.addDependent(this)

  def currentValue: (Z, Long) = synchronized {
    val (v, t) = a.currentValue
    if (t > ct) {
      value = f(v)
      ct = t
    }
    (value -> ct)
  }

}

final case class FuncCell2[A, B, Z](a: Cell[A], b: Cell[B], f: (A, B) => Z) extends Cell[Z] {
  private var value: Z = _
  private var ct: Long = 0

  /**
   * If the predicate cell changes, the Dependent will be notified
   */
  def predicateChanged(which: Cell[_]): Unit = notifyDependents()

  a.addDependent(this)
  b.addDependent(this)

  def currentValue: (Z, Long) = synchronized {
    val (v1, t1) = a.currentValue
    val (v2, t2) = b.currentValue
    val t = WiringHelper.max(t1, t2)
    if (t > ct) {
      value = f(v1, v2)
      ct = t
    }
    (value -> ct)
  }
}

final case class FuncCell3[A, B, C, Z](a: Cell[A], b: Cell[B], c: Cell[C], f: (A, B, C) => Z) extends Cell[Z] {
  private var value: Z = _
  private var ct: Long = 0

  /**
   * If the predicate cell changes, the Dependent will be notified
   */
  def predicateChanged(which: Cell[_]): Unit = notifyDependents()

  a.addDependent(this)
  b.addDependent(this)
  c.addDependent(this)

  def currentValue: (Z, Long) = synchronized {
    val (v1, t1) = a.currentValue
    val (v2, t2) = b.currentValue
    val (v3, t3) = c.currentValue
    val t = WiringHelper.max(t1, t2, t3)
    if (t > ct) {
      value = f(v1, v2, v3)
      ct = t
    }
    (value -> ct)
  }
}

final case class FuncCell4[A, B, C, D, Z](a: Cell[A], b: Cell[B], c: Cell[C], d: Cell[D], f: (A, B, C, D) => Z) extends Cell[Z] {
  private var value: Z = _
  private var ct: Long = 0

  /**
   * If the predicate cell changes, the Dependent will be notified
   */
  def predicateChanged(which: Cell[_]): Unit = {
    notifyDependents()
  }

  a.addDependent(this)
  b.addDependent(this)
  c.addDependent(this)
  d.addDependent(this)

  def currentValue: (Z, Long) = synchronized {
    val (v1, t1) = a.currentValue
    val (v2, t2) = b.currentValue
    val (v3, t3) = c.currentValue
    val (v4, t4) = d.currentValue
    val t = WiringHelper.max(t1, t2, t3, t4)
    if (t > ct) {
      value = f(v1, v2, v3, v4)
      ct = t
    }
    (value -> ct)
  }
}

final case class FuncCell5[A, B, C, D, E, Z](a: Cell[A], b: Cell[B], c: Cell[C], d: Cell[D], e: Cell[E], f: (A, B, C, D, E) => Z) extends Cell[Z] {
  private var value: Z = _
  private var ct: Long = 0

  /**
   * If the predicate cell changes, the Dependent will be notified
   */
  def predicateChanged(which: Cell[_]): Unit = {
    notifyDependents()
  }

  a.addDependent(this)
  b.addDependent(this)
  c.addDependent(this)
  d.addDependent(this)
  e.addDependent(this)

  def currentValue: (Z, Long) = synchronized {
    val (v1, t1) = a.currentValue
    val (v2, t2) = b.currentValue
    val (v3, t3) = c.currentValue
    val (v4, t4) = d.currentValue
    val (v5, t5) = e.currentValue
    val t = WiringHelper.max(t1, t2, t3, t4, t5)
    if (t > ct) {
      value = f(v1, v2, v3, v4, v5)
      ct = t
    }
    (value -> ct)
  }
}

private object WiringHelper {
  def max(a: Long, b: Long*): Long = b.foldLeft(a){
    (v1, v2) =>
      if (v1 > v2) v1 else v2
  }
}

Other Lift Framework examples (source code examples)

Here is a short list of links related to this Lift Framework Wiring.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.