Skip to content

Commit c8bbd8a

Browse files
committed
Added a lot of files and dependencies to create the skeleton application. Will branch from this to have it saved and usable for the others.
1 parent 0fa6b8a commit c8bbd8a

File tree

16 files changed

+419
-0
lines changed

16 files changed

+419
-0
lines changed

README.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,54 @@ scala-api
22
=========
33

44
A simple api written in Scala using the Spray Framework.
5+
6+
Features
7+
--------
8+
9+
The API includes the following libraries:
10+
11+
1. Spray.IO: This is the core of the API that allows users to generate API services.
12+
The main components of spray.io are the **spray-servlet**, **spray-routing** and all the **Akka**-related dependencies.
13+
Additionally we have added support for caching and json marshalling and unmarshalling using the **spray-caching** and **spray-json** dependencies.
14+
2. Jetty: This is the application container.
15+
3. Typesafe config: The application and the underlying **Akka** classes use the typesafe config system for configuration.
16+
4. Slick: This is a library for database query and access that supports various underlying DBMSs. The user is free to use whatever they want and add the required connector later.
17+
5. Testing tools: **Scalatest** is the preferred testing tool, together with **Mockito**.
18+
6. **sbt-assembly**: For creating a fat jar with embedded Jetty for distribution.
19+
7. **sbt-release**: For defining custom release steps.
20+
21+
Starting the Server
22+
-------------------
23+
24+
Starting the server is relatively easy. There are two ways of doing this:
25+
26+
1. Without building the fat jar.
27+
2. Building the fat jar and running it.
28+
29+
### Running the Application Through SBT
30+
31+
To run the application through SBT, run the following command:
32+
33+
> sbt container:start shell
34+
35+
It might take some time to compile if you haven't done this yet and then you will see a shell. Then your service will become available and you will be able to query it through the browser.
36+
37+
To stop the server, run:
38+
39+
> container:stop
40+
41+
### Running the Server Through a Fat JAR
42+
43+
For this operation you will need to create the fat jar first and then simply start it as normal Java application.
44+
45+
1. Building the fat jar:
46+
> sbt assembly
47+
2. Running the application:
48+
> java -jar jar-name.jar
49+
50+
Then to stop the application, just press Ctrl+C.
51+
52+
Conclusion
53+
----------
54+
55+
This is the skeleton application you can use to quickly start your development. From then on, it is up to you to add the dependencies you need and make the API do whatever you want.

assembly.sbt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import sbtassembly.Plugin.AssemblyKeys._
2+
3+
assemblySettings
4+
5+
// Could add a merge strategy if something doesn't work when building the fat jar.
6+
7+
mainClass in assembly := Some("com.ivan.nikolov.JettyStart")
8+
9+
jarName in assembly := { s"${name.value}_${scalaVersion.value}-${version.value}-assembly.jar" }
10+
11+
artifact in (Compile, assembly) ~= {art =>
12+
art.copy(`classifier` = Some("assembly"))
13+
}
14+
15+
addArtifact(artifact in (Compile, assembly), assembly)

build.sbt

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
organization := "com.ivan.nikolov"
2+
3+
name := "scala-api"
4+
5+
scalaVersion := "2.10.3"
6+
7+
scalacOptions := Seq("-unchecked", "-deprecation", "-encoding", "utf8")
8+
9+
javaOptions ++= Seq("-target", "1.7", "-source", "1.7")
10+
11+
resolvers ++= Seq(
12+
"spray repo" at "http://repo.spray.io"
13+
)
14+
15+
publishMavenStyle := true
16+
17+
libraryDependencies ++= {
18+
val akkaVersion = "2.3.0"
19+
val sprayVersion = "1.3.1"
20+
val sprayJsonVersion = "1.2.6"
21+
val typesafeVersion = "1.2.0"
22+
val slickVersion = "2.0.1"
23+
Seq(
24+
"org.scalatest" % "scalatest_2.10" % "2.1.3" % "test",
25+
"io.spray" % "spray-servlet" % sprayVersion,
26+
"io.spray" % "spray-routing" % sprayVersion,
27+
"io.spray" % "spray-caching" % sprayVersion,
28+
"io.spray" %% "spray-json" % sprayJsonVersion,
29+
"io.spray" % "spray-testkit" % sprayVersion % "test",
30+
"org.eclipse.jetty" % "jetty-webapp" % "9.1.0.v20131115" % "container",
31+
"org.eclipse.jetty" % "jetty-plus" % "9.1.0.v20131115" % "container",
32+
"org.eclipse.jetty.orbit" % "javax.servlet" % "3.0.0.v201112011016" % "container" artifacts Artifact("javax.servlet", "jar", "jar"),
33+
"org.eclipse.jetty" % "jetty-server" % "9.1.3.v20140225",
34+
"org.eclipse.jetty" % "jetty-servlet" % "9.1.3.v20140225",
35+
"com.typesafe.akka" %% "akka-actor" % akkaVersion,
36+
"com.typesafe.akka" %% "akka-testkit" % akkaVersion % "test",
37+
"com.typesafe" % "config" % typesafeVersion, // configuration.
38+
"com.typesafe.slick" %% "slick" % slickVersion, // for database connectivity.
39+
"org.scala-tools.testing" % "specs_2.9.1" % "1.6.9" % "test", // for the mockito sugar
40+
"org.mockito" % "mockito-all" % "1.9.5" % "test" // mockito for tests
41+
)
42+
}
43+
44+
// Import the web settings.
45+
seq(webSettings: _*)
46+
47+
port in container.Configuration := 8888
48+
49+
//ssl in container.Configuration := Some("192.168.1.4", 8443, "keystore_path", "keystore_password", "key_password")

