SlideShare a Scribd company logo
Sept 06 2014
Ngoc Dao 
https://github.com/ngocdaothanh 
Takeharu Oshida 
https://github.com/georgeOsdDev 
http://mobilus.co.jp/
What is 
Xitrum? 
Xitrum is an async and clustered ! 
Scala web framework and HTTP(S) server ! 
on top of Netty, Akka
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
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
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.
Xitrum:! 
WebSocket (SockJS)! 
CORS support
2010-2013 Xitrum 1.x-2.x 
http://bit.ly/xitrum13 
2014 Xitrum 3.x 
• Netty 4.x 
• Swagger 
• Component 
• FileMonitor, i18n 
• CORS 
• WebJARs 
• Glokka 
• Agent7 (autoreload classes on change) 
! 
! 
http://bit.ly/xitrum-changelog 
!
How Xitrum 
works?
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
http://bit.ly/xitrum-handlers
Client 
Client Client 
Akka cluster (code)! 
Hazelcast (data) 
Client 
Netty 
Xitrum 
A FA AA 
Akka 
Netty 
Xitrum 
A FA AA 
Akka 
Server N Server N+1
Embed Xitrum 
object MyApp { 
def main(args: Array[String]) { 
... 
// Somewhere in your app 
xitrum.Server.start() 
... 
} 
1. Collect routes! 
} 
! 
2. Start HTTP/HTTPS servers
Action example 
import xitrum.Action 
import xitrum.annotation.GET 
! 
@GET("hello") 
class MyAction extends Action { 
def execute() { 
respondText("Hello") 
} 
} 
FutureAction! 
ActorAction
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(); 
}
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
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
Annotations defined by Xitrum:! 
http://bit.ly/xitrum-annotations! 
! 
Lib to scan classes in classpath to collect routes:! 
https://github.com/xitrum-framework/sclasner
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
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
DB Cluseter 
Xitrum1 Akka Hazelcast 
Xitrum2 Akka Hazelcast 
Xitrum3 
Cluster 
LB 
(HAProxy, Nginx, 
Route53 etc.) 
NoSQL 
RDB 
Other services 
Akka Hazelcast 
https://github.com/xitrum-framework/glokka 
https://github.com/xitrum-framework/xitrum-hazelcast
Xitrum Web Framework Live Coding Demos / Xitrum Web Framework ライブコーディング
Getting started 
with xitrum-new 
skeleton 
https://github.com/xitrum-framework/xitrum-new 
https://github.com/xitrum-framework/xitrum-scalate
@GET("admin") 
class AdminIndex extends Action { 
def execute() { 
// Get all users 
val users = User.listAll() 
// Pass users to view template 
at("users") = users 
! 
// Response respons view with template 
respondView() 
} 
} 
ActorAction 
FutureAction 
Action
- import matsuri.demo.action._! 
- import matsuri.demo.model.User! 
! 
div.row#usersTable! 
table.table.table-striped#messageTable! 
thead! 
tr.bg-primary! 
View 
• Scalate template with jade 
(mustache, scaml, or ssp) 
• "at" function 
• i18n with GNU gettext 
th.col-xs-2 =t("Name")! 
th.col-xs-2 =t("Age")! 
th.col-xs-2 =t("Desc")! 
th.col-xs-2 =t("Created time")! 
th.col-xs-2 =t("Updated time")! 
th.col-xs-2 =t("Last login time")! 
tbody! 
- for (user <- at("users").asInstanceOf[List[User]])! 
tr! 
th! 
a(href={url[AdminUserShow](("name", user.name))}) = user.name! 
th = user.age! 
th = user.desc! 
th = user.createdAtAsStr! 
th = user.updatedAtAsStr! 
th = user.lastLoginAsStr
└── src 
└── scalate 
└── matsuri 
└── demo 
└── action 
├── AdminIndex.jade 
└── DefaultLayout.jade 
package matsuri.demo.action 
! 
import xitrum.Action 
! 
trait DefaultLayout extends Action { 
override def layout = 
renderViewNoLayout[DefaultLayout]() 
} 
Layout
!!! 5 
html 
head 
!= antiCsrfMeta 
!= xitrumCss 
! 
meta(content="text/html; charset=utf-8" http-equiv="content-type") 
title ScalaMatsuri2014 Xitrum Demo 
! 
link(rel="shortcut icon" href={publicUrl("favicon.ico")}) 
link(type="text/css" rel="stylesheet" media="all" href={webJarsUrl("bootstrap/3.2.0/css", 
"bootstrap.css", "bootstrap.min.css")}) 
link(type="text/css" rel="stylesheet" media="all" href={publicUrl("app.css")}) 
! 
body 
.container 
h1 
! 
#flash 
!~ jsRenderFlash() 
!= renderedView 
Layout 
! 
!= jsDefaults 
script(src={webJarsUrl("bootstrap/3.2.0/js", "bootstrap.js", "bootstrap.min.js")}) 
script(src={webJarsUrl("underscorejs/1.6.0", "underscore.js", "underscore-min.js")}) 
!= jsForView
form(role="form" method="post" action={url[AdminUserCreate]}) 
!= antiCsrfInput 
div.modal-header 
button.close(type="button" data-dismiss="modal") 
Form 
span(aria-hidden="true") &times; 
span.sr-only =t("Close") 
h4.modal-title#myModalLabel =t("Create New User") 
div.modal-body 
div.form-group 
label(for="newUserName") =t("Name") 
input.form-control#newUserName(name="name" type="text" 
• "url" function 
• jquery-validation 
• Anti csrf token 
placeholder={t("Enter Name")} minlength=5 maxlenght=10 required=true) 
div.form-group 
label(for="newUserPass") =t("Password") 
input.form-control#newUserPass(name="password" type="password" 
placeholder={t("Enter Password")} minlength=8 required=true) 
! 
div.modal-footer 
button.btn.btn-default(type="button" data-dismiss="modal") = t("Cancel") 
button.btn.btn-primary(type="submit") = t("Save")
@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)
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
@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
@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
jsAddToView( 
"var url = '" + sockJsUrl[ChatAction] + "';" + 
""" 
var socket; 
var initSocket = function() { 
socket = new SockJS(url); 
socket.onopen = function(event) { 
console.log("socket onopen", event.data); 
socket.send(JSON.parse({"msg":"Hello Xitrum"})); 
}; 
socket.onclose = function(event) {console.log("socket onclose", event.data);}; 
socket.onmessage = function(event) {console.log("socket onmessage", event.data);}; 
}; 
initSocket(); 
""" 
) 
!= jsDefaults 
script(src={webJarsUrl("bootstrap/3.2.0/js", "bootstrap.js", "bootstrap.min.js")}) 
script(src={webJarsUrl("underscorejs/1.6.0", "underscore.js", "underscore-min.js")}) 
!= jsForView 
• jsAddToView/jsForView 
• sockJsUrl 
• webJarsUrl 
Create 
chat 
client 
with 
SockJS
import xitrum.{SockJsAction, SockJsText} 
import xitrum.annotation.SOCKJS 
! 
@SOCKJS("connect") 
class ChatAction extends SockJsAction with LoginFilter { 
def execute() { 
context.become { 
SockJsAction 
(an Actor) 
case SockJsText(text) => 
SeriDeseri.fromJson[Map[String, String]](text) match { 
case Some(jsonMap) => 
// echo 
respondSockJsText(SeriDeseri.toJson(jsonMap)) 
case None => 
log.warn(s"Failed to parse request: $text") 
respondSockJsText("invalid request") 
} 
Create 
} 
• SockJsAction 
• SockJsText/respondSockJsText 
• SeriDeseri.fromJson[T] / SeriDeseri.toJson(ref:AnyRef)
Lookup 
singleton 
Actor 
with 
Glokka 
Xitrum 
socket open 
Client 
HubActor 
trait Hub extends Actor { 
protected var clients = Seq[ActorRef]() 
def receive = { 
case Subscribe(option) => 
clients = clients :+ sender 
case Unsubscribe(option) => 
clients = clients.filterNot(_ == sender) 
case Terminated(client) => 
clients = clients.filterNot(_ == client) 
case ignore => 
} 
import glokka.Registry 
object Hub { 
val KEY_PROXY = "HUB_PROXY" 
val actorRegistry = Registry.start(Config.actorSystem, 
KEY_PROXY) 
} 
! 
def lookUpHub(key: String, hubProps: Props, option: Any = None) 
{ 
Hub.actorRegistry ! Registry.Register(key, hubProps) 
context.become { 
hub ! Subscribe 
ChatAction ChatAction ChatAction ChatAction 
case result: Registry.FoundOrCreated => 
result.ref ! Subscribe 
} 
} 
Client Client Client 
https://github.com/xitrum-framework/glokka
Messaging overview 
SockJsText! 
(socket.send) hub ! Push(msg) 
clients.foreach { _ ! Publish(msg)} respondSockJSText(msg:String) 
Client ChatAction HubActor 
socket.onmessage 
SockJsText hub ! Pull(msg) 
case class Done (option: Map[String, Any] = Map.empty) // Hub -> Action 
case class Publish(option: Map[String, Any] = Map.empty) // Hub -> Action 
case class Pull (option: Map[String, Any] = Map.empty) // Action -> Hub 
case class Push (option: Map[String, Any] = Map.empty) // Action -> Hub 
https://github.com/georgeOsdDev/glokka-demo 
ChatAction Client 
ChatAction 
ChatAction 
Client 
Client 
respondSockJSText(msg:String) sender ! Done(msg) 
Client ChatAction HubActor 
respondSockJSText(msg:String) sender ! Done(msg) 
socket.onmessage
Cluster config for Hazelcast 
hazelcastMode = clusterMember 
! 
cache = xitrum.hazelcast.Cache 
#cache { 
# # Simple in-memory cache 
# "xitrum.local.LruCache" { 
xitrum.conf 
# maxElems = 10000 
# } 
• Xitrum-hazelcast 
#} 
• Shared Session 
• Shared Cache 
! 
session { 
store = xitrum.hazelcast.Session 
# Store sessions on client side 
#store = xitrum.scope.session.CookieSessionStore
akka { 
loggers = ["akka.event.slf4j.Slf4jLogger"] 
logger-startup-timeout = 30s 
! 
actor { 
provider = "akka.cluster.ClusterActorRefProvider" 
} 
! 
# This node 
remote { 
log-remote-lifecycle-events = off 
netty.tcp { 
hostname = "127.0.0.1" 
port = 2551 # 0 means random port 
} 
} 
! 
cluster { 
seed-nodes = [ 
"akka.tcp://xitrum@127.0.0.1:2551", 
"akka.tcp://xitrum@127.0.0.1:2552"] 
! 
auto-down-unreachable-after = 10s 
} 
} 
Cluster 
config 
for 
Akka
Live class reload 
during development 
https://github.com/xitrum-framework/agent7 
https://github.com/dcevm/dcevm 
java -javaagent:`dirname $0`/agent7-1.0.jar 
-XXaltjvm=dcevm -Xms256M -Xmx512M -Xss1M 
-XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=384M 
-jar `dirname $0`/sbt-launch-0.13.5.jar "$@" 
https://github.com/xitrum-framework/xitrum-package
Package project for 
deploying to 
production server 
https://github.com/xitrum-framework/xitrum-package 
sbt/sbt xitrum-package
Monitor Xitrum 
in production mode 
• Scalive 
• Metrics 
• Log to fluentd 
https://github.com/xitrum-framework/scalive 
http://www.slideshare.net/georgeosd/scalive 
http://xitrum-framework.github.io/guide/3.18/en/ 
log.html#log-to-fluentd
Thank 
you!

More Related Content

PPTX
JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)
Stephen Chin
 
PDF
Node.js vs Play Framework (with Japanese subtitles)
Yevgeniy Brikman
 
PDF
Play vs Rails
Daniel Cukier
 
PDF
Akka and the Zen of Reactive System Design
Lightbend
 
PDF
Http4s, Doobie and Circe: The Functional Web Stack
GaryCoady
 
PPTX
Scala Matsuri 2016: Japanese Text Mining with Scala and Spark
Eduardo Gonzalez
 
PDF
Scala Frustrations
takezoe
 
PDF
Hi performance table views with QuartzCore and CoreText
Mugunth Kumar
 
JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)
Stephen Chin
 
Node.js vs Play Framework (with Japanese subtitles)
Yevgeniy Brikman
 
Play vs Rails
Daniel Cukier
 
Akka and the Zen of Reactive System Design
Lightbend
 
Http4s, Doobie and Circe: The Functional Web Stack
GaryCoady
 
Scala Matsuri 2016: Japanese Text Mining with Scala and Spark
Eduardo Gonzalez
 
Scala Frustrations
takezoe
 
Hi performance table views with QuartzCore and CoreText
Mugunth Kumar
 

What's hot (20)

PDF
Spring data requery
Sunghyouk Bae
 
PPTX
SenchaCon 2016: Modernizing the Ext JS Class System - Don Griffin
Sencha
 
PDF
JavaCro'14 - Scala and Java EE 7 Development Experiences – Peter Pilgrim
HUJAK - Hrvatska udruga Java korisnika / Croatian Java User Association
 
PDF
Survive JavaScript - Strategies and Tricks
Juho Vepsäläinen
 
PPTX
Demystifying Oak Search
Justin Edelson
 
PPT
Mastering Java ByteCode
Ecommerce Solution Provider SysIQ
 
PDF
Java EE 6 CDI Integrates with Spring & JSF
Jiayun Zhou
 
PDF
Activator and Reactive at Play NYC meetup
Henrik Engström
 
PPT
Building a java tracer
rahulrevo
 
PPT
Jet presentation
Peter Sellars
 
PDF
Performance Optimization and JavaScript Best Practices
Doris Chen
 
PDF
Java FX 2.0 - A Developer's Guide
Stephen Chin
 
PDF
Node Architecture and Getting Started with Express
jguerrero999
 
PPTX
Softshake 2013: 10 reasons why java developers are jealous of Scala developers
Matthew Farwell
 
KEY
Building a real life application in node js
fakedarren
 
PDF
Using Ruby on Rails with legacy Oracle databases
Raimonds Simanovskis
 
PDF
How and Where in GLORP
ESUG
 
PDF
Zen of Akka
Konrad Malawski
 
PDF
Building servers with Node.js
ConFoo
 
PDF
The DOM is a Mess @ Yahoo
jeresig
 
Spring data requery
Sunghyouk Bae
 
SenchaCon 2016: Modernizing the Ext JS Class System - Don Griffin
Sencha
 
JavaCro'14 - Scala and Java EE 7 Development Experiences – Peter Pilgrim
HUJAK - Hrvatska udruga Java korisnika / Croatian Java User Association
 
Survive JavaScript - Strategies and Tricks
Juho Vepsäläinen
 
Demystifying Oak Search
Justin Edelson
 
Mastering Java ByteCode
Ecommerce Solution Provider SysIQ
 
Java EE 6 CDI Integrates with Spring & JSF
Jiayun Zhou
 
Activator and Reactive at Play NYC meetup
Henrik Engström
 
Building a java tracer
rahulrevo
 
Jet presentation
Peter Sellars
 
Performance Optimization and JavaScript Best Practices
Doris Chen
 
Java FX 2.0 - A Developer's Guide
Stephen Chin
 
Node Architecture and Getting Started with Express
jguerrero999
 
Softshake 2013: 10 reasons why java developers are jealous of Scala developers
Matthew Farwell
 
Building a real life application in node js
fakedarren
 
Using Ruby on Rails with legacy Oracle databases
Raimonds Simanovskis
 
How and Where in GLORP
ESUG
 
Zen of Akka
Konrad Malawski
 
Building servers with Node.js
ConFoo
 
The DOM is a Mess @ Yahoo
jeresig
 
Ad

Similar to Xitrum Web Framework Live Coding Demos / Xitrum Web Framework ライブコーディング (20)

PDF
Rich Portlet Development in uPortal
Jennifer Bourey
 
PPTX
Spine.js
wearefractal
 
PDF
RESTful Web Applications with Apache Sling
Bertrand Delacretaz
 
PDF
soft-shake.ch - Hands on Node.js
soft-shake.ch
 
PDF
Universal JavaScript
名辰 洪
 
PDF
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
Doris Chen
 
PPT
jQuery Tips Tricks Trivia
Cognizant
 
PDF
WebNet Conference 2012 - Designing complex applications using html5 and knock...
Fabio Franzini
 
PDF
Front End Development for Back End Developers - UberConf 2017
Matt Raible
 
KEY
Using and scaling Rack and Rack-based middleware
Alona Mekhovova
 
PPTX
Azure F#unctions
☁️ Mikhail Shilkov
 
PDF
An Introduction to Tornado
Gavin Roy
 
PPT
Play!ng with scala
Siarzh Miadzvedzeu
 
PDF
vJUG - The JavaFX Ecosystem
Andres Almiray
 
PDF
Bonnes pratiques de développement avec Node js
Francois Zaninotto
 
PDF
GitBucket: The perfect Github clone by Scala
takezoe
 
PDF
Ajax tutorial
Kat Roque
 
PDF
5.node js
Geunhyung Kim
 
KEY
Express Presentation
aaronheckmann
 
PPT
Build Your Own CMS with Apache Sling
Bob Paulin
 
Rich Portlet Development in uPortal
Jennifer Bourey
 
Spine.js
wearefractal
 
RESTful Web Applications with Apache Sling
Bertrand Delacretaz
 
soft-shake.ch - Hands on Node.js
soft-shake.ch
 
Universal JavaScript
名辰 洪
 
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
Doris Chen
 
jQuery Tips Tricks Trivia
Cognizant
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
Fabio Franzini
 
Front End Development for Back End Developers - UberConf 2017
Matt Raible
 
Using and scaling Rack and Rack-based middleware
Alona Mekhovova
 
Azure F#unctions
☁️ Mikhail Shilkov
 
An Introduction to Tornado
Gavin Roy
 
Play!ng with scala
Siarzh Miadzvedzeu
 
vJUG - The JavaFX Ecosystem
Andres Almiray
 
Bonnes pratiques de développement avec Node js
Francois Zaninotto
 
GitBucket: The perfect Github clone by Scala
takezoe
 
Ajax tutorial
Kat Roque
 
5.node js
Geunhyung Kim
 
Express Presentation
aaronheckmann
 
Build Your Own CMS with Apache Sling
Bob Paulin
 
Ad

More from scalaconfjp (20)

PDF
脆弱性対策のためのClean Architecture ~脆弱性に対するレジリエンスを確保せよ~
scalaconfjp
 
PDF
Alp x BizReach SaaS事業を営む2社がお互い気になることをゆるゆる聞いてみる会
scalaconfjp
 
PDF
GraalVM Overview Compact version
scalaconfjp
 
PDF
Run Scala Faster with GraalVM on any Platform / GraalVMで、どこでもScalaを高速実行しよう by...
scalaconfjp
 
PPTX
Monitoring Reactive Architecture Like Never Before / 今までになかったリアクティブアーキテクチャの監視...
scalaconfjp
 
PPTX
Scala 3, what does it means for me? / Scala 3って、私にはどんな影響があるの? by Joan Goyeau
scalaconfjp
 
PDF
Functional Object-Oriented Imperative Scala / 関数型オブジェクト指向命令型 Scala by Sébasti...
scalaconfjp
 
PDF
Scala ♥ Graal by Flavio Brasil
scalaconfjp
 
PPTX
Introduction to GraphQL in Scala
scalaconfjp
 
PDF
Safety Beyond Types
scalaconfjp
 
PDF
Reactive Kafka with Akka Streams
scalaconfjp
 
PDF
Reactive microservices with play and akka
scalaconfjp
 
PDF
Scalaに対して意識の低いエンジニアがScalaで何したかの話, by 芸者東京エンターテインメント
scalaconfjp
 
PDF
DWANGO by ドワンゴ
scalaconfjp
 
PDF
OCTOPARTS by M3, Inc.
scalaconfjp
 
PDF
Try using Aeromock by Marverick, Inc.
scalaconfjp
 
PDF
統計をとって高速化する
Scala開発 by CyberZ,Inc.
scalaconfjp
 
PDF
Short Introduction of Implicit Conversion by TIS, Inc.
scalaconfjp
 
PPTX
ビズリーチ x ScalaMatsuri by BIZREACH, Inc.
scalaconfjp
 
PDF
sbt, past and future / sbt, 傾向と対策
scalaconfjp
 
脆弱性対策のためのClean Architecture ~脆弱性に対するレジリエンスを確保せよ~
scalaconfjp
 
Alp x BizReach SaaS事業を営む2社がお互い気になることをゆるゆる聞いてみる会
scalaconfjp
 
GraalVM Overview Compact version
scalaconfjp
 
Run Scala Faster with GraalVM on any Platform / GraalVMで、どこでもScalaを高速実行しよう by...
scalaconfjp
 
Monitoring Reactive Architecture Like Never Before / 今までになかったリアクティブアーキテクチャの監視...
scalaconfjp
 
Scala 3, what does it means for me? / Scala 3って、私にはどんな影響があるの? by Joan Goyeau
scalaconfjp
 
Functional Object-Oriented Imperative Scala / 関数型オブジェクト指向命令型 Scala by Sébasti...
scalaconfjp
 
Scala ♥ Graal by Flavio Brasil
scalaconfjp
 
Introduction to GraphQL in Scala
scalaconfjp
 
Safety Beyond Types
scalaconfjp
 
Reactive Kafka with Akka Streams
scalaconfjp
 
Reactive microservices with play and akka
scalaconfjp
 
Scalaに対して意識の低いエンジニアがScalaで何したかの話, by 芸者東京エンターテインメント
scalaconfjp
 
DWANGO by ドワンゴ
scalaconfjp
 
OCTOPARTS by M3, Inc.
scalaconfjp
 
Try using Aeromock by Marverick, Inc.
scalaconfjp
 
統計をとって高速化する
Scala開発 by CyberZ,Inc.
scalaconfjp
 
Short Introduction of Implicit Conversion by TIS, Inc.
scalaconfjp
 
ビズリーチ x ScalaMatsuri by BIZREACH, Inc.
scalaconfjp
 
sbt, past and future / sbt, 傾向と対策
scalaconfjp
 

Recently uploaded (20)

PDF
MiniTool Power Data Recovery Crack New Pre Activated Version Latest 2025
imang66g
 
PDF
49785682629390197565_LRN3014_Migrating_the_Beast.pdf
Abilash868456
 
PPTX
ASSIGNMENT_1[1][1][1][1][1] (1) variables.pptx
kr2589474
 
PDF
10 posting ideas for community engagement with AI prompts
Pankaj Taneja
 
PPTX
Contractor Management Platform and Software Solution for Compliance
SHEQ Network Limited
 
PPTX
Maximizing Revenue with Marketo Measure: A Deep Dive into Multi-Touch Attribu...
bbedford2
 
PDF
Download iTop VPN Free 6.1.0.5882 Crack Full Activated Pre Latest 2025
imang66g
 
PDF
New Download FL Studio Crack Full Version [Latest 2025]
imang66g
 
PPTX
TRAVEL APIs | WHITE LABEL TRAVEL API | TOP TRAVEL APIs
philipnathen82
 
PPTX
Can You Build Dashboards Using Open Source Visualization Tool.pptx
Varsha Nayak
 
PDF
49784907924775488180_LRN2959_Data_Pump_23ai.pdf
Abilash868456
 
PPTX
Presentation about variables and constant.pptx
safalsingh810
 
PDF
Adobe Illustrator Crack Full Download (Latest Version 2025) Pre-Activated
imang66g
 
PPTX
Web Testing.pptx528278vshbuqffqhhqiwnwuq
studylike474
 
PDF
Generating Union types w/ Static Analysis
K. Matthew Dupree
 
DOCX
Can You Build Dashboards Using Open Source Visualization Tool.docx
Varsha Nayak
 
PDF
Exploring AI Agents in Process Industries
amoreira6
 
PPTX
classification of computer and basic part of digital computer
ravisinghrajpurohit3
 
PPTX
Presentation about Database and Database Administrator
abhishekchauhan86963
 
PPTX
The-Dawn-of-AI-Reshaping-Our-World.pptxx
parthbhanushali307
 
MiniTool Power Data Recovery Crack New Pre Activated Version Latest 2025
imang66g
 
49785682629390197565_LRN3014_Migrating_the_Beast.pdf
Abilash868456
 
ASSIGNMENT_1[1][1][1][1][1] (1) variables.pptx
kr2589474
 
10 posting ideas for community engagement with AI prompts
Pankaj Taneja
 
Contractor Management Platform and Software Solution for Compliance
SHEQ Network Limited
 
Maximizing Revenue with Marketo Measure: A Deep Dive into Multi-Touch Attribu...
bbedford2
 
Download iTop VPN Free 6.1.0.5882 Crack Full Activated Pre Latest 2025
imang66g
 
New Download FL Studio Crack Full Version [Latest 2025]
imang66g
 
TRAVEL APIs | WHITE LABEL TRAVEL API | TOP TRAVEL APIs
philipnathen82
 
Can You Build Dashboards Using Open Source Visualization Tool.pptx
Varsha Nayak
 
49784907924775488180_LRN2959_Data_Pump_23ai.pdf
Abilash868456
 
Presentation about variables and constant.pptx
safalsingh810
 
Adobe Illustrator Crack Full Download (Latest Version 2025) Pre-Activated
imang66g
 
Web Testing.pptx528278vshbuqffqhhqiwnwuq
studylike474
 
Generating Union types w/ Static Analysis
K. Matthew Dupree
 
Can You Build Dashboards Using Open Source Visualization Tool.docx
Varsha Nayak
 
Exploring AI Agents in Process Industries
amoreira6
 
classification of computer and basic part of digital computer
ravisinghrajpurohit3
 
Presentation about Database and Database Administrator
abhishekchauhan86963
 
The-Dawn-of-AI-Reshaping-Our-World.pptxx
parthbhanushali307
 

Xitrum Web Framework Live Coding Demos / Xitrum Web Framework ライブコーディング

  • 2. Ngoc Dao https://github.com/ngocdaothanh Takeharu Oshida https://github.com/georgeOsdDev http://mobilus.co.jp/
  • 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.
  • 8. 2010-2013 Xitrum 1.x-2.x http://bit.ly/xitrum13 2014 Xitrum 3.x • Netty 4.x • Swagger • Component • FileMonitor, i18n • CORS • WebJARs • Glokka • Agent7 (autoreload classes on change) ! ! http://bit.ly/xitrum-changelog !
  • 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
  • 12. Client Client Client Akka cluster (code)! Hazelcast (data) Client Netty Xitrum A FA AA Akka Netty Xitrum A FA AA Akka Server N Server N+1
  • 13. Embed Xitrum object MyApp { def main(args: Array[String]) { ... // Somewhere in your app xitrum.Server.start() ... } 1. Collect routes! } ! 2. Start HTTP/HTTPS servers
  • 14. Action example import xitrum.Action import xitrum.annotation.GET ! @GET("hello") class MyAction extends Action { def execute() { respondText("Hello") } } FutureAction! ActorAction
  • 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
  • 21. DB Cluseter Xitrum1 Akka Hazelcast Xitrum2 Akka Hazelcast Xitrum3 Cluster LB (HAProxy, Nginx, Route53 etc.) NoSQL RDB Other services Akka Hazelcast https://github.com/xitrum-framework/glokka https://github.com/xitrum-framework/xitrum-hazelcast
  • 23. Getting started with xitrum-new skeleton https://github.com/xitrum-framework/xitrum-new https://github.com/xitrum-framework/xitrum-scalate
  • 24. @GET("admin") class AdminIndex extends Action { def execute() { // Get all users val users = User.listAll() // Pass users to view template at("users") = users ! // Response respons view with template respondView() } } ActorAction FutureAction Action
  • 25. - import matsuri.demo.action._! - import matsuri.demo.model.User! ! div.row#usersTable! table.table.table-striped#messageTable! thead! tr.bg-primary! View • Scalate template with jade (mustache, scaml, or ssp) • "at" function • i18n with GNU gettext th.col-xs-2 =t("Name")! th.col-xs-2 =t("Age")! th.col-xs-2 =t("Desc")! th.col-xs-2 =t("Created time")! th.col-xs-2 =t("Updated time")! th.col-xs-2 =t("Last login time")! tbody! - for (user <- at("users").asInstanceOf[List[User]])! tr! th! a(href={url[AdminUserShow](("name", user.name))}) = user.name! th = user.age! th = user.desc! th = user.createdAtAsStr! th = user.updatedAtAsStr! th = user.lastLoginAsStr
  • 26. └── src └── scalate └── matsuri └── demo └── action ├── AdminIndex.jade └── DefaultLayout.jade package matsuri.demo.action ! import xitrum.Action ! trait DefaultLayout extends Action { override def layout = renderViewNoLayout[DefaultLayout]() } Layout
  • 27. !!! 5 html head != antiCsrfMeta != xitrumCss ! meta(content="text/html; charset=utf-8" http-equiv="content-type") title ScalaMatsuri2014 Xitrum Demo ! link(rel="shortcut icon" href={publicUrl("favicon.ico")}) link(type="text/css" rel="stylesheet" media="all" href={webJarsUrl("bootstrap/3.2.0/css", "bootstrap.css", "bootstrap.min.css")}) link(type="text/css" rel="stylesheet" media="all" href={publicUrl("app.css")}) ! body .container h1 ! #flash !~ jsRenderFlash() != renderedView Layout ! != jsDefaults script(src={webJarsUrl("bootstrap/3.2.0/js", "bootstrap.js", "bootstrap.min.js")}) script(src={webJarsUrl("underscorejs/1.6.0", "underscore.js", "underscore-min.js")}) != jsForView
  • 28. form(role="form" method="post" action={url[AdminUserCreate]}) != antiCsrfInput div.modal-header button.close(type="button" data-dismiss="modal") Form span(aria-hidden="true") &times; span.sr-only =t("Close") h4.modal-title#myModalLabel =t("Create New User") div.modal-body div.form-group label(for="newUserName") =t("Name") input.form-control#newUserName(name="name" type="text" • "url" function • jquery-validation • Anti csrf token placeholder={t("Enter Name")} minlength=5 maxlenght=10 required=true) div.form-group label(for="newUserPass") =t("Password") input.form-control#newUserPass(name="password" type="password" placeholder={t("Enter Password")} minlength=8 required=true) ! div.modal-footer button.btn.btn-default(type="button" data-dismiss="modal") = t("Cancel") button.btn.btn-primary(type="submit") = t("Save")
  • 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
  • 33. jsAddToView( "var url = '" + sockJsUrl[ChatAction] + "';" + """ var socket; var initSocket = function() { socket = new SockJS(url); socket.onopen = function(event) { console.log("socket onopen", event.data); socket.send(JSON.parse({"msg":"Hello Xitrum"})); }; socket.onclose = function(event) {console.log("socket onclose", event.data);}; socket.onmessage = function(event) {console.log("socket onmessage", event.data);}; }; initSocket(); """ ) != jsDefaults script(src={webJarsUrl("bootstrap/3.2.0/js", "bootstrap.js", "bootstrap.min.js")}) script(src={webJarsUrl("underscorejs/1.6.0", "underscore.js", "underscore-min.js")}) != jsForView • jsAddToView/jsForView • sockJsUrl • webJarsUrl Create chat client with SockJS
  • 34. import xitrum.{SockJsAction, SockJsText} import xitrum.annotation.SOCKJS ! @SOCKJS("connect") class ChatAction extends SockJsAction with LoginFilter { def execute() { context.become { SockJsAction (an Actor) case SockJsText(text) => SeriDeseri.fromJson[Map[String, String]](text) match { case Some(jsonMap) => // echo respondSockJsText(SeriDeseri.toJson(jsonMap)) case None => log.warn(s"Failed to parse request: $text") respondSockJsText("invalid request") } Create } • SockJsAction • SockJsText/respondSockJsText • SeriDeseri.fromJson[T] / SeriDeseri.toJson(ref:AnyRef)
  • 35. Lookup singleton Actor with Glokka Xitrum socket open Client HubActor trait Hub extends Actor { protected var clients = Seq[ActorRef]() def receive = { case Subscribe(option) => clients = clients :+ sender case Unsubscribe(option) => clients = clients.filterNot(_ == sender) case Terminated(client) => clients = clients.filterNot(_ == client) case ignore => } import glokka.Registry object Hub { val KEY_PROXY = "HUB_PROXY" val actorRegistry = Registry.start(Config.actorSystem, KEY_PROXY) } ! def lookUpHub(key: String, hubProps: Props, option: Any = None) { Hub.actorRegistry ! Registry.Register(key, hubProps) context.become { hub ! Subscribe ChatAction ChatAction ChatAction ChatAction case result: Registry.FoundOrCreated => result.ref ! Subscribe } } Client Client Client https://github.com/xitrum-framework/glokka
  • 36. Messaging overview SockJsText! (socket.send) hub ! Push(msg) clients.foreach { _ ! Publish(msg)} respondSockJSText(msg:String) Client ChatAction HubActor socket.onmessage SockJsText hub ! Pull(msg) case class Done (option: Map[String, Any] = Map.empty) // Hub -> Action case class Publish(option: Map[String, Any] = Map.empty) // Hub -> Action case class Pull (option: Map[String, Any] = Map.empty) // Action -> Hub case class Push (option: Map[String, Any] = Map.empty) // Action -> Hub https://github.com/georgeOsdDev/glokka-demo ChatAction Client ChatAction ChatAction Client Client respondSockJSText(msg:String) sender ! Done(msg) Client ChatAction HubActor respondSockJSText(msg:String) sender ! Done(msg) socket.onmessage
  • 37. Cluster config for Hazelcast hazelcastMode = clusterMember ! cache = xitrum.hazelcast.Cache #cache { # # Simple in-memory cache # "xitrum.local.LruCache" { xitrum.conf # maxElems = 10000 # } • Xitrum-hazelcast #} • Shared Session • Shared Cache ! session { store = xitrum.hazelcast.Session # Store sessions on client side #store = xitrum.scope.session.CookieSessionStore
  • 38. akka { loggers = ["akka.event.slf4j.Slf4jLogger"] logger-startup-timeout = 30s ! actor { provider = "akka.cluster.ClusterActorRefProvider" } ! # This node remote { log-remote-lifecycle-events = off netty.tcp { hostname = "127.0.0.1" port = 2551 # 0 means random port } } ! cluster { seed-nodes = [ "akka.tcp://[email protected]:2551", "akka.tcp://[email protected]:2552"] ! auto-down-unreachable-after = 10s } } Cluster config for Akka
  • 39. Live class reload during development https://github.com/xitrum-framework/agent7 https://github.com/dcevm/dcevm java -javaagent:`dirname $0`/agent7-1.0.jar -XXaltjvm=dcevm -Xms256M -Xmx512M -Xss1M -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=384M -jar `dirname $0`/sbt-launch-0.13.5.jar "$@" https://github.com/xitrum-framework/xitrum-package
  • 40. Package project for deploying to production server https://github.com/xitrum-framework/xitrum-package sbt/sbt xitrum-package
  • 41. Monitor Xitrum in production mode • Scalive • Metrics • Log to fluentd https://github.com/xitrum-framework/scalive http://www.slideshare.net/georgeosd/scalive http://xitrum-framework.github.io/guide/3.18/en/ log.html#log-to-fluentd