Skip to content

Commit 3d54a00

Browse files
committed
In the beginning there was darkness
This is a production-grade play application that does absolutely nothing of note. ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄░░░░░░░░░ ░░░░░░░░▄▀░░░░░░░░░░░░▄░░░░░░░▀▄░░░░░░░ ░░░░░░░░█░░▄░░░░▄░░░░░░░░░░░░░░█░░░░░░░ ░░░░░░░░█░░░░░░░░░░░░▄█▄▄░░▄░░░█░▄▄▄░░░ ░▄▄▄▄▄░░█░░░░░░▀░░░░▀█░░▀▄░░░░░█▀▀░██░░ ░██▄▀██▄█░░░▄░░░░░░░██░░░░▀▀▀▀▀░░░░██░░ ░░▀██▄▀██░░░░░░░░▀░██▀░░░░░░░░░░░░░▀██░ ░░░░▀████░▀░░░░▄░░░██░░░▄█░░░░▄░▄█░░██░ ░░░░░░░▀█░░░░▄░░░░░██░░░░▄░░░▄░░▄░░░██░ ░░░░░░░▄█▄░░░░░░░░░░░▀▄░░▀▀▀▀▀▀▀▀░░▄▀░░ ░░░░░░█▀▀█████████▀▀▀▀████████████▀░░░░ ░░░░░░████▀░░███▀░░░░░░▀███░░▀██▀░░░░░░ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
0 parents  commit 3d54a00

20 files changed

+519
-0
lines changed

.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/logs/
2+
/modules
3+
/project/project
4+
/project/target
5+
/target
6+
server.pid
7+
*.iml
8+
*.eml
9+
.cache
10+
.ensime*
11+
/project/local.sbt
12+
.DS_Store

