/platform/testGuiFramework/src/com/intellij/testGuiFramework/remote/client/JUnitClientImpl.kt

http://github.com/JetBrains/intellij-community · Kotlin · 153 lines · 114 code · 21 blank · 18 comment · 8 complexity · b35c96dcd22fdc5c41384fdb53dbe31a MD5 · raw file

  1. /*
  2. * Copyright 2000-2017 JetBrains s.r.o.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.intellij.testGuiFramework.remote.client
  17. import com.intellij.openapi.diagnostic.Logger
  18. import com.intellij.testGuiFramework.remote.transport.MessageType
  19. import com.intellij.testGuiFramework.remote.transport.TransportMessage
  20. import com.intellij.util.ConcurrencyUtil
  21. import java.io.ObjectInputStream
  22. import java.io.ObjectOutputStream
  23. import java.net.InetAddress
  24. import java.net.InetSocketAddress
  25. import java.net.Socket
  26. import java.net.SocketException
  27. import java.util.*
  28. import java.util.concurrent.BlockingQueue
  29. import java.util.concurrent.LinkedBlockingQueue
  30. import java.util.concurrent.ScheduledExecutorService
  31. import java.util.concurrent.TimeUnit
  32. /**
  33. * @author Sergey Karashevich
  34. */
  35. class JUnitClientImpl(host: String, val port: Int, initHandlers: Array<ClientHandler>? = null) : JUnitClient {
  36. private val LOG = Logger.getInstance("#com.intellij.testGuiFramework.remote.client.JUnitClientImpl")
  37. private val RECEIVE_THREAD = "JUnit Client Receive Thread"
  38. private val SEND_THREAD = "JUnit Client Send Thread"
  39. private val connection: Socket
  40. private val clientConnectionTimeout = 60000 //in ms
  41. private val clientReceiveThread: ClientReceiveThread
  42. private val clientSendThread: ClientSendThread
  43. private val poolOfMessages: BlockingQueue<TransportMessage> = LinkedBlockingQueue()
  44. private val handlers: ArrayList<ClientHandler> = ArrayList()
  45. private val keepAliveExecutor: ScheduledExecutorService = ConcurrencyUtil.newSingleScheduledThreadExecutor("JUnit keep-alive client");
  46. init {
  47. if (initHandlers != null) handlers.addAll(initHandlers)
  48. LOG.info("Client connecting to Server($host, $port) ...")
  49. connection = Socket()
  50. connection.connect(InetSocketAddress(InetAddress.getByName(host), port), clientConnectionTimeout)
  51. LOG.info("Client connected to Server($host, $port) successfully")
  52. clientSendThread = ClientSendThread()
  53. clientSendThread.start()
  54. clientReceiveThread = ClientReceiveThread()
  55. clientReceiveThread.start()
  56. startKeepAlive()
  57. }
  58. override fun addHandler(handler: ClientHandler) {
  59. handlers.add(handler)
  60. }
  61. override fun removeHandler(handler: ClientHandler) {
  62. handlers.remove(handler)
  63. }
  64. override fun removeAllHandlers() {
  65. handlers.clear()
  66. }
  67. override fun send(message: TransportMessage) {
  68. poolOfMessages.add(message)
  69. }
  70. override fun stopClient() {
  71. val clientPort = connection.port
  72. LOG.info("Stopping client on port: $clientPort ...")
  73. clientSendThread.interrupt()
  74. clientReceiveThread.interrupt()
  75. poolOfMessages.clear()
  76. handlers.clear()
  77. connection.close()
  78. keepAliveExecutor.shutdownNow()
  79. LOG.info("Stopped client on port: $clientPort")
  80. }
  81. private fun startKeepAlive() =
  82. keepAliveExecutor.scheduleWithFixedDelay(
  83. {
  84. if (!connection.isClosed) {
  85. send(TransportMessage(MessageType.KEEP_ALIVE))
  86. }
  87. else {
  88. throw SocketException("Connection is broken")
  89. }
  90. }, 0L, 5, TimeUnit.SECONDS)
  91. private inner class ClientReceiveThread: Thread(RECEIVE_THREAD) {
  92. override fun run() {
  93. LOG.info("Starting Client Receive Thread")
  94. ObjectInputStream(connection.getInputStream()).use { inputStream ->
  95. try {
  96. while (!connection.isClosed) {
  97. val obj = inputStream.readObject()
  98. LOG.info("Received message: $obj")
  99. obj as TransportMessage
  100. handlers.filter { it.accept(obj) }.forEach { it.handle(obj) }
  101. }
  102. }
  103. catch (e: Exception) {
  104. when (e) {
  105. is InterruptedException -> { /* ignore */ }
  106. else -> LOG.info("Transport receiving message exception", e)
  107. }
  108. }
  109. }
  110. }
  111. }
  112. private inner class ClientSendThread: Thread(SEND_THREAD) {
  113. override fun run() {
  114. LOG.info("Starting Client Send Thread")
  115. ObjectOutputStream(connection.getOutputStream()).use { outputStream ->
  116. try {
  117. while (!connection.isClosed) {
  118. val transportMessage = poolOfMessages.take()
  119. LOG.info("Sending message: $transportMessage")
  120. outputStream.writeObject(transportMessage)
  121. }
  122. }
  123. catch (e: Exception) {
  124. when (e) {
  125. is InterruptedException -> { /* ignore */ }
  126. else -> LOG.info(e)
  127. }
  128. }
  129. }
  130. }
  131. }
  132. }