diff --git a/dev/dependencyList b/dev/dependencyList
index 9dce44b28..ebe2659ed 100644
--- a/dev/dependencyList
+++ b/dev/dependencyList
@@ -33,6 +33,7 @@ htrace-core4/4.1.0-incubating//htrace-core4-4.1.0-incubating.jar
jackson-annotations/2.11.4//jackson-annotations-2.11.4.jar
jackson-core/2.11.4//jackson-core-2.11.4.jar
jackson-databind/2.11.4//jackson-databind-2.11.4.jar
+jackson-module-jaxb-annotations/2.9.9//jackson-module-jaxb-annotations-2.9.9.jar
jackson-module-paranamer/2.11.4//jackson-module-paranamer-2.11.4.jar
jackson-module-scala_2.12/2.11.4//jackson-module-scala_2.12-2.11.4.jar
jakarta.annotation-api/1.3.5//jakarta.annotation-api-1.3.5.jar
@@ -46,8 +47,10 @@ jcl-over-slf4j/1.7.30//jcl-over-slf4j-1.7.30.jar
jersey-client/2.30//jersey-client-2.30.jar
jersey-common/2.30//jersey-common-2.30.jar
jersey-container-servlet-core/2.30//jersey-container-servlet-core-2.30.jar
+jersey-entity-filtering/2.30//jersey-entity-filtering-2.30.jar
jersey-hk2/2.30//jersey-hk2-2.30.jar
jersey-media-jaxb/2.30//jersey-media-jaxb-2.30.jar
+jersey-media-json-jackson/2.30//jersey-media-json-jackson-2.30.jar
jersey-server/2.30//jersey-server-2.30.jar
jetty-http/9.4.41.v20210516//jetty-http-9.4.41.v20210516.jar
jetty-io/9.4.41.v20210516//jetty-io-9.4.41.v20210516.jar
diff --git a/kyuubi-server/pom.xml b/kyuubi-server/pom.xml
index 150f0cda6..dbc1aec25 100644
--- a/kyuubi-server/pom.xml
+++ b/kyuubi-server/pom.xml
@@ -81,6 +81,11 @@
jersey-hk2
+
+ org.glassfish.jersey.media
+ jersey-media-json-jackson
+
+
org.apache.kyuubi
kyuubi-common_${scala.binary.version}
diff --git a/kyuubi-server/src/main/java/org/apache/kyuubi/server/api/v1/dto/SessionOpenedCount.java b/kyuubi-server/src/main/java/org/apache/kyuubi/server/api/v1/dto/SessionOpenedCount.java
new file mode 100644
index 000000000..914793b3a
--- /dev/null
+++ b/kyuubi-server/src/main/java/org/apache/kyuubi/server/api/v1/dto/SessionOpenedCount.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.kyuubi.server.api.v1.dto;
+
+import java.io.Serializable;
+
+public class SessionOpenedCount implements Serializable {
+
+ private int openSessionCount;
+
+ public SessionOpenedCount() {
+ }
+
+ public int getOpenSessionCount() {
+ return openSessionCount;
+ }
+
+ public void setOpenSessionCount(int openSessionCount) {
+ this.openSessionCount = openSessionCount;
+ }
+}
diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/RestFrontendService.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/RestFrontendService.scala
index b84c34aad..857219624 100644
--- a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/RestFrontendService.scala
+++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/RestFrontendService.scala
@@ -113,6 +113,16 @@ private[server] class RestFrontendService private(name: String, be: BackendServi
private def stopHttpServer(): Unit = {
if (jettyServer != null) {
+ try {
+ connector.stop()
+ info("Rest frontend service server connector has stopped.")
+ } catch {
+ case err: Exception =>
+ error("Cannot safely stop rest frontend service server connector", err)
+ } finally {
+ connector = null
+ }
+
try {
jettyServer.stop()
info("Rest frontend service jetty server has stopped.")
diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/api.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/api.scala
index 9313fe220..862163cf0 100644
--- a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/api.scala
+++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/api.scala
@@ -71,5 +71,3 @@ private[server] object ApiUtils {
}
}
-
-
diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/ApiRootResource.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/ApiRootResource.scala
index e915026ba..49acabbc8 100644
--- a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/ApiRootResource.scala
+++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/ApiRootResource.scala
@@ -30,4 +30,7 @@ private[v1] class ApiRootResource extends ApiRequestContext {
@Produces(Array(MediaType.TEXT_PLAIN))
def ping(): String = "pong"
+ @Path("sessions")
+ def sessions: Class[SessionsResource] = classOf[SessionsResource]
+
}
diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/SessionsResource.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/SessionsResource.scala
new file mode 100644
index 000000000..9fcc9dd1f
--- /dev/null
+++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/SessionsResource.scala
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.kyuubi.server.api.v1
+
+import javax.ws.rs.{GET, Path, Produces}
+import javax.ws.rs.core.MediaType
+
+import org.apache.kyuubi.server.api.ApiRequestContext
+import org.apache.kyuubi.server.api.v1.dto.SessionOpenedCount
+
+@Produces(Array(MediaType.APPLICATION_JSON))
+private[v1] class SessionsResource extends ApiRequestContext {
+
+ @GET
+ @Path("count")
+ def sessionCount(): SessionOpenedCount = {
+ val sessionOpenedCount = new SessionOpenedCount()
+ sessionOpenedCount.setOpenSessionCount(
+ backendService.sessionManager.getOpenSessionCount
+ )
+ sessionOpenedCount
+ }
+
+}
diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/RestFrontendServiceSuite.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/RestFrontendServiceSuite.scala
index f453a2e5e..531bda6ed 100644
--- a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/RestFrontendServiceSuite.scala
+++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/RestFrontendServiceSuite.scala
@@ -19,13 +19,16 @@ package org.apache.kyuubi.server
import java.util.Locale
+import com.fasterxml.jackson.databind.ObjectMapper
import org.scalatest.time.SpanSugar._
import scala.io.Source
import org.apache.kyuubi.KyuubiFunSuite
import org.apache.kyuubi.config.KyuubiConf
-import org.apache.kyuubi.service.NoopServer
+import org.apache.kyuubi.server.api.v1.dto.SessionOpenedCount
+import org.apache.kyuubi.service.{NoopBackendService, NoopServer}
import org.apache.kyuubi.service.ServiceState._
+import org.apache.kyuubi.session.{NoopSessionImpl, NoopSessionManager, SessionManager}
class RestFrontendServiceSuite extends KyuubiFunSuite{
@@ -61,29 +64,63 @@ class RestFrontendServiceSuite extends KyuubiFunSuite{
}
test("kyuubi rest frontend service http basic") {
+ withKyuubiRestServer {
+ (_, host, port) =>
+ eventually(timeout(10.seconds), interval(50.milliseconds)) {
+ val html = Source.fromURL(s"http://$host:$port/api/v1/ping").mkString
+ assert(html.toLowerCase(Locale.ROOT).equals("pong"))
+ }
+ }
+ }
+
+ test("kyuubi rest frontend service for sessions resource") {
+ withKyuubiRestServer {
+ (_, host, port) =>
+ val expectedCount = new SessionOpenedCount()
+ expectedCount.setOpenSessionCount(1)
+ val expectedStr = new ObjectMapper().writeValueAsString(expectedCount)
+
+ eventually(timeout(10.seconds), interval(50.milliseconds)) {
+ val html = Source.fromURL(s"http://$host:$port/api/v1/sessions/count").mkString
+ assert(html.toLowerCase(Locale.ROOT).equalsIgnoreCase(expectedStr))
+ }
+ }
+ }
+
+ def withKyuubiRestServer(f: (RestFrontendService, String, Int) => Unit): Unit = {
val server = new RestNoopServer()
server.stop()
val conf = KyuubiConf()
conf.set(KyuubiConf.FRONTEND_REST_BIND_HOST, "localhost")
server.initialize(conf)
- val frontendService = server.getServices(0).asInstanceOf[RestFrontendService]
server.start()
- assert(server.getServiceState === STARTED)
- assert(frontendService.getServiceState == STARTED)
- eventually(timeout(10.seconds), interval(50.milliseconds)) {
- val html = Source.fromURL("http://localhost:10099/api/v1/ping").mkString
- assert(html.toLowerCase(Locale.ROOT).equals("pong"))
+ val frontendService = server.getServices(0).asInstanceOf[RestFrontendService]
+
+ try {
+ f(frontendService, conf.get(KyuubiConf.FRONTEND_REST_BIND_HOST).get,
+ conf.get(KyuubiConf.FRONTEND_REST_BIND_PORT))
+ } finally {
+ server.stop()
}
-
- server.stop()
}
class RestNoopServer extends NoopServer {
-
+ override val backendService: NoopBackendService = new RestMockedBeService
override val frontendService = new RestFrontendService(backendService)
+ }
+ class RestMockedBeService extends NoopBackendService {
+ override val sessionManager: SessionManager = new RestMockedSessionManager()
+ }
+
+ class RestMockedSessionManager extends NoopSessionManager {
+ // It's a ugly and temporally implementation will replace it via creation rest API.
+ var session = new NoopSessionImpl(null, null, null, null, Map(), this)
+ setSession(session.handle, session)
+
+ override protected def isServer: Boolean = true
}
}
diff --git a/pom.xml b/pom.xml
index f9fb1e0cf..c663977c9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1185,6 +1185,12 @@
jersey-hk2
${jersey.version}
+
+
+ org.glassfish.jersey.media
+ jersey-media-json-jackson
+ ${jersey.version}
+