README.org

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
* Carjump challenge
2+
3+
** Dependencies
4+
You will need to install [[http://www.scala-sbt.org/][SBT]] which requires a JDK installation.
5+
6+
** Run the tests:
7+
#+BEGIN_SRC
8+
sbt test
9+
#+END_SRC
10+
11+
** Run the application:
12+
#+BEGIN_SRC
13+
sbt run
14+
#+END_SRC
15+
16+
** Design decisions

app/clients/ClientsModule.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package clients
2+
3+
import scala.concurrent.ExecutionContext
4+
5+
import play.api.Configuration
6+
import play.api.libs.ws.WSClient
7+
8+
trait ClientsModule {
9+
def wsClient: WSClient
10+
11+
implicit def configuration: Configuration
12+
13+
implicit val executionContext: ExecutionContext
14+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package controllers
2+
3+
import scala.concurrent.ExecutionContext
4+
5+
import com.softwaremill.macwire._
6+
import play.api.Configuration
7+
8+
trait ControllerModule {
9+
10+
implicit def configuration: Configuration
11+
12+
implicit val executionContext: ExecutionContext
13+
14+
lazy val statusController: StatusController = wire[StatusController]
15+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package controllers
2+
3+
import scala.concurrent.{ Future, ExecutionContext }
4+
5+
import play.api.mvc.{ AnyContent, Action, Controller }
6+
import util.SLF4JLogging
7+
8+
class StatusController()(implicit ec: ExecutionContext) extends Controller with SLF4JLogging {
9+
def status: Action[AnyContent] = Action.async {
10+
request
11+
Future.successful(Ok("OK"))
12+
}
13+
}

app/jobs/JobsModule.scala

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package jobs
2+
3+
import scala.concurrent.ExecutionContext
4+
5+
import akka.actor.{ ActorSystem, Props }
6+
import akka.stream.Materializer
7+
import com.softwaremill.macwire._
8+
import play.api.Configuration
9+
10+
trait JobsModule {
11+
12+
implicit val actorSystem: ActorSystem
13+
14+
implicit val executionContext: ExecutionContext
15+
16+
implicit def configuration: Configuration
17+
18+
implicit def materializer: Materializer
19+
20+
lazy val jobsSupervisorActor = {
21+
actorSystem.actorOf(Props(wire[JobsSupervisorActor]))
22+
}
23+
}

app/jobs/JobsSupervisorActor.scala

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package jobs
2+
3+
import akka.actor._
4+
import jobs.JobsSupervisorActor.{ JobDispatcherName, StartAll, StopAll }
5+
6+
class JobsSupervisorActor() extends Actor {
7+
8+
override val supervisorStrategy =
9+
OneForOneStrategy() {
10+
case _: ActorInitializationException SupervisorStrategy.Stop
11+
case _: ActorKilledException SupervisorStrategy.Stop
12+
case _: DeathPactException SupervisorStrategy.Stop
13+
case _: Exception SupervisorStrategy.Resume
14+
}
15+
16+
def receive: PartialFunction[Any, Unit] = {
17+
case StartAll ()
18+
case StopAll ()
19+
}
20+
}
21+
22+
object JobsSupervisorActor {
23+
case object StartAll
24+
case object StopAll
25+
val JobDispatcherName = "carjump-dispatcher"
26+
}

app/launch/CarjumpLoader.scala

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package launch
2+
3+
import com.softwaremill.macwire._
4+
import controllers.Assets
5+
import play.api._
6+
import play.api.ApplicationLoader.Context
7+
import play.api.inject.Injector
8+
import play.api.libs.crypto.AESCTRCrypter
9+
import play.api.libs.logback.LogbackLoggerConfigurator
10+
import play.api.libs.ws.ahc.AhcWSComponents
11+
import play.api.routing.Router
12+
import router.Routes
13+
import util.SLF4JLogging
14+
15+
class CarjumpLoader extends ApplicationLoader {
16+
def load(context: Context): Application = {
17+
LoggerConfigurator(context.environment.classLoader).foreach(_.configure(context.environment))
18+
19+
val module: BuiltInComponentsFromContext with CarjumpComponents = new BuiltInComponentsFromContext(context) with CarjumpComponents
20+
module.startJobs()
21+
module.application
22+
}
23+
}
24+
25+
trait CarjumpComponents extends BuiltInComponents with CarjumpModule with AhcWSComponents {
26+
27+
lazy val assets: Assets = wire[Assets]
28+
29+
lazy val router: Router = {
30+
def prefixedRoutes(prefix: String): Routes = {
31+
wire[Routes]
32+
}
33+
prefixedRoutes("/")
34+
}
35+
36+
override implicit lazy val executionContext = actorSystem.dispatcher
37+
}

app/launch/CarjumpModule.scala

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package launch
2+
3+
import scala.concurrent.{ ExecutionContext, Future, blocking }
4+
5+
import clients.ClientsModule
6+
import controllers.ControllerModule
7+
import jobs.{ JobsModule, JobsSupervisorActor }
8+
import play.api.Configuration
9+
import play.api.inject.ApplicationLifecycle
10+
import services.ServicesModule
11+
import util.SLF4JLogging
12+
13+
trait CarjumpModule
14+
extends ControllerModule
15+
with ServicesModule
16+
with JobsModule
17+
with ClientsModule
18+
with SLF4JLogging {
19+
20+
def configuration: Configuration
21+
def applicationLifecycle: ApplicationLifecycle
22+
override implicit val executionContext: ExecutionContext
23+
24+
def startJobs(): Unit = {
25+
jobsSupervisorActor ! JobsSupervisorActor.StartAll
26+
27+
// start jobs here
28+
29+
applicationLifecycle.addStopHook(() stopActors())
30+
}
31+
32+
private def stopActors(): Future[Unit] = {
33+
Future {
34+
jobsSupervisorActor ! JobsSupervisorActor.StopAll
35+
}
36+
}
37+
}

app/services/ServicesModule.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package services
2+
3+
import java.time.{ Clock, ZoneId }
4+
5+
import scala.concurrent.ExecutionContext
6+
7+
import play.api.Configuration
8+
9+
trait ServicesModule {
10+
11+
implicit def configuration: Configuration
12+
13+
implicit val executionContext: ExecutionContext
14+
15+
lazy implicit val clock = Clock.system(ZoneId.of("Europe/Berlin"))
16+
}

0 commit comments

Comments
 (0)