-
Notifications
You must be signed in to change notification settings - Fork 97
scala support #116
scala support #116
Changes from all commits
1174c00
44c5fa4
4d213fd
f728b3b
76b8276
bc6fbd6
905394f
48204e2
3b9af0f
861b09d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -86,10 +86,13 @@ headerSources in Compile ++= { | |||||
} | ||||||
|
||||||
lazy val root = (project in file(".")) | ||||||
// Don't forget to add your sbt module here! | ||||||
// A missing module here can lead to failing Travis test results | ||||||
.aggregate(`proxy-core`, | ||||||
`proxy-cassandra`, | ||||||
`proxy-postgres`, | ||||||
`java-support`, | ||||||
`scala-support`, | ||||||
`java-shopping-cart`, | ||||||
`akka-client`, | ||||||
operator, | ||||||
|
@@ -630,6 +633,70 @@ lazy val `java-support` = (project in file("java-support")) | |||||
) | ||||||
) | ||||||
|
||||||
lazy val `scala-support` = (project in file("scala-support")) | ||||||
.enablePlugins(AkkaGrpcPlugin, BuildInfoPlugin) | ||||||
.settings( | ||||||
name := "cloudstate-scala-support", | ||||||
common, | ||||||
crossPaths := false, | ||||||
publishMavenStyle := true, | ||||||
publishTo := sonatypePublishTo.value, | ||||||
buildInfoKeys := Seq[BuildInfoKey](name, version), | ||||||
buildInfoPackage := "io.cloudstate.scalasupport", | ||||||
// Generate javadocs by just including non generated Java sources | ||||||
sourceDirectories in (Compile, doc) := Seq((javaSource in Compile).value), | ||||||
sources in (Compile, doc) := { | ||||||
val javaSourceDir = (javaSource in Compile).value.getAbsolutePath | ||||||
(sources in (Compile, doc)).value.filter(_.getAbsolutePath.startsWith(javaSourceDir)) | ||||||
}, | ||||||
// javadoc (I think java 9 onwards) refuses to compile javadocs if it can't compile the entire source path. | ||||||
// but since we have java files depending on Scala files, we need to include ourselves on the classpath. | ||||||
dependencyClasspath in (Compile, doc) := (fullClasspath in Compile).value, | ||||||
javacOptions in (Compile, doc) ++= Seq( | ||||||
"-overview", | ||||||
((javaSource in Compile).value / "overview.html").getAbsolutePath, | ||||||
"-notimestamp", | ||||||
"-doctitle", | ||||||
"CloudState Scala Support" | ||||||
), | ||||||
libraryDependencies ++= Seq( | ||||||
// Remove these explicit gRPC/netty dependencies once akka-grpc 0.7.1 is released and we've upgraded to using that | ||||||
"io.grpc" % "grpc-core" % GrpcJavaVersion, | ||||||
"io.grpc" % "grpc-netty-shaded" % GrpcJavaVersion, | ||||||
"com.typesafe.akka" %% "akka-stream" % AkkaVersion, | ||||||
"com.typesafe.akka" %% "akka-slf4j" % AkkaVersion, | ||||||
"com.typesafe.akka" %% "akka-discovery" % AkkaVersion, | ||||||
"com.typesafe.akka" %% "akka-http" % AkkaHttpVersion, | ||||||
"com.typesafe.akka" %% "akka-http-spray-json" % AkkaHttpVersion, | ||||||
"com.typesafe.akka" %% "akka-http-core" % AkkaHttpVersion, | ||||||
"com.typesafe.akka" %% "akka-http2-support" % AkkaHttpVersion, | ||||||
"com.google.protobuf" % "protobuf-java" % ProtobufVersion % "protobuf", | ||||||
"com.google.protobuf" % "protobuf-java-util" % ProtobufVersion, | ||||||
"org.scalatest" %% "scalatest" % ScalaTestVersion % Test, | ||||||
"com.typesafe.akka" %% "akka-testkit" % AkkaVersion % Test, | ||||||
"com.typesafe.akka" %% "akka-stream-testkit" % AkkaVersion % Test, | ||||||
"com.typesafe.akka" %% "akka-http-testkit" % AkkaHttpVersion % Test, | ||||||
"com.thesamet.scalapb" %% "scalapb-runtime" % scalapb.compiler.Version.scalapbVersion % "protobuf", | ||||||
"org.slf4j" % "slf4j-simple" % "1.7.26", | ||||||
"com.fasterxml.jackson.core" % "jackson-databind" % "2.9.9.3" | ||||||
), | ||||||
javacOptions in Compile ++= Seq("-encoding", "UTF-8"), | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Move this to the other javacOptiuons above? |
||||||
akkaGrpcGeneratedSources in Compile := Seq(AkkaGrpc.Server), | ||||||
akkaGrpcGeneratedLanguages in Compile := Seq(AkkaGrpc.Scala), // FIXME should be Java, but here be dragons | ||||||
|
||||||
// Work around for https://github.com/akka/akka-grpc/pull/673 | ||||||
(PB.targets in Compile) := { | ||||||
val old = (PB.targets in Compile).value | ||||||
val ct = crossTarget.value | ||||||
|
||||||
old.map(_.copy(outputPath = ct / "akka-grpc" / "main")) | ||||||
}, | ||||||
PB.protoSources in Compile ++= { | ||||||
val baseDir = (baseDirectory in ThisBuild).value / "protocols" | ||||||
Seq(baseDir / "protocol", baseDir / "frontend") | ||||||
} | ||||||
) | ||||||
|
||||||
lazy val `java-shopping-cart` = (project in file("samples/java-shopping-cart")) | ||||||
.dependsOn(`java-support`) | ||||||
.enablePlugins(AkkaGrpcPlugin, AssemblyPlugin) | ||||||
|
@@ -659,6 +726,29 @@ lazy val `java-shopping-cart` = (project in file("samples/java-shopping-cart")) | |||||
} | ||||||
) | ||||||
|
||||||
lazy val `scala-shopping-cart` = (project in file("samples/scala-shopping-cart")) | ||||||
.dependsOn(`scala-support`) | ||||||
.enablePlugins(AkkaGrpcPlugin) | ||||||
.settings( | ||||||
name := "scala-shopping-cart", | ||||||
PB.generate in Compile := (PB.generate in Compile).dependsOn(PB.generate in (`scala-support`, Compile)).value, | ||||||
PB.protoSources in Compile ++= { | ||||||
val baseDir = (baseDirectory in ThisBuild).value / "protocols" | ||||||
Seq(baseDir / "frontend", baseDir / "example") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @janory Have you tried
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @viktorklang The TCK is almost complete, the only issue is this:
It is the same content, but the order is different. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @janory I had the excactly same "issue" in the Go Support first :-), had the items in a list that is not ordered. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @marcellanz :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Had the same thought, yes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The reason for checking the response as a String was to avoid having parsing influencing things needlessly. I'm very much open for a better way of verifying the responses :) |
||||||
}, | ||||||
mainClass in assembly := Some("io.cloudstate.samples.shoppingcart.Main"), | ||||||
assemblyJarName in assembly := "scala-shopping-cart.jar", | ||||||
test in assembly := {}, | ||||||
// logLevel in assembly := Level.Debug, | ||||||
assemblyMergeStrategy in assembly := { | ||||||
/*ADD CUSTOMIZATIONS HERE*/ | ||||||
//case PathList("META-INF", "io.netty.versions.properties") => MergeStrategy.last | ||||||
case x => | ||||||
val oldStrategy = (assemblyMergeStrategy in assembly).value | ||||||
oldStrategy(x) | ||||||
} | ||||||
) | ||||||
|
||||||
lazy val `akka-client` = (project in file("samples/akka-client")) | ||||||
.enablePlugins(AkkaGrpcPlugin) | ||||||
.settings( | ||||||
|
@@ -720,7 +810,7 @@ lazy val `tck` = (project in file("tck")) | |||||
fork in test := true, | ||||||
parallelExecution in IntegrationTest := false, | ||||||
executeTests in IntegrationTest := (executeTests in IntegrationTest) | ||||||
.dependsOn(`proxy-core` / assembly, `java-shopping-cart` / assembly) | ||||||
.dependsOn(`proxy-core` / assembly, `java-shopping-cart` / assembly, `scala-shopping-cart` / assembly) | ||||||
.value | ||||||
) | ||||||
|
||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package io.cloudstate.samples.shoppingcart | ||
|
||
import com.example.shoppingcart.ShoppingcartProto | ||
import io.cloudstate.javasupport._ | ||
|
||
object Main extends App { | ||
new CloudState() | ||
.registerEventSourcedEntity( | ||
classOf[ShoppingCartEntity], | ||
ShoppingcartProto.javaDescriptor.findServiceByName("ShoppingCart"), | ||
com.example.shoppingcart.persistence.DomainProto.javaDescriptor | ||
) | ||
.start | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package io.cloudstate.samples.shoppingcart | ||
|
||
import com.example.shoppingcart.persistence.{ | ||
Cart => DCart, | ||
ItemAdded => DItemAdded, | ||
ItemRemoved => DItemRemoved, | ||
LineItem => DLineItem | ||
} | ||
import com.example.shoppingcart.{ | ||
AddLineItem => SAddLineItem, | ||
Cart => SCart, | ||
LineItem => SLineItem, | ||
RemoveLineItem => SRemoveLineItem | ||
} | ||
import com.google.protobuf.Empty | ||
import io.cloudstate.javasupport.EntityId | ||
import io.cloudstate.javasupport.eventsourced._ | ||
|
||
import scala.collection.mutable | ||
|
||
/** An event sourced entity. */ | ||
@EventSourcedEntity | ||
class ShoppingCartEntity(@EntityId val entityId: String) { | ||
|
||
private val cart = mutable.LinkedHashMap.empty[String, SLineItem] | ||
|
||
@Snapshot | ||
def snapshot: DCart = | ||
DCart(cart.values.map(convert).toSeq) | ||
|
||
@SnapshotHandler | ||
def handleSnapshot(cart: DCart): Unit = { | ||
this.cart.clear() | ||
cart.items.foreach { item => | ||
this.cart.put(item.productId, convert(item)) | ||
} | ||
} | ||
|
||
@EventHandler | ||
def itemAdded(itemAdded: DItemAdded): Unit = { | ||
val item = cart | ||
.get(itemAdded.getItem.productId) | ||
.fold(convert(itemAdded.getItem))( | ||
item => item.copy(quantity = item.quantity + itemAdded.item.fold(0)(_.quantity)) | ||
) | ||
cart.put(item.productId, item) | ||
} | ||
|
||
@EventHandler | ||
def itemRemoved(itemRemoved: DItemRemoved): Unit = cart.remove(itemRemoved.productId) | ||
|
||
@CommandHandler | ||
def getCart: SCart = SCart(cart.values.toSeq) | ||
|
||
@CommandHandler | ||
def addItem(item: SAddLineItem, ctx: CommandContext): Empty = { | ||
if (item.quantity <= 0) ctx.fail("Cannot add negative quantity of to item" + item.productId) | ||
ctx.emit( | ||
DItemAdded(Some(DLineItem(item.productId, item.name, item.quantity))) | ||
) | ||
Empty.getDefaultInstance | ||
} | ||
|
||
@CommandHandler | ||
def removeItem(item: SRemoveLineItem, ctx: CommandContext): Empty = { | ||
if (!cart.contains(item.productId)) { | ||
ctx.fail("Cannot remove item " + item.productId + " because it is not in the cart.") | ||
} | ||
ctx.emit(DItemRemoved(item.productId)) | ||
Empty.getDefaultInstance | ||
} | ||
|
||
private def convert(item: DLineItem) = SLineItem(item.productId, item.name, item.quantity) | ||
|
||
private def convert(item: SLineItem) = DLineItem(item.productId, item.name, item.quantity) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package io.cloudstate.javasupport; | ||
|
||
/** | ||
* Context that provides client actions, which include failing and forwarding. | ||
* | ||
* <p>These contexts are typically made available in response to commands. | ||
*/ | ||
public interface ClientActionContext extends Context { | ||
/** | ||
* Fail the command with the given message. | ||
* | ||
* @param errorMessage The error message to send to the client. | ||
*/ | ||
RuntimeException fail(String errorMessage); | ||
|
||
/** | ||
* Instruct the proxy to forward handling of this command to another entity served by this | ||
* stateful function. | ||
* | ||
* <p>The command will be forwarded after successful completion of handling this command, | ||
* including any persistence that this command does. | ||
* | ||
* <p>{@link ServiceCall} instances can be created using the {@link ServiceCallFactory} obtained | ||
* from any (including this) contexts {@link Context#serviceCallFactory()} method. | ||
* | ||
* @param to The service call to forward command processing to. | ||
*/ | ||
void forward(ServiceCall to); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Try addding this project to
aggregate
: