scalajettyembedded-jettyscalatrascalatra-sbt

unable to run web-app developed using scalatra scala


I have developed a web app using scalatra 2.6.3 and scala 2.11.8 for the first time and it is not getting executed using jar. Below are my dependencies in build.sbt

scalaVersion := "2.11.8"
val scalatraVersion = "2.6.3"

dependencyOverrides += "com.fasterxml.jackson.core" % "jackson-core" % "2.9.4"
dependencyOverrides += "com.fasterxml.jackson.core" % "jackson-databind" % "2.9.4"
dependencyOverrides += "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.9.4"


libraryDependencies ++= Seq(
  "com.microsoft.sqlserver" % "mssql-jdbc" % "6.4.0.jre8", //Microsoft JDBC Driver For SQL Server
  "com.typesafe.play" %% "play-json" % "2.5.10",
  "com.typesafe" % "config" % "1.2.1", //Configuration
  "org.scalaj" %% "scalaj-http" % "2.3.0" % "compile",
  "org.apache.spark" %% "spark-core" % "2.2.0",
  "org.apache.spark" %% "spark-sql" % "2.2.0",
  "org.scala-lang" % "scala-library" % "${scala.version}",
  "org.apache.lucene" % "lucene-queryparser" % "7.2.1",
  "org.apache.lucene" % "lucene-queries" % "7.2.1",
  "org.apache.lucene" % "lucene-analyzers-common" % "7.2.1",
  "org.apache.lucene" % "lucene-codecs" % "7.2.1" ,
  "com.microsoft.azure" % "azure-storage" % "3.1.0",
  "com.microsoft.azure" % "azure-eventhubs" % "0.6.6",
  "org.apache.hadoop" % "hadoop-azure" % "2.7.0",
  "com.github.scala-incubator.io" %% "scala-io-file" % "0.4.3-1",
  "com.amazonaws" % "aws-java-sdk-logs" % "1.10.40",

  //Logging
  "org.slf4j" % "slf4j-api" % "1.7.25",
  "ch.qos.logback" % "logback-classic" % "1.2.3",

  "org.scalatra" %% "scalatra" % scalatraVersion,
  "org.scalatra" %% "scalatra-scalatest" % scalatraVersion % "test",
  "org.eclipse.jetty" % "jetty-webapp" % "9.4.10.RC1",
  "javax.servlet" % "javax.servlet-api" % "3.1.0" % "provided",
  "org.scalatra" %% "scalatra-scalate" % scalatraVersion
)

unmanagedResourceDirectories in Compile += { baseDirectory.value / "src/main/webapp" }
enablePlugins(ScalatraPlugin)

assemblyMergeStrategy in assembly := {

  case PathList("META-INF", xs @ _*) =>
    (xs map {_.toLowerCase}) match {
       case "services" :: xs =>
        MergeStrategy.first
      case _ => MergeStrategy.discard
    }
   case x => MergeStrategy.first
}

I know scalatra internally uses jetty to run App, I have setup webapp directory (src/main/webapp/) in project and I am able to run App in local using intellij but when I run it from jar file (created using sbt assembly) then it fails to find web app folder. Below is the code of Main app.

val server = {
  val listenPort = if (System.getenv.containsKey("PORT")) System.getenv.get("PORT").toShort else ConfigFactory.load.getString("api.port_num").toShort;
  logger.info("Listen Port: " + listenPort)
  new Server(listenPort)
}

val context: WebAppContext = new WebAppContext();
val webappDirLocation = "src/main/webapp/"
context.setServer(server)
context.setContextPath("/");
context.setDescriptor(webappDirLocation + "/WEB-INF/web.xml")
context.setResourceBase(webappDirLocation)
server.setHandler(context);

try {
  server.start()
  server.join()
} catch {
  case e: Exception => logger.error(s"Error occurred while starting App : $e")
    throw new RuntimeException(s"Unable to start App : $e")
}

Please suggest how to resolve this error, I am completely stuck at this. Tried below steps to resolve it, but no luck: -set war location using context.setWar method. -getting absolute path of src/main/webapp before setting in context

Thanks in advance!


Solution

  • If your assembly jar file contains /WEB-INF/web.xml, you can setup WebAppContext as follows:

    val context: WebAppContext = new WebAppContext()
    val webXml = getClass.getResource("/WEB-INF/web.xml")
    
    val webappDirLocation = if(webXml != null){
      // running the assembly jar
      webXml.toString.replaceFirst("/WEB-INF/web.xml$", "/")
    } else {
      // running on the source tree
      "src/main/webapp/"
    }
    
    context.setResourceBase(webappDirLocation)
    context.setDescriptor(webappDirLocation + "WEB-INF/web.xml")
    

    In above example, configuration is switched because it needs different configuration for running on the source tree and for running the assembly jar.

    In addition, note that you need to add following line to your build.sbt to include webapp/* to your assembly jar file by sbt-assembly-plugin:

    unmanagedResourceDirectories in Compile += { baseDirectory.value / "src/main/webapp" }