/*
* Copyright 2009-2010 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 _root_.java.util.concurrent.{ConcurrentHashMap => CHash}
import _root_.java.lang.ThreadLocal
import _root_.scala.reflect.Manifest
import common._
import xml.NodeSeq
/**
* A trait that does basic dependency injection.
*/
trait Injector {
implicit def inject[T](implicit man: Manifest[T]): Box[T]
}
/**
* An implementation of Injector that has an implementation
*/
trait SimpleInjector extends Injector {
private val diHash: CHash[String, Function0[_]] = new CHash
/**
* Perform the injection for the given type. You can call:
* inject[Date] or inject[List[Map[String, PaymentThing]]]. The
* appropriate Manifest will be
*/
implicit def inject[T](implicit man: Manifest[T]): Box[T] =
(Box !! diHash.get(man.toString)).flatMap(f => Helpers.tryo(f.apply())).asInstanceOf[Box[T]]
/**
* Register a function that will inject for the given Manifest
*/
def registerInjection[T](f: () => T)(implicit man: Manifest[T]) {
diHash.put(man.toString, f)
}
/**
* Create an object or val that is a subclass of the FactoryMaker to
* generate factory for a particular class as well as define session and
* request specific vendors and use doWith to define the vendor just for
* the scope of the call.
*/
abstract class Inject[T](_default: Vendor[T])
(implicit man: Manifest[T]) extends StackableMaker[T] with Vendor[T] {
registerInjection(this)(man)
/**
* The default function for vending an instance
*/
object default extends PSettableValueHolder[Vendor[T]] {
private var value = _default
def get = value
def is = get
def set(v: Vendor[T]): Vendor[T] = {
value = v
v
}
}
/**
* Vend an instance
*/
implicit def vend: T = make openOr default.is.apply()
/**
* Make a Box of the instance.
*/
override implicit def make: Box[T] = super.make or Full(default.is.apply())
}
}
/**
* In addition to an Injector, you can have a Maker which will make a given
* type. The important thing about a Maker is that it's intended to be used
* as part of a factory that can vend an instance without the vaguaries of
* whether the given class has registered a with the injector.
*/
trait Maker[T] {
implicit def make: Box[T]
}
object Maker {
def apply[T](value: T): Maker[T] = new Maker[T]{implicit def make: Box[T] = Full(value)}
def apply[T](func:() => T): Maker[T] = new Maker[T]{implicit def make: Box[T] = Full(func())}
def apply[T](func: Box[() => T]): Maker[T] = new Maker[T]{implicit def make: Box[T] = func.map(_.apply())}
def apply1[T](box: Box[T]): Maker[T] = new Maker[T]{implicit def make: Box[T] = box}
def apply2[T](func: Box[() => Box[T]]): Maker[T] = new Maker[T]{implicit def make: Box[T] = func.flatMap(_.apply())}
def apply3[T](func: () => Box[T]): Maker[T] = new Maker[T]{implicit def make: Box[T] = func.apply()}
implicit def vToMake[T](v: T): Maker[T] = this.apply(v)
implicit def vToMake[T](v: () => T): Maker[T] = this.apply(v)
implicit def vToMakeB1[T](v: Box[T]): Maker[T] = this.apply1(v)
implicit def vToMakeB2[T](v: Box[() => T]): Maker[T] = this.apply(v)
implicit def vToMakeB3[T](v: Box[() => Box[T]]): Maker[T] = this.apply2(v)
implicit def vToMakeB4[T](v: () => Box[T]): Maker[T] = this.apply3(v)
}
/**
* A StackableMaker allows DynamicVar functionality by supply a Maker or function
* that will vend an instance during any sub-call on the stack and then
* restore the implementation. This is value for testing.
*/
trait StackableMaker[T] extends Maker[T] {
private val _stack: ThreadLocal[List[PValueHolder[Maker[T]]]] = new ThreadLocal
private def stack: List[PValueHolder[Maker[T]]] = _stack.get() match {
case null => Nil
case x => x
}
def doWith[F](value: T)(f: => F): F =
doWith(PValueHolder(Maker(value)))(f)
def doWith[F](vFunc: () => T)(f: => F): F =
doWith(PValueHolder(Maker(vFunc)))(f)
def doWith[F](addl: PValueHolder[Maker[T]])(f: => F): F = {
val old = _stack.get()
_stack.set(addl :: stack)
try {
f
} finally {
_stack.set(old)
}
}
protected final def find(in: List[PValueHolder[Maker[T]]]): Box[T] = in match {
case Nil => Empty
case x :: rest =>
x.is.make match {
case Full(v) => Full(v)
case _ => find(rest)
}
}
implicit def make: Box[T] = find(stack)
}
/**
* An implementation where you can define the stack of makers.
*/
class MakerStack[T](subMakers: PValueHolder[Maker[T]]*) extends StackableMaker[T] {
private val _sub: List[PValueHolder[Maker[T]]] = subMakers.toList
override implicit def make: Box[T] = super.make or find(_sub)
}
/**
* A Vendor is a Maker that also guarantees that it will return a value
*/
trait Vendor[T] extends Maker[T] with Function0[T] {
implicit def vend: T
def apply() = vend
}
/**
* A companion to the Vendor trait
*/
object Vendor {
def apply[T](f: () => T): Vendor[T] = new Vendor[T] {
implicit def vend: T = f()
implicit def make: Box[T] = Full(f())
}
def apply[T](f: T): Vendor[T] = new Vendor[T] {
implicit def vend: T = f
implicit def make: Box[T] = Full(f)
}
implicit def valToVender[T](value: T): Vendor[T] = apply(value)
implicit def funcToVender[T](f: () => T): Vendor[T] = apply(f)
}
case class FormBuilderLocator[T](func: (T, T => Unit) => NodeSeq)(implicit val manifest: Manifest[T])
}
}