Prudence
The Scalable REST/JVM
Web Development Platform

Creative Commons License

The Prudence Instance

Here we'll describe the directory and file structure of a Prudence instance, and how to configure it.

Subdirectory Structure

/applications/

This is where you deploy your applications, each occupying a subdirectory. Your application's subdirectory name serves as a useful default name for your application. It is also the default base URL, and the default logging name.
The /applications/ subdirectory is "zip-aware," meaning that zip archives placed here will be automatically expanded.
See Prudence applications for a complete reference.

/common/

This subdirectory is similar in structure to that of an application, and acts as a shared area for all applications to use. You can thus install libraries, fragments and other resources here without having to duplicate them in each application.
The /common/ subdirectory is "zip-aware," meaning that zip archives placed here will be automatically expanded.
See Prudence applications for more information on how /common/ is used.

/bin/

These shell scripts start up the Prudence instance. Use run.sh for Unix-like operating systems, such as Linux, *BSD and Mac OS X, and run.bat for Windows.
In production environments, it's best to run Prudence as a daemon in Unix-like systems or a service in Windows, via a lightweight wrapper.
What the /bin/ scripts do is:
  1. Set the JVM classpath to include all the JARs in /libraries/
  2. Start the JVM
  3. Delegate to your /instance/ script

/instance/

Your Prudence instance's configuration scripts go here. You need, at the very least, a "default.*" script.

/defaults/

The default configuration scripts for both the Prudence instance and for applications go here.

/logs/

This is where your rolling logs will appear. Prudence logs are highly configurable and powerful. In particular, your web.log will show all requests hitting your Prudence server, using a standard format that can be consumed and analyzed by many monitoring tools.
See logging.

/configuration/

There are a few essential configuration files here.

/libraries/

Here you will find Prudence's main libraries as well as support libraries. The main /libraries/ subdirectory is for Java archives (JARs).
We've named or renamed all Prudence JARs according to their main Java package prefix, but you do not have to follow this convention.

Configuration Scripts

In Prudence, most instance and application configuration files are written in programming language code, rather than XML or other configuration formats. This method is sometimes called "bootstrapping" or just "scripting." So, rather than referring to them as "configuration files," we'll call them "configuration scripts."
Scripting is powerful. It lets your configuration be dynamic, such that the same configuration script might configure things differently depending on the actual deployment environment and runtime circumstances. For example, you can deploy the same instance to a development environment, in which case your instance would start various debugging processes and logs, and a production environment, in which case it would optimize for performance and scale. You can even have different optimizations for different deployments. For example, a weak cloud-based instance with a single virtual CPU could be use a different HTTP engine from a dedicated box with 8 cores and a lot of RAM. With scripts, you can dynamically test for the presence of installed optional components, etc.
But you can do more with configuration scripts: anything, in fact, that the language and its libraries allow you. You can start external services, log startup errors, notify monitoring daemons, etc.
Prudence's configuration scripts are designed to fall back on default scripts, which are all in the /defaults/ subdirectory. These idea is for these scripts to handle configuration sensibly, as would be appropriate, or good enough, for most common use cases. You can do a lot with Prudence without changing any of these default scripts!
The common way to override any default script is to create your own version, execute the default script first, and then apply your overrides. You can also not execute the default script, and instead handle things your own way. You can edit the defaults directly to apply changes across the board: they are all simple, straightforward scripts.
The disadvantage of configuration by script is more limited portability. For example, if you write your configuration scripts in Ruby, they will not work in Prudence for Python—unless you manually install Python support. If you want to support all Prudence flavors, you would have to include scripts for all languages.
Another disadvantage, for now, is that you will need to restart the Prudence instance for changes in your configuration scripts to take effect. This is true for Prudence 1.1: we plan to support "hot" configuration in a future version of Prudence.
For the purposes of this manual, we'll use the "filename.*" for configuration script names. To get the actual script file name, replace the "*" with the filename extension appropriate for your Prudence flavor: "js" for JavaScript, "rb" for Ruby, "py" for Python, etc.

/defaults/

Here you'll find the default scripts used in /instance/ and /applications/. Generally, you won't want to edit the /defaults/ scripts directly, but instead override them there. Prudence tries to make configuration easy by implementing sensible default behavior with a straightforward override mechanism: simply execute the /defaults/ script and then apply your own code. It's always a good idea to at least look at the code in the /defaults/ scripts so you can precisely understand what you're overriding.
Here's an overriding example in the JavaScript flavor. We'll override the default cache installed in the component by creating a "/instance/component.js" script:
// Implement defaults
document.execute('/defaults/instance/component/')
​
// Replace default cache with a Hazelcast-based cache
importClass(com.threecrickets.prudence.cache.HazelcastCache)
component.context.attributes.put('com.threecrickets.prudence.cache',
	new HazelcastCache())
Rather than explain the role of individual /defaults/ scripts here, we will refer to them as they are used in the sections below.

/instance/

This is where the Prudence instance gets initialized. The instance is the overall container which manages the servers and the applications.

/instance/default.*

This is the only required instance configuration script, and is the entry point for Prudence. Usually, all it does is simply execute /defaults/instance/, which bootstraps the Prudence instance.
You'd likely prefer to override the other configuration scripts. Override "/instance/default.*" if you want to do things after everything else in the instance has been initialized.
The default script does the following:
  1. Prints the Prudence welcome message to the console
  2. Sets up logging, including applying /configuration/logging.conf
  3. Executes /instance/component/ or /defaults/instance/component/
  4. Executes /instance/clients/ or /defaults/instance/clients/
  5. Executes /instance/routing/ or /defaults/instance/routing/
  6. Executes /instance/servers/ or /defaults/instance/servers/
  7. Starts the component
  8. Submits bootstrap tasks for execution