project/build.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
sbt.version=0.13.1
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
akka {
2+
loglevel = INFO
3+
}
4+
5+
spray.servlet {
6+
boot-class = "com.ivan.nikolov.Boot"
7+
request-timeout = 30s
8+
}
9+
10+
11+
# The api configurations.
12+
scala-api {
13+
application {
14+
port = 8888
15+
}
16+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.ivan.nikolov
2+
3+
import spray.servlet.WebBoot
4+
import akka.actor.{Props, ActorSystem}
5+
import com.ivan.nikolov.actor.ScalaApiActor
6+
7+
/**
8+
* The boot class the initialized the actor system and assigns the
9+
* service actor. It is instantiated by the servlet initializer.
10+
*/
11+
class Boot extends WebBoot {
12+
val system = ActorSystem("scala-api")
13+
14+
val serviceActor = system.actorOf(Props[ScalaApiActor])
15+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.ivan.nikolov
2+
3+
import org.eclipse.jetty.server.Server
4+
import org.eclipse.jetty.servlet.ServletContextHandler
5+
import spray.servlet.{Servlet30ConnectorServlet, Initializer}
6+
import com.ivan.nikolov.app.ComponentRegistry._
7+
8+
/**
9+
* Starts the embedded Jetty server that runs the given application.
10+
*/
11+
object JettyStart {
12+
13+
def main(args: Array[String]) {
14+
start()
15+
}
16+
17+
/**
18+
* Starts the embedded Jetty instance. This is similar to the
19+
* web.xml contents here.
20+
*/
21+
def start() {
22+
try {
23+
val server = new Server(settings.Application.port)
24+
25+
val contextHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS)
26+
contextHandler.setContextPath("/")
27+
server.setHandler(contextHandler)
28+
contextHandler.addEventListener(new Initializer)
29+
30+
contextHandler.addServlet(classOf[Servlet30ConnectorServlet].getName, "/*")
31+
32+
server.start()
33+
server.join()
34+
} catch {
35+
case e: Throwable => e.printStackTrace()
36+
}
37+
}
38+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.ivan.nikolov.actor
2+
3+
import akka.actor.Actor
4+
import com.ivan.nikolov.routes.PingRoute
5+
import com.ivan.nikolov.app.ComponentRegistry._
6+
7+
/**
8+
* The Scala API actor.
9+
*/
10+
class ScalaApiActor extends Actor with PingRoute {
11+
12+
val settingsDep = settings
13+
14+
implicit def actorRefFactory = context
15+
16+
def receive = runRoute(pingRoute)
17+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.ivan.nikolov.app
2+
3+
import com.ivan.nikolov.config.SettingsComponent
4+
5+
/**
6+
* The component registry that leverages the cake design pattern.
7+
*/
8+
object ComponentRegistry extends SettingsComponent {
9+
val settings = Settings.createSettings("/etc/ivan/nikolov/scala-api/config.properties")
10+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.ivan.nikolov.config
2+
3+
import com.typesafe.config.{ConfigSyntax, ConfigParseOptions, ConfigFactory, Config}
4+
import java.io.File
5+
6+
/**
7+
* Created by volcom on 13/04/14.
8+
*/
9+
trait SettingsComponent {
10+
11+
val settings: Settings
12+
13+
class Settings(config: Config) {
14+
config.checkValid(ConfigFactory.defaultReference(), "scala-api")
15+
16+
object Application {
17+
val port = config.getInt("scala-api.application.port")
18+
}
19+
}
20+
21+
object Settings {
22+
/**
23+
* Creates settings that can exist in different environments.
24+
* @param configPath The path to the config file.
25+
* @param configName The name of the config file. The default is application.conf, as
26+
* the typesafe config recommendations are.
27+
* @return
28+
*/
29+
def createSettings(configPath: String, configName: Option[String] = None): Settings = {
30+
val file = new File(configPath)
31+
if (file.exists()) {
32+
val fileConfig = ConfigFactory.parseFile(file, ConfigParseOptions.defaults().setSyntax(ConfigSyntax.CONF))
33+
new Settings(ConfigFactory.load(fileConfig))
34+
} else if (configName.isDefined) {
35+
new Settings(ConfigFactory.load(configName.get))
36+
} else {
37+
new Settings(ConfigFactory.load())
38+
}
39+
}
40+
}
41+
}

0 commit comments

Comments
 (0)