Code Monkey home page Code Monkey logo

xsbt-web-plugin's Introduction

xsbt-web-plugin

Current release: 3.0.3

xsbt-web-plugin is an sbt extension for building J2EE Web applications in Scala and Java. It is best suited for projects that:

For previous releases, see the docs directory. Releases follow Specified Versioning guidelines.

Requirements

  • Scala 2.10.2+
  • sbt 0.13.6+

Quick reference

Add xsbt-web-plugin to project/plugins.sbt:

addSbtPlugin("com.earldouglas" % "xsbt-web-plugin" % "3.0.3")

Enable the Jetty plugin:

build.sbt:

enablePlugins(JettyPlugin)

From the sbt console:

  • Start (or restart) the container with jetty:start
  • Stop the container with jetty:stop
  • Build a .war file with package

To use Tomcat instead of Jetty:

  • Substitute TomcatPlugin for JettyPlugin
  • Substitute tomcat:start for jetty:start
  • Substitute tomcat:stop for jetty:stop

Starting from scratch

Create a new empty project:

mkdir myproject
cd myproject

Set up the project structure:

mkdir project
mkdir -p src/main/scala
mkdir -p src/main/webapp/WEB-INF

Configure sbt:

project/build.properties:

sbt.version=0.13.8

project/build.sbt:

addSbtPlugin("com.earldouglas" % "xsbt-web-plugin" % "3.0.3")

build.sbt:

scalaVersion := "2.11.6"

libraryDependencies += "javax.servlet" % "javax.servlet-api" % "3.0.1" % "provided"

enablePlugins(JettyPlugin)

Add a servlet:

src/main/scala/servlets.scala:

package servlets

import javax.servlet.http._

class MyServlet extends HttpServlet {

  override def doGet(request: HttpServletRequest, response: HttpServletResponse) {
    response.setContentType("text/html")
    response.setCharacterEncoding("UTF-8")
    response.getWriter.write("""<h1>Hello, world!</h1>""")
  }

}

src/main/webapp/WEB-INF/web.xml:

<web-app>

  <servlet>
    <servlet-name>my servlet</servlet-name>
    <servlet-class>servlets.MyServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>my servlet</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>

</web-app>

Configuration and use

Triggered execution

xsbt-web-plugin supports sbt's triggered execution by prefixing commands with ~.

sbt console:

> ~jetty:start

This starts the Jetty container, then monitors the sources, resources, and webapp directories for changes, which triggers a container restart.

Container arguments

To pass extra arguments to the Jetty or Tomcat container, set containerArgs:

containerArgs := Seq("--path", "/myservice")

Custom container

To use a custom J2EE container, e.g. a main class named runner.Run, enable ContainerPlugin and set containerLibs and containerLaunchCmd:

enablePlugins(ContainerPlugin)

containerLibs in Container := Seq(
    "org.eclipse.jetty" %  "jetty-webapp" % "9.1.0.v20131115"
  , "org.eclipse.jetty" %  "jetty-plus"   % "9.1.0.v20131115"
  , "test"              %% "runner"       % "0.1.0-SNAPSHOT"
)

containerLaunchCmd in Container :=
  { (port, path) => Seq("runner.Run", port.toString, path) }

sbt:

> container:start
> container:stop

Example: container/custom-runner

Forked JVM options

To set system properties for the forked container JVM, set containerForkOptions:

containerForkOptions := new ForkOptions(runJVMOptions = Seq("-Dh2g2=42"))

Example: container/fork-options

Alternatively, set javaOptions in the Jetty (or Tomcat) configuration:

javaOptions in Jetty += "-Dh2g2=42"

Example: container/java-options

To attach a debugger, set -Xdebug and -Xrunjdwp:

build.sbt:

javaOptions in Jetty ++= Seq(
  "-Xdebug",
  "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000"
)

In Eclipse:

  • Create and run a new Remote Java Application launch configuration
  • Set Connection Type to Scala debugger (Socket Attach)
  • Configure to connect to localhost on port 8000

