diff --git a/app/actors/FizzBuzzActor.java b/app/actors/FizzBuzzActor.java new file mode 100644 index 0000000000000000000000000000000000000000..2279274199bf0e80fdfff6f59f32a583480dc1d6 --- /dev/null +++ b/app/actors/FizzBuzzActor.java @@ -0,0 +1,73 @@ +package actors; + +import akka.actor.ActorRef; +import akka.actor.Props; +import akka.actor.UntypedActor; + +/** + * A rather trivial Actor that just plays FizzBuzz + */ +public class FizzBuzzActor extends UntypedActor { + + int nextNum = 0; + + /** + * The marshall. We'll also send them the messages + */ + ActorRef marshallActor; + + /** + * + */ + public static Props props = Props.create(FizzBuzzActor.class); + + + @Override + public void onReceive(Object message) { + if (message.equals("Marshall")) { + /* + * We're given the marshall's ActorRef by a message saying "Marshall". The Marshall will appear + * to be the sender (even though it's actually been sent by Setup) + */ + marshallActor = getSender(); + } else if (message instanceof ActorRef) { + // If we're sent an ActorRef, that's the marshall telling us who our opponent is and to get started + ((ActorRef) message).tell(1, getSelf()); + marshallActor.tell(1, getSelf()); + } else if (message instanceof Integer) { + nextNum = (Integer) message + 1; + reply(); + } else { + nextNum = nextNum + 2; + + // Stop at 1000 so we don't blow the heap by writing forever into a StringBuilder + if (nextNum < 1000) { + reply(); + } + } + } + + void reply() { + if (nextNum % 15 == 0) { + getSender().tell("fizzbuzz", getSelf()); + marshallActor.tell("fizzbuzz", getSelf()); + } else if (nextNum % 5 == 0) { + getSender().tell("buzz", getSelf()); + marshallActor.tell("buzz", getSelf()); + } else if (nextNum % 3 == 0) { + getSender().tell("fizz", getSelf()); + marshallActor.tell("fizz", getSelf()); + } else { + getSender().tell(nextNum, getSelf()); + marshallActor.tell(nextNum, getSelf()); + } + + // Put this Actor to sleep for 250ms before it checks its next message + try { + Thread.sleep(250); + } catch (InterruptedException ex) { + // do nothing + } + } + +} diff --git a/app/actors/MarshallActor.java b/app/actors/MarshallActor.java new file mode 100644 index 0000000000000000000000000000000000000000..f3dfbd39a2577aa10b2a129ef5248e6aeb866f51 --- /dev/null +++ b/app/actors/MarshallActor.java @@ -0,0 +1,36 @@ +package actors; + +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.actor.UntypedActor; + +import javax.inject.Inject; + +/** + * You might or might not want this actor in the end. In this example, its role is to be the central point of + * contact between your web app and the actor system that might be receiving outside events. + */ +public class MarshallActor extends UntypedActor { + + StringBuilder messages = new StringBuilder(); + + public static Props props = Props.create(MarshallActor.class); + + public MarshallActor() { + + } + + @Override + public void onReceive(Object message) { + if (message.equals("Report!")) { + getSender().tell(messages.toString(), getSelf()); + } else { + messages.append(getSender().toString()); + messages.append(" said "); + messages.append(message); + messages.append("\n"); + } + + } + +} diff --git a/app/actors/Setup.java b/app/actors/Setup.java new file mode 100644 index 0000000000000000000000000000000000000000..834a9c6745bef1c050a224d285a7f3de2c74327c --- /dev/null +++ b/app/actors/Setup.java @@ -0,0 +1,36 @@ +package actors; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Holds all the "famous" Actors in our system. This hopefully makes things convenient, because if you @Inject Setup, + * you'll then be able to look up ActorRefs to all the actors just by Setup.marshallActor, etc. + * + * It's a Singleton, so Google Guice will only create one of these for us. + */ +@Singleton +public class Setup { + + /** + * This is a reference to an Actor + */ + public final ActorRef marshallActor; + + @Inject + public Setup(ActorSystem system) { + marshallActor = system.actorOf(MarshallActor.props); + + ActorRef fb1 = system.actorOf(FizzBuzzActor.props, "Player1"); + ActorRef fb2 = system.actorOf(FizzBuzzActor.props, "Player2"); + fb1.tell("Marshall", marshallActor); + fb2.tell("Marshall", marshallActor); + + fb1.tell(fb2, fb2); + + } + +} \ No newline at end of file diff --git a/app/controllers/Application.java b/app/controllers/Application.java index 20304f43ab21070c2f616f0ff2ed6a66fbeacf1b..7fa68bf2cff2d1b727f5f7d3af78aa354a82be8a 100644 --- a/app/controllers/Application.java +++ b/app/controllers/Application.java @@ -1,42 +1,50 @@ package controllers; -import model.BCryptExample; -import model.Captcha; +import actors.Setup; +import com.google.inject.Inject; +import com.google.inject.Singleton; import play.mvc.Controller; import play.mvc.Result; +import scala.compat.java8.FutureConverters; +import play.libs.ws.*; -import java.util.Arrays; +import java.util.concurrent.CompletionStage; +import static akka.pattern.Patterns.ask; +@Singleton public class Application extends Controller { - public static Result index() { - int arrayLength = 5; - int[] indexes = new int[arrayLength]; - for (int i = 0; i < arrayLength; i++) { - indexes[i] = (int)(Captcha.numPhotos() * Math.random()); - } + Setup actorSetup; - return ok(views.html.application.index.render(indexes)); - } + WSClient wsClient; - private static int countBeagles(String[] indexes) { - int i = 0; - for (String s : indexes) { - if (Captcha.isCorrect(Integer.valueOf(s))) { - i++; - } - } - return i; + @Inject + public Application(Setup actorSetup, WSClient wsClient) { + this.actorSetup = actorSetup; + this.wsClient = wsClient; } - public static Result matches() { - String[] sent = request().body().asFormUrlEncoded().get("sent"); - String[] beagles = request().body().asFormUrlEncoded().get("beagle"); - - int numBeagles = countBeagles(sent); - int numFound = countBeagles(beagles); - - return ok(views.html.application.matches.render(numBeagles, numFound)); + /** + * Play framework suppors asynchronous controller methods -- that is, methods that instead of returning a Result + * return a CompletionStage, which will produce a Result some time in the future + */ + public CompletionStage<Result> index() { + /* + * This code might look a little complex. + * + * ask sends a message to an ActorRef, and then returns a Future that will eventually contain the response. + * But Future is a Scala class, so FutureConverters.toJava converts it into a CompletionStage, which is Java's equivalent. + * thenApply is a method on CompletionStage that means "when you get the result, do this with it, and return a new CompletionStage" + */ + return FutureConverters.toJava(ask(actorSetup.marshallActor, "Report!", 1000)) + .thenApply(response -> ok(response.toString())); } + /** + * This controller method uses Play's Web Service client to make another HTTP call, and do something with the + * response + */ + public CompletionStage<Result> whatDidGitLabSay() { + return wsClient.url("http://www.une.edu.au/foo").get().thenApply(r -> ok(r.getStatusText())); + } } diff --git a/build.sbt b/build.sbt index d8d59d2431e4629d14111842ed344454299570da..faca572fb7ee0fbb27f468d91dd72253f8247be1 100644 --- a/build.sbt +++ b/build.sbt @@ -2,10 +2,14 @@ name := "chirper" version := "1.0" -scalaVersion := "2.11.6" +scalaVersion := "2.11.7" lazy val root = (project in file(".")).enablePlugins(PlayJava) +routesGenerator := InjectedRoutesGenerator + libraryDependencies ++= Seq( + javaWs, "org.mindrot" % "jbcrypt" % "0.3m" ) + diff --git a/conf/routes b/conf/routes index 88b0c087c9f12b5fdb988757ff1e94e67347db3a..8fd27619f0706985e55aba011fe4211026d82edd 100644 --- a/conf/routes +++ b/conf/routes @@ -3,7 +3,7 @@ # ~~~~ GET / controllers.Application.index() -POST /matches controllers.Application.matches() +GET /ws controllers.Application.whatDidGitLabSay() # Map static resources from the /public folder to the /assets URL path GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset) \ No newline at end of file diff --git a/project/plugins.sbt b/project/plugins.sbt index 6d2584df5d4de6c2326478db31dcd04a3117afd5..f9cdc994ad9fcc7d8efbb539aad9bc7d530c1a02 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,2 +1,2 @@ // Use the Play sbt plugin for Play projects -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.4.2") +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.5.4")