2011/10/09

How to write a SBT 0.10+ plugin?


To draft a SBT 0.10+ plugin, TWO parts should be taken into consideration:
1- the build file of the plugin;
2- the source code file or the definition files of the plugin;

------------------------------------------------------------------------------
|     the build file of the plugin sample (build.sbt under project root)     |
------------------------------------------------------------------------------
sbtPlugin := true
name := "aspectj_sbt_plugin"
version := "0.0.1"
organization := "name.fujohnwang"
publishMavenStyle := true
scalacOptions := Seq("-deprecation", "-unchecked")
resolvers += "Typesafe Repo" at "http://repo.typesafe.com/typesafe/releases/"
libraryDependencies ++= Seq("org.aspectj" % "aspectjtools" % "1.6.11.RELEASE", "org.aspectj" % "aspectjrt" % "1.6.11.RELEASE","org.aspectj" % "aspectjweaver" % "1.6.11.RELEASE")

------------------------------------------------------------------------------
|    the definition file of the plugin sample(src/main/scala/*.scala)        |
------------------------------------------------------------------------------
import sbt._
import Keys._

object MyPlugin extends Plugin {
val MyConfiguration = config("myconf")
val mySetting = SettingKey[String]("my-setting")
val myTask = TaskKey[Unit]("my-task", "task description")
override lazy val settings = inConfig(MyConfiguration)(Seq(
mySetting := "initial value for my-setting",
myTask <<= (streams, mySetting, …) map{
(s, ms, …)=> 
// do what u want to do with the arguments
},
// other settings 
))
}

Note: U refer to each setting via their key and refer to their values via map from key.

------------------------------------------------------------------------------
|         Last Mile - How to use the plugin u have just finished?            |
------------------------------------------------------------------------------
in your project, 2 places should be taken care about:
1- the "project/plugins.sbt"
resolvers += yourResolver   // help sbt to find out where your plugin is
addSbtPlugin("name.fujohnwang" % "aspectj_sbt_plugin" % "0.0.1")   // declare to use your plugin
2- build.sbt under the root path of your project(light configuration) or project/Build.scala(full configuration)
usually, you can customize the settings of the plugin or add necessary dependencies in your build file(s), this is variable as per your usage scenarios. If default values are ok for you, nothing about plugin is needed to add to your build file.

------------------------------------------------------------------------------
|         What U can learn from the experience of writing a plugin?          |
------------------------------------------------------------------------------
1- declare custom Configuration to enhance the modularity;
2- declare necessary SettingKey(s) to make your plugin flexible(which allows your users to customize the plugin)
3- each Keys(Setting or Task) can be initialized or implemented by <<= with other Key(s)




References:
1- https://github.com/harrah/xsbt/wiki/Plugins-Best-Practices
2- https://github.com/harrah/xsbt/wiki/sbt-0.10-plugins-list
3- http://eed3si9n.com/sbt-010-guide
4- The AspectJ compiler API
5- typesafehub-sbt-aspectj plugin

2011/09/26

一个scala编译错误

针对类似如下代码:
package e3.configuration


trait IConfigurationFactory[R] extends Disposable {
  /**
   * the load method will only responsible for the load strategy, but will not be responsible for the content manipulation works.
   */
  def load(): Option[R]
}

case class EromangaConfigurations(serverCfg: EromangaConfig, commonCfg: ErosaCommonConfiguration, channelsCfg: Array[ErosaChannelConfigurationWrapper])


class EromangaSpringContextConfigurationFactory[EromangaConfigurations](configLocation: File, fileFinder: IFileFinder = new XmlFileFinder) extends IConfigurationFactory[EromangaConfigurations] {
  require(configLocation != null && configLocation.isDirectory)
  require(fileFinder != null)

  var context: FileSystemXmlApplicationContext = _

  def load(): Option[EromangaConfigurations] = {
    val resources = fileFinder.findUnder(configLocation).map("file://" + _.getAbsolutePath)
    if (context != null) {
      return None
    }
    context = new FileSystemXmlApplicationContext(resources, true)
    val e3config = context.getBean(classOf[EromangaConfig])
    val erosaCommonCfg = context.getBean(classOf[ErosaCommonConfiguration])
    val buffer = new scala.collection.mutable.ArrayBuffer[ErosaChannelConfigurationWrapper]()
    context.getBeansOfType(classOf[ErosaChannelConfigurationWrapper]).values().foreach(buffer += _)
    val channelCfgs = buffer.toArray[ErosaChannelConfigurationWrapper]
    Some(EromangaConfigurations.apply(e3config, erosaCommonCfg, channelCfgs))
  }

  def dispose() {
    if (context != null) {
      context.close()
      context = null
    }
  }
}

碰到如下编译错误:

[error] /Users/fujohnwang/workspace/e3_filestore_branch/src/main/scala/Configuration.scala:70: type mismatch;
[error]  found   : e3.configuration.EromangaConfigurations
[error]  required: EromangaConfigurations
[error]     Some(EromangaConfigurations.apply(e3config, erosaCommonCfg, channelCfgs))
[error]                                      ^
[error] one error found

猜猜哪里出了问题,^_^

2011/09/07

Darren's Casual Thoughts On Distributed RPC Service Framework


Darren's Casual Thoughts On Distributed RPC Service Framework


service identity: 
[artifact version] + FQname + version


service identity: 
[artifact version] + FQname + version

service lookup: 
1- how many services exist?
2- what kind of details operations/services in each service?!
3- what's the signature of each operations?


service extensions:
1- can I replace the data structure serialization and deserialization?!
1.1 use custom serialization mechanism
1.2 some flag to indicate the mechanism that's used by service providers
2- can I intercept service operations without service implementations' intrusion?!
3- can I replace default service lookup service provider?
4- can I hook in custom LB and failover mechanisms in the service users' side?
5- can I hook in audit and monitoring concerns?
6- can I tune the server side of the service exposion?
6.1 TcpNoDelay?!
6.2 send buffer or receive buffer size
6.3 timeout
6.4 etc.
7- can I expose same service via different transports at the same time?!

service upgrade
1- service framework upgrade
2- service upgrade

service deployment
1- how to ease the large scale service deployment?! even make it automatically?
2- template publication node?!

potential points
1- are overloaded methods allowed?!
2- are multiple languages inter-operations supported?!
3- If you want to provide OO-RPC interface for clients to use, what kind of interception mechanisms u want to use? reflection or bytecode gen?  Are there some overheads in this point?