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

org.beangle.commons.cdi.bind.Binder.scala Maven / Gradle / Ivy

/*
 * Beangle, Agile Development Scaffold and Toolkit
 *
 * Copyright (c) 2005-2017, Beangle Software.
 *
 * Beangle is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Beangle is distributed in the hope that it will be useful.
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Beangle.  If not, see .
 */
package org.beangle.commons.cdi.bind

import org.beangle.commons.lang.Strings
import Binder._
import scala.collection.mutable.ListBuffer
import org.beangle.commons.cdi.Scope
import org.beangle.commons.lang.annotation.description
import org.beangle.commons.collection.Collections

object Binder {

  case class ReferenceValue(ref: String)
  case class Injection[T](clazz: Class[T])
  object InjectPlaceHolder
  case class PropertyPlaceHolder(name: String, defaultValue: String)

  /**
   * Bean Definition
   */
  class Definition(var beanName: String, val clazz: Class[_], scopeName: String) {

    var scope: String = if (null == scopeName) "Singleton" else scopeName

    var initMethod: String = _

    var properties = new collection.mutable.HashMap[String, Any]

    var lazyInit: Boolean = _

    var abstractFlag: Boolean = _

    var primary: Boolean = _

    var parent: String = _

    var targetClass: Class[_] = _

    var constructorArgs: Seq[_] = _

    var description: String = _

    val nowires = Collections.newSet[String]

    def isAbstract: Boolean = abstractFlag

    def property(property: String, value: AnyRef): Definition = {
      properties.put(property, value)
      this
    }

    def constructor(args: Any*): this.type = {
      this.constructorArgs = args
      this
    }

    def nowire(properties: String*): this.type = {
      nowires ++= properties
      this
    }
  }

  class DefinitionBinder(val config: Binder, classes: Class[_]*) {

    private val beans = new ListBuffer[Definition]

    bind(classes: _*)

    def shortName(b: Boolean = true): this.type = {
      for (definition <- beans) definition.beanName = getBeanName(definition.clazz, b)
      this
    }

    def description(descs: String*): this.type = {
      require(descs.size == 1 || descs.size == beans.size)
      if (descs.size == 1) for (definition <- beans) definition.description = descs.head
      else {
        val beanIter = beans.iterator
        val descIter = descs.iterator
        while (beanIter.hasNext) {
          beanIter.next.description = descIter.next
        }
      }
      this
    }
    def lazyInit(lazyInit: Boolean = true): this.type = {
      for (definition <- beans) definition.lazyInit = lazyInit
      this
    }

    def parent(parent: String): this.type = {
      for (definition <- beans) definition.parent = parent
      this
    }

    def proxy(property: String, clazz: Class[_]): this.type = {
      val targetBean = config.newInnerBeanName(clazz)
      val targetDefinition = new Definition(targetBean, clazz, Scope.Singleton.toString)
      val an = clazz.getAnnotation(classOf[description])
      if (null != an) targetDefinition.description = an.value()
      config.add(targetDefinition)
      for (definition <- beans) {
        definition.targetClass = clazz
        definition.properties.put(property, new ReferenceValue(targetBean))
      }
      this
    }

    def proxy(property: String, target: Definition): this.type = {
      config.add(target)
      for (definition <- beans) {
        definition.targetClass = target.clazz
        definition.properties.put(property, new ReferenceValue(target.beanName))
      }
      this
    }

    def primary(): this.type = {
      for (definition <- beans) definition.primary = true
      this
    }

    def setAbstract(): this.type = {
      for (definition <- beans) definition.abstractFlag = true
      this
    }

    def in(scope: Scope.Val): this.type = {
      for (definition <- beans) definition.scope = scope.toString
      this
    }

    def property(property: String, value: Any): this.type = {
      for (definition <- beans) definition.properties.put(property, value)
      this
    }

    def constructor(args: Any*): this.type = {
      for (definition <- beans) definition.constructorArgs = args
      this
    }

    def init(method: String): this.type = {
      for (definition <- beans) definition.initMethod = method
      this
    }

    def nowire(properties: String*): this.type = {
      for (definition <- beans) definition.nowire(properties: _*)
      this
    }

    def bind(classes: Class[_]*): this.type = {
      for (clazz <- classes) {
        val definition = new Definition(getBeanName(clazz, false), clazz, Scope.Singleton.toString)
        val an = clazz.getAnnotation(classOf[description])
        if (null != an) definition.description = an.value()
        config.add(definition)
        beans += definition
      }
      this
    }

    def bind(name: String, clazz: Class[_]): this.type = {
      val definition = new Definition(name, clazz, Scope.Singleton.toString)
      val an = clazz.getAnnotation(classOf[description])
      if (null != an) definition.description = an.value()
      config.add(definition)
      beans += definition
      this
    }

    private def getBeanName(clazz: Class[_], shortName: Boolean): String = {
      var className = clazz.getName
      if (shortName) className = Strings.uncapitalize(Strings.substringAfterLast(className, "."))
      className
    }

    def head: Definition = beans.head
  }
}

/**
 * Binder class.
 *
 * @author chaostone
 */
class Binder(val module: String) {

  val definitions = new ListBuffer[Definition]

  val singletons = Collections.newMap[String, AnyRef]

  def newInnerBeanName(clazz: Class[_]): String = {
    clazz.getSimpleName + "#" + Math.abs(module.hashCode) + definitions.size
  }

  /**
   * bind class with a name.
   */
  def bind(beanName: String, clazz: Class[_]): DefinitionBinder = {
    new DefinitionBinder(this).bind(beanName, clazz)
  }

  /**
   * bind object with a name.
   */
  def bind(beanName: String, singleton: AnyRef): Unit = {
    singletons += (beanName -> singleton)
  }
  /**
   * bind.
   */
  def bind(classes: Class[_]*): DefinitionBinder = {
    new DefinitionBinder(this, classes: _*)
  }
  /**
   * add.
   */
  protected[bind] def add(definition: Definition) {
    definitions += definition
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy