SlideShare a Scribd company logo
1 of 42
Download to read offline
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
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

What's hot

JavaCro'14 - Scala and Java EE 7 Development Experiences – Peter Pilgrim
JavaCro'14 - Scala and Java EE 7 Development Experiences – Peter PilgrimJavaCro'14 - Scala and Java EE 7 Development Experiences – Peter Pilgrim
JavaCro'14 - Scala and Java EE 7 Development Experiences – Peter Pilgrim
HUJAK - Hrvatska udruga Java korisnika / Croatian Java User Association
 
Java EE 6 CDI Integrates with Spring & JSF
Java EE 6 CDI Integrates with Spring & JSFJava EE 6 CDI Integrates with Spring & JSF
Java EE 6 CDI Integrates with Spring & JSF
Jiayun Zhou
 
Building a java tracer
Building a java tracerBuilding a java tracer
Building a java tracer
rahulrevo
 
Using Ruby on Rails with legacy Oracle databases
Using Ruby on Rails with legacy Oracle databasesUsing Ruby on Rails with legacy Oracle databases
Using Ruby on Rails with legacy Oracle databases
Raimonds Simanovskis
 
Building servers with Node.js
Building servers with Node.jsBuilding servers with Node.js
Building servers with Node.js
ConFoo
 

What's hot (20)

Spring data requery
Spring data requerySpring data requery
Spring data requery
 
SenchaCon 2016: Modernizing the Ext JS Class System - Don Griffin
SenchaCon 2016: Modernizing the Ext JS Class System - Don GriffinSenchaCon 2016: Modernizing the Ext JS Class System - Don Griffin
SenchaCon 2016: Modernizing the Ext JS Class System - Don Griffin
 
JavaCro'14 - Scala and Java EE 7 Development Experiences – Peter Pilgrim
JavaCro'14 - Scala and Java EE 7 Development Experiences – Peter PilgrimJavaCro'14 - Scala and Java EE 7 Development Experiences – Peter Pilgrim
JavaCro'14 - Scala and Java EE 7 Development Experiences – Peter Pilgrim
 
Survive JavaScript - Strategies and Tricks
Survive JavaScript - Strategies and TricksSurvive JavaScript - Strategies and Tricks
Survive JavaScript - Strategies and Tricks
 
Demystifying Oak Search
Demystifying Oak SearchDemystifying Oak Search
Demystifying Oak Search
 
Mastering Java ByteCode
Mastering Java ByteCodeMastering Java ByteCode
Mastering Java ByteCode
 
Java EE 6 CDI Integrates with Spring & JSF
Java EE 6 CDI Integrates with Spring & JSFJava EE 6 CDI Integrates with Spring & JSF
Java EE 6 CDI Integrates with Spring & JSF
 
Activator and Reactive at Play NYC meetup
Activator and Reactive at Play NYC meetupActivator and Reactive at Play NYC meetup
Activator and Reactive at Play NYC meetup
 
Building a java tracer
Building a java tracerBuilding a java tracer
Building a java tracer
 
Jet presentation
Jet presentationJet presentation
Jet presentation
 
Performance Optimization and JavaScript Best Practices
Performance Optimization and JavaScript Best PracticesPerformance Optimization and JavaScript Best Practices
Performance Optimization and JavaScript Best Practices
 
Java FX 2.0 - A Developer's Guide
Java FX 2.0 - A Developer's GuideJava FX 2.0 - A Developer's Guide
Java FX 2.0 - A Developer's Guide
 
Node Architecture and Getting Started with Express
Node Architecture and Getting Started with ExpressNode Architecture and Getting Started with Express
Node Architecture and Getting Started with Express
 
Softshake 2013: 10 reasons why java developers are jealous of Scala developers
Softshake 2013: 10 reasons why java developers are jealous of Scala developersSoftshake 2013: 10 reasons why java developers are jealous of Scala developers
Softshake 2013: 10 reasons why java developers are jealous of Scala developers
 
Building a real life application in node js
Building a real life application in node jsBuilding a real life application in node js
Building a real life application in node js
 
Using Ruby on Rails with legacy Oracle databases
Using Ruby on Rails with legacy Oracle databasesUsing Ruby on Rails with legacy Oracle databases
Using Ruby on Rails with legacy Oracle databases
 