/instance/component.*

The "component" in REST terminology refers to the highest-level communication abstraction: the network is made of "components" communicating with other "components." Every Prudence instance is in essence a single component, which can include multiple servers and clients.
Override this script to change the way the component is created. In particular you might want to change the default cache backend or executor.
The default script does the following:
  1. Creates a Restlet component
  2. Configures its logService
  3. Sets its statusService to be a DelegatedStatusService
  4. Creates a global thread pool executor, which is used for application.task
  5. Creates a cache chain with a Hazelcast cache, used for document.cache

/instance/clients.*

Override this script to add more clients to your component.
The default script adds file and HTTP clients. The file client is required for static web support, and also for you to access files on your filesystem as REST resources. The HTTP client is required for you to access external REST resources on the web.
Configuration parameters for clients are documented in the HttpClientHelper.

/instance/routing.*

Override this script to change the way the component initializes its routing. Because this script delegates to /instance/hosts/ and to your /applications/, it's more likely that you'll want to override those.
The default script does the following:
  1. Executes /instance/hosts/ or /defaults/instances/hosts/
  2. Initializes all applications in /applications/ (this list is accessible as "com.threecrickets.prudence.applications" in the component's context)
  3. If there are no applications, the Prudence instance is terminated

/instance/hosts.*

Virtual hosting allows you to serve multiple web sites from a single component. You can configure individual applications to attach one or more hosts, and to have different base URLs on each of these hosts. Prudence allows you to create virtual hosts for multiple domain names and HTTP ports, using simple expressions and wildcards. See virtual hosts.
By default, an "allHosts" virtual host is created, and set as the component's default host, which in turn all applications attach to by default. "allHosts" accepts all incoming requests, to any domain name, to any port.
Override this script to create additional virtual hosts for your component, and to change the default host.
For example, you might want your Prudence component to only serve requests for "www.mysite.org" instead of the permissive "allHosts." Or, you might want to serve multiple web sites with different sets of applications on each.
The default script does the following:
  1. Creates the "allHosts" virtual host
  2. Sets it as the component's default host

/instance/servers.*

Servers do the low-level work of listening to a port, accepting requests, and returning responses according to supported protocols. Prudence currently supports your choice among various HTTP server technologies: Jetty, Grizzly, Netty and an "internal" connector. To change the HTTP server technology, you have to add its JARs to /libraries/. See the Restlet documentation for more information.
You can create as many servers as you need to listen on multiple ports. Remember that routing is actually handled by virtual hosts, not the servers. So, if you have servers on ports 8081, 8082, and 8083, and your applications all attach to "allHosts," then the applications will be available on all ports. To limit applications to specific ports, you will need to create additional virtual hosts. See virtual hosts.
Override this script to change the default port (8080) or add additional servers on other ports.
The default script does the following:
  1. Creates an HTTP server on port 8080, with support for the X-FORWARDED-FOR header used by proxies
  2. Prints out information about this server
Secure Servers (https)
If you are using a load balancer or another kind of proxy, it makes more sense to handle secure connections there. See the example there on how to do this with Perlbal.
Note, though, that if you want to handle secure requests differently in Prudence, you must allow for some way to distinguish them. This can easily be done by creating a separate non-secure server to which the proxy would send secure requests. You can then use virtual hosts or other kinds of routing to send requests to different applications or resources. Alternatively, you could check for the reference in code. For example:
if(conversation.reference.schemeProtocol.name == 'HTTPS') {
	...
}
Prudence can also handle secure connections itself. Here's an example "/instance/severs.js":
// Implement defaults
document.execute('/defaults/instance/servers/')
​
// Create secure server listening on the default HTTPS port (443)
var secureServer = new Server(Protocol.HTTPS, 443)
secureServer.name = 'secure'
component.servers.add(secureServer)
​
// Configure it to use our security keys
secureServer.context.parameters.add('keystorePath', '/path/prudence.jks')
secureServer.context.parameters.add('keystorePassword', 'mykeystorepassword')
//secureServer.context.parameters.add('keyPassword', 'mykeypassword')
​
// Add support for the X-FORWARDED-FOR header used by proxies
secureServer.context.parameters.add('useForwardedForHeader', 'true')
See the Restlet Jetty HttpServerHelper documentation for more configuration parameters.
The above configuration script assumes the you have a JKS ("Java keystore") file at "/path/prudence.jks" with your security keys. You can create one with the "keytool" command that is bundled with most JVMs. For example:
keytool -keystore /path/prudence.jks -alias mykey -genkey -keyalg RSA
When creating the keystore, you will be asked provide a password for it, and you may optionally provide a different password for your key, in which case you need to comment out the relevant line in the "servers.js" above. (The key alias and key password would be kept if you move the key to a different keystore.)
Such self-created keys may be useful for controlled intranet environments, in which you can provide clients with the public key, but for Internet applications you will likely want a key created by one of the "certificate authorities" trusted by major browsers. Some of these certificate authorities may let your get your key in JKS format. Otherwise, if they support PKCS12 format, you can use keytool (from version 6) to convert it to JKS. For example:
keytool -importkeystore -srcstoretype PKCS12 -srckeystore /path/prudence.pkcs12 -destkeystore /path/prudence.jks
If you don't even have access to a PKCS12 file, you can create one from your ".key" and ".crt" (or ".pem") files using OpenSSL:
openssl pkcs12 -inkey /path/mykey.key -in /path/mykey.crt -export -out /path/prudence.pkcs12 
(Note that you must give your PKCS12 a non-empty password, or else keytool will fail with an unhelpful error message.)