はじめに / android - kotlin,java併用 / ios - swift,objective-c併用...
TRANSCRIPT
-
PYXIS
IntelliJ
IncomingWebHooksScalaSlack
BeanstalkforDockerPlayFramework
PythonScala
GANMA!Cache
PlayFramework
AkkaSchedulerInstagramTumblr
scalaDDD
AndroidKotlin10
2
-
Scala
3
-
GANMA!
""
2015645
"GANMA!""MANT"
""GANMA!
PYXIS
FacebookTwitter
Playframework+Scala/AngularJS+TypeScriptDDD
4
-
Yahoo!JAPAN
GANMA!
http://ganma.jp
Playframework+Scala/AngularJS+TypeScript/iOS-Swift/Android-ScalaDDD
200DL2015/1212Twitter
MANT
http://mant.jp
10
LAMP/Android-Kotlin,Java/iOS-Swift,Objective-C
5
http://ganma.jphttp://mant.jp
-
""
ScalaCI
6
-
PYXIS
@kimutyam(1)PYXIS(2)PYXIS
()shardOracleMySQLGizzard(3)2
Shardingstrategiesofteninvolvetwotechniques:partitioningandreplication.
Wikipedia(4)
(Partition)
135DB130
MySQL5.6InnoDB
DDL
7PYXIS
-
CREATETABLE`Sample`(`sampleId`BIGINTNOTNULLCOMMENT'ID',`date`DATENOTNULLCOMMENT'',`name`VARCHAR(255)NOTNULLCOMMENT'',`hogeId`BIGINTNOTNULLCOMMENT'HogeID',PRIMARYKEY(`sampleId`,`date`),CONSTRAINT`sample_hogeId`FOREIGNKEY(`hogeId`)REFERENCES`Hoge`(`hogeId`)ONDELETECASCADEONUPDATECASCADE)ENGINE=InnoDBDEFAULTCHARACTERSET=utf8mb4COMMENT='';
MySQL
(5)
InnoDB(6)InnoDBMySQLInnoDBInnoDB
[]MySQL[]
((7)()RDBMSMySQL
8PYXIS
-
Gizzard
MySQL
RANGE(8)Sample.dateRANGE1
(9)
MySQL5.6.7NDB1024MySQL5.6.78192MySQLServer
11
CREATETABLE`Sample`(`sampleId`BIGINTNOTNULLCOMMENT'ID',`date`DATENOTNULLCOMMENT'',`name`VARCHAR(255)NOTNULLCOMMENT'',`hogeId`BIGINTNOTNULLCOMMENT'HogeID',PRIMARYKEY(`sampleId`,`date`),)ENGINE=InnoDBDEFAULTCHARACTERSET=utf8mb4COMMENT=''PARTITIONBYRANGE(`date`)(PARTITIONp20151001VALUESLESSTHAN('2015-11-01')COMMENT='~2015/10/31'ENGINE=InnoDB)
DDLMySQL
1SQL
9PYXIS
-
ALTERTABLEAdReportPARTITIONBYRANGE(`date`)(PARTITIONp20151001VALUESLESSTHAN('2015-10-01')ENGINE=InnoDB,PARTITIONp20151101VALUESLESSTHAN('2015-11-01')ENGINE=InnoDB,PARTITIONp20151201VALUESLESSTHAN('2015-12-01')ENGINE=InnoDB,PARTITIONp20160101VALUESLESSTHAN('2016-01-01')ENGINE=InnoDB,PARTITIONp20160201VALUESLESSTHAN('2016-02-01')ENGINE=InnoDB....);
ALTERTABLEALTERTABLE
RANGEALTERTABLEADDPARTITION
ALTERTABLEAdReportADDPARTITION(PARTITIONp20151202VALUESLESSTHAN('2020-12-02'));
InnoDBDDL(10)
RANGELISTADDPARTITIONDROPPARTITION
MAXVALUE
CREATETABLE`Sample`(`sampleId`BIGINTNOTNULLCOMMENT'ID',`date`DATENOTNULLCOMMENT'',`name`VARCHAR(255)NOTNULLCOMMENT'',`hogeId`BIGINTNOTNULLCOMMENT'HogeID',PRIMARYKEY(`sampleId`,`date`),)ENGINE=InnoDBDEFAULTCHARACTERSET=utf8mb4COMMENT=''PARTITIONBYRANGE(`date`)(PARTITIONp20151001VALUESLESSTHAN('2015-11-01')COMMENT='~2015/10/31'ENGINE=InnoDB,PARTITIONpmaxVALUESLESSTHANMAXVALUEENGINE=InnoDB)
ALTERTABLEAdReportREORGANIZEPARTITIONpmaxINTO(PARTITIONp20151101VALUESLESSTHAN('2015-12-01')COMMENT='~2015/11/30'ENGINE=InnoDB,PARTITIONpmaxVALUESLESSTHANMAXVALUEENGINE=InnoDB)
ALTERTABLE
10PYXIS
-
[]
RANGE()
11PYXIS
-
ScalaScalikeJDBC(11)Joda-Time(12)
RANGEVO
packagedb.partition
importorg.joda.time.LocalDateimportorg.joda.time.format.ISODateTimeFormat
traitPartitionRange{valpartitionName:PartitionRangeNamevalvalue:Any}
private[partition]caseclassPartitionRangeImpl(partitionName:PartitionRangeName,value:Any)extendsPartitionRange
objectPartitionRange{
/***Date1**jodaTime*/defofDateRangePerMonth(year:Int,month:Int):PartitionRange={valdate=newLocalDate(year,month,PartitionRangeConstant.BeginningOfMonthDay)
ofDateRangePerMonth(date)}
/***Date1*/defofDateRangePerMonth(date:LocalDate):PartitionRange={
//require(date.getDayOfMonth==PartitionRangeConstant.BeginningOfMonthDay)
PartitionRangeImpl(PartitionRangeName.ofDateRangePerMonth(date),date.plusMonths(1).toString(ISODateTimeFormat.date))}}
12PYXIS
-
RANGEVO
packagedb.partition
importorg.joda.time.LocalDateimportorg.joda.time.format.ISODateTimeFormat
traitPartitionRangeName{valvalue:String}
private[partition]caseclassPartitionRangeColumnsNameImpl(value:String)extendsPartitionRangeName
objectPartitionRangeName{privatevalpartitionNamePrefix="p"
defapply(value:String):PartitionRangeName={PartitionRangeColumnsNameImpl(value)}
private[partition]defofDateRangePerMonth(date:LocalDate):PartitionRangeName={
//require(date.getDayOfMonth==PartitionRangeConstant.BeginningOfMonthDay)
PartitionRangeColumnsNameImpl(partitionNamePrefix+date.toString(ISODateTimeFormat.basicDate))}}
packagedb.partition
importscalikejdbc._
traitPartitionProviderOnMySQLextendsFindFeaturePartitionOnMySQLwithAddFeaturePartitionOnMySQLwithDropFeaturePartitionOnMySQL
/*****trait*/traitFindFeaturePartitionOnMySQLextendsBasicPartitionHelper{
13PYXIS
-
deffindPartitionNameBy(partitionRangeName:PartitionRangeName)(implicits:DBSession):Option[PartitionRangeName]={SQL(s"""|SELECTPARTITION_NAME|FROMINFORMATION_SCHEMA.PARTITIONS|WHERETABLE_NAME='$tableName'ANDPARTITION_NAME='${partitionRangeName.value}';""".stripMargin).map{resultSet=>
PartitionRangeName(resultSet.string("PARTITION_NAME"))}.single().apply()}}
traitAddFeaturePartitionOnMySQLextendsBasicPartitionHelper{
defaddRangeColumnsPartition(range:PartitionRange)(implicits:DBSession):Int={SQL(s"""|ALTERTABLE${toBackQuoteString(tableName)}ADDPARTITION(|PARTITION${range.partitionName.value}VALUESLESSTHAN(?)|)""".stripMargin).bind(range.value).update().apply()}}
traitDropFeaturePartitionOnMySQLextendsBasicPartitionHelper{
defdropRangeColumnsPartition(partitionRangeName:PartitionRangeName)(implicits:DBSession):Int={dropPartition(partitionRangeName.value)}
defdropPartition(partitionName:String)(implicits:DBSession):Int={SQL(s"""|ALTERTABLE${toBackQuoteString(tableName)}DROPPARTITION$partitionName""".stripMargin).update().apply()}}
traitBasicPartitionHelper{protecteddeftableName:String
protecteddeftoBackQuoteString(self:String):String=s"`$self`"
14PYXIS
-
}
packagedb.partition
objectPartitionRangeConstant{/****/valBeginningOfMonthDay=1}
packagedb.partition.sample
importdb.partition.PartitionProviderOnMySQL
classSamplePartitionProviderextendsPartitionProviderOnMySQL{protecteddeftableName="Sample"}
15PYXIS
-
packagebatch
importorg.joda.time.LocalDateimportdb.partition.PartitionRangeimportdb.partition.sample.SamplePartitionProviderimportscalikejdbc.{AutoSession,DBSession}
objectSamplePartitionAddBatchextendsApp{implicitvals:DBSession=AutoSession
valnowDate=LocalDate.nowvalpartitionRange=PartitionRange.ofDateRangePerMonth(nowDate.getYear,nowDate.getMonthOfYear)
valprovider=newSamplePartitionProvider
if(provider.findPartitionNameBy(partitionRange.partitionName).isEmpty){provider.addRangeColumnsPartition(partitionRange)}}
16PYXIS
-
packagebatch
importorg.joda.time.LocalDateimportdb.partition.PartitionRangeimportdb.partition.sample.SamplePartitionProviderimportscalikejdbc.{AutoSession,DBSession}
objectSamplePartitionDeleteBatchextendsApp{implicitvals:DBSession=AutoSession
valtargetDate=LocalDate.now.minusYears(1)
valpartitionRange=PartitionRange.ofDateRangePerMonth(targetDate.getYear,targetDate.getMonthOfYear)
valprovider=newSamplePartitionProvider
provider.findPartitionNameBy(partitionRange.partitionName).map{_=>provider.dropRangeColumnsPartition(partitionRange.partitionName)}}
1Twitterhttps://twitter.com/kimutyam2PYXIShttp://pyxis-social.com/PYXIS3Twitterhttps://github.com/twitter/gizzard4https://ja.wikipedia.org/wiki/%E3%83%91%E3%83%BC%E3%83%86%E3%82%A3%E3%82%B7%E3%83%A7%E3%83%B35https://dev.mysql.com/doc/refman/5.6/ja/partitioning-pruning.html6https://dev.mysql.com/doc/refman/5.6/ja/partitioning-limitations-storage-engines.html7()MySQLhttps://songmu.github.io/slides/fk-night/#08https://dev.mysql.com/doc/refman/5.6/ja/partitioning-range.html9https://dev.mysql.com/doc/refman/5.6/ja/partitioning-limitations.html10https://dev.mysql.com/doc/refman/5.6/ja/online-ddl-partitioning.html11http://scalikejdbc.org/12http://www.joda.org/joda-time/
17PYXIS
https://twitter.com/kimutyamhttp://pyxis-social.com/https://github.com/twitter/gizzardhttps://ja.wikipedia.org/wiki/%E3%83%91%E3%83%BC%E3%83%86%E3%82%A3%E3%82%B7%E3%83%A7%E3%83%B3https://dev.mysql.com/doc/refman/5.6/ja/partitioning-pruning.htmlhttps://dev.mysql.com/doc/refman/5.6/ja/partitioning-limitations-storage-engines.htmlhttps://songmu.github.io/slides/fk-night/#0https://dev.mysql.com/doc/refman/5.6/ja/partitioning-range.htmlhttps://dev.mysql.com/doc/refman/5.6/ja/partitioning-limitations.htmlhttps://dev.mysql.com/doc/refman/5.6/ja/online-ddl-partitioning.htmlhttp://scalikejdbc.org/http://www.joda.org/joda-time/
-
IntelliJ
ScalaIntelliJIDEAIDEIntelliJIntelliJIntelliJIntelliJIntelliJGitScala
ScalaOSMacIntelliJ14.1.5
Command+Alt+
Ctrl+G
()
Command+/
Alt+Enter
IntelliJ
18IntelliJ
-
Command+Shift+V
IntelliJ
Alt+Shift+
Command+Shift+F
Shift2
Command+F4
Command+B
Command+D
Command+Y
Command+Alt+L
Command+E
19IntelliJ
-
Command+Alt+B
Ctrl+H
IntelliJHierarchy
Alt+Shift+H
IntelliJHierarchy
Command+WCommand+Shift+W
Command+G
()
Command+Shift+/
Command+Shift+
/
Command+1
/
Command+7
Command+
20IntelliJ
-
ifwhilefor
Command+Alt+T
forif
Shift+Enter
Command+Alt+N
[]
Command+Alt+F7
Command+Alt+M
Command+Alt+F
UML
Command+Alt+U
UML
UML
Command+Alt+Shift+T
21IntelliJ
-
Command+
Alt+
->[Annotate]
Git
[Annotate]
->[Rollback]
Diff
->[Git]->[ShowHistory]->
Git
->[Local
22IntelliJ
-
History]->[ShowHistory]
IntelliJIDEA-http://qiita.com/yoppe/items/f7cbeb825c071691d3f2IntelliJIDEAGit-http://qiita.com/yoppe/items/fd03607d4d4f191d32dd
23IntelliJ
http://qiita.com/yoppe/items/f7cbeb825c071691d3f2http://qiita.com/yoppe/items/fd03607d4d4f191d32dd
-
IncomingWebHooksScalaSlack
RedmineBitbucketWebHookWebHook=ScalaSlackIncomingWebHooks
IncomingWebHooks
IncomingWebHooksJsonURLSlackSlack
Slack
Slack
1. IncomingWebHookshttps://[].slack.com/services/new/incoming-webhook
2. IncomingWebHookshttps://[].slack.com/services#serviceIncomingWebHookswebhookURL
Slack
Slack
curl-XPOST--data-urlencode'payload={"text":"helloworld"}'https://(webhookurl)
ScalaSlack
SlackScala@Slacksbt
URLJsonbuild.sbthttpJson
build.sbt
24IncomingWebHooksScalaSlack
https://[].slack.com/services/new/incoming-webhookhttps://[].slack.com/services#service
-
libraryDependencies+="com.typesafe.play"%"play-ws_2.11"%"2.4.3"libraryDependencies+="com.typesafe.play"%"play-json_2.11"%"2.4.3"
SlackJson
importplay.api.libs.json._
/****@paramlink_names@*@paramattachments*/caseclassMessage(link_names:Int,attachments:Seq[Attachment])
/****@paramfallback*@paramcolor(?)good,warning,danger*@paramtitle*@paramtext*/caseclassAttachment(fallback:String,color:String,title:String,text:String)
/***Json*/objectMessage{implicitvalattachmentWrite=Json.writes[Attachment]implicitvalmessageWrite=Json.writes[Message]}
link_namescolorEnum
25IncomingWebHooksScalaSlack
-
/***@MentionEnum*/sealedabstractclassMention(valvalue:Int)objectMention{caseobjectTrueextendsMention(1)caseobjectFalseextendsMention(0)}
/***Enum*/sealedabstractclassColor(valvalue:String)objectColor{caseobjectGoodextendsColor("good")caseobjectWarningextendsColor("warning")caseobjectDangerextendsColor("danger")}
URL
26IncomingWebHooksScalaSlack
-
Slack
SlackwebHookURLSlack2
importplay.api.libs.json._importplay.api.libs.ws._importplay.api.libs.ws.ning.NingWSClientimportscala.concurrent.duration._importscala.concurrent.{Await,Future}
//SlackvalwebHookURL="https://hooks.slack.com/services/????"
valmessage=Message(link_names=Mention.True.value,attachments=Seq(Attachment(fallback="@hoge",color=Color.Good.value,title="",text="@hoge")))
valdata=Json.toJson(message)
defusing[A](client:NingWSClient)(f:NingWSClient=>A):A={try{f(client)
}finally{client.close()}}
using[WSResponse](NingWSClient()){client=>valfutureResponse:Future[WSResponse]=client.url(webHookURL).post(data)Await.result(futureResponse,Duration.Inf)}
27IncomingWebHooksScalaSlack
-
IncomingWebHooksSlack
URL
https://api.slack.com/incoming-webhookshttps://api.slack.com/docs/formattinghttps://api.slack.com/docs/attachments
28IncomingWebHooksScalaSlack
https://api.slack.com/incoming-webhookshttps://api.slack.com/docs/formattinghttps://api.slack.com/docs/attachments
-
BeanstalkforDockerPlayFramework
BeanstalkforDockerPlayFramework
Docker1.8AWSCloudformation
sfn1
sparkle_formation2
AWSElasticBeanstalkforDocker()3
DockerHub(EC2build)PlayFramework2.4
key_pairsample_project~/.sshebssh
29BeanstalkforDockerPlayFramework
-
1. BeanstalkwithCloudformation2. PlayFramework3. Docker4. Docker5. (awsebcli)6. Beanstalk
CloudformationBeanstalk
CloudformationBeanstalkforDocker
1.
jsonsfnsparkle_formationgemRuby
sparkle_formation
##VPC#InternetGateway
30BeanstalkforDockerPlayFramework
-
#RouteTable#Subnet#SecurityGroup#BeanstalkforDocker
SparkleFormation.new(:SampleProjectTemplate)doset!('AWSTemplateFormatVersion','2010-09-09')description"SampleProject"
parametersdoprojectdodescription'ProjectName'type'String'default'sample-project'endend##########################VPC#########################resources(:Vpc)dotype'AWS::EC2::VPC'propertiesdocidr_block'10.0.0.0/16'endend
##########################InternetGateway#########################resources(:InternetGateway)dotype'AWS::EC2::InternetGateway'propertiesdotags_array(->{
key'Project'valueref!(:Project)})
endend
resources(:AttachGateway)dotype'AWS::EC2::VPCGatewayAttachment'propertiesdointernet_gateway_idref!(:internet_gateway)vpc_idref!(:vpc)endend
31BeanstalkforDockerPlayFramework
-
##########################RouteTable#########################resources(:PublicRouteTable)dotype'AWS::EC2::RouteTable'propertiesdovpc_idref!(:Vpc)endend
##RouteforInternetresources(:PublicRoute)dotype'AWS::EC2::Route'propertiesdodestination_cidr_block'0.0.0.0/0'gateway_idref!(:InternetGateway)route_table_idref!(:PublicRouteTable)endend
##########################Subnet#########################resources(:PublicSubnet)dotype'AWS::EC2::Subnet'propertiesdoavailability_zone'ap-northeast-1b'cidr_block'10.0.0.0/24'map_public_ip_on_launch'true'vpc_idref!(:Vpc)endend
resources(:PublicSubnetRouteTableAssociation)dotype'AWS::EC2::SubnetRouteTableAssociation'propertiesdoroute_table_idref!(:PublicRouteTable)subnet_idref!(:PublicSubnet)endend
##########################SecurityGroup#########################resources(:PublicSecurityGroup)dotype'AWS::EC2::SecurityGroup'propertiesdogroup_description'PublicSecurityGroup'
32BeanstalkforDockerPlayFramework
-
vpc_idref!(:Vpc)endend
resources(:PublicSecurityGroupIngress1)dotype'AWS::EC2::SecurityGroupIngress'propertiesdosource_security_group_idref!(:PublicSecurityGroup)from_port0to_port65535ip_protocol-1group_idref!(:PublicSecurityGroup)endend
resources(:PublicSecurityGroupEgress1)dotype'AWS::EC2::SecurityGroupEgress'propertiesdocidr_ip'0.0.0.0/0'from_port0to_port65535ip_protocol-1group_idref!(:PublicSecurityGroup)endend
resources(:ServerRole)dotype'AWS::IAM::Role'propertiesdoassume_role_policy_documentdostatement_array(->{
effect'Allow'principaldoservice_array(
'ec2.amazonaws.com')
endaction['sts:AssumeRole']})
endpath'/'endend
resources(:ServerPolicy)dotype'AWS::IAM::Policy'depends_on"ServerRole"
33BeanstalkforDockerPlayFramework
-
propertiesdopolicy_name'ServerRole'policy_documentdostatement_array(->{
effect'Allow'not_action'iam:*'resource'*'})
endroles_array(
ref!(:ServerRole))
endendresources(:ServerInstanceProfile)dotype'AWS::IAM::InstanceProfile'depends_on"ServerRole"propertiesdopath'/'roles_array(
ref!(:ServerRole))
endend
resources(:SampleProjectApplicatioin)dotype'AWS::ElasticBeanstalk::Application'propertiesdodescription'SampleProjectApplication'application_name'SampleProject'endend
resources(:SampleProjectApplicatioinEnvironment)dotype'AWS::ElasticBeanstalk::Environment'depends_on["SampleProjectApplicatioin","ServerRole"]propertiesdoapplication_nameref!(:SampleProjectApplicatioin)description"SampleProjectforStaging"solution_stack_name'64bitAmazonLinux2015.03v2.0.2runningDocker1.7.1'environment_name'SampleProjectStaging'CNAMEPrefix'sample-projet-staging'tierdoname'WebServer'type'Standard'end
34BeanstalkforDockerPlayFramework
-
option_settings_array(->{
namespace'aws:autoscaling:launchconfiguration'option_name'SSHSourceRestriction'value"tcp,22,22,113.34.78.168/32"},->{
namespace'aws:autoscaling:launchconfiguration'option_name'SecurityGroups'valueref!(:PublicSecurityGroup)},->{
namespace'aws:autoscaling:launchconfiguration'option_name'EC2KeyName'value'sample_project'},->{
namespace'aws:ec2:vpc'option_name'VPCId'valueref!(:Vpc)},->{
namespace'aws:ec2:vpc'option_name'AssociatePublicIpAddress'value"true"},->{
namespace'aws:ec2:vpc'option_name'Subnets'valueref!(:PublicSubnet)},->{
namespace'aws:ec2:vpc'option_name'ELBSubnets'valueref!(:PublicSubnet)},->{
namespace'aws:autoscaling:launchconfiguration'option_name'InstanceType'value't2.micro'})
endendend
35BeanstalkforDockerPlayFramework
-
2.stack
sfnstack
$bundleexecsfncreatesample-project-Beanstalk-btemplates/-ftemplates/Beanstalks.json-P
[Sfn]:SparkleFormation:create[Sfn]:->Name:sample-project[Sfn]:Stackruntimeparameters:[Sfn]:Project[sample-project]:
[Sfn]:EventsforStack:sample-projectTimeResourceLogicalIdResourceStatusResourceStatusReason
2015-11-2703:01:36UTCsample-projectCREATE_IN_PROGRESSUserInitiated
2015-11-2703:01:40UTCVpcCREATE_IN_PROGRESS2015-11-2703:01:40UTCInternetGatewayCREATE_IN_PROGRESS2015-11-2703:01:40UTCSampleProjectApplicatioinCREATE_IN_PROGRESS
(snip)
2015-11-2703:04:08UTCServerInstanceProfileCREATE_COMPLETE2015-11-2703:08:32UTCSampleProjectApplicatioinEnvironmentCREATE_COMPLETE2015-11-2703:08:34UTCsample-projectCREATE_COMPLETE[Sfn]:Stackcreatecomplete:SUCCESS[Sfn]:Stackdescriptionofsample-project:
[Sfn]:Outputsforstack:sample-project[Sfn]:Nooutputsfound
3.Beanstalk
BeanstalkURLcname_prefixsample-projet-staginghttp://sample-projet-staging.elasticbeanstalk.com/URL
36BeanstalkforDockerPlayFramework
http://sample-projet-staging.elasticbeanstalk.com/
-
1.
PlayFramework
#$./activatornewsample-projectplay-scala
$cdsample-project/
#$vimapp/views/main.scala.html@(title:String)(content:Html)
@title
2016ScalaMaturiSampleProject
#$./activatorrun
2.buildjar
SBTassemblyplugin4jar5
37BeanstalkforDockerPlayFramework
-
$vimproject/plugins.sbt
#addSbtPlugin("com.eed3si9n"%"sbt-assembly"%"0.14.1")
$vimbuild.sbt
#importAssemblyKeys._
assemblySettings
mainClassinassembly:=Some("play.core.server.NettyServer")
fullClasspathinassembly+=Attributed.blank(PlayKeys.playPackageAssets.value)
#java.lang.RuntimeException:deduplicate:differentfilecontentsfoundinthe#following:mergeStrategyinassemblyMergeStrategy.firstcasex=>old(x)}}
#build$./activatorassembly[info]Loadingprojectdefinitionfrom/Users/t_saeki/Develop/sample-project/project
[info]Setcurrentprojecttosample-project(inbuildfile:/Users/t_saeki/Develop/sample-project/)
[info]Includingfromcache:config-1.3.0.jar[info]Includingfromcache:bonecp-0.8.0.RELEASE.jar
(snip)
[info]Assemblyuptodate:/Users/t_saeki/Develop/sample-project/target/scala-2.11/sample-project-assembly-1.0-SNAPSHOT.jar[success]Totaltime:6s,completed2015/11/2618:24:05
##http://localhost:9000$java-jartarget/scala-2.11/sample-project-assembly-1.0-SNAPSHOT.jarNettyServer.mainisdeprecated.PleasestartyourPlayserverwiththe${ProdServerStart.getClass.getName}.main.[info]-play.api.Play-Applicationstarted(Prod)
[info]-play.core.server.NettyServer-ListeningforHTTPon/0:0:0:0:0:0:0:0:9000
38BeanstalkforDockerPlayFramework
-
Docker
Docker
1.Docker
6docker-machinedocker-compose
2.Dockerfile
Dockerfile7java8
$vimDockerfile
FROMjava:8
RUNmkdir/opt/sample-project
COPYtarget/scala-2.11/sample-project-assembly-1.0-SNAPSHOT.jar/opt/sample-project/
EXPOSE9000CMD["java","-jar","/opt/sample-project/sample-project-assembly-1.0-SNAPSHOT.jar"]
39BeanstalkforDockerPlayFramework
-
3.Dockerbuildrun
DockerbuildDockerDocker9
$dockerbuild-ttsaeki/sample-project.
SendingbuildcontexttoDockerdaemon162MBStep0:FROMjava:8--->36621d4ab8e3Step1:RUNmkdir/opt/sample-project--->Usingcache--->b5e800d8653f
Step2:COPYtarget/scala-2.11/sample-project-assembly-1.0-SNAPSHOT.jar/opt/sample-project/--->Usingcache
--->74ec351a9034Step3:EXPOSE9000--->Usingcache--->fd1947bdc2e5
Step4:CMDjava-jar/opt/sample-project/sample-project-assembly-1.0-SNAPSHOT.jar--->Usingcache
--->0a8f13d586ceSuccessfullybuilt0a8f13d586ce
##http://192.168.99.100:9000$Dockerrun-it--rm-p9000:9000tsaeki/sample-projectNettyServer.mainisdeprecated.PleasestartyourPlayserverwiththe${ProdServerStart.getClass.getName}.main.[info]-play.api.Play-Applicationstarted(Prod)
[info]-play.core.server.NettyServer-ListeningforHTTPon/0:0:0:0:0:0:0:0:9000
40BeanstalkforDockerPlayFramework
-
4.Dockerrun.aws.json
BeanstalkDockerDockerrun.aws.json10
{
"AWSEBDockerrunVersion":"1","Image":{"Name":"tsaeki/sample-project","Update":"true"},
"Ports":[{
"ContainerPort":"9000"}],
"Volumes":[],"Logging":""}
Beanstalk
1.EBCLIforMac
EBCLI1112brew2.xpip
$sudopipinstallawsebcli
2.EBCLI
ebinitRegionApplication
41BeanstalkforDockerPlayFramework
-
$ebinit
Selectadefaultregion
1)us-east-1:USEast(N.Virginia)2)us-west-1:USWest(N.California)3)us-west-2:USWest(Oregon)4)eu-west-1:EU(Ireland)5)eu-central-1:EU(Frankfurt)6)ap-southeast-1:AsiaPacific(Singapore)7)ap-southeast-2:AsiaPacific(Sydney)8)ap-northeast-1:AsiaPacific(Tokyo)9)sa-east-1:SouthAmerica(SaoPaulo)10)cn-north-1:China(Beijing)(defaultis3):8
Selectanapplicationtouse
1)SampleProject2)[CreatenewApplication](defaultis2):1
ItappearsyouareusingDocker.Isthiscorrect?(y/n):y
Selectaplatformversion.
1)Docker1.7.12)Docker1.6.2(defaultis1):1DoyouwanttosetupSSHforyourinstances?(y/n):y
Selectakeypair.
1)sample_project2)[CreatenewKeyPair](defaultis2):sample_project
ebinit-i
42BeanstalkforDockerPlayFramework
-
3.
#Environmentlist$eblist*SampleProjectStaging
$ebdeploySampleProjectStaging
Creatingapplicationversionarchive"app-151127_133042".Uploading:[##################################################]100%Done...INFO:Environmentupdateisstarting.INFO:TheenvironmentdoesnothaveanIAMinstanceprofileassociatedwithit.ToimprovedeploymentspeedpleaseassociateanIAMinstanceprofilewiththeenvironment.INFO:Deployingnewversiontoinstance(s).
INFO:Successfullypulledjava:8INFO:Successfullybuiltaws_Beanstalk/staging-appINFO:Dockercontainerd72d6432f5f8isrunningaws_Beanstalk/current-app.INFO:NewapplicationversionwasdeployedtorunningEC2instances.INFO:Environmentupdatecompletedsuccessfully.
#SampleProjectStaging(*)
4.
http://sample-projet-staging.elasticbeanstalk.com/
(mackerel)
mackerel13mackerel
mackerel.ebextensions14Dockerjvmhttpjolokia15mackerelapikey
1.jolokia
DockerJVMjolokiahttpJVM16
#jolokiajar$curl-Ohttps://repo1.maven.org/maven2/org/jolokia/jolokia-jvm/1.3.2/jolokia-jvm-1.3.2-agent.jar
43BeanstalkforDockerPlayFramework
http://sample-projet-staging.elasticbeanstalk.com/
-
#jarjolokiaagent$vimDockerfile
FROMjava:8
RUNmkdir/opt/sample-project
COPYtarget/scala-2.11/sample-project-assembly-1.0-SNAPSHOT.jar/opt/sample-project/
#jarCOPYjolokia-jvm-1.3.2-agent.jar/opt/sample-project/
#8778EXPOSE90008778
#"-javaagent:/opt/sample-project/jolokia-jvm-1.3.2-agent.jar=port=8778,host=0.0#.0.0"CMD["java","-javaagent:/opt/sample-project/jolokia-jvm-1.3.2-agent.jar=port=8778,host=0.0.0.0","-jar","/opt/sample-project/sample-project-assembly-1.0-SNAPSHOT.jar"]
#Dockerbuild,run$Dockerbuild-ttsaeki/sample-project.
#8778-p8778:8778$Dockerrun-it--rm-p9000:9000-p8778:8778tsaseki/sample-project
#$curl-shttp://192.168.99.100:8778/jolokia/|jq.{
"request":{"type":"version"},
"value":{"agent":"1.3.2","protocol":"7.2","config":{"maxDepth":"15","discoveryEnabled":"true","maxCollectionSize":"0","agentId":"172.17.0.3-1-5e2de80c-jvm","debug":"false","agentType":"jvm","historyMaxEntries":"10","agentContext":"/jolokia","maxObjects":"0","debugMaxEntries":"100"},
"info":{}},
"timestamp":1448603006,
44BeanstalkforDockerPlayFramework
-
"status":200}
2..ebextensionsmackerelplugin
$mkdir.ebextensions
$vim.ebextensions/01_install_mackerel.configfiles:/etc/mackerel-agent/mackerel-agent.conf:
mode:"00644"owner:rootgroup:rootencoding:plaincontent:|
apikey=""include="/etc/mackerel-agent/conf.d/*.conf"[plugin.metrics.Docker]
command="/usr/local/bin/mackerel-plugin-Docker"
#IP/opt/elasticBeanstalk/hooks/appdeploy/post/99_setup-jolokia-config-for-mackerel.sh:
mode:"00755"owner:rootgroup:rootencoding:plaincontent:|
#!/bin/sh#setupjolokiamonotoringDocker_IP=$(dockerinspect--format'{{.NetworkSettings.IPAddress}}'$(dockerps-q-l))MACKEREL_HOSTID=$(cat/var/lib/mackerel-agent/id)cat>/etc/mackerel-agent/conf.d/jolokia.conf
-
require'mackerel/client'require'socket'require'uri'require'net/http'require'json'
MACKEREL_KEY='etEwwFKkZJW6goWf8Tqmx7awjz5aPucZC46xQm92WDHH'
monitoring_ip=ARGV[0]host_id=ARGV[1]base_url="https://mackerel.io//api/v0/tsdb"end_time=Time.now
uri=URI.parse("http://#{monitoring_ip}:8778/jolokia/read/java.lang:type=Memory/HeapMemoryUsage")get_json_memory=Net::HTTP.get(uri)get_heep_memory=JSON.load(get_json_memory)
metrics=[
{'hostId'=>host_id,'name'=>"HeapMemoryUsage.init",'time'=>end_time.to_i,'value'=>get_heep_memory['value']['init']},{'hostId'=>host_id,'name'=>"HeapMemoryUsage.committed",'time'=>end_time.to_i,'value'=>get_heep_memory['value']['committed']},{'hostId'=>host_id,'name'=>"HeapMemoryUsage.max",'time'=>end_time.to_i,'value'=>get_heep_memory['value']['max']},{'hostId'=>host_id,'name'=>"HeapMemoryUsage.used",'time'=>end_time.to_i,'value'=>get_heep_memory['value']['used']},]
@mackerel=Mackerel::Client.new(:mackerel_api_key=>MACKEREL_KEY)[email protected]_metrics(metrics)
commands:
00_enable_sudo:command:sed-i's/requiretty/!requiretty/'/etc/sudoers01_setup_yumrepo_for_mackerel:command:curl-fsSLhttps://mackerel.io/assets/files/scripts/setup-yum.sh|sh
02_install_mackerel_rpm_packages:command:yuminstall-ymackerel-agentmackerel-agent-plugins03_install_mackerel_gem_packages:command:/usr/bin/geminstallmackerel-client04_create_mackerel_dir:command:mkdir-p/etc/mackerel-agent/conf.d
container_commands:start_mackerel_agent:
command:"/etc/init.d/mackerel-agentrestart"
46BeanstalkforDockerPlayFramework
-
3..ebextentions
$ebdeploySampleProjectStaging$ebdeploySampleProjectStaging
Creatingapplicationversionarchive"app-151127_162030".Uploading:[##################################################]100%Done...INFO:Environmentupdateisstarting.INFO:Deployingnewversiontoinstance(s).
INFO:Successfullypulledjava:8INFO:Successfullybuiltaws_Beanstalk/staging-app
INFO:Dockercontainer1c4d16bd9b12isrunningaws_Beanstalk/current-app.INFO:NewapplicationversionwasdeployedtorunningEC2instances.INFO:Environmentupdatecompletedsuccessfully.
4.mackerel
01_prefix/opt/elasticBeanstalk/hooks/appdeploy/post/
DockerBeanstalkmackerelBeanstalkDocker
1https://github.com/sparkleformation/sfn
47BeanstalkforDockerPlayFramework
https://github.com/sparkleformation/sfn
-
2https://github.com/sparkleformation/sparkle_formation3http://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/docker-singlecontainer-deploy.html4https://github.com/sbt/sbt-assembly5https://www.playframework.com/documentation/ja/2.3.x/ProductionDist6https://docs.docker.com/v1.8/installation/mac/7https://docs.docker.com/v1.8/reference/builder/8https://hub.docker.com/_/java/9https://docs.docker.com/v1.8/reference/commandline/cli/10
http://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/create_deploy_docker_image.html#create_deploy_docker_image_dockerrun11http://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/eb-cli3.html12http://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/eb-cli3-install.html13https://mackerel.io/ja/14http://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/ebextensions.html15https://jolokia.org/16Play2JVMJolokiahttp://blog.cloudpack.jp/2014/11/20/monitor-jvm-running-play-framework-2-with-jolokia/
48BeanstalkforDockerPlayFramework
https://github.com/sparkleformation/sparkle_formationhttp://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/docker-singlecontainer-deploy.htmlhttps://github.com/sbt/sbt-assemblyhttps://www.playframework.com/documentation/ja/2.3.x/ProductionDisthttps://docs.docker.com/v1.8/installation/mac/https://docs.docker.com/v1.8/reference/builder/https://hub.docker.com/_/java/https://docs.docker.com/v1.8/reference/commandline/cli/http://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/create_deploy_docker_image.html#create_deploy_docker_image_dockerrunhttp://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/eb-cli3.htmlhttp://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/eb-cli3-install.htmlhttps://mackerel.io/ja/http://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/ebextensions.htmlhttps://jolokia.org/http://blog.cloudpack.jp/2014/11/20/monitor-jvm-running-play-framework-2-with-jolokia/
-
PythonScala
2015PythonWebPYXISForFacebookScalaScalaScala
3
(@OE_uia)ScalaScala&PlayScala&Play&(DDD)
(@OE_uia)Scala
@OE_uia1ScalaScalasbtspecs2Scala
1. 2. ()REPL3. 4. @OE_uia
PythonScala
PythonScala
ScalaPythonScalavalval
Python
49PythonScala
-
fromabcimportABCMeta,abstractmethodclassAbstractClass(object):__metaclass__=ABCMeta#
@abstractmethod#defsample_method(self):print"abstract"
@abstractmethod
abstractclassAbstractClass(){defsampleMethod():Unit={println("abstract")}}
Scalaabstractclass
mapPython
>>>result=range(0,10)>>>result=map(lambdax:x+1,result)>>>result[1,2,3,4,5,6,7,8,9,10]
Scala
scala>(0until10).map(f=>f+1).toListres4:List[Int]=List(1,2,3,4,5,6,7,8,9,10)
Scala
Scala
50PythonScala
-
Scala
Scala
Scala&Play
ScalaScala&PlayWebPlayFrameworkSpecs2
ScrumScrumPOPOSLSLPOSL
1.
2. POSL
1. 2. 3. 4. 5. 6.
51PythonScala
-
SQL
//defindex=Action{implicitvalconnection=DB.getConnection()valsql=SQL("""SELECTMessage.id,detail,emailFROMUserJOINMessage|ONUser.id=user_idORDERBYMessage.idASC""".stripMargin)
valuserSeq=sql().map(row=>row[String]("detail")->row[String]("email")).toSeq
Ok(views.html.index(userSeq))}
PlayFrameworkSpecs2Web
Scala&Play&(DDD)
2
scala-dddbase1
52PythonScala
-
1. 2.
3. 2.
1. 2. 3. 4.
1.
PO
PO
or
53PythonScala
-
2.
ID
3.
2resolveBy
54PythonScala
-
4.
/****id:ID*message:*email:*dateTime:*/caseclassPostingID(value:String)extendsIdentifier[String]
traitPostingextendsEntity[PostingID]{
validentifier:PostingIDvalmessage:Stringvalemail:StringvaldateTime:String
}
/****email:*password:*createPosting:*/
caseclassLoginUserEmail(value:String)extendsIdentifier[String]
traitLoginUserextendsEntity[LoginUserEmail]{
validentifier:LoginUserEmailvalpassword:String
}
55PythonScala
-
//private[loginUser]caseclassLoginUserImp(identifier:LoginUserEmail,password:String)extendsLoginUser{
defcreatePostingEntity(message:String):Posting={Posting(PostingID(java.util.UUID.randomUUID.toString),message,identifier.value,
DateTime.now.toString)}}
/***AbstractRepository*store(entity:E):*resolveBy(identifier:ID):*/abstractclassAbstractRepositoryOnAnorm[ID
-
}
/***LoginUserRepositoryOnAnorm*/classLoginUserRepositoryOnAnormextendsAbstractRepositoryOnAnorm[LoginUserEmail,LoginUser]
3
Scala
1
DDDPO
57PythonScala
-
Scala
3Scala
ScalaScala
58PythonScala
-
GANMA!Cache
GANMA!MemcacheCacheDDDDI
CacheCache
CacheCache
GANMA!Cache3
CacheCacheCache
GANMA!(DDD)DDD"Model""Controller"
CacheDBCache
MethodCacheCacheCache
//classCatsTable{defget(catName:String):Option[Row]=???//1
59GANMA!Cache
-
deflist(offset:Int=0):Seq[Row]=???
defstore(cat:RawData):Unit=???
//}
//CacheobjectCache{
defmakeKey(tag:String,args:Any*):String=???
defgetOrElseUpdate[A:ClassTag](key:String,op:=>A,expire:Int=300):A=???
defclear(key:String):Unit=???
//}
//CacheclassCachedCatsTableextendsCatsTable{
privatevalclassName=getClass.getName
overridedefget(catName:String):Option[Row]={valkey=Cache.makeKey(className+".get",catName)Cache.getOrElseUpdate(key,super.get(catName))}
overridedeflist(offset:Int=0):Seq[Row]={offsetmatch{case0=>//2valkey=Cache.makeKey(className+".list")Cache.getOrElseUpdate(key,super.list(offset))
case_=>super.list(offset)}}
overridedefstore(cat:RawData)={super.store(cat)clearCache(cat)}
privatedefclearCache(cat:RawData):Unit={//3Cache.makeKey(className+".get",cat.name)Cache.makeKey(className+".list")}}
60GANMA!Cache
-
1-Future2-offset=0Cache3-MemcacheRedisHash
CacheDDDEntityIDRepositoryCache
GANMA!
1. DI(GANMA!http://qiita.com/takezoux2@github/items/a2b607cdfedd21974687)
2. DI1HTTP3. Cache
4.
61GANMA!Cache
http://qiita.com/takezoux2@github/items/a2b607cdfedd21974687
-
Cache
classInstanceCachedCatsRepositoryextendsCatsRepository{
importscala.collection._importscala.collection.convert.decorateAsScala._
privateobjectcache{
valget:concurrent.Map[String,Option[Cat]]=newConcurrentHashMap[String,Option[Cat]]().asScalavallist:concurrent.Map[Int,List[Cat]]=newConcurrentHashMap[Int,List[Cat]].asScala
defclear():Unit={get.clear()list.clear()}}
overridedefget(catName:String):Option[Cat]=cache.get.getOrElseUpdate(catName,super.get(catName))
overridedeflist(offset:Int=0):List[Cat]=cache.list.getOrElseUpdate(offset,super.list(offset))
overridedefstore(cat:Cat):Unit={super.store(cat)cache.clear()}}
62GANMA!Cache
-
DI
traitCatMomictureServiceDepends{implicitlazyvalcatRepository=newInstanceCachedCatsRepository}
classDomainInjectorextendsCatMomictureServiceDepends
classCatMomictureService(implicitdepends:CatMomictureServiceDepends){
importdepends._
defmomi(catName:String):Unit={catRepository.get(catName)foreachdoMomicture}
privatedefdoMomicture(cat:Cat)=???
}
classCatsController(implicitinjector:DomainInjector=newDomainInjector)extendsController{
importinjector._
defmomi(catName:String)=Action{
catRepository.get(catName)foreachdoSomething
valservice=newCatMomictureServiceservice.momi(catName)
Ok("")}
Cache
Cache(htmljson)
63GANMA!Cache
-
MapGoogleGuavaCacheBuilderExpireMap
GANMA!
64GANMA!Cache
https://github.com/google/guava
-
PlayFramework
2
PlayScala+DDD
4
projectRootapplicationdomaininfrastructure
PlayControllerViewJSONRESTAPIUIPlayViewAndroidiOSWebUI
PlayPlay
65PlayFramework
-
build.sbt
/****/lazyvalroot=(projectinfile(".")).aggregate(application,domain,infrastructure)
/*****Play*/lazyvalapplication=Project(id="application",base=file("application")).dependsOn(domain,infrastructure).enablePlugins(
PlayScala)
/******/lazyvaldomain=Project(id="domain",base=file("domain")).dependsOn(infrastructure).settings(
scalaSourceinCompile:=baseDirectory.value/"src"/"main"/"scala",scalaSourceinTest:=baseDirectory.value/"src"/"test"/"scala")
/****/lazyvalinfrastructure=Project(
66PlayFramework
-
id="infrastructure",base=file("infrastructure")).settings(
scalaSourceinCompile:=baseDirectory.value/"src"/"main"/"scala",scalaSourceinTest:=baseDirectory.value/"src"/"test"/"scala")
projectRootapplicationapp/conf/public/target/domainsrc/target/infrastructuresrc/target/project/target/activatorbuild.sbt
$./activator"projectapplication"run#./activator"application/run"
$./activator[projectRoot]projectapplication[application]run
1. High-levelmodulesshouldnotdependonlow-levelmodules.Bothshoulddependonabstractions.()
2. Abstractionsshouldnotdependondetails.Detailsshoulddependonabstractions.()
DIP(DependencyInversionPrinciple)
67PlayFramework
-
DIPDDD
Play
ScalaPlayFrameworkDDD
68PlayFramework
-
(Ports&Adapters)22
Hexagonalarchitecturehttp://alistair.cockburn.us/Hexagonal+architecture
1()(4)
69
http://alistair.cockburn.us/Hexagonal+architecture
-
2RESTAPIWEB
2
WebServicePlayframework2.4Database
70
-
SBTSBTrootroot
build.sbt
name:="""hexagonal_sample"""
lazyvalcommonSettings=Seq(scalaVersion:="2.11.7")
lazyvalroot=(projectinfile("root")).enablePlugins(PlayScala).dependsOn(portWebService,portDatabase).settings(commonSettings).settings(
routesGenerator:=InjectedRoutesGenerator)
lazyvalportWebService=Project(id="port-webservice",base=file("port/webservice")).dependsOn(application).settings(commonSettings)
.settings(/*Port*/)
lazyvalportDatabase=Project(id="port-database",base=file("port/database")).dependsOn(application).settings(commonSettings)
.settings(/*Port*/)
lazyvalapplication=Project(id="application",base=file("application")).enablePlugins(PlayScala).settings(commonSettings)
.settings(/*Application*/)
71
-
packagesample.application.user
caseclassUserId(value:Long)
classUser(valid:UserId,valname:String,valpassword:String)
traitUserRepository{
defresolveBy(id:UserId):Option[User]
defstore(user:User):Unit}
classUserRegistrationService(userRepository:UserRepository){
defregister(name:String,password:String):User={valuser=createNewUser(name,password)userRepository.store(user)user}
privatedefcreateNewUser(name:String,password:String):User={//???}}
72
-
Database
packagesample.port.database.rdbmsadapter.user
importsample.application.user.{UserRepository,User,UserId}
classUserRepositoryOnRDBMSextendsUserRepository{
overridedefresolveBy(id:UserId):Option[User]={//DB???}
overridedefstore(user:User):Unit={//DB???}}
WebService
RESTAPI
packagesample.port.webservice.restadapter.user
importcom.google.inject.Injectimportplay.api.data.Formsimportplay.api.data.Formimportplay.api.libs.json._importplay.api.mvc._importsample.application.user._
caseclassUserDTO(id:Long,name:String)
objectUserDTO{
deffromModel(user:User):UserDTO=UserDTO(user.id.value,user.name)
implicitvaljsonWrites=Json.writes[UserDTO]}
caseclassUserCreateForm(name:String,password:String)
objectUserCreateForm{
73
-
valform:Form[UserCreateForm]=Form(Forms.mapping("name"->Forms.nonEmptyText,"password"->Forms.nonEmptyText)(apply)(unapply))}
classUserController@Inject()(userRepository:UserRepository,userRegistrationService:UserRegistrationService)extendsController{
defget(id:Long)=Action{valuser:Option[User]=userRepository.resolveBy(UserId(id))user.fold[Result](NotFound){u=>
Ok(Json.toJson(UserDTO.fromModel(u)))}}
defcreate=Action{implicitrequest=>UserCreateForm.form.bindFromRequest().fold(errors=>BadRequest,form=>{
valuser=userRegistrationService.register(form.name,form.password)Ok(Json.toJson(UserDTO.fromModel(user)))})}}
74
-
Root
packagesample
importcom.google.inject.AbstractModuleimportsample.application.user.{UserRegistrationService,UserRepository}importsample.port.database.rdbmsadapter.user.UserRepositoryOnRDBMS
classSampleInjectorextendsAbstractModule{
lazyvaluserRepository:UserRepository=newUserRepositoryOnRDBMS()
lazyvaluserRegistrationService:UserRegistrationService=newUserRegistrationService(userRepository)
overridedefconfigure():Unit={bind(classOf[UserRepository]).toInstance(userRepository)
bind(classOf[UserRegistrationService]).toInstance(userRegistrationService)}}
application.conf
play.modules.enabled+="sample.SampleInjector"
routes
GET/users/:[email protected](id:Long)POST/users@sample.port.webservice.restadapter.user.UserController.create
RESTAPIWEB2
75
-
76
-
AkkaSchedulerInstagramTumblrAkkaSchedulerInstagramTumblr
Akka
Akka
AkkaScalaJavaScalaTypesafeAkkaActor
akka-quartz-schedulercronplayframeworkTumblrInsta
1. build.sbt
libraryDependencies+="com.enragedginger"%%"akka-quartz-scheduler"%"1.4.0-akka-2.3.x"
2. application.conf
akka{quartz{
defaultTimezone="Asia/Tokyo"schedules{
AutomationBlog{description="3"expression="000-23/3?**"}}}}
31cronhttp://quartz-scheduler.org/api/2.1.7/org/quartz/CronExpression.html
77AkkaSchedulerInstagramTumblr
http://quartz-scheduler.org/api/2.1.7/org/quartz/CronExpression.html
-
3. ActorInstagramTumblr
classGetInstagramImageCreateTumblrextendsActor{
defreceive={casemsg:String=>valinstaImgUrl=GetHashTagImagevaltumblrResponce=CreateBlog(instaImgUrl)}}
wGetHashTagImageInstagramCreateBlog(instaImgUrl)URLTumblr
4. Global
objectGlobalextendsGlobalSettings{
valsystem=ActorSystem("SampleSystem")valactor=system.actorOf(Props(classOf[GetInstagramImageCreateTumblr]))
overridedefonStart(app:Application)={QuartzSchedulerExtension(system).schedule("AutomationBlog",actor,"")}
overridedefonStop(app:Application)={system.shutdown()}}
GlobalonStartAutomationBlogapplication.conf
activatorrunGlobalonStart
InstagramAPI1.
InstagramAPIhttps://syncer.jp/instagram-api-matome#sec-1https://syncer.jp/instagram-api-matome#sec-2
78AkkaSchedulerInstagramTumblr
https://syncer.jp/instagram-api-matome#sec-1https://syncer.jp/instagram-api-matome#sec-2
-
2. Instagram1APIhttps://www.instagram.com/developer/endpoints/tags/#get_tags_media_recent
privatedefGetHashTagImage={//valhashTag="cat"
//API(count)valapiUrl="https://api.instagram.com/v1/"+"tags/"+hashTag+"/media/recent?count=1&access_token="+"**************************************************"
//WSjsonvalapiResult=WS.url(apiUrl).get().map{response=>response.json}
valjson=Await.result(apiResult,Duration.Inf)
//jsonURLvalimageUrl=json\"data"\\"low_resolution"map(_\"url")valimageUrlStr=imageUrl.map{a=>a.get.toString()}
//imageUrlStr.head.replace("\"","")}
InstajsonURLimageslow_resolutionurl
79AkkaSchedulerInstagramTumblr
https://www.instagram.com/developer/endpoints/tags/#get_tags_media_recent
-
"images":{"low_resolution":{"height":320,"url":"https://scontent.cdninstagram.com/***.jpg","width":320},
"standard_resolution":{"height":640,"url":"https://scontent.cdninstagram.com/***.jpg","width":640},
"thumbnail":{"height":150,"url":"https://scontent.cdninstagram.com/***.jpg","width":150}},
80AkkaSchedulerInstagramTumblr
-
TumblrAPIInstagramTumblr
1. Instagramhttps://syncer.jp/tumblr-api-matome#sec-1
2. OAuthTumblrAPIURLPhotoPostsGETPOSTOAuthhttps://www.tumblr.com/docs/en/api/v2#posting
3. OAuthtokenTumblrInstagramTwittertokentokenAPITumblrtoken
4. JumblrApiconsoleJavaJavaTumblrOAuthJumblrscalaJumblr
5. build.sbtJumblr
libraryDependencies+="com.tumblr"%"jumblr"%"0.0.11"
81AkkaSchedulerInstagramTumblr
https://syncer.jp/tumblr-api-matome#sec-1https://www.tumblr.com/docs/en/api/v2#posting
-
1.
privatedefCreateBlog(imageUrl:String)={valconsumerKey="**************************************************"valconsumerSecret="**************************************************"
valclient:JumblrClient=newJumblrClient(consumerKey,consumerSecret)client.setToken(
//oauthToken"**************************************************",//oauthTokenSecret"**************************************************")
//postCreateparamjava.util.MapscalaMapvalparams:java.util.Map[String,String]=newHashMap[String,String]()params.put("type","photo")params.put("source",imageUrl)client.postCreate("instagramtagimage.tumblr.com",params)}
JumblrimageUrlInstaURLconsumerKeyconsumerSecretoauthTokenoauthTokenSecret4TumblrApiconsole
82AkkaSchedulerInstagramTumblr
-
Tumblr
AkkaschedulercronPlay
TwitterPinterestSNSw
83AkkaSchedulerInstagramTumblr
-
scalaDDD
GANMA!onDDD
DIP:theDependencyInversionPrinciple
5
DDD
84scalaDDD
-
GANMA!Android
DIP
85scalaDDD
-
packagecom.sample.domain.magazin.trait
traitMagazineIdSource{valrawId:String}
traitMagazineSource{valid:MagazineIdSourcevaltitle:String}
packagecom.sample.domain.magazine
importcom.COMICSMART.GANMA.domain.magazine.traits.{MagazineIdSource,MagazineSource}importcom.sample.infra.magazine.MagazineAPIimportscala.concurrent.ExecutionContext.Implicits.globalimportscala.concurrent.Future
caseclassMagazineId(rawid:String)extendsMagazineIdSource
//caseclassMagazine(id:MagazineId,title:String)extendsMagazineSource
//MagazineobjectMagazine{defapply(src:MagazineSource):Magazine={Magazine(MagazineId(src.id.rawId),src.title)}}
classMagazineRepository(api:MagazineApi=MagazineAPI()){
defget(magazineId:MagazineId):Future[Magazine]=api.get(magazineId).map(Magazine(_))
}
86scalaDDD
-
packagecom.sample.infra.magazine
importcom.COMICSMART.GANMA.domain.magazine.traits.{MagazineIdSource,MagazineSource}importscala.concurrent.ExecutionContext.Implicits.globalimportscala.concurrent.Future
classMagazineAPI(){
defget(magazineId:MagazineIdSource):Future[MagazineSource]={//httpjson}}
GANMA!AndroidView
packagecom.sample.application.magazine
importandroid.app.Activityimportandroid.os.Bundleimportcom.sample.domain.magazine.{MagazineId,Magazine}importcom.sample.domain.magazine.MagazineRepositoryimportscala.concurrent.ExecutionContext.Implicits.global
classMagazineActivityextendsActivity{
valmagazineRepository=MagazineRepository()
overridedefonCreate(savedInstanceState:Bundle):Unit={super.onCreate(savedInstanceState)
valmagazineId=MagazineId(getIntent.getStringExtra("magazineId"))magazineRepository.get(magazineId).onSuccess{casem:Magazine=>//viewcase_=>}
}
------
}
87scalaDDD
-
DDD
VaughnVernon(2015)()
http://d.hatena.ne.jp/asakichy/20090128/1233144989
http://www.atmarkit.co.jp/fdotnet/designptn/designptn07/designptn07_01.html
88scalaDDD
http://d.hatena.ne.jp/asakichy/20090128/1233144989http://www.atmarkit.co.jp/fdotnet/designptn/designptn07/designptn07_01.html
-
AndroidKotlin1010MANTAndroid
2015AndroidKotlinMANT
KotlinAndroidAndroid10
1.setOnClickListener
inlinefunT.onClick(crossinlinef:(T)->Unit)=setOnClickListener{f(this)}
//button.onClick{/*dosomething*/}
2.
funContext.loadColor(@ColorResresId:Int)=ContextCompat.getColor(this,resId)
//view.setBackgroundColor(loadColor(R.color.orange))
3.
funActivity.hideKeyoard()=(getSystemService(Context.INPUT_METHOD_SERVICE)asInputMethodManager).hideSoftInputFromWindow(currentFocus.windowToken,0)
//hideKeyboard()
89AndroidKotlin10
-
4.Fragmentreplace
funFragmentManager.replace(resId:Int=R.id.default_content,fragment:Fragment,tag:String?=null,stack:String?=null){begiTransaction().replace(resId,fragment,tag).addToBackStack(stack).commit()}
//supportFragmentManager.replace(fragment=MyFragment())
5.JSONObject
funJSONObject.pick(key:String):T?=try{get(key)as?T}catch(e:JSONException){null}
//valfirstName=json.pick("firstName")
6.LoaderCallbackinitrestart
funLoaderManager.init(id:Int=0,args:Bundle?=null,onCreate:(Int,Bundle?)->Loader,onLoadFinish:(Loader?,T)->Unit,onLoadReset:(Loader?)->Unit={})=initLoader(id,args,object:LoaderManager.LoaderCallbacks{overridefunonCreateLoader(id:Int,args:Bundle?):Loader?=onCreate(id,args)overridefunonLoadFinished(loader:Loader?,data:T)=onLoadFinish(loader,data)overridefunonLoadReset(loader:Loader?)=onLoadReset(loader)})
//supportLoaderManager.init(onCreate={id,args->createNewLoader()}onLoadFinish={loader,c->bindData(c)})
90AndroidKotlin10
-
7.ScrollListener
funT.onScroll(onStateChange:(T?,Int)->Unit={view,scrollState->}onScroll:(T?,Int,Int,Int)->Unit={view,f,v,t->}){setOnScrollListener(object:AbsListView.OnScrollListener{overridefunonScrollStateChanged(view:AbsListView?,scrollState:Int){onStateChange(viewasT,scrollState)}
overridefunonScroll(view:AbsListView?,firstVisibleItem:Int,visibleItemCount:Int,totalItemCount:Int){onScroll(viewasT,firstVisibleItem,visibleItemCount,totalItemCount)}})}
//listView.onScroll(onStateChange={view,scrollState->/*dosomething*/})
8.ImageView
funImageView.setImage(source:Any?){source?.javaClass?.name
when(source){null->setImageBitmap(null)isInt->setImageResource(source)isBitmap->setImageBitmap(source)isDrawable->setImageDrawable(source)isUri->setImageURI(source)else->throwIllegalArgumentException("Thissourcetypeof${source.javaClass.name}isnotsupported")}}
//imageView1.setImage(bitmap)imageView2.setImage(R.drawable.icon)
91AndroidKotlin10
-
9.Animator.AnimationListener
funViewPropertyAnimator.listener(onStart:(Animator?)->Unit={},onCancel:(Animator?)->Unit={},onRepeat:(Animator?)->Unit={},onEnd:(Animator?)->Unit={}){setListener(object:Animator.AnimatorListener{overridefunonAnimationStart(a:Animator?)=onStart(a)overridefunonAnimationCancel(a:Animator?)=onCancel(a)overridefunonAnimationRepeat(a:Animator?)=onRepeat(a)overridefunonAnimationEnd(a:Animator?)=onEnd(a)})}
//view.animate().x(80f).listener(onStart={view.alpha=0.5f},onEnd={view.alpha=1.0f})
10.ViewTreeObserber.OnGlobalLayoutListener
inlinefunView.newGlobalLayoutListener(crossinlinef:(ViewTreeObserver.OnGlobalLayoutListener)->Unit):ViewTreeObserver.OnGlobalLayoutListener{
returnobject:ViewTreeObserver.OnGlobalLayoutListener{overridefunonGlobalLayout()=f(this)}.apply{viewTreeObserver.addOnGlobalLayoutListener(this)}}
funView.removeGlobalLayoutListener(listener:ViewTreeObserver.OnGlobalLayoutListener)=viewTreeObserver.addOnGlobalLayoutListener(listener)
//view.newGlobalLayoutListener{textView.visibility=View.VISIBLEview.removeGlobalLayoutListener(it)}
92AndroidKotlin10
-
Scala
http://septeni-original.co.jp
http://tour.septeni.net/
SeptenixScalaconnpassScala
http://septeni-scala.connpass.com/
Scala-Scala/-ScalaDDD-GANMA!DDD1-DDD-
URLconnpass
93
http://septeni-original.co.jphttp://tour.septeni.net/http://septeni-scala.connpass.com/
PYXISIntelliJIncoming WebHooksScalaSlackBeanstalk for DockerPlay FrameworkPythonScalaGANMA!CachePlay FrameworkAkka SchedulerInstagramTumblrscala DDD AndroidKotlin10