How and Where in GLORP
How and Where in GLORPHow and Where in GLORP
How and Where in GLORP
 
Zen of Akka
Zen of AkkaZen of Akka
Zen of Akka
 
Building servers with Node.js
Building servers with Node.jsBuilding servers with Node.js
Building servers with Node.js
 
The DOM is a Mess @ Yahoo
The DOM is a Mess @ YahooThe DOM is a Mess @ Yahoo
The DOM is a Mess @ Yahoo
 

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

WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...
Fabio Franzini
 
An Introduction to Tornado
An Introduction to TornadoAn Introduction to Tornado
An Introduction to Tornado
Gavin Roy
 
GitBucket: The perfect Github clone by Scala
GitBucket: The perfect Github clone by ScalaGitBucket: The perfect Github clone by Scala
GitBucket: The perfect Github clone by Scala
takezoe
 
Ajax tutorial
Ajax tutorialAjax tutorial
Ajax tutorial
Kat Roque
 
Build Your Own CMS with Apache Sling
Build Your Own CMS with Apache SlingBuild Your Own CMS with Apache Sling
Build Your Own CMS with Apache Sling
Bob Paulin
 

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

Rich Portlet Development in uPortal
Rich Portlet Development in uPortalRich Portlet Development in uPortal
Rich Portlet Development in uPortal
 
Spine.js
Spine.jsSpine.js
Spine.js
 
RESTful Web Applications with Apache Sling
RESTful Web Applications with Apache SlingRESTful Web Applications with Apache Sling
RESTful Web Applications with Apache Sling
 
soft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.jssoft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.js
 
Universal JavaScript
Universal JavaScriptUniversal JavaScript
Universal JavaScript
 
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
 
jQuery Tips Tricks Trivia
jQuery Tips Tricks TriviajQuery Tips Tricks Trivia
jQuery Tips Tricks Trivia
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...
 
Front End Development for Back End Developers - UberConf 2017
Front End Development for Back End Developers - UberConf 2017Front End Development for Back End Developers - UberConf 2017
Front End Development for Back End Developers - UberConf 2017
 
Using and scaling Rack and Rack-based middleware
Using and scaling Rack and Rack-based middlewareUsing and scaling Rack and Rack-based middleware
Using and scaling Rack and Rack-based middleware
 
Azure F#unctions
Azure F#unctionsAzure F#unctions
Azure F#unctions
 
An Introduction to Tornado
An Introduction to TornadoAn Introduction to Tornado
An Introduction to Tornado
 
Play!ng with scala
Play!ng with scalaPlay!ng with scala
Play!ng with scala
 
vJUG - The JavaFX Ecosystem
vJUG - The JavaFX EcosystemvJUG - The JavaFX Ecosystem
vJUG - The JavaFX Ecosystem
 
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
 
GitBucket: The perfect Github clone by Scala
GitBucket: The perfect Github clone by ScalaGitBucket: The perfect Github clone by Scala
GitBucket: The perfect Github clone by Scala
 
Ajax tutorial
Ajax tutorialAjax tutorial
Ajax tutorial
 
5.node js
5.node js5.node js
5.node js
 
Express Presentation
Express PresentationExpress Presentation
Express Presentation
 
Build Your Own CMS with Apache Sling
Build Your Own CMS with Apache SlingBuild Your Own CMS with Apache Sling
Build Your Own CMS with Apache Sling
 

More from scalaconfjp

Scalaに対して意識の低いエンジニアがScalaで何したかの話, by 芸者東京エンターテインメント
Scalaに対して意識の低いエンジニアがScalaで何したかの話, by 芸者東京エンターテインメントScalaに対して意識の低いエンジニアがScalaで何したかの話, by 芸者東京エンターテインメント
Scalaに対して意識の低いエンジニアがScalaで何したかの話, by 芸者東京エンターテインメント
scalaconfjp
 

More from scalaconfjp (20)

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

Recently uploaded

CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
masabamasaba
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
mohitmore19
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
VictorSzoltysek
 

Recently uploaded (20)

%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
SHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions PresentationSHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions Presentation
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 

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
  • 22.
  • 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://xitrum@127.0.0.1:2551", "akka.tcp://xitrum@127.0.0.1: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