vert-x3 / vertx-lang-scala Goto Github PK
View Code? Open in Web Editor NEWVert.x for Scala
Home Page: http://vert-x3.github.io/vertx-lang-scala/
Vert.x for Scala
Home Page: http://vert-x3.github.io/vertx-lang-scala/
Julien told me that we should change 1.0.0-SNAPSHOT to 3.0.0-SNAPSHOT.
Since eclipse-vertx/vert.x#2106 is merge, build fails because Scala class has the keyword override
on method handle
but it does extend Handler
.
The template must be changed to implement Handler
via mixin when Vert.x core class extends a another API type and implements Handler
.
👋 Hello 🌍
This is my baby steps with Scala and Vert.x
I'm trying to create a microservice sample scala project "from scratch" with the Redis backend
(you can read the code here https://github.com/botsgarden/b.nlp/blob/master/src/main/scala/brain/BeeNlp.scala)
Almost all is ok:
I deploy the ScalaVerticle with a companion object:
object BeeNlp extends App {
val vertx = Vertx.vertx
// do some stuff, initialize discovery backend, etc...
vertx
.deployVerticleFuture(ScalaVerticle.nameForVerticle[brain.BeeNlp])
.onComplete {
case Success(verticleId) => println(s"Successfully deployed verticle: $verticleId")
case Failure(error) => println(s"Failed to deploy verticle: $error")
}
}
this is my verticle:
class BeeNlp extends ScalaVerticle {
override def startFuture(): Future[_] = {
val server = vertx.createHttpServer()
val router = Router.router(vertx)
val httpPort = sys.env.getOrElse("PORT", "8080").toInt
// publish the microservice record
BeeNlp.discovery.publishFuture(BeeNlp.record).onComplete{
case Success(result) => println(s"😃 publication OK")
case Failure(cause) => println(s"😡 publication KO: $cause")
}
router.route().handler(BodyHandler.create)
router.get("/hey").handler(context =>
context
.response
.putHeader("content-type", "application/json;charset=UTF-8")
.end(new JsonObject().put("message", "👋 hey!").encodePrettily)
)
router.route("/*").handler(StaticHandler.create)
println(s"🌍 Listening on $httpPort - Enjoy 😄")
server.requestHandler(router.accept _).listenFuture(httpPort)
}
I would like to unpublish the record verticle from the Redis backend when I quit.
With Java I do like that:
public void stop(Future<Void> stopFuture) {
System.out.println("Unregistration process is started ("+record.getRegistration()+")...");
discovery.unpublish(record.getRegistration(), asyncResult -> {
if(asyncResult.succeeded()) {
System.out.println("👋 bye bye " + record.getRegistration());
} else {
System.out.println("😡 Not able to unpublish the microservice: " + asyncResult.cause().getMessage());
//asyncResult.cause().printStackTrace();
}
stopFuture.complete();
});
}
and stop
method is triggered when I quit
but I can't do the same thing with Scala :
I try something like that with override def stopFuture(): Future[_] = {...}
but I can't trigger anything when the microservice exits (again: this is my baby steps 😉)
override def stopFuture(): Future[_] = {
var unpublishRecordFuture = BeeSlack.discovery.unpublishFuture(BeeSlack.record.getRegistration)
unpublishRecordFuture.onComplete {
case Success(result) => {
println(s"😃 removing publication OK")
Future.successful(())
}
case Failure(cause) => {
println(s"😡 removing publication KO: $cause")
Future.failed(new Throwable())
}
}
unpublishRecordFuture
}
It's probably easy, but I don't find a solution.
Does anybody know an example about this or has an idea?
Regards
Philippe
the build actually fails now in Vert.x Web:
[ERROR] /Users/julien/java/vertx-lang-scala/vertx-lang-scala-stack/vertx-web/src/main/scala/io/vertx/scala/ext/web/handler/BasicAuthHandler.scala:91: error: method parseCredentialsFuture overrides nothing
[ERROR] override def parseCredentialsFuture(context: RoutingContext): scala.concurrent.Future[io.vertx.core.json.JsonObject] = {
[ERROR] ^
[ERROR] /Users/julien/java/vertx-lang-scala/vertx-lang-scala-stack/vertx-web/src/main/scala/io/vertx/scala/ext/web/handler/BasicAuthHandler.scala:100: error: method authorizeFuture overrides nothing
[ERROR] override def authorizeFuture(user: User): scala.concurrent.Future[Unit] = {
[ERROR] ^
[ERROR] /Users/julien/java/vertx-lang-scala/vertx-lang-scala-stack/vertx-web/src/main/scala/io/vertx/scala/ext/web/handler/ChainAuthHandler.scala:115: error: method parseCredentialsFuture overrides nothing
[ERROR] override def parseCredentialsFuture(context: RoutingContext): scala.concurrent.Future[io.vertx.core.json.JsonObject] = {
[ERROR] ^
[ERROR] /Users/julien/java/vertx-lang-scala/vertx-lang-scala-stack/vertx-web/src/main/scala/io/vertx/scala/ext/web/handler/ChainAuthHandler.scala:124: error: method authorizeFuture overrides nothing
[ERROR] override def authorizeFuture(user: User): scala.concurrent.Future[Unit] = {
[ERROR] ^
[ERROR] /Users/julien/java/vertx-lang-scala/vertx-lang-scala-stack/vertx-web/src/main/scala/io/vertx/scala/ext/web/handler/DigestAuthHandler.scala:91: error: method parseCredentialsFuture overrides nothing
[ERROR] override def parseCredentialsFuture(context: RoutingContext): scala.concurrent.Future[io.vertx.core.json.JsonObject] = {
[ERROR] ^
[ERROR] /Users/julien/java/vertx-lang-scala/vertx-lang-scala-stack/vertx-web/src/main/scala/io/vertx/scala/ext/web/handler/DigestAuthHandler.scala:100: error: method authorizeFuture overrides nothing
[ERROR] override def authorizeFuture(user: User): scala.concurrent.Future[Unit] = {
[ERROR] ^
[ERROR] /Users/julien/java/vertx-lang-scala/vertx-lang-scala-stack/vertx-web/src/main/scala/io/vertx/scala/ext/web/handler/JWTAuthHandler.scala:121: error: method parseCredentialsFuture overrides nothing
[ERROR] override def parseCredentialsFuture(context: RoutingContext): scala.concurrent.Future[io.vertx.core.json.JsonObject] = {
[ERROR] ^
[ERROR] /Users/julien/java/vertx-lang-scala/vertx-lang-scala-stack/vertx-web/src/main/scala/io/vertx/scala/ext/web/handler/JWTAuthHandler.scala:130: error: method authorizeFuture overrides nothing
[ERROR] override def authorizeFuture(user: User): scala.concurrent.Future[Unit] = {
[ERROR] ^
[ERROR] /Users/julien/java/vertx-lang-scala/vertx-lang-scala-stack/vertx-web/src/main/scala/io/vertx/scala/ext/web/handler/OAuth2AuthHandler.scala:113: error: method parseCredentialsFuture overrides nothing
[ERROR] override def parseCredentialsFuture(context: RoutingContext): scala.concurrent.Future[io.vertx.core.json.JsonObject] = {
[ERROR] ^
[ERROR] /Users/julien/java/vertx-lang-scala/vertx-lang-scala-stack/vertx-web/src/main/scala/io/vertx/scala/ext/web/handler/OAuth2AuthHandler.scala:122: error: method authorizeFuture overrides nothing
[ERROR] override def authorizeFuture(user: User): scala.concurrent.Future[Unit] = {
[ERROR] ^
[ERROR] /Users/julien/java/vertx-lang-scala/vertx-lang-scala-stack/vertx-web/src/main/scala/io/vertx/scala/ext/web/handler/RedirectAuthHandler.scala:91: error: method parseCredentialsFuture overrides nothing
[ERROR] override def parseCredentialsFuture(context: RoutingContext): scala.concurrent.Future[io.vertx.core.json.JsonObject] = {
[ERROR] ^
[ERROR] /Users/julien/java/vertx-lang-scala/vertx-lang-scala-stack/vertx-web/src/main/scala/io/vertx/scala/ext/web/handler/RedirectAuthHandler.scala:100: error: method authorizeFuture overrides nothing
[ERROR] override def authorizeFuture(user: User): scala.concurrent.Future[Unit] = {
[ERROR] ^
[WARNING] 202 warnings found
[ERROR] 12 errors found
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] vertx-lang-scala-stack_2.12 ........................ SUCCESS [ 0.612 s]
[INFO] vertx-mqtt-scala_2.12 .............................. SUCCESS [ 17.580 s]
[INFO] vertx-sql-common-scala_2.12 ........................ SUCCESS [ 11.549 s]
[INFO] vertx-bridge-common-scala_2.12 ..................... SUCCESS [ 7.869 s]
[INFO] vertx-jdbc-client-scala_2.12 ....................... SUCCESS [ 7.479 s]
[INFO] vertx-mongo-client-scala_2.12 ...................... SUCCESS [ 14.757 s]
[INFO] vertx-mongo-service-scala_2.12 ..................... SUCCESS [ 12.189 s]
[INFO] vertx-auth-common-scala_2.12 ....................... SUCCESS [ 10.030 s]
[INFO] vertx-auth-shiro-scala_2.12 ........................ SUCCESS [ 7.981 s]
[INFO] vertx-auth-htdigest-scala_2.12 ..................... SUCCESS [ 6.649 s]
[INFO] vertx-auth-oauth2-scala_2.12 ....................... SUCCESS [ 13.453 s]
[INFO] vertx-auth-mongo-scala_2.12 ........................ SUCCESS [ 10.349 s]
[INFO] vertx-auth-jwt-scala_2.12 .......................... SUCCESS [ 9.262 s]
[INFO] vertx-auth-jdbc-scala_2.12 ......................... SUCCESS [ 8.963 s]
[INFO] vertx-web-scala_2.12 ............................... FAILURE [ 7.546 s]
[INFO] vertx-web-common-scala_2.12 ........................ SKIPPED
[INFO] vertx-web-client-scala_2.12 ........................ SKIPPED
[INFO] vertx-sockjs-service-proxy-scala_2.12 .............. SKIPPED
[INFO] vertx-web-templ-freemarker-scala_2.12 .............. SKIPPED
[INFO] vertx-web-templ-handlebars-scala_2.12 .............. SKIPPED
[INFO] vertx-web-templ-jade-scala_2.12 .................... SKIPPED
[INFO] vertx-web-templ-mvel-scala_2.12 .................... SKIPPED
[INFO] vertx-web-templ-pebble-scala_2.12 .................. SKIPPED
[INFO] vertx-web-templ-thymeleaf-scala_2.12 ............... SKIPPED
[INFO] vertx-mysql-postgresql-client-scala_2.12 ........... SKIPPED
[INFO] vertx-mail-client-scala_2.12 ....................... SKIPPED
[INFO] vertx-rabbitmq-client-scala_2.12 ................... SKIPPED
[INFO] vertx-redis-client-scala_2.12 ...................... SKIPPED
[INFO] vertx-stomp-scala_2.12 ............................. SKIPPED
[INFO] vertx-tcp-eventbus-bridge-scala_2.12 ............... SKIPPED
[INFO] vertx-amqp-bridge-scala_2.12 ....................... SKIPPED
[INFO] vertx-shell-scala_2.12 ............................. SKIPPED
[INFO] vertx-dropwizard-metrics-scala_2.12 ................ SKIPPED
[INFO] vertx-hawkular-metrics-scala_2.12 .................. SKIPPED
[INFO] vertx-kafka-client-scala_2.12 ...................... SKIPPED
[INFO] vertx-circuit-breaker-scala_2.12 ................... SKIPPED
[INFO] vertx-config-scala_2.12 ............................ SKIPPED
[INFO] vertx-config-git-scala_2.12 ........................ SKIPPED
[INFO] vertx-config-hocon-scala_2.12 ...................... SKIPPED
[INFO] vertx-config-kubernetes-configmap-scala_2.12 ....... SKIPPED
[INFO] vertx-config-redis-scala_2.12 ...................... SKIPPED
[INFO] vertx-config-spring-config-server-scala_2.12 ....... SKIPPED
[INFO] vertx-config-yaml-scala_2.12 ....................... SKIPPED
[INFO] vertx-config-zookeeper-scala_2.12 .................. SKIPPED
[INFO] vertx-config-parent-scala_2.12 ..................... SKIPPED
[INFO] vertx-service-discovery-scala_2.12 ................. SKIPPED
[INFO] vertx-service-discovery-backend-redis-scala_2.12 ... SKIPPED
[INFO] vertx-service-discovery-backend-zookeeper-scala_2.12 SKIPPED
[INFO] vertx-service-discovery-bridge-consul-scala_2.12 ... SKIPPED
[INFO] vertx-service-discovery-bridge-docker-links-scala_2.12 SKIPPED
[INFO] vertx-service-discovery-bridge-zookeeper-scala_2.12 SKIPPED
[INFO] vertx-service-discovery-bridge-docker-scala_2.12 ... SKIPPED
[INFO] vertx-service-discovery-bridge-kubernetes-scala_2.12 SKIPPED
[INFO] vertx-service-discovery-parent-scala_2.12 .......... SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 02:27 min
[INFO] Finished at: 2017-07-24T21:51:57+02:00
[INFO] Final Memory: 177M/1901M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal net.alchim31.maven:scala-maven-plugin:3.2.2:compile (scala-compile) on project vertx-web-scala_2.12: wrap: org.apache.commons.exec.ExecuteException: Process exited with an error: 1 (Exit value: 1) -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
[ERROR]
[ERROR] After correcting the problems, you can resume the build with the command
[ERROR] mvn <goals> -rf :vertx-web-scala_2.12
When we use a circuit breaker with web-client we have this exception:
15:49:40.631 [vert.x-eventloop-thread-6] 83171574-ac36-4212-abc9-f51656734a2a ERROR io.vertx.core.impl.ContextImpl - Unhandled exception
java.lang.NoSuchMethodException: io.vertx.scala.ext.web.client.HttpResponse$.apply(io.vertx.ext.web.client.HttpResponse)
at java.lang.Class.getMethod(Class.java:1786)
at io.vertx.lang.scala.Converter$.toScala(Converter.scala:31)
at io.vertx.scala.core.Future.$anonfun$setHandler$2(Future.scala:57)
at io.vertx.lang.scala.AsyncResultWrapper.result$lzycompute(AsyncResultWrapper.scala:26)
at io.vertx.lang.scala.AsyncResultWrapper.result(AsyncResultWrapper.scala:26)
at com.norauto.api.external.organizationalunit.OUClient.$anonfun$vertxFutureToScalaFuture$1(OUClient.scala:77)
at io.vertx.scala.core.Future.$anonfun$setHandler$1(Future.scala:57)
at io.vertx.core.impl.FutureImpl.tryComplete(FutureImpl.java:125)
at io.vertx.core.impl.FutureImpl.complete(FutureImpl.java:86)
at io.vertx.circuitbreaker.impl.CircuitBreakerImpl.lambda$null$3(CircuitBreakerImpl.java:220)
at io.vertx.core.impl.ContextImpl.lambda$wrapTask$2(ContextImpl.java:339)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute$$$capture(AbstractEventExecutor.java:163)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:463)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:886)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
The code is the following:
breaker.executeCommandFuture[HttpResponse[Buffer]](future => {
performSomeHttpRequest() onComplete {
case Success(httpResult) => future.complete(httpResult)
case Failure(error) => future.fail(error)
}
})
To fix that, we have encapsulated the HttpResource
on a custom class Wrapper
.
It seem that this failure occurs because HttpResponse.apply
need an implicit type scala.reflect.runtime.universe.TypeTag
, and the method toScala
doesn't support that.
Scala 2.12.2 is out and we should update to that version.
Updates for Scala 2.12 break module dependencies, resolved with conflicting cross-version suffixes.
[error] Modules were resolved with conflicting cross-version suffixes in {file:/Users/vertx-microservices-workshop-scala/}common:
[error] io.vertx:vertx-sql-common _2.12, <none>
[error] io.vertx:vertx-jdbc-client _2.12, <none>
[error] io.vertx:vertx-redis-client _2.12, <none>
[error] io.vertx:vertx-web _2.12, <none>
[error] io.vertx:vertx-service-discovery _2.12, <none>
It looks like sbt couldn't differentiate Scala library with _2.12 suffix and Java library without _2.12 suffix.
In other words, domain objects should extend AnyVal
. Scala value objects have no runtime cost (for example, no boxing or unboxing) when used as is currently done in vertx-lang-scala
.
io.vertx.scala.ext.web.handler.BodyHandler
is an example. This type should be implemented as a case class with a public property, and the property should probably be of type io.vertx.ext.web.handler.BodyHandler
:
package io.vertx.scala.ext.web.handler
import io.vertx.ext.web.handler.{BodyHandler => JBodyHandler}
case class BodyHandler(value: JBodyHandler) extends AnyVal {
override def toString: String = value
}
This would simplify other library and application code, and would be more idiomatic Scala. There would be no need for an asJava
method, and the implementation could dispense with all the occurances of asInstanceOf[JBodyHandler]
, which unfortunately the current implementation also forces on application code.
In fact, all of the casts in this method should be eliminated, and this can be done easily. As written, the library code overrides type safety, and this is both undesirable and unnecessary.
This pattern can be found in other areas of the same library, for example JDBCClient.create
. Currently one must write:
JDBCClient(JJDBCClient.create(vertx.asJava.asInstanceOf[io.vertx.core.Vertx], dataSource))
instead of the typesafe and succinct expression:
JDBCClient(vertx, dataSource)
In vert-x3/vertx-web@961c2ce bridge classes have been deprecated and updated to extend the web-common
classes.
This breaks the lang-scala
build.
I have included the following dependencies in my project.
"io.vertx" %% "vertx-service-discovery-scala" % Version.Vertx withSources(),
"io.vertx" % "vertx-service-discovery-backend-consul" % Version.Vertx withSources()
Created setBackendConfiguration
with host => localhost, port => 8500, dc => dc1. On publishing records, PUT request is sent into Consul.
http: Request PUT /v1/agent/service/register (166.747µs)
No data is sent to it. Getting bad request because of this.
@codepitbull, Thanks for dropping the email.
Could not resolve dependencies for project io.vertx:vertx-lang-scala:jar:3.0.0-SNAPSHOT: The following artifacts could not be resolved: io.vertx:vertx-codegen:jar:sources:3.0.0-SNAPSHOT,
The current scala compilation emits lot of unused imports during the build. Such warnings are not really useful and they produce lot of verbosity, raising issues with Travis CI.
Running io.vertx.lang.scala.tck.ApiTest
Tests run: 59, Failures: 0, Errors: 2, Skipped: 0, Time elapsed: 0.121 sec <<< FAILURE! - in io.vertx.lang.scala.tck.ApiTest
testNullJsonParams should work(io.vertx.lang.scala.tck.ApiTest) Time elapsed: 0.01 sec <<< ERROR!
java.lang.NullPointerException: null
at io.vertx.scala.codegen.testmodel.TestInterface.methodWithNullJsonParams(TestInterface.scala:411)
at io.vertx.lang.scala.tck.ApiTest.$anonfun$new$158(ApiTest.scala:650)
testNullJsonHandlerAsyncResultParams should work(io.vertx.lang.scala.tck.ApiTest) Time elapsed: 0.016 sec <<< ERROR!
org.scalatest.exceptions.TestFailedException: null did not equal None
at org.scalatest.Assertions.newAssertionFailedException(Assertions.scala:528)
at org.scalatest.Assertions.newAssertionFailedException$(Assertions.scala:527)
at org.scalatest.FlatSpec.newAssertionFailedException(FlatSpec.scala:1685)
at org.scalatest.Assertions$AssertionsHelper.macroAssert(Assertions.scala:501)
at io.vertx.lang.scala.tck.ApiTest.$anonfun$new$174(ApiTest.scala:698)
A basic fat-jar created using the g8-template has a size of 27 MB.
We should check how this size can be reduced.
There's Web Framework Benchmarks at techempower.com
:
https://www.techempower.com/benchmarks/#section=data-r16
https://news.ycombinator.com/item?id=17254152
and Vert.x is super fast :- )
What about constructing and submitting benchmarks for Vert.x + Scala? I think it'd be really interesting to see how fast Scala is currently, and ... maybe if it's slower than Java, that indicates there's lots of room for improvement?
https://groups.google.com/forum/#!topic/framework-benchmarks/6JwoofFRrOU
(I'm thinking someone will suggest that I do this myself. That's a good idea ... and I work to long weeks already, and feel I'm a bit short of time. Otherwise yes it'd been interesting to do that :- ) now I'm just hoping that someone else will think this would be an interesting thing to do, & do all the work)
Maybe if Vert.x + Scala turns out to be 10 x faster than Play Framework 2 + Scala — that's something that can make people even more interested in Vert.x (?).
Hi,
I found out downloading vertx-lang-scala fails. Not sure from when it started to happen. :(
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: FAILED DOWNLOADS ::
[warn] :: ^ see resolution messages for details ^ ::
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: io.vertx#vertx-lang-scala_2.12;3.4.0-SNAPSHOT!vertx-lang-scala_2.12.jar(src)
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[trace] Stack trace suppressed: run last common/*:update for the full output.
[error] (common/*:update) sbt.ResolveException: download failed: io.vertx#vertx-lang-scala_2.12;3.4.0-SNAPSHOT!vertx-lang-scala_2.12.jar(src)
Getting the below error on using sbt assembly.
java.lang.RuntimeException: deduplicate: different file contents found in the following
.ivy2/cache/io.vertx/vertx-service-discovery-scala_2.12/jars/vertx-service-discovery-scala_2.12-3.5.1.jar:vertx-service-discovery-js/service_importer.js
.ivy2/cache/io.vertx/vertx-service-discovery/jars/vertx-service-discovery-3.5.1.jar:vertx-service-discovery-js/service_importer.js
My verticle:
class HttpVerticle extends ScalaVerticle {
val logger = Logger.getLogger(this.getClass.getSimpleName)
override def startFuture(): Future[_] = {
val router = Router.router(vertx)
val sockJSHandler = SockJSHandler.create(vertx).bridge(
BridgeOptions()
.setInboundPermitted(mutable.Buffer(PermittedOptions().setAddress("testAddress")))
.setOutboundPermitted(mutable.Buffer(PermittedOptions().setAddress("testAddress")))
)
router.route("/eventbus/*").handler(sockJSHandler)
vertx
.createHttpServer()
.requestHandler(router.accept _)
.listenFuture(8666, "0.0.0.0")
}
}
In html head:
<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vertx/3.5.1/vertx-eventbus.min.js"></script>
My js script:
<script>
var eb=new EventBus("http://****/eventbus")
eb.onopen=function () {
console.log("eventbus opened~~~")
// send(address,body,header,handler)
eb.send("testAddress",{document:"some_doc"},{action:"dont move"},function (reply) {
console.log(reply);
})
}
</script>
Eventbus was succesfully opened. eb.send will cause exception on backend:
java.lang.ClassCastException: scala.collection.immutable.Map$Map1 cannot be cast to io.vertx.core.json.JsonObject
at io.vertx.core.json.JsonObject.getJsonObject(JsonObject.java:216)
at io.vertx.ext.web.handler.sockjs.impl.EventBusBridgeImpl.doSendOrPub(EventBusBridgeImpl.java:374)
at io.vertx.ext.web.handler.sockjs.impl.EventBusBridgeImpl.lambda$internalHandleSendOrPub$5(EventBusBridgeImpl.java:194)
at io.vertx.ext.web.handler.sockjs.impl.EventBusBridgeImpl.checkCallHook(EventBusBridgeImpl.java:159)
at io.vertx.ext.web.handler.sockjs.impl.EventBusBridgeImpl.internalHandleSendOrPub(EventBusBridgeImpl.java:187)
at io.vertx.ext.web.handler.sockjs.impl.EventBusBridgeImpl.handleSocketData(EventBusBridgeImpl.java:137)
at io.vertx.ext.web.handler.sockjs.impl.EventBusBridgeImpl.lambda$null$18(EventBusBridgeImpl.java:314)
at io.vertx.ext.web.handler.sockjs.impl.SockJSSession.handleMessages(SockJSSession.java:372)
at io.vertx.ext.web.handler.sockjs.impl.WebSocketTransport$WebSocketListener.handleMessages(WebSocketTransport.java:113)
at io.vertx.core.http.impl.WebSocketImplBase$FrameAggregator.handleTextFrame(WebSocketImplBase.java:334)
at io.vertx.core.http.impl.WebSocketImplBase$FrameAggregator.handle(WebSocketImplBase.java:300)
at io.vertx.core.http.impl.WebSocketImplBase$FrameAggregator.handle(WebSocketImplBase.java:289)
at io.vertx.core.http.impl.WebSocketImplBase.handleFrame(WebSocketImplBase.java:282)
at io.vertx.core.http.impl.Http1xServerConnection.handleOther(Http1xServerConnection.java:474)
at io.vertx.core.http.impl.Http1xServerConnection.processMessage(Http1xServerConnection.java:439)
at io.vertx.core.http.impl.Http1xServerConnection.handleMessage(Http1xServerConnection.java:141)
at io.vertx.core.http.impl.HttpServerImpl$ServerHandlerWithWebSockets.handleMessage(HttpServerImpl.java:693)
at io.vertx.core.http.impl.HttpServerImpl$ServerHandlerWithWebSockets.handleMessage(HttpServerImpl.java:636)
at io.vertx.core.net.impl.VertxHandler.lambda$channelRead$1(VertxHandler.java:146)
at io.vertx.core.impl.ContextImpl.lambda$wrapTask$2(ContextImpl.java:337)
at io.vertx.core.impl.ContextImpl.executeFromIO(ContextImpl.java:195)
at io.vertx.core.net.impl.VertxHandler.channelRead(VertxHandler.java:144)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:310)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:284)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1359)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:935)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:141)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:645)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:580)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:497)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:459)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:886)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
Methods with kind=HANDLER (see codegen readme) should be transformed into curried functions. Examples:
// java
AsyncFile handler(Handler<Buffer> handler);
// scala
def handler(handler: Buffer => Unit): AsyncFile
// java
AsyncFile endHandler(Handler<Void> endHandler);
// scala
def endHandler(handler: => Unit): AsyncFile
// java
HttpClientRequest request(HttpMethod method, String absoluteURI,
Handler<HttpClientResponse> responseHandler);
// scala
def request(method: HttpMethod, absoluteURI: String)
(responseHandler: HttpClientResponse => Unit): HttpClientRequest
Hi galder, the new slick version includes a thread pool allowing do async request, really cool, the problem is than this approach collide with vertx architecture, http://slick.typesafe.com/doc/3.0.0-M1/database.html#using-typesafe-config , I know than you did some researchs about how run futures inside vertx and I think than would be possible a similar approach with slick because it also has an AsyncContext, but sincerally I don't know much about these concepts..
do you think than is possible/simple use this new slick feature inside vertx??...thanks!!.....
vertx doesn't have executeBlockingFuture.
Reference Document: http://vertx.io/docs/vertx-core/scala/
vertx.executeBlockingFuture((future: io.vertx.scala.core.Future<java.lang.Object>) => {
// Call some blocking API that takes a significant amount of time to return
var result = someAPI.blockingMethod("hello")
future.complete(result)
}).onComplete{
case Success(result) => println("Success")
case Failure(cause) => println("Failure")
}
It looks like there's a mismatch between Route.handler interface and documentation.
According to the vertx-web-scala document, for example, StaticHandler could be used like this:
import io.vertx.scala.ext.web.Router
import io.vertx.scala.ext.web.handler.StaticHandler
router.route("/static/*").handler(StaticHandler.create())
However, StaticHandler.create()
returns StaticHandler
object, which Route.handler()
signature doesn't allow to pass.
def handler(requestHandler : scala.Function1[io.vertx.scala.ext.web.RoutingContext, scala.Unit])
: io.vertx.scala.ext.web.Route
So I had to do Java conversion, then use Java StaticHandler.
import io.vertx.scala.ext.web.Router
import io.vertx.ext.web.handler.StaticHandler
router.route("/*").asJava.handler(StaticHandler.create())
Methods with kind=FUTURE (see codegen readme) should be remove Handler<AsyncResult<T>>
as parameter, and instead return a Scala Future[T]
. Examples:
// java
HttpServer listen(Handler<AsyncResult<HttpServer>> listenHandler);
// scala
def listen(): Future[HttpServer]
As a result of this, methods like this:
// java
HttpServer listen();
will have no equivalent in the Scala language extension, because a blocking version of the method can easily be achieved by calling scala.concurrent.Await.ready()
for void-returning Futures, or scala.concurrent.Await.result()
for non-void-returning Futures. This promotes the use of non-blocking APIs in favour of blocking ones.
If a method has multiple Handler<AsyncResult<T>>
instances, the Scala version will return a tuple of Futures, e.g.
void multiResult(Handler<AsyncResult<A>> handlerA, Handler<AsyncResult<B>> handlerB);
def multiResult(): (Future[A], Future[B])
There's no such example in the Java API at the moment, but if there was, one could make the point that such method is not following the single-responsibility principle, and hence it should be split up.
MVEL is broken for Java 10 onwards so we have to port the code-generation part.
I'm running the following code, I only included the relevant code:
import io.vertx.core.buffer.Buffer
import io.vertx.lang.scala.ScalaVerticle
import io.vertx.lang.scala.json.JsonObject
import io.vertx.scala.core.eventbus.{DeliveryOptions, Message}
import scala.concurrent.Future
import scala.util.{Failure, Success}
class HttpEndpointVerticle extends ScalaVerticle{
override def startFuture(): Future[Unit] = {
// address is a string
// params is a JsonObject
// sOpt is a DeliveryOptions
val eb = vertx.eventBus
eb.sendFuture[Message[Buffer]](address, params, dOpt).onComplete{
case Success(result) => {
val r = result.body().body()
val response = routingContext.response
response.putHeader("content-type", "application/json")
response.end(r)
}
case Failure(cause) => {
routingContext.response().setStatusCode(404).end(cause.getMessage())
}
}
}
}
and I get the following error:
Failed executing on contet
java.lang.NoSuchMethodException: io.vertx.scala.core.eventbus.Message$.apply(io.vertx.core.buffer.Buffer)
at java.lang.Class.getMethod(Class.java:1786)
at io.vertx.lang.scala.Converter$.toScala(Converter.scala:27)
at io.vertx.scala.core.eventbus.Message.body(Message.scala:52)
at com.anubor.dingo.vertx.scala.api.rest.HttpEndpointVerticle.$anonfun$startFuture$3(HttpEndpointVerticle.scala:56)
at com.anubor.dingo.vertx.scala.api.rest.HttpEndpointVerticle.$anonfun$startFuture$3$adapted(HttpEndpointVerticle.scala:54)
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:60)
at io.vertx.lang.scala.VertxExecutionContext.$anonfun$execute$1(VertxExecutionContext.scala:36)
at io.vertx.scala.core.Context.$anonfun$runOnContext$1(Context.scala:84)
at io.vertx.core.impl.ContextImpl.lambda$wrapTask$2(ContextImpl.java:337)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:403)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:445)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858)
at java.lang.Thread.run(Thread.java:748)
I can tell that the message gets sent and the verticle that replies produces a reply without errors.
Thanks in advance for looking into my issue.
The docs show examples of how to generate keystore files. Running the suggested keytool
commands yields the following warning:
$ keytool -genseckey -keystore keystore.jceks -storetype jceks -storepass secret \
-keyalg HMacSHA256 -keysize 2048 -alias HS256 -keypass secret
Warning:
The JCEKS keystore uses a proprietary format.
It is recommended to migrate to PKCS12 which is an industry standard format using
"keytool -importkeystore -srckeystore keystore.jceks -destkeystore keystore.jceks -deststoretype pkcs12".
Seems that modifying the examples to follow the advice in the warning would be a good idea. This would also require modifying the JWT Authorization code example so references to JCEKS are updated to PKCS12.
BTW, JDK 9 uses PKCS12 by default, and Oracle recommends using openssl instead of keytool.
Do you plan on providing an rxscala toolkit for vertx applications? If so, would you want some assistance?
In Vert.x 4 the current Logger
API is deprecated.
ScalaVerticle.startFuture/stopFuture currently return Future[Unit] that in many cases forces users to do an awkward conversion.
override def startFuture(): Future[Unit] = {
Future.sequence(Seq(
vertx.eventBus().consumer[String]("asd").handler(a => println(a)).completionFuture(),
vertx.eventBus().consumer[String]("asd2").handler(a => println(a)).completionFuture())
).map(_ => ())
}
By switching to Future[_] we can do
override def startFuture(): Future[Unit] = {
Future.sequence(Seq(
vertx.eventBus().consumer[String]("asd").handler(a => println(a)).completionFuture(),
vertx.eventBus().consumer[String]("asd2").handler(a => println(a)).completionFuture())
)
}
vertx-web instruction says that for blocking operation we need to use blockingHandler (to avoid blocking the main event loop). Does this requirement apply on Future ? For example, is the code below still considered blocking ?
router.get("/a").handler(ctx => {
val f = for {
f1 <- ...
f2 <- ...
} yield f2
f onComplete {
case Success(b) => ctx.response.end("ok")
case Failure(e) => ctx.response.end("not ok")
}
})
The MongoService lacks several @nullable annotations which breaks the vertx-lang-scala build (params including @nullable will be wrappend in scala.Options, those without won't).
I wanted to provide a PR but can't seem to fix it.
Here an example:
Method in MongoService:
MongoService saveWithOptions(String collection, JsonObject document, WriteOption writeOption, Handler<AsyncResult<String>> resultHandler);
Overridden method in MongoClient:
MongoClient saveWithOptions(String collection, JsonObject document, @Nullable WriteOption writeOption, Handler<AsyncResult<String>> resultHandler);
I updated the method in MongoService to include the missing annotation:
MongoService saveWithOptions(String collection, JsonObject document, @Nullable WriteOption writeOption, Handler<AsyncResult<String>> resultHandler);
Building the project then results in:
[ERROR] diagnostic: /Users/jochenmader/Development/8_vertx/vertx-mongo-client/vertx-mongo-service/src/main/java/io/vertx/ext/mongo/MongoService.java:39: error: Could not generate model for writeOption: Nullable type cannot override non nullable
MongoService saveWithOptions(String collection, JsonObject document, @Nullable WriteOption writeOption, Handler<AsyncResult<String>> resultHandler);
Any idea on how to solve this?
I read official doc about vertx-hazelcast in which code written by java.
I found io.vertx.scala.core.VertxOptions not having setClusterManager function
env:
Scala = "2.12.1"
ScalaTest = "3.0.1"
Vertx = "3.5.0"
vertx_lang_scala
vertx_hazelcast
I think vertx-hazelcast official doc should be more detailed.
The switch to Java 9 highlighted the need for a smoketest-project.
It should include several vertx-scala-modules and validate their functionality so we can see issues around modularity and dependencies.
I expect, that future result, computated on global context will be called on event loop, as I clearly specify executionContext
in onSucsess
. But it calls on my computation context.
class HttpVerticle extends ScalaVerticle {
override def startFuture(): Future[Unit] = {
//Create a router to answer GET-requests to "/hello" with "world"
val router = Router.router(vertx)
val route = router
.get("/hello")
.handler((ctx: RoutingContext) => {
Future {
Thread.sleep(1000)
"computed"
}(ExecutionContext.global)
.onSuccess {
//here calls on global context
case s => println(Thread.currentThread().getName); ctx.response().end(s)
}(executionContext)
})
vertx
.createHttpServer()
.requestHandler(router.accept)
.listenFuture(8666, "0.0.0.0")
.map(_ => ())
}
}
Perhaps, it because
https://github.com/vert-x3/vertx-lang-scala/blob/master/vertx-lang-scala/src/main/scala/io/vertx/lang/scala/VertxExecutionContext.scala#L35
don't calls on vertx context?
Looks like they finally fixed the issue I reported a while back (https://issues.scala-lang.org/browse/SI-9853)
To simplify the build we should get rid of the current two-step process of first building Java and then Scala.
registerCodec is marked @GenIgnore and therefore not generated for the Scala-API.
It should still be visible as registering a codec is a pretty common thing.
When making a request with the web client like this:
WebClient.create(vertx)
.getAbs("https://...")
.sendFuture()
.recoverWith { ??? } // retry logic
If the server resets the connection, vertx logs the error:
ERROR i.vertx.core.net.impl.ConnectionBase - java.io.IOException: Connection reset by peer
Because I'm handling the error with retries, the error log is a bit misleading.
I found the actual log on ConnectionBase:
protected synchronized void handleException(Throwable t) {
metrics().exceptionOccurred(metric(), remoteAddress(), t);
if (exceptionHandler != null) {
exceptionHandler.handle(t);
} else {
log.error(t);
}
}
I don't know if this is related to vertx-lang-scala (may be the initialization order of handlers) or if it is something with vertx-web in java.
Thank you
Left a TODO item in scala-methods.templ:
/TODO: some methods lack necessary type infos for scala/
Currently addInterceptor removeInterceptor both use a Handler. SendContext takes a type param which is left out in the Java-version.
I need a nice way for dealing with that.
Hi,
When I do
val aJson = new JsonObject("{\"key\": [\"value\"]}")
aJson.copy()
I have this error (only in version 3.5.1). Need to deploy before at least a verticle (JsonInit is call in VerticleExecutionContext)
java.lang.IllegalStateException: Illegal type in JsonObject: class scala.collection.immutable.$colon$colon
at io.vertx.core.json.Json.checkAndCopy(Json.java:210)
at io.vertx.core.json.JsonObject.copy(JsonObject.java:796)
at io.vertx.core.impl.DeploymentManager.doDeploy(DeploymentManager.java:461)
at io.vertx.core.impl.DeploymentManager.lambda$doDeployVerticle$2(DeploymentManager.java:203)
at io.vertx.core.impl.FutureImpl.setHandler(FutureImpl.java:76)
at io.vertx.core.impl.DeploymentManager.doDeployVerticle(DeploymentManager.java:171)
at io.vertx.core.impl.DeploymentManager.doDeployVerticle(DeploymentManager.java:143)
at io.vertx.core.impl.DeploymentManager.deployVerticle(DeploymentManager.java:131)
at io.vertx.core.impl.VertxImpl.deployVerticle(VertxImpl.java:665)
at io.vertx.scala.core.Vertx.deployVerticleFuture(Vertx.scala:566)
It's due to we register now with io.vertx.lang.scala.JsonInit the scala module in ObjectMapper. So now array is sequence and not an java.util.ArrayList.
I have found a workaround
import scala.collection.JavaConverters._
val newJson = Json.obj(aJson.getMap.asScala.toSeq: _*)
newJson.copy()
But I think It's a regression because there is lots of code in Java which produce JsonObject from String perhaps need to override and extends JsonObject with a scala object (or implicit conversion).
With version 3.5.0 there is no problem:
This works
val aJson = new JsonObject("{\"key\": [\"value\"]}")
aJson.copy()
We need a way to resolve the Scala-stack:
https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!msg/vertx/13MJz1Ak_T4/i2ZsjfCBBQAJ
When deploying non-compiled scala verticles, the factory should compile them. This would improve the usage of Scala verticle when using the vertx
CLI:
For instance:
vertx run MyVerticle.scala --redeploy="*.scala"
Hi @codepitbull and thanks for all your amazing work on vertx-lang-scala.
Something I've been looking for years with Vert.x is :
RoutingContext
like context.getParam("test")
should be an Integer if I checked for it beforeAt the end of the day, I think Java won't allow such features. I tried a few implementations that mostly use reflection (thus no compile-time checking). I was looking for another way to do so.
I found the akka-http very interesting, and am pretty sure we could be able to build such a thing with Vert.x.
It extensively uses the magnet pattern (which is also very very interesting).
I wanted to see if you were interested in helping me building such a "DSL" kindof. That'd allow Vert.x scala users to work in a very very type safe environment, reducing the need to check parameters at runtime and returning errors manually, and also generating accurate documentation.
Let me know if you have some questions ! Thanks.
##scalaVersion = "2.12.4"
##VertxVersion = "3.5.1"
when contains blocking code:
io.vertx.scala.core.vertx.executeBlocking(()=>{
println("blocking start")
some.blockApi() -- the blocking operation will not be performed.
println("blocking stop") -- not performed
}).onComplete{ -- future will not complete
case Success(result)=>println("complete")
case Failure(cause)=>cause.printStackTrace()
}
when blocking code removed, every thing fine
io.vertx.scala.core.vertx.executeBlocking(()=>{
println("blocking start")
//some.blockApi() -- blocking code removed
println("blocking stop") -- normally printed
}).onComplete{ -- future completed
case Success(result)=>println("complete")
case Failure(cause)=>cause.printStackTrace()
}
I notice that in some cases Futures from scala.concurrent.Future
and io.vertx.scala.Future
have been confused with each other.
One example is MessageConsumer (used primarily by Handler) and Verticle's startFuture (addressed by #43 ) which both return scala.concurrent.Future
whereas CompositeFuture takes in io.vertx.scala.Future
. As such CompositeFeature cannot be used to group and asynchronously run Futures from verticle deployment.
Many Scala users will have prior experience with Twirl, and those with existing Twirl templates would be glad to know that those templates could be used on Vert.x with little or no changes.
Would be nice to extend Vertx#deployVerticle
passing directly an instance of ScalaVerticle
as is possible in the Java version. This would allow, for example, to do DI of already instantiated services passing them into the constructor of the new deployed verticle.
Is this possible or am I asking for something that breaks Vert.x philosophy?
btw, thanks @codepitbull for the great porting!
Hi,
It seems we can't add a codec from Vert.x Scala API. We need to retrieve Vert.x Java API in order to add a codec.
I saw the issue #60 is closed but it seems it doesn't do it.
My version 3.5.3
It would be very nice to deserialize JSON directly to a case class.
To achieve that we need to update Jackson to 2.8.7 and add the following dependency to vetx-lang-scala:
"com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.8.7"
We could then do the following:
Json.mapper.registerModule(com.fasterxml.jackson.module.scala.DefaultScalaModule)
case class TestIt(name: String, value: Option[Int])
val src = "{\"name\":\"hallo\"}"
val result:TestIt = Json.decodeValue[TestIt](src, classOf[TestIt])
I use zookeeper. (version:3.4.8-1)
make a class Users extends AbstractUser
router.route.handler(CookieHandler.create())
router.route.handler(BodyHandler.create())
router.route.handler(SessionHandler.create(ClusteredSessionStore.create(vertx)).setNagHttps(false))
there isn't exception, after i login .
but when i get user from session. all field are null.
{"code":1,"result":{"id":null,"username":null,"shopName":null,"active":true,"email":null,"phone":null,"lastConnect":null,"createDate":null,"groupIds":[],"endDate":null}}
then i change sessionStore and try login again
router.route.handler(SessionHandler.create(LocalSessionStore.create(vertx)).setNagHttps(false))
i can work
{"code":1,"result":{"id":1,"username":"admin","shopName":null,"active":true,"email":"[email protected]","phone":null,"lastConnect":"2017-04-18 20:46:14","createDate":"2017-04-08 23:33:21","groupIds":[{"id":1,"name":"administrator","ruleIds":[{"id":3,"name":"customer"},{"id":1,"name":"admin"},{"id":2,"name":"manager"}],"parentId":null,"categoryId":{"id":1,"name":"system"}}],"endDate":null}}
so i check my zookeeper node data
[zk: localhost:2181(CONNECTED) 0] get /io.vertx/asyncMap/vertx-web.sessions/bf141f7bea93b005796ceeaceb572a25
�(io.vertx.ext.web.sstore.impl.SessionImpl� bf141f7bea93b005796ceeaceb572a25�w@�[��(�
(io.vertx.ext.web.handler.impl.UserHolder�%com.yubao.data.data.entity.base.Users
cZxid = 0x31f4
ctime = Tue Apr 18 20:47:47 CST 2017
mZxid = 0x321a
mtime = Tue Apr 18 20:48:17 CST 2017
pZxid = 0x31f4
cversion = 0
dataVersion = 37
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 243
numChildren = 0
So Is there bug of object serialization? can you help me ? thx
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.