/kevoree-library/javase/org.kevoree.library.javase.gossiperNetty/src/main/scala/org/kevoree/library/javase/gossiperNetty/TCPActor.scala

https://github.com/joseph2000/kevoree · Scala · 132 lines · 104 code · 17 blank · 11 comment · 6 complexity · 0e3da3b0c93ccaf10bafb335ea6ce51a MD5 · raw file

  1. package org.kevoree.library.javase.gossiperNetty
  2. import java.net.InetSocketAddress
  3. import org.kevoree.library.gossiperNetty.protocol.message.KevoreeMessage.Message
  4. import org.slf4j.LoggerFactory
  5. import java.util.concurrent.Executors
  6. import org.jboss.netty.handler.codec.compression.{ZlibEncoder, ZlibWrapper, ZlibDecoder}
  7. import org.jboss.netty.handler.codec.protobuf.{ProtobufEncoder, ProtobufVarint32LengthFieldPrepender, ProtobufDecoder, ProtobufVarint32FrameDecoder}
  8. import org.jboss.netty.channel._
  9. import socket.nio.{NioClientSocketChannelFactory, NioServerSocketChannelFactory}
  10. import org.jboss.netty.bootstrap.{ClientBootstrap, ServerBootstrap}
  11. import org.jboss.netty.channel.group.DefaultChannelGroup
  12. import scala.collection.JavaConversions._
  13. /**
  14. * User: Erwan Daubert - erwan.daubert@gmail.com
  15. * Date: 12/09/11
  16. * Time: 10:26
  17. */
  18. class TCPActor (port: Int, processValue: ProcessValue, processRequest: ProcessRequest) extends NetworkActor {
  19. private val logger = LoggerFactory.getLogger(classOf[TCPActor])
  20. // configure the server
  21. var factoryServer = new
  22. NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool())
  23. var bootstrapServer = new ServerBootstrap(factoryServer)
  24. bootstrapServer.setPipelineFactory(new ChannelPipelineFactory() {
  25. override def getPipeline: ChannelPipeline = {
  26. val p: ChannelPipeline = Channels.pipeline()
  27. p.addLast("inflater", new ZlibDecoder(ZlibWrapper.ZLIB))
  28. p.addLast("frameDecoder", new ProtobufVarint32FrameDecoder)
  29. p.addLast("protobufDecoder", new ProtobufDecoder(Message.getDefaultInstance))
  30. p.addLast("deflater", new ZlibEncoder(ZlibWrapper.ZLIB))
  31. p.addLast("frameEncoder", new ProtobufVarint32LengthFieldPrepender)
  32. p.addLast("protobufEncoder", new ProtobufEncoder)
  33. p.addLast("handler", new TCPRequestHandler(processRequest))
  34. p
  35. }
  36. })
  37. bootstrapServer.setOption("tcpNoDelay", true)
  38. var channelServer: Channel = bootstrapServer.bind(new InetSocketAddress(port))
  39. // Configure the client.
  40. val factory = new NioClientSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool())
  41. val bootstrap = new ClientBootstrap(factory)
  42. bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
  43. override def getPipeline: ChannelPipeline = {
  44. val p: ChannelPipeline = Channels.pipeline()
  45. p.addLast("inflater", new ZlibDecoder(ZlibWrapper.ZLIB))
  46. p.addLast("frameDecoder", new ProtobufVarint32FrameDecoder)
  47. p.addLast("protobufDecoder", new ProtobufDecoder(Message.getDefaultInstance))
  48. p.addLast("deflater", new ZlibEncoder(ZlibWrapper.ZLIB))
  49. p.addLast("frameEncoder", new ProtobufVarint32LengthFieldPrepender)
  50. p.addLast("protobufEncoder", new ProtobufEncoder)
  51. p.addLast("handler", new TCPValueHandler(processValue))
  52. p
  53. }
  54. });
  55. // keep all created channels to delete it when we stop
  56. // we only keep 5 channels, if a sixth channel is created, we release the fifth first.
  57. val channelGroup = new DefaultChannelGroup();
  58. protected def stopInternal () {
  59. channelServer.close().addListener(ChannelFutureListener.CLOSE)
  60. // Shut down all thread pools to exit.
  61. bootstrap.releaseExternalResources();
  62. bootstrapServer.releaseExternalResources();
  63. }
  64. protected def sendMessageInternal (o: Message, address: InetSocketAddress) {
  65. val future = bootstrap.connect(address)
  66. // Wait until the connection attempt succeeds or fails.
  67. val channel = future.awaitUninterruptibly().getChannel
  68. if (!future.isSuccess) {
  69. logger.error(address + "is not available", future.getCause.printStackTrace())
  70. } else {
  71. channel.write(o)
  72. if (channelGroup.size() == 10) {
  73. channelGroup.foreach {
  74. channel => {
  75. channel.close().addListener(ChannelFutureListener.CLOSE)
  76. logger.debug("releasing too old channel ...")
  77. }
  78. }
  79. channelGroup.clear()
  80. }
  81. channelGroup.add(channel);
  82. }
  83. }
  84. protected def sendMessageToChannelInternal (o: Message, channel: Channel, address: InetSocketAddress) {
  85. channel.write(o)
  86. channel.close()
  87. }
  88. private class TCPRequestHandler (processRequest: ProcessRequest) extends SimpleChannelUpstreamHandler {
  89. override def messageReceived (ctx: ChannelHandlerContext, e: MessageEvent) {
  90. if (e.getMessage.isInstanceOf[Message]) {
  91. processRequest.receiveRequest(e.getMessage.asInstanceOf[Message], e.getChannel,
  92. e.getRemoteAddress.asInstanceOf[InetSocketAddress])
  93. }
  94. e.getChannel.getCloseFuture.addListener(ChannelFutureListener.CLOSE)
  95. }
  96. override def exceptionCaught (ctx: ChannelHandlerContext, e: ExceptionEvent) {
  97. logger.error("Communication failed between " + ctx.getChannel.getLocalAddress + " and " +
  98. ctx.getChannel.getRemoteAddress, e.getCause)
  99. e.getChannel.close()
  100. }
  101. }
  102. private class TCPValueHandler (processValue: ProcessValue) extends SimpleChannelUpstreamHandler {
  103. override def messageReceived (ctx: ChannelHandlerContext, e: MessageEvent) {
  104. if (e.getMessage.isInstanceOf[Message]) {
  105. processValue.receiveValue(e.getMessage.asInstanceOf[Message])
  106. }
  107. e.getChannel.close()
  108. }
  109. override def exceptionCaught (ctx: ChannelHandlerContext, e: ExceptionEvent) {
  110. logger.error("Communication failed between " + ctx.getChannel.getLocalAddress + " and " +
  111. ctx.getChannel.getRemoteAddress, e.getCause)
  112. e.getChannel.close()
  113. }
  114. }
  115. }