Skip to content

Commit

Permalink
finagle-thrift: Introduce ServiceClass.fqn that renders a Scrooge-gen…
Browse files Browse the repository at this point in the history
…erated Thrift class name

Problem

We want a utility to convert Scrooge-generated service stub into a human-readable form that's also FQN.

Solution

Add `ThriftUtil.extractServiceFqn`.

JIRA Issues: CSL-10941

Differential Revision: https://phabricator.twitter.biz/D676897
  • Loading branch information
vkostyukov authored and jenkins committed May 27, 2021
1 parent 68481f1 commit 3bd62f8
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 1 deletion.
35 changes: 34 additions & 1 deletion finagle-thrift/src/main/scala/com/twitter/finagle/Thrift.scala
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,40 @@ object Thrift
val default = PerEndpointStats(false)
}

final case class ServiceClass(clazz: Option[Class[_]])
// This is based on the generated stubs from Scrooge.
private val ScroogeGeneratedSuffixes = Seq(
"$ServiceIface",
"$FutureIface",
"$MethodPerEndpoint",
"$ServicePerEndpoint",
"$MethodIface",
"$MethodPerEndpoint$MethodPerEndpointImpl",
"$ReqRepServicePerEndpoint",
"$ReqRepMethodPerEndpoint$ReqRepMethodPerEndpointImpl"
)

private def stripSuffix(iface: Class[_]): Option[String] = {
val ifaceName = iface.getName
ScroogeGeneratedSuffixes.find(s => ifaceName.endsWith(s)).map(s => ifaceName.stripSuffix(s))
}

/**
* A `Param` that captures a class of a Scrooge-generated service stub that's associated
* with a given client or server.
*/
final case class ServiceClass(clazz: Option[Class[_]]) {

/**
* Extracts the Thrift IDL FQN from the Scrooge-generated service class in `clazz`. The main
* purpose of this method is to drop the Scrooge-specific suffix from the class name, leaving
* only domain-relevant name behind.
*/
val fullyQualifiedName: Option[String] = clazz.flatMap { c =>
val all = Seq(c) ++ c.getInterfaces.toSeq ++ Option(c.getSuperclass)
all.flatMap(stripSuffix).headOption
}
}

implicit object ServiceClass extends Stack.Param[ServiceClass] {
val default = ServiceClass(None)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.twitter.finagle.thrift

import com.twitter.finagle.Service
import com.twitter.finagle.Thrift.param.ServiceClass
import com.twitter.finagle.thrift.thriftscala.{Echo => ScalaEcho}
import com.twitter.finagle.thrift.thriftjava.{Echo => JavaEcho}
import com.twitter.finagle.thrift.thriftscala.Echo.Echo
import com.twitter.scrooge.{Request, Response}
import com.twitter.util.Future
import org.scalatest.funsuite.AnyFunSuite
import scala.reflect.{ClassTag, classTag}

object ServiceClassParamTest {
class EchoMPE extends ScalaEcho.MethodPerEndpoint {
override def echo(msg: String): Future[String] = ???
}

class EchoSPE extends ScalaEcho.ServicePerEndpoint {
override def echo: Service[Echo.Args, String] = ???
}

class EchoReqRepSPE extends ScalaEcho.ReqRepServicePerEndpoint {
override def echo: Service[Request[Echo.Args], Response[String]] = ???
}

class EchoFutureIface extends ScalaEcho.FutureIface {
override def echo(msg: String): Future[String] = ???
}

class EchoServiceIface extends JavaEcho.ServiceIface {
override def echo(msg: String): Future[String] = ???
}
}

class ServiceClassParamTest extends AnyFunSuite {
import ServiceClassParamTest._

private def fqn[A: ClassTag]: String = ServiceClass(
Some(classTag[A].runtimeClass)).fullyQualifiedName.get

test("extractServiceFqn for Scala clients") {
assert(fqn[ScalaEcho.MethodPerEndpoint] == "com.twitter.finagle.thrift.thriftscala.Echo")
assert(fqn[ScalaEcho.ServicePerEndpoint] == "com.twitter.finagle.thrift.thriftscala.Echo")
assert(fqn[ScalaEcho.ServiceIface] == "com.twitter.finagle.thrift.thriftscala.Echo")
}

test("extractServiceFqn for Java clients") {
assert(fqn[JavaEcho.ServiceIface] == "com.twitter.finagle.thrift.thriftjava.Echo")
}

test("extractServiceFqn for scala servers") {
assert(fqn[EchoMPE] == "com.twitter.finagle.thrift.thriftscala.Echo")
assert(fqn[EchoSPE] == "com.twitter.finagle.thrift.thriftscala.Echo")
assert(fqn[EchoReqRepSPE] == "com.twitter.finagle.thrift.thriftscala.Echo")
assert(fqn[EchoFutureIface] == "com.twitter.finagle.thrift.thriftscala.Echo")
}

test("extractServiceFqn for java servers") {
assert(fqn[EchoServiceIface] == "com.twitter.finagle.thrift.thriftjava.Echo")
}
}

0 comments on commit 3bd62f8

Please sign in to comment.