Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
ongo.reactivemongo-jmx_2.12.1.1.0-RC9.source-code.ConnectionListener.scala Maven / Gradle / Ivy
package reactivemongo.jmx
import java.util.Hashtable
import javax.management.{
AttributeChangeNotification,
MBeanNotificationInfo,
Notification,
NotificationBroadcasterSupport,
ObjectName
}
import scala.collection.mutable.{ Map => MMap }
import scala.reflect.ClassTag
import reactivemongo.api.MongoConnectionOptions
import reactivemongo.core.nodeset.{ NodeInfo, NodeSetInfo }
/** Listener definition for the connection events. */
@SuppressWarnings(Array("CatchThrowable"))
final class ConnectionListener
extends external.reactivemongo.ConnectionListener {
import java.lang.management.ManagementFactory
import javax.management.MBeanServer
private lazy val mbs: MBeanServer = ManagementFactory.getPlatformMBeanServer()
@inline private def nodeProps(node: NodeInfo) = {
val props = new Hashtable[String, String]()
props.put("type", "Node")
props.put("name", s"${node.host}-${node.port}")
props
}
private lazy val nodeSet: NodeSet = new NodeSet()
// Handler functions
private val poolNames = MMap.empty[(String, String), ObjectName]
def poolCreated(
options: MongoConnectionOptions,
supervisor: String,
connection: String
): Unit = {
val props = new Hashtable[String, String]()
props.put("type", "NodeSet")
val domain = s"org.reactivemongo.$supervisor.$connection"
val objName = new ObjectName(domain, props)
def opts = MongoConnectionOptions.toStrings(options).mkString(", ")
nodeSet.init(opts, supervisor, connection)
mbs.registerMBean(nodeSet, objName)
poolNames += (supervisor -> connection) -> objName
nodeSet.sendNotification(
"stateChange",
domain,
"The connection pool is has been created"
)
}
private val nodes = MMap.empty[(String, String), MMap[String, Node]]
def nodeSetUpdated(
supervisor: String,
connection: String,
previous: NodeSetInfo,
updated: NodeSetInfo
): Unit = {
nodeSet.update(updated)
def nodeMap(ns: NodeSetInfo): Map[String, NodeInfo] =
Option(ns)
.fold(List.empty[NodeInfo])(_.nodes.toList)
.map { n => n.name -> n }
.toMap
val prev = nodeMap(previous)
val upd = nodeMap(updated)
val ns = nodes.getOrElseUpdate(
(supervisor -> connection),
MMap.empty[String, Node]
)
ns.synchronized {
val rmd = prev -- upd.keys
// Removed nodes
rmd.foreach {
case (name, removed) =>
lazy val objName = new ObjectName(
s"org.reactivemongo.$supervisor.$connection",
nodeProps(removed)
)
try {
mbs.unregisterMBean(objName)
ns -= name
nodeSet.sendNotification(
"nodeRemoved",
objName,
s"The node is no longer available: $name"
)
} catch {
case _: javax.management.InstanceNotFoundException =>
logger.debug(s"The node MBean is not registered: $objName")
case reason: Throwable =>
logger.warn(s"Fails to remove node MBean: $objName", reason)
}
}
// Added nodes
(upd -- prev.keys).foreach {
case (name, added) =>
val node = new Node(supervisor, connection)
lazy val objName = new ObjectName(
s"org.reactivemongo.$supervisor.$connection",
nodeProps(added)
)
try {
mbs.registerMBean(node, objName)
ns += name -> node
node.update(added)
nodeSet.sendNotification(
"nodeAdded",
objName,
s"The node is now available: $name"
)
} catch {
case _: javax.management.InstanceAlreadyExistsException =>
logger.warn(s"The node MBean is already registered: $objName")
case reason: Throwable =>
logger.warn(s"Fails to register the node MBean: $objName", reason)
}
}
// Updated nodes
(prev -- rmd.keys).foreach {
case (name, node) =>
try {
ns.get(name).foreach { bean =>
bean.update(node)
nodeSet.sendNotification(
"nodeUpdated",
name,
s"The node properties have been updated: $name"
)
}
} catch {
case reason: Throwable =>
logger.warn(s"Fails to update the node MBean: $name", reason)
}
}
}
}
private def unregisterNodes(ns: MMap[String, Node]): Unit =
ns.foreach {
case (name, node) =>
ns -= name
try {
val props = new Hashtable[String, String]()
props.put("type", "Node")
props.put("name", s"${node.getHost}-${node.getPort}")
val objName = new ObjectName(
s"org.reactivemongo.${node.getSupervisor}.${node.getConnection}",
props
)
mbs.unregisterMBean(objName)
} catch {
case reason: Throwable =>
logger.warn(s"Fails to unregister the node MBean: $name", reason)
}
}
def poolShutdown(supervisor: String, connection: String) = {
val key = supervisor -> connection
poolNames.get(key).foreach { name =>
try {
mbs.unregisterMBean(name)
} catch {
case reason: Throwable =>
logger.warn(s"Fails to unregister the pool MBean: $name", reason)
}
}
nodes.remove(key).foreach { ns =>
ns.synchronized {
unregisterNodes(ns)
}
}
}
def shutdown(): Unit = {
poolNames.values.foreach { name =>
try {
mbs.unregisterMBean(name)
} catch {
case reason: Throwable =>
logger.warn(s"Fails to unregister the pool MBean: $name", reason)
}
}
nodes.values.foreach { ns =>
ns.synchronized {
unregisterNodes(ns)
}
}
}
}
sealed trait NotificationSupport { self: NotificationBroadcasterSupport =>
protected val changeSeq = new java.util.concurrent.atomic.AtomicLong()
protected def attributeChanged[T: ClassTag](
name: String,
message: String,
oldValue: T,
newValue: T
)(f: T => Unit
): Unit = if (oldValue != newValue) {
val n = new AttributeChangeNotification(
this,
changeSeq.incrementAndGet(),
System.currentTimeMillis(),
message,
name,
implicitly[ClassTag[T]].toString,
oldValue,
newValue
)
f(newValue)
sendNotification(n)
}
}
@SuppressWarnings(Array("NullAssignment"))
final class NodeSet private[jmx] ()
extends NotificationBroadcasterSupport
with NodeSetMBean
with NotificationSupport {
private var options: String = null
private var supervisor: String = null
private var connection: String = null
private var name: String = null
private var version: Long = -1L
private var primary: String = null
private var mongos: String = null
private var nearest: String = null
private var nodes: String = null
private var secondaries: String = null
private var awaitingRequests: Int = -1
private var maxAwaitingRequestsPerChannel: Int = -1
// MBean attributes
def getConnectionOptions() = options
def getSupervisor() = supervisor
def getConnection() = connection
def getName() = name
def getVersion() = version
def getMongos(): String = mongos
def getNearest(): String = nearest
def getPrimary(): String = primary
def getNodes() = nodes
def getSecondaries() = secondaries
def getAwaitingRequests() = awaitingRequests
def getMaxAwaitingRequestsPerChannel() = maxAwaitingRequestsPerChannel
// Notification support
private[jmx] def sendNotification[T](
typ: String,
source: T,
msg: String
): Unit = {
sendNotification(
new Notification(
typ,
source,
changeSeq.incrementAndGet(),
System.currentTimeMillis(),
msg
)
)
}
override def getNotificationInfo() = NodeSet.notificationInfo
// ---
private[jmx] def init(opts: String, s: String, c: String): Unit = {
options = opts
supervisor = s
connection = c
}
private[jmx] def update(updated: NodeSetInfo): Unit = {
val info = Option(updated)
var _name: String = null
var _version: Long = -1L
var _primary: String = null
var _mongos: String = null
var _nearest: String = null
var _nodes: String = null
var _secondaries: String = null
var _awaitingRequests: Int = -1
var _maxAwaitingRequestsPerChannel: Int = -1
info.foreach { i =>
_name = i.name.getOrElse(null)
_version = i.version.getOrElse(-1L)
_primary = i.primary.fold[String](null)(_.toString)
_mongos = i.mongos.fold[String](null)(_.toString)
_nearest = i.nearest.fold[String](null)(_.toString)
_nodes = i.nodes.toArray.map(_.toString).mkString("; ")
_secondaries = i.secondaries.toArray.map(_.toString).mkString("; ")
_awaitingRequests = i.awaitingRequests.getOrElse(-1)
_maxAwaitingRequestsPerChannel =
i.maxAwaitingRequestsPerChannel.getOrElse(-1)
}
attributeChanged("Name", "The name of node set has changed", name, _name) {
name = _
}
attributeChanged[java.lang.Long](
"Version",
"The version of node set has changed",
version,
_version
) { version = _ }
attributeChanged(
"Primary",
"The information about the primary node",
primary,
_primary
) { primary = _ }
attributeChanged(
"Mongos",
"The information about the mongos node",
mongos,
_mongos
) { mongos = _ }
attributeChanged(
"Nearest",
"The information about the nearest node",
nearest,
_nearest
) { nearest = _ }
attributeChanged(
"Nodes",
"The information about the node list",
nodes,
_nodes
) { nodes = _ }
attributeChanged(
"Secondaries",
"The information about the secondary nodes",
secondaries,
_secondaries
) { secondaries = _ }
attributeChanged[java.lang.Integer](
"AwaitingRequests",
"The number of awaiting requests",
awaitingRequests,
_awaitingRequests
) { awaitingRequests = _ }
attributeChanged[java.lang.Integer](
"MaxAwaitingRequestsPerChannel",
"The maximum number of awaiting requests per channel",
maxAwaitingRequestsPerChannel,
_maxAwaitingRequestsPerChannel
) {
maxAwaitingRequestsPerChannel = _
}
}
}
object NodeSet {
lazy val notificationInfo: Array[MBeanNotificationInfo] = Array(
new MBeanNotificationInfo(
Array("stateChange"),
classOf[Notification].getName,
"The state of the connection pool has changed"
),
new MBeanNotificationInfo(
Array("nodeAdded"),
classOf[Notification].getName,
"A node has been added to the set"
),
new MBeanNotificationInfo(
Array("nodeUpdated"),
classOf[Notification].getName,
"A node has been updated to the set"
),
new MBeanNotificationInfo(
Array("nodeRemoved"),
classOf[Notification].getName,
"A node has been removed to the set"
),
new MBeanNotificationInfo(
Array[String](AttributeChangeNotification.ATTRIBUTE_CHANGE),
classOf[AttributeChangeNotification].getName,
"The node set has changed"
)
)
}
@SuppressWarnings(Array("NullAssignment"))
final class Node private[jmx] (
supervisor: String,
connection: String)
extends NotificationBroadcasterSupport
with NodeMBean
with NotificationSupport {
private var name = "unknown"
private var aliases: String = null
private var host = "unknown"
private var port = -1
private var status = "unknown"
private var connections = 0
private var connected = 0
private var authenticated = 0
private var tags: String = null
private var protocolMetadata = "unknown"
private var pingInfo = "unknown"
private var mongos = false
private[jmx] def update(info: NodeInfo): Unit = {
val _name = info.name
val _aliases = info.aliases.mkString(", ")
val _host = info.host
val _port = info.port
val _status = info.status.toString
val _connections = info.connections
val _connected = info.connected
val _authenticated = info.authenticated
val _tags = info.tags.mkString("{", ", ", "}")
val _mongos = info.isMongos
val _protocolMetadata = {
val m = info.protocolMetadata
s"minWireVersion = ${m.minWireVersion}, maxWireVersion = ${m.maxWireVersion}, maxMessageSizeBytes = ${m.maxMessageSizeBytes}, maxBsonSize = ${m.maxBsonSize}, maxBulkSize = ${m.maxBulkSize}"
}
val _pingInfo = {
val i = info.pingInfo
s"sent = ${i.ping}, lastIsMaster(time = ${i.lastIsMasterTime}, id = ${i.lastIsMasterId})"
}
attributeChanged("Name", "The node name", name, _name) { name = _ }
attributeChanged("Aliases", "The aliases of the node", aliases, _aliases) {
aliases = _
}
attributeChanged("Host", "The name of the node host", host, _host) {
host = _
}
attributeChanged("Port", "The MongoDB port on the node", port, _port) {
port = _
}
attributeChanged("Status", "The node status", status, _status) {
status = _
}
attributeChanged(
"Connections",
"The number of connections to the node",
connections,
_connections
) { connections = _ }
attributeChanged(
"Connected",
"The number of connections established to the node",
connected,
_connected
) { connected = _ }
attributeChanged(
"Authenticated",
"The number of authenticated connections to the node",
authenticated,
_authenticated
) { authenticated = _ }
attributeChanged("Tags", "The tags for the node", tags, _tags) { tags = _ }
attributeChanged(
"ProtocolMetadata",
"The metadata for the protocol to connect to the node",
protocolMetadata,
_protocolMetadata
) { protocolMetadata = _ }
attributeChanged(
"PingInfo",
"The information about the ping to the node",
pingInfo,
_pingInfo
) { pingInfo = _ }
attributeChanged(
"Mongos",
"Indicates whether the node is a Mongos one",
mongos,
_mongos
) { mongos = _ }
}
// MBean attributes
def getSupervisor() = supervisor
def getConnection() = connection
def getName() = name
def getAliases() = aliases
def getHost() = host
def getPort() = port
def getStatus() = status
def getConnections() = connections
def getConnected() = connected
def getAuthenticated() = authenticated
def getTags() = tags
def getProtocolMetadata() = protocolMetadata
def getPingInfo() = pingInfo
def isMongos() = mongos
// Notification support
override def getNotificationInfo() = Node.notificationInfo
}
object Node {
lazy val notificationInfo: Array[MBeanNotificationInfo] = Array(
new MBeanNotificationInfo(
Array[String](AttributeChangeNotification.ATTRIBUTE_CHANGE),
classOf[AttributeChangeNotification].getName,
"The node has changed"
)
)
}