Skip to content

Commit c4fd287

Browse files
committed
[KYUUBI #1639] Make ApiRequestContext provide KyuubiRestFrontendService directly
<!-- Thanks for sending a pull request! Here are some tips for you: 1. If this is your first time, please read our contributor guidelines: https://kyuubi.readthedocs.io/en/latest/community/contributions.html 2. If the PR is related to an issue in https://github.com/apache/incubator-kyuubi/issues, add '[KYUUBI #XXXX]' in your PR title, e.g., '[KYUUBI #XXXX] Your PR title ...'. 3. If the PR is unfinished, add '[WIP]' in your PR title, e.g., '[WIP][KYUUBI #XXXX] Your PR title ...'. --> ### _Why are the changes needed?_ <!-- Please clarify why the changes are needed. For instance, 1. If you add a feature, you can talk about the use case of it. 2. If you fix a bug, you can clarify why it is a bug. --> Make full use of KyuubiRestFrontendService without hacking, e.g. for the swagger UI base. We can do further improvement based on this PR. ### _How was this patch tested?_ - [ ] Add some test cases that check the changes thoroughly including negative and positive cases if possible - [ ] Add screenshots for manual tests if appropriate - [ ] [Run test](https://kyuubi.readthedocs.io/en/latest/develop_tools/testing.html#running-tests) locally before make a pull request Closes #1639 from yaooqinn/ApiRequestContext. Closes #1639 3c0c706 [Kent Yao] Make ApiRequestContext provides KyuubiRestFrontendService directly 10506c2 [Kent Yao] Make ApiRequestContext provides KyuubiRestFrontendService directly 1482bd7 [Kent Yao] Make ApiRequestContext provides KyuubiRestFrontendService directly 01a0b02 [Kent Yao] Make ApiRequestContext provides KyuubiRestFrontendService directly d3119fa [Kent Yao] Make ApiRequestContext provides KyuubiRestFrontendService directly 0f45258 [Kent Yao] Make ApiRequestContext provides KyuubiRestFrontendService directly Authored-by: Kent Yao <yao@apache.org> Signed-off-by: Kent Yao <yao@apache.org>
1 parent cb8721f commit c4fd287

File tree

5 files changed

+64
-69
lines changed

5 files changed

+64
-69
lines changed

kyuubi-server/src/main/scala/org/apache/kyuubi/server/KyuubiRestFrontendService.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler
2626
import org.apache.kyuubi.{KyuubiException, Logging, Utils}
2727
import org.apache.kyuubi.config.KyuubiConf
2828
import org.apache.kyuubi.config.KyuubiConf.{FRONTEND_REST_BIND_HOST, FRONTEND_REST_BIND_PORT}
29-
import org.apache.kyuubi.server.api.ApiUtils
29+
import org.apache.kyuubi.server.api.v1.ApiRootResource
3030
import org.apache.kyuubi.service.{AbstractFrontendService, Serverable, Service}
3131

3232
/**
@@ -56,7 +56,7 @@ class KyuubiRestFrontendService(override val serverable: Serverable)
5656
errorHandler.setServer(jettyServer)
5757
jettyServer.addBean(errorHandler)
5858

59-
jettyServer.setHandler(ApiUtils.getServletHandler(serverable.backendService))
59+
jettyServer.setHandler(ApiRootResource.getServletHandler(this))
6060

6161
connector = new ServerConnector(
6262
jettyServer,

kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/api.scala

Lines changed: 7 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,8 @@ import javax.servlet.http.HttpServletRequest
2222
import javax.ws.rs.core.Context
2323

2424
import org.eclipse.jetty.server.handler.ContextHandler
25-
import org.eclipse.jetty.servlet.{DefaultServlet, ServletContextHandler, ServletHolder}
26-
import org.glassfish.jersey.server.ResourceConfig
27-
import org.glassfish.jersey.servlet.ServletContainer
2825

29-
import org.apache.kyuubi.service.BackendService
26+
import org.apache.kyuubi.server.KyuubiRestFrontendService
3027

3128
private[api] trait ApiRequestContext {
3229

@@ -36,42 +33,18 @@ private[api] trait ApiRequestContext {
3633
@Context
3734
protected var httpRequest: HttpServletRequest = _
3835

39-
def backendService: BackendService = BackendServiceProvider.getBackendService(servletContext)
40-
36+
final protected def fe: KyuubiRestFrontendService = FrontendServiceContext.get(servletContext)
4137
}
4238

43-
private[api] object BackendServiceProvider {
39+
private[api] object FrontendServiceContext {
4440

4541
private val attribute = getClass.getCanonicalName
4642

47-
def setBackendService(contextHandler: ContextHandler, be: BackendService): Unit = {
48-
contextHandler.setAttribute(attribute, be)
49-
}
50-
51-
def getBackendService(context: ServletContext): BackendService = {
52-
context.getAttribute(attribute).asInstanceOf[BackendService]
43+
def set(contextHandler: ContextHandler, fe: KyuubiRestFrontendService): Unit = {
44+
contextHandler.setAttribute(attribute, fe)
5345
}
54-
}
55-
56-
private[server] object ApiUtils {
57-
58-
def getServletHandler(backendService: BackendService): ServletContextHandler = {
59-
val openapiConf: ResourceConfig = new OpenAPIConfig
60-
val servlet = new ServletHolder(new ServletContainer(openapiConf))
61-
val handler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS)
62-
BackendServiceProvider.setBackendService(handler, backendService)
63-
handler.addServlet(servlet, "/*")
6446

65-
// install swagger-ui, these static files are copied from
66-
// https://github.com/swagger-api/swagger-ui/tree/master/dist
67-
val swaggerUI = new ServletHolder("swagger-ui", classOf[DefaultServlet])
68-
swaggerUI.setInitParameter(
69-
"resourceBase",
70-
getClass.getClassLoader()
71-
.getResource("META-INF/resources/webjars/swagger-ui/4.1.3/")
72-
.toExternalForm)
73-
swaggerUI.setInitParameter("pathInfoOnly", "true")
74-
handler.addServlet(swaggerUI, "/swagger-ui-redirected/*");
75-
handler
47+
def get(context: ServletContext): KyuubiRestFrontendService = {
48+
context.getAttribute(attribute).asInstanceOf[KyuubiRestFrontendService]
7649
}
7750
}

kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/ApiRootResource.scala

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@ import javax.ws.rs.{GET, Path, Produces}
2222
import javax.ws.rs.core.{MediaType, Response}
2323

2424
import com.google.common.annotations.VisibleForTesting
25+
import org.eclipse.jetty.servlet.{DefaultServlet, ServletContextHandler, ServletHolder}
26+
import org.glassfish.jersey.server.ResourceConfig
27+
import org.glassfish.jersey.servlet.ServletContainer
2528

26-
import org.apache.kyuubi.server.{KyuubiRestFrontendService, KyuubiServer}
27-
import org.apache.kyuubi.server.api.ApiRequestContext
29+
import org.apache.kyuubi.server.KyuubiRestFrontendService
30+
import org.apache.kyuubi.server.api.{ApiRequestContext, FrontendServiceContext, OpenAPIConfig}
2831

2932
@Path("/api/v1")
3033
private[v1] class ApiRootResource extends ApiRequestContext {
@@ -52,15 +55,33 @@ private[v1] class ApiRootResource extends ApiRequestContext {
5255
@GET
5356
@Path("swagger-ui")
5457
@Produces(Array(MediaType.TEXT_HTML))
55-
def swaggerUi(): Response = {
56-
val restServiceOpt = KyuubiServer.kyuubiServer
57-
.frontendServices
58-
.collectFirst { case rest: KyuubiRestFrontendService => rest }
59-
assert(restServiceOpt.isDefined)
60-
val serverIP = restServiceOpt.map(_.connectionUrl).get
61-
val swaggerUi =
62-
s"http://$serverIP/swagger-ui-redirected/index.html?url=http://$serverIP/openapi.json"
63-
Response.temporaryRedirect(new URI(swaggerUi)).build()
58+
def swaggerUI(): Response = {
59+
val swaggerUI = s"http://${fe.connectionUrl}/swagger-ui-redirected/index.html?url=" +
60+
s"http://${fe.connectionUrl}/openapi.json"
61+
Response.temporaryRedirect(new URI(swaggerUI)).build()
6462
}
6563

6664
}
65+
66+
private[server] object ApiRootResource {
67+
68+
def getServletHandler(fe: KyuubiRestFrontendService): ServletContextHandler = {
69+
val openapiConf: ResourceConfig = new OpenAPIConfig
70+
val servlet = new ServletHolder(new ServletContainer(openapiConf))
71+
val handler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS)
72+
FrontendServiceContext.set(handler, fe)
73+
handler.addServlet(servlet, "/*")
74+
75+
// install swagger-ui, these static files are copied from
76+
// https://github.com/swagger-api/swagger-ui/tree/master/dist
77+
val swaggerUI = new ServletHolder("swagger-ui", classOf[DefaultServlet])
78+
swaggerUI.setInitParameter(
79+
"resourceBase",
80+
getClass.getClassLoader()
81+
.getResource("META-INF/resources/webjars/swagger-ui/4.1.3/")
82+
.toExternalForm)
83+
swaggerUI.setInitParameter("pathInfoOnly", "true")
84+
handler.addServlet(swaggerUI, "/swagger-ui-redirected/*");
85+
handler
86+
}
87+
}

kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/OperationsResource.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ private[v1] class OperationsResource extends ApiRequestContext {
5050
@PathParam("operationHandle") operationHandleStr: String): KyuubiOperationEvent = {
5151
try {
5252
val opHandle = parseOperationHandle(operationHandleStr)
53-
val operation = backendService.sessionManager.operationManager.getOperation(opHandle)
53+
val operation = fe.be.sessionManager.operationManager.getOperation(opHandle)
5454
KyuubiOperationEvent(operation.asInstanceOf[KyuubiOperation])
5555
} catch {
5656
case NonFatal(_) =>
@@ -72,8 +72,8 @@ private[v1] class OperationsResource extends ApiRequestContext {
7272
try {
7373
val operationHandle = parseOperationHandle(operationHandleStr)
7474
request.action.toLowerCase() match {
75-
case "cancel" => backendService.cancelOperation(operationHandle)
76-
case "close" => backendService.closeOperation(operationHandle)
75+
case "cancel" => fe.be.cancelOperation(operationHandle)
76+
case "close" => fe.be.closeOperation(operationHandle)
7777
case _ => throw KyuubiSQLException(s"Invalid action ${request.action}")
7878
}
7979
Response.ok().build()
@@ -97,7 +97,7 @@ private[v1] class OperationsResource extends ApiRequestContext {
9797
try {
9898
val operationHandle = parseOperationHandle(operationHandleStr)
9999
ResultSetMetaData(
100-
backendService.getResultSetMetadata(operationHandle).getColumns.asScala.map(c => {
100+
fe.be.getResultSetMetadata(operationHandle).getColumns.asScala.map(c => {
101101
val tPrimitiveTypeEntry = c.getTypeDesc.getTypes.get(0).getPrimitiveEntry
102102
var precision = 0
103103
var scale = 0
@@ -134,7 +134,7 @@ private[v1] class OperationsResource extends ApiRequestContext {
134134
@PathParam("operationHandle") operationHandleStr: String,
135135
@QueryParam("maxrows") maxRows: Int): OperationLog = {
136136
try {
137-
val rowSet = backendService.sessionManager.operationManager.getOperationLogRowSet(
137+
val rowSet = fe.be.sessionManager.operationManager.getOperationLogRowSet(
138138
parseOperationHandle(operationHandleStr),
139139
FetchOrientation.FETCH_NEXT,
140140
maxRows)

kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/SessionsResource.scala

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ private[v1] class SessionsResource extends ApiRequestContext {
4848
@GET
4949
def sessionInfoList(): SessionList = {
5050
SessionList(
51-
backendService.sessionManager.getSessionList().asScala.map {
51+
fe.be.sessionManager.getSessionList().asScala.map {
5252
case (handle, session) =>
5353
SessionOverview(session.user, session.ipAddress, session.createTime, handle)
5454
}.toSeq)
@@ -63,7 +63,8 @@ private[v1] class SessionsResource extends ApiRequestContext {
6363
@Path("{sessionHandle}")
6464
def sessionInfo(@PathParam("sessionHandle") sessionHandleStr: String): KyuubiSessionEvent = {
6565
try {
66-
KyuubiSessionEvent(backendService.sessionManager.getSession(
66+
// TODO: need to use KyuubiSessionEvent in session
67+
KyuubiSessionEvent(fe.be.sessionManager.getSession(
6768
parseSessionHandle(sessionHandleStr)).asInstanceOf[AbstractSession])
6869
} catch {
6970
case NonFatal(e) =>
@@ -85,7 +86,7 @@ private[v1] class SessionsResource extends ApiRequestContext {
8586
@PathParam("infoType") infoType: Int): InfoDetail = {
8687
try {
8788
val info = TGetInfoType.findByValue(infoType)
88-
val infoValue = backendService.getInfo(parseSessionHandle(sessionHandleStr), info)
89+
val infoValue = fe.be.getInfo(parseSessionHandle(sessionHandleStr), info)
8990
InfoDetail(info.toString, infoValue.getStringValue)
9091
} catch {
9192
case NonFatal(e) =>
@@ -102,7 +103,7 @@ private[v1] class SessionsResource extends ApiRequestContext {
102103
@GET
103104
@Path("count")
104105
def sessionCount(): SessionOpenCount = {
105-
SessionOpenCount(backendService.sessionManager.getOpenSessionCount)
106+
SessionOpenCount(fe.be.sessionManager.getOpenSessionCount)
106107
}
107108

108109
@ApiResponse(
@@ -114,8 +115,8 @@ private[v1] class SessionsResource extends ApiRequestContext {
114115
@Path("execPool/statistic")
115116
def execPoolStatistic(): ExecPoolStatistic = {
116117
ExecPoolStatistic(
117-
backendService.sessionManager.getExecPoolSize,
118-
backendService.sessionManager.getActiveCount)
118+
fe.be.sessionManager.getExecPoolSize,
119+
fe.be.sessionManager.getActiveCount)
119120
}
120121

121122
@ApiResponse(
@@ -126,7 +127,7 @@ private[v1] class SessionsResource extends ApiRequestContext {
126127
@POST
127128
@Consumes(Array(MediaType.APPLICATION_JSON))
128129
def openSession(request: SessionOpenRequest): SessionHandle = {
129-
backendService.openSession(
130+
fe.be.openSession(
130131
TProtocolVersion.findByValue(request.protocolVersion),
131132
request.user,
132133
request.password,
@@ -142,7 +143,7 @@ private[v1] class SessionsResource extends ApiRequestContext {
142143
@DELETE
143144
@Path("{sessionHandle}")
144145
def closeSession(@PathParam("sessionHandle") sessionHandleStr: String): Response = {
145-
backendService.closeSession(parseSessionHandle(sessionHandleStr))
146+
fe.be.closeSession(parseSessionHandle(sessionHandleStr))
146147
Response.ok().build()
147148
}
148149

@@ -157,7 +158,7 @@ private[v1] class SessionsResource extends ApiRequestContext {
157158
@PathParam("sessionHandle") sessionHandleStr: String,
158159
request: StatementRequest): OperationHandle = {
159160
try {
160-
backendService.executeStatement(
161+
fe.be.executeStatement(
161162
parseSessionHandle(sessionHandleStr),
162163
request.statement,
163164
request.runAsync,
@@ -177,7 +178,7 @@ private[v1] class SessionsResource extends ApiRequestContext {
177178
@Path("{sessionHandle}/operations/typeInfo")
178179
def getTypeInfo(@PathParam("sessionHandle") sessionHandleStr: String): OperationHandle = {
179180
try {
180-
backendService.getTypeInfo(parseSessionHandle(sessionHandleStr))
181+
fe.be.getTypeInfo(parseSessionHandle(sessionHandleStr))
181182
} catch {
182183
case NonFatal(_) =>
183184
throw new NotFoundException(s"Error getting type information")
@@ -193,7 +194,7 @@ private[v1] class SessionsResource extends ApiRequestContext {
193194
@Path("{sessionHandle}/operations/catalogs")
194195
def getCatalogs(@PathParam("sessionHandle") sessionHandleStr: String): OperationHandle = {
195196
try {
196-
backendService.getCatalogs(parseSessionHandle(sessionHandleStr))
197+
fe.be.getCatalogs(parseSessionHandle(sessionHandleStr))
197198
} catch {
198199
case NonFatal(_) =>
199200
throw new NotFoundException(s"Error getting catalogs")
@@ -212,7 +213,7 @@ private[v1] class SessionsResource extends ApiRequestContext {
212213
request: GetSchemasRequest): OperationHandle = {
213214
try {
214215
val sessionHandle = parseSessionHandle(sessionHandleStr)
215-
val operationHandle = backendService.getSchemas(
216+
val operationHandle = fe.be.getSchemas(
216217
sessionHandle,
217218
request.catalogName,
218219
request.schemaName)
@@ -234,7 +235,7 @@ private[v1] class SessionsResource extends ApiRequestContext {
234235
@PathParam("sessionHandle") sessionHandleStr: String,
235236
request: GetTablesRequest): OperationHandle = {
236237
try {
237-
backendService.getTables(
238+
fe.be.getTables(
238239
parseSessionHandle(sessionHandleStr),
239240
request.catalogName,
240241
request.schemaName,
@@ -255,7 +256,7 @@ private[v1] class SessionsResource extends ApiRequestContext {
255256
@Path("{sessionHandle}/operations/tableTypes")
256257
def getTableTypes(@PathParam("sessionHandle") sessionHandleStr: String): OperationHandle = {
257258
try {
258-
backendService.getTableTypes(parseSessionHandle(sessionHandleStr))
259+
fe.be.getTableTypes(parseSessionHandle(sessionHandleStr))
259260
} catch {
260261
case NonFatal(_) =>
261262
throw new NotFoundException(s"Error getting table types")
@@ -273,7 +274,7 @@ private[v1] class SessionsResource extends ApiRequestContext {
273274
@PathParam("sessionHandle") sessionHandleStr: String,
274275
request: GetColumnsRequest): OperationHandle = {
275276
try {
276-
backendService.getColumns(
277+
fe.be.getColumns(
277278
parseSessionHandle(sessionHandleStr),
278279
request.catalogName,
279280
request.schemaName,
@@ -296,7 +297,7 @@ private[v1] class SessionsResource extends ApiRequestContext {
296297
@PathParam("sessionHandle") sessionHandleStr: String,
297298
request: GetFunctionsRequest): OperationHandle = {
298299
try {
299-
backendService.getFunctions(
300+
fe.be.getFunctions(
300301
parseSessionHandle(sessionHandleStr),
301302
request.catalogName,
302303
request.schemaName,
@@ -320,7 +321,7 @@ private[v1] class SessionsResource extends ApiRequestContext {
320321

321322
try {
322323
val operationHandle = parseOperationHandle(operationHandleStr)
323-
backendService.sessionManager.getSession(parseSessionHandle(sessionHandleStr))
324+
fe.be.sessionManager.getSession(parseSessionHandle(sessionHandleStr))
324325
.closeOperation(operationHandle)
325326
operationHandle
326327
} catch {

0 commit comments

Comments
 (0)