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

oiscochard.sindi.sindi-core_2.9.0-1.0.5.source-code.context.scala Maven / Gradle / Ivy

The newest version!
//      _____         ___  
//     / __(_)__  ___/ (_)
//    _\ \/ / _ \/ _  / /
//   /___/_/_//_/\_,_/_/
//
//  (c) 2011, Alois Cochard
//
//  http://aloiscochard.github.com/sindi
//

package sindi
package context

import scala.annotation.tailrec
import scala.collection.immutable.{HashMap, List, Map}

import injector.{Binding, Injector, Injection, Qualifiers}
import processor.Processor

/** A trait providing operations for object injection using a delegated [[sindi.injector.Injector]],
  * which is encapsulated using a processing system.
  *
  * The processing system is set-up using a list of [[sindi.processor.Processor]].
  */
trait Context extends Injector {
  /** Return the injector associated with this context. */
  lazy val injector: Injector = Injector(bounds)

  /** Return the bindings associated with this context. */
  protected val bindings: Bindings = Nil

  override def injectionAs[T : Manifest](qualifiers: Qualifiers) =
    process[T](qualifiers)(injector.injectionAs[T](qualifiers))
  override def injectionAll[T : Manifest](qualifiers: Qualifiers) =
    injector.injectionAll(qualifiers).map(process[T](qualifiers) _)

  /** Return the processors associated with this context. */
  def processors: List[Processor[_]] = Nil

  protected def processing: List[Processor[_]] = processors
  protected def bounds = bindings.map(_.build.asInstanceOf[Binding])

  private def process[T : Manifest](qualifiers: Qualifiers)(injection: Injection[T]) = 
    Processor.process[T](processing, this, qualifiers, injection)(manifest[T])
}

/** A trait adding hierarchical relationship to a [[sindi.context.Context]]. */
trait Childable extends Context {
  /** Return the injector associated with this context. */
  override lazy val injector = Injector(bounds, ctx.injector _)
  protected val ctx: Context

  override protected def processing = {
    @tailrec def collect(context: Context, acc: List[Processor[_]] = Nil): List[Processor[_]] = context match {
      case context: Childable => collect(context.ctx, context.processors ++ acc)
      case _ => context.processors ++ acc
    }
    collect(this).distinct
  }
}

/** A trait adding wiring capability to a [[sindi.context.Context]]. */
trait Wirable extends Context with WirableTemplate {
  import java.lang.reflect.Constructor
  import scala.util.control.Exception._
  import exception._

  // TODO [aloiscochard] Improve exception message details

  protected def wire[T : Manifest]: Option[T] = catching(classOf[TypeNotBoundException]).opt(inject(manifest[T]))

  private[context] def wireFirst[T]
      (tpe: Manifest[_], signatures: Seq[Tuple2[List[Manifest[_]], (List[Any]) => T]]): T =
    wireAll[T](signatures).headOption.getOrElse {
      throw new TypeNotBoundException(tpe, " during autowiring")
    }

  private[context] def wireAll[T]
      (signatures: Seq[Tuple2[List[Manifest[_]], (List[Any]) => T]]): Seq[T] = {
    signatures.view.flatMap {
      case (parameters, constructor) => {
        // TODO [aloiscochard] Cache wire calls
        val values = parameters.toList.flatMap((m) => wire(m.asInstanceOf[Manifest[Any]]))
        if (values.size == parameters.size) Some(constructor(values)) else None
      }
    }
  }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy