3. What is
Xitrum?
Xitrum is an async and clustered !
Scala web framework and HTTP(S) server !
on top of Netty, Akka
4. Why you should use
Xitrum?
• Featureful!
• Easy to use!
• High performance
Scala, Netty, and Akka are fast!
• Scalable
Can scale to a cluster of servers using
Akka cluster and/or Hazelcast
5. Homepage:
http://xitrum-framework.github.io/
(there are various demos)
Guides (English, Japanese, Russian):
http://xitrum-framework.github.io/guide.html
(Korean version is in progress)
!
Community (Google Group):
https://groups.google.com/forum/#!forum/
xitrum-framework
6. Where
Xitrum is used?
KONNECT (Messaging Service)!
http://mobilus.co.jp/konnect/!
!
KONNECT can be used in mobile games,
mobiles apps, SNS websites etc.
Xitrum is also being used in France, Korea,
Russia, Singapore etc.
10. Client
Netty
Async
Dispatch
request
Action FutureAction ActorAction
Akka
Xitrum
I/O thread pool to
accept requests and reply
responses
Thread pool
to run FutureAction and
ActorAction
Client
Run directly on
Netty I/O thread
Netty handler
Netty handler
Netty handler
Netty handler
Xitrum
Your program
15. Annotations: Scala vs Java
Scala: @GET("matsuri", "festival")
Java: @GET(Array("matsuri", "festival"))
!
Scala:
case class GET(paths: String*) extends
scala.annotation.StaticAnnotation
!
Java:
public @interface GET {
String[] value();
}
16. Benefits of using annotations
Routes in .class and .jar in classpath are
automatically collected and merged.
A.class
B.class
lib1.jar
lib2.jar
Routes
17. Problem with annotations
Collecting routes from .class and .jar files is slow.!
!
Solutions:!
• In development mode, routes in .class and .jar
files that are not in the current working directory
are cached to file routes.cache.
• To avoid loading lots of classes, don't collect
routes from: java.xxx, javax.xxx, scala.xxx,
sun.xxx, com.sun.xxx
18. Annotations defined by Xitrum:!
http://bit.ly/xitrum-annotations!
!
Lib to scan classes in classpath to collect routes:!
https://github.com/xitrum-framework/sclasner
19. Demo overview
GET / GET /chat
username
password
login
Hello
!
Hello!
How are you?
Fine
message send
POST /login SockJS /connect
https://github.com/xitrum-framework/matsuri14
20. Demo overview
• Simple HTTP CRUD with MongoDB
POST /admin/user
GET /admin/user
GET /admin/user/:userId
PUT /admin/user/:userId
DELETE /admin/user/:userId
PUT/PATCH/DELETE can be emulated via
POST with _method=PUT/PATCH/DELETE
!
• API documentation with Swagger
29. @POST("admin/user")
class AdminUserCreate extends AdminAction {
def execute() {
// Get request paramaters
val name = param("name")
val password = param("password")
// Optional parameters
val age = paramo[Int]("age")
val desc = paramo("desc")
!
Required.exception("name", name)
Required.exception("password", password)
!
User.create(name, password, age, desc)
flash(t("Success"))
redirectTo[AdminIndex]()
}
Get
request
params
with
param(s)
and
param(o)
30. object SVar {
object isAdmin extends SessionVar[Boolean]
}
Use before filter
to check
trait AdminFilter {
this: Action =>
!
beforeFilter {
if (SVar.isAdmin.isDefined) true else authBasic()
}
!
private def authBasic(): Boolean = {
basicAuth(Config.basicAuth.realm) { (username, password) =>
if (username == Config.basicAuth.name && password == Config.basicAuth.pass) {
SVar.isAdmin.set(true)
true
} else {
false
}
}
}
authentication
info in session
31. @Swagger(
Swagger.Summary("Create User"),
Swagger.Response(200, "status = 0: success, 1: failed to create user"),
Swagger.Response(400, "Invalid request parameter"),
Swagger.StringForm("name"),
Swagger.StringForm("password"),
Swagger.OptIntForm("age"),
Swagger.OptStringForm("desc")
)
API
doc
• /xitrum/swagger
• /xitrum/swagger-ui
• Create test client with Swagger-codegen
https://github.com/wordnik/swagger-ui
https://github.com/wordnik/swagger-codegen
https://github.com/wordnik/swagger-spec
32. @GET("login", "")
class LoginIndex extends DefaultLayout {
def execute() {
respondView()
}
}
!
@POST("login")
class Login extends Action {
def execute() {
session.clear()
val name = param("name")
val password = param("password")
!
User.authLogin(name, password) match {
case Some(user) =>
SVar.userName.set(user.name)
redirectTo[ChatIndex]()
!
case None =>
flash(t(s"Invalid username or password"))
redirectTo[LoginIndex]()
}
}
}
Login