Chapter 13. Writing Play Plugins

In order to make our applications manageable, we break them down into independent modules. These modules can also be extracted into individual projects/libraries.

A Play plugin is nothing but another module with an additional ability—of binding tasks before starting, on starting and/or stopping a Play application. In this chapter, we will see how to write custom plugins.

In this chapter, we will cover the following topics:

  • Plugin definition
  • Plugin declaration
  • Exposing services through plugins
  • Tips for writing a plugin

Plugin definition

A Play plugin can be defined by extending play.api.plugin, which is defined as follows:

trait Plugin {

  //Called when the application starts.
  def onStart() {}

  // Called when the application stops.
  def onStop() {}

  // Is the plugin enabled?
  def enabled: Boolean = true
}

Now, we might be in a situation where we need to send an e-mail when an application is started or stopped so that the administrator can later use this time interval to monitor the application's performance and check why it stopped. We could define a plugin to do this for us:

class NotifierPlugin(app:Application) extends Plugin{ 

  private def notify(adminId:String,status:String):Unit = { 

    val time = new Date() 

    val msg = s"The app has been $status at $time" 

    //send email to admin with the msg

    log.info(msg)

  } 



  override def onStart() { 

    val emailId = app.configuration.getString("notify.admin.id").get 

    notify(emailId,"started") 

  } 



  override def onStop() {     

    val emailId = app.configuration.getString("notify.admin.id").get 

    notify(emailId,"stopped") 

  } 



  override def enabled: Boolean = true 

}

We can also define plugins that make use of other libraries. We might need to build a plugin that builds a connection pool to Cassandra (a NoSQL database) on startup and allows users to use this pool later on. To build this plugin, we will use the cassandra-driver for Java. Our plugin will then be as follows:

class CassandraPlugin(app: Application) extends Plugin {

  private var _helper: Option[CassandraConnection] = None

  def helper = _helper.getOrElse(throw new RuntimeException("CassandraPlugin error: CassandraHelper initialization failed"))

  override def onStart() = {

    val appConfig = app.configuration.getConfig("cassandraPlugin").get
    val appName: String = appConfig.getString("appName").getOrElse("appWithCassandraPlugin")

    val hosts: Array[java.lang.String] = appConfig.getString("host").getOrElse("localhost").split(",").map(_.trim)
    val port: Int = appConfig.getInt("port").getOrElse(9042)

    val cluster = Cluster.builder()
      .addContactPoints(hosts: _*)
      .withPort(port).build()

    _helper = try {
      val session = cluster.connect()
      Some(CassandraConnection(hosts, port, cluster, session))
    } catch {
      case e: NoHostAvailableException =>
        val msg =
          s"""Failed to initialize CassandraPlugin.
             |Please check if Cassandra is accessible at
             | ${hosts.head}:$port or update configuration""".stripMargin
        throw app.configuration.globalError(msg)
    }
  }

  override def onStop() = {
    helper.session.close()
    helper.cluster.close()
  }

  override def enabled = true
}

Here, CassandraConnection is defined as follows:

private[plugin] case class CassandraConnection(hosts: Array[java.lang.String],
  port: Int,
  cluster: Cluster,
session: Session)

The cassandra-driver node is declared as a library dependency and its classes are imported where they're required.

Note

The dependency on Play in the build definition of the plugin should be marked as provided, since the application using the plugin will already have a dependency on Play, as shown here:

libraryDependencies ++= Seq(
  "com.datastax.cassandra" % "cassandra-driver-core" % "2.0.4",
  "com.typesafe.play" %% "play" % "2.3.0" % "provided" )
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.71.94