In IntelliJ IDEA:

  • Add a Remote run configuration: Run -> Edit Configurations...
  • Under Defaults select Remote and push + to add a new configuration
  • By default the configuration uses port 5005; update it to 8000 as above
  • Name this configuration, and run it in debug mode

Debug mode

To enable debugging through JDWP, use jetty:debug or tomcat:debug. Optionally set debugAddress, which defaults to "debug" under Windows and "8888" otherwise, and debugOptions, which defaults to:

port =>
  Seq( "-Xdebug"
     , Seq( "-Xrunjdwp:transport=dt_socket"
          , "address=" + port
          , "server=y"
          , "suspend=n"
          ).mkString(",")
     )

Jetty version

By default, Jetty 9.4.1 is used. To use a different version, set containerLibs:

containerLibs in Jetty := Seq("org.mortbay.jetty" % "jetty-runner" % "7.0.0.v20091005" intransitive())

Depending on the version, it may also be necessary to specify the name of Jetty's runner:

containerMain := "org.mortbay.jetty.runner.Runner"

Examples:

Container port

By default, the container runs on port 8080. To use a different port, set containerPort:

containerPort := 9090

Examples:

jetty.xml

To use a jetty.xml configuration file, set containerConfigFile:

containerConfigFile := Some(file("etc/jetty.xml"))

This option can be used to enable SSL and HTTPS.

Examples:

Multi-project applications

Examples:

Tomcat version

By default, Tomcat 8.5.9.0 is used. To use a different version, set containerLibs:

containerLibs in Tomcat := Seq("com.github.jsimone" % "webapp-runner" % "7.0.34.1" intransitive())

Depending on the version, it may also be necessary to specify the name of Tomcat's runner:

containerMain in Tomcat := "webapp.runner.launch.Main"

Renaming the .war file

This can be useful for keeping the version number out of the .war file name, using a non-conventional file name or path, adding additional information to the file name, etc.

artifactName := { (v: ScalaVersion, m: ModuleID, a: Artifact) =>
  a.name + "." + a.extension
}

See "Modifying default artifacts" in the sbt documentation for additional information.

Massaging the .war file

After the /target/webapp directory is prepared, it can be modified with an arbitrary File => Unit function by setting webappPostProcess.

To list the contents of the webapp directory after it is prepared:

webappPostProcess := {
  webappDir: File =>
    def listFiles(level: Int)(f: File): Unit = {
      val indent = ((1 until level) map { _ => "  " }).mkString
      if (f.isDirectory) {
        streams.value.log.info(indent + f.getName + "/")
        f.listFiles foreach { listFiles(level + 1) }
      } else streams.value.log.info(indent + f.getName)
    }
    listFiles(1)(webappDir)
}

To include webapp resources from multiple directories in the prepared webapp directory:

webappPostProcess := {
  webappDir: File =>
    val baseDir = baseDirectory.value / "src" / "main"
    IO.copyDirectory(baseDir / "webapp1", webappDir)
    IO.copyDirectory(baseDir / "webapp2", webappDir)
    IO.copyDirectory(baseDir / "webapp3", webappDir)
}

Examples:

Custom resources directory

Files in the extra resource directory are not compiled, and are bundled directly in the project artifact .jar file.

To add a custom resources directory, set unmanagedResourceDirectories:

unmanagedResourceDirectories in Compile += (sourceDirectory in Compile).value / "extra"

Example: webapp/unmanaged-resources

Custom sources directory

Scala files in the extra source directory are compiled, and bundled in the project artifact .jar file.

To add a custom sources directory, set unmanagedSourceDirectories:

unmanagedSourceDirectories in Compile += (sourceDirectory in Compile).value / "extra"

Example: webapp/unmanaged-sources

Utilizing WEB-INF/classes

By default, project classes are packaged into a .jar file, shipped in the WEB-INF/lib directory of the .war file. To instead keep them extracted in WEB-INF/classes, set webappWebInfClasses:

webappWebInfClasses := true

Examples:

Web application destination

The Web application destination directory is where the static Web content, compiled Scala classes, library .jar files, etc. are placed. By default, they go to /target/webapp.

To specify a different directory, set target in the webappPrepare configuration:

