Configuration
As you develop, test, and get ready for final deployment, you’ll need to configure things about your app: its environment, its settings, initial configurations when it starts up, and the software it depends on.
Configuring your app using the ScalatraBootstrap file
As of 3.0.x, the ScalatraBootstrap
file is the recommended way
of configuring your application. It allows you to easily mount different
servlets, set application parameters, and run initialization code for your
app, without touching much in the way of XML.
If you’ve just started a new project in Scalatra 3.0.x, using the giter8 template, all of this will already be set up for you. However, if you’re upgrading from 2.x, or you just want to understand what’s going on, read on.
First, the bad news: there is some XML involved, because this is one of the points where Scalatra needs to interface with Java servlets, the underlying technology it’s sitting on top of.
All Scalatra projects have a web.xml
file, in src/main/webapp/WEB-INF/
.
Find yours and open it.
In a regular Java servlet application, most application configuration is done
inside web.xml
. However, Scalatra applications can drop in some standard
config code, and use regular Scala code for configuration afterwards.
The XML which allows you to do this is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<listener>
<listener-class>org.scalatra.servlet.ScalatraListener</listener-class>
</listener>
</web-app>
If you started your project in an older version of Scalatra, and want to start using the new ScalatraBootstrap configuration style, drop that XML into your web.xml and you’re all set.
Note that there are no servlet-names, servlet classes, etc. That’s all
handled dynamically by the ScalatraListener
class, which will supply our actual
configuration to the underlying servlet container.
This closes the XML portion of our broadcast.
Note that there is also a file called ScalatraBootstrap.scala
in your src/main/scala
directory. This is the Scalatra bootstrap config file, and it’s where you should
do most of your app configuration work.
The simplest version of this file, which gets generated when you make a new project using the giter8 template, looks something like this:
import org.scalatra.LifeCycle
import jakarta.servlet.ServletContext
import org.yourdomain.projectname._
class ScalatraBootstrap extends LifeCycle {
override def init(context: ServletContext) = {
// mount servlets like this:
context.mount(new ArticlesServlet, "/articles/*")
}
}
Custom location of Scalatra bootstrap class
If you would like to move the ScalatraBootstrap.scala
out of the default package and into one of your own, you can specify the location of the bootstrap file in your web.xml
file:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<context-param>
<param-name>org.scalatra.LifeCycle</param-name>
<param-value>org.yourdomain.project.MyScalatraBootstrap</param-value>
</context-param>
<listener>
<listener-class>org.scalatra.servlet.ScalatraListener</listener-class>
</listener>
</web-app>
Now your bootstrap class file can be located in the org.yourdomain.project
package and be named MyScalatraBootstrap.scala
.
Mounting multiple servlets (or filters)
If you’ve got more than one servlet or filter in your application, you’ll need to mount them.
The ScalatraBootstrap
config class allows you to mount servlets or
filters (or both) into your application, and define URL path patterns that
they’ll respond to.
override def init(context: ServletContext) = {
// mount a first servlet like this:
context.mount(new ArticlesServlet, "/articles/*")
// mount a second servlet like this:
context.mount(new CommentsServlet, "/comments/*")
}
Init params
You can set init params in the Scalatra bootstrap file. For instance, you
can set the org.scalatra.environment
init parameter to set the application
environment:
override def init(context: ServletContext) = {
// mount a first servlet like this:
context.mount(new ArticlesServlet, "/articles/*")
// Let's set the environment
context.setInitParameter("org.scalatra.environment", "production")
}
Environment init param
context.setInitParameter(org.scalatra.EnvironmentKey, "production")
or
context.setInitParameter("org.scalatra.environment", "production")
This init param sets the application environment.
The default is development
.
If the environment starts with “dev”, then isDevelopmentMode
returns true.
In development mode, a few things happen.
- In a ScalatraServlet, the notFound handler is enhanced so that it dumps the effective request path and the list of routes it tried to match. This does not happen in a ScalatraFilter, which just delegates to the filterChain when no route matches.
- Meaningful error pages are enabled (e.g. on 404s, 500s).
- The Scalate console is enabled.
Container init params
context.setInitParameter(ScalatraBase.HostNameKey, "myapp.local")
or
context.setInitParameter("org.scalatra.HostName", "myapp.local")
context.setInitParameter(ScalatraBase.PortKey, "443")
or
context.setInitParameter("org.scalatra.Port", "443")
context.setInitParameter(ScalatraBase.ForceHttpsKey, "true")
or
context.setInitParameter("org.scalatra.ForceHttps", "true")
By default, the values for hostname, port, and SSL settings are inherited from the servlet container’s settings. You can set these init params if you want to override the domain or port your website is hosted on, or force the use of https.
So if Jetty is running at http://localhost:8080 on your machine you may want
to expose it as: https://myapp.local:443 (with an appropriate entry in
/etc/hosts
).
Cross Origin Resource Sharing init params
These keys and their purposes are documented in the CORS guide, but for completeness, here they are.
The CORS guide uses the alternate forms of these keys, so check in that guide if you’d like to see the alternate form.
context.setInitParameter(CorsSupport.AllowedOriginsKey, "www.other.com,www.foo.com")
context.setInitParameter(CorsSupport.AllowedMethodsKey, "GET,PUT")
context.setInitParameter(CorsSupport.AllowedHeadersKey, "Content-Type")
context.setInitParameter(CorsSupport.AllowCredentialsKey, "true")
context.setInitParameter(CorsSupport.PreflightMaxAgeKey, "1800")
Async init params
context.setAttribute(AsyncSupport.ExecutionContextKey, executionContext)
This key sets the ExecutionContext
which Scalatra should use when creating an
Future
.
Running code at application start
The ScalatraBootstrap file is also a good place to put things like database
initialization code, which need to be set up once in your application. You can
mix in whatever traits you want, and run any Scala code you want from inside
the init
method:
import org.scalatra.LifeCycle
import jakarta.servlet.ServletContext
// Import the trait:
import com.yourdomain.yourapp.DatabaseInit
// Mixing in the trait:
class ScalatraBootstrap extends LifeCycle with DatabaseInit {
override def init(context: ServletContext) = {
// call a method that comes from inside our DatabaseInit trait:
configureDb()
// Mount our servlets as normal:
context.mount(new Articles, "/articles/*")
context.mount(new Users, "/users/*")
}
}
Configuring your app using web.xml
web.xml
file in traditional servlet style, so you
may not want to use the Scalatra bootstrap file. If you want, you can use
web.xml for some things and the Scalatra bootstrap file for others.
Mounting multiple servlets (or filters) using web.xml
You can mount multiple servlets looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>BasicAuthExample</servlet-name>
<servlet-class>org.scalatra.BasicAuthExample</servlet-class>
</servlet>
<servlet>
<servlet-name>TemplateExample</servlet-name>
<servlet-class>org.scalatra.TemplateExample</servlet-class>
</servlet>
</web-app>
Setting init params using web.xml
You can set init params for your servlets in the normal manner:
<servlet>
<servlet-name>BasicAuthExample</servlet-name>
<servlet-class>org.scalatra.BasicAuthExample</servlet-class>
<init-param>
<param-name>org.scalatra.environment</param-name>
<param-value>development</param-value>
</init-param>
</servlet>
Application environments
The application environment is defined by:
- The
org.scalatra.environment
system property. - The
org.scalatra.environment
init parameter.
You can set the application’s environment in the following ways:
- The preferred method: as an init-param in the Scalatra Bootstrap file.
- As an init-param in web.xml.
- As a system property: this is most commonly set with a
-D
option on the command line:java -Dorg.scalatra.environment=development
When you deploy your application to a production environment, you’ll typically want to change its environment to “production”.
There are a few ways you can accomplish this.
Environment variables
If you’re using Scalatra 2.1 or better, you can set it in your ScalatraBootstrap file based on an environment variable that’s present on production machines.
Massaging your WAR file
If you’re using Scalatra 2.0.x or just happen to like XML configuration, you can use a post-hook in the xsbt-web-plugin to massage the contents of your WAR file during packaging.
Load the Web.xml file and replace the value for org.scalatra.environment
using
Scala’s standard XML tools.
Changing the port in development
Add Jetty / containerPort := 8081
to build.sbt
if you would
like your Scalatra app to run on something other than the default port (8080).
You may need to add the following imports if you get errors upon adding the configuration above:
import com.earldouglas.xwp.JettyPlugin
import com.earldouglas.xwp.JettyPlugin.autoImport._
import com.earldouglas.xwp.ContainerPlugin.autoImport._