target in webappPrepare := target.value / "WebContent"

Example: webapp/webapp-dest

Web application resources

The Web application resources directory is where static Web content (including .html, .css, and .js files, the web.xml container configuration file, etc. By default, this is kept in /src/main/webapp.

To specify a different directory, set sourceDirectory in the webappPrepare configuration:

sourceDirectory in webappPrepare := (sourceDirectory in Compile).value / "WebContent"

Example: webapp/webapp-src

Prepare the Web application for execution and deployment

For situations when the prepared /target/webapp directory is needed, but the packaged .war file isn't.

sbt console:

webappPrepare

Add manifest attributes

Manifest attributes of the .war file can be configured via packageOptions in sbt.Keys.package in build.sbt:

packageOptions in sbt.Keys.`package` +=
  Package.ManifestAttributes( java.util.jar.Attributes.Name.SEALED -> "true" )

Inherit manifest attributes

To configure the .war file to inherit the manifest attributes of the .jar file, typically set via packageOptions in (Compile, packageBin), set inheritJarManifest to true:

inheritJarManifest := true

Container shutdown and sbt

By default, sbt will shutdown the running container when exiting sbt.

To allow the container to continue running after sbt exits, set containerShutdownOnExit:

containerShutdownOnExit := false

Deploying to Heroku

Enable the HerokuDeploy plugin and configure your app name:

enablePlugins(HerokuDeploy)

herokuAppName := "my-heroku-app"

Either install the Heroku Toolbelt, or set your Heroku API key as an environment variable, launch sbt, and deploy with herokuDeploy:

$ HEROKU_API_KEY="xxx-xxx-xxxx" sbt
> herokuDeploy

Check out your deployed application at https://my-heroku-app.herokuapp.com.

Deploying to Elastic Beanstalk

Before trying to deploy anything, create an application and a Tomcat-based environment for it in Elastic Beanstalk.

Enable the ElasticBeanstalkDeployPlugin plugin, and configure your application's name, environment, and region:

enablePlugins(ElasticBeanstalkDeployPlugin)

elasticBeanstalkAppName := "my-elastic-beanstalk-app"

elasticBeanstalkEnvName := "production"

elasticBeanstalkRegion  := "us-west-1"

Add AWS credentials to your environment, launch sbt, and deploy with elasticBeanstalkDeploy:

$ AWS_ACCESS_KEY="xxx" AWS_SECRET_KEY="xxx" sbt
> elasticBeanstalkDeploy

Check out your deployed application at http://my-elastic-beanstalk-app.us-west-1.elasticbeanstalk.com.

Block sbt on running container

To start the container from the command line and block sbt from exiting prematurely, use jetty:join:

$ sbt jetty:start jetty:join

This is useful for running sbt in production (e.g. in a Docker container).

Quickstart mode

The development cycle can be sped up by serving static resources directly from source, and avoiding packaging of compiled artifacts.

Use <container>:quickstart in place of <container>:start to run the container in quickstart mode:

> jetty:quickstart

Note that this necessarily circumvents any behavior set in webappPostProcess.

Running multiple containers

To launch using more than a single container, set containerScale:

containerScale := 5

This will configure the container to launch in five forked JVMs, using five sequential ports starting from containerPort.

In debug mode, five additional sequential debug ports starting from debugPort will be opened.

JRebel integration

The development cycle can be further sped up by skipping server restarts between code recompilation.

Add -agentpath to the container's JVM options:

javaOptions in Jetty += "-agentpath:/path/to/jrebel/lib/libjrebel64.so"

Launch the container with quickstart, and run triggered compilation:

> jetty:quickstart
> ~compile

xsbt-web-plugin's People

Contributors

agjini avatar ambisoft avatar aolshevskiy avatar aryairani avatar bwkimmel avatar cdow avatar davidharcombe avatar earldouglas avatar guersam avatar hjast avatar janheise avatar jannic avatar jcranky avatar joeytsaiexpedia avatar kiris avatar mdedetrich avatar mtye avatar rladstaetter avatar tptodorov avatar xuwei-k avatar ymasory avatar zvozin avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.