Hosted by Three Crickets

Prudence
Scalable REST Platform
For the JVM

Prudence logo: bullfinch in flight

Implementing Resources

Prudence offers two options for implementing resources in which the content dynamically changes: "manual" resources are "raw," giving you complete low-level control over the behavior and format of the encapsulated resource, while "template" resources are simplified and highly optimized for cached textual resources, such as HTML web pages. Prudence also provides comprehensive support for static (unchanging) resources, just like conventional web servers.

Programmable Resources

These notes apply to both manual and template resources:

Manual Resources

These are implemented as a set of encapsulated entry points in any of the supported programming languages. The entry points all receive the current conversation API namespace as their only argument.
Prudence does the encapsulation for you: it treats the entry points as together belonging to a single logical RESTful resource, and ensures that the same conversation namespace is used for every user request.
There are two ways to define this encapsulation, depending on which routing paradigm you're using:
The implementation is in essence the same for both styles. For simplicity, our examples below will be tuned to resource mapping.

Configuration

Add support for manual resources using the "manual" route type in your routing.js, mapping it to a URI template ending in a wildcard:
app.routes = {
	'/*': 'manual'
}
The default configuration for "manual" will map all files from your application's "/resources/" subdirectory with the ".m." pre-extension. Here is the above configuration with all the defaults fleshed out:
app.routes = {
	'/*': {
		type: 'manual',
		root: 'resources',
		passThroughs: [],
		preExtension: 'm',
		trailingSlashRequired: true,
		internalUri: '/_manual/',
		clientCachingMode: 'conditional',
		maxClientCachingDuration: -1,
		compress: true
	}
}
General configuration for your code is done in setting.js.

handleInit

This is the only required entry point. It is called once for every user request, and always before any of the other entry points.
The main work is to initialize supported media types via the conversation.addMediaType APIs, in order of preference. For example:
function handleInit(conversation) {
	conversation.addMediaTypeByName('application/json')
	conversation.addMediaTypeByName('text/plain')
}
Note that you can also add language information:
function handleInit(conversation) {
	conversation.addMediaTypeByNameWithLanguage('text/plain', 'en')
	conversation.addMediaTypeByNameWithLanguage('text/plain', 'fr')
}
Prudence will use these values for content negotiation, choosing the best media type and language according to list of acceptable and preferred formats sent by the client and this list.
handleInit is also where you should set up caching, if you're using it:
function handleInit(conversation) {
	conversation.addMediaTypeByName('application/xml')
	caching.duration = '5s'
	caching.tags.add('blog')
}
Dynamic Content Negotiation
You might wonder why we add these supported media types via API calls for each request, since they are usually always the same for a resource. Why not simply configure them into the resource permanently?
The reason is that they should not always permanent. In handleInit, you can check for various conditions of the conversation, or even external to the conversation, to decide which media types and languages to support. For example, you might not want to support XHTML for old browsers, but you'd want it at the top of the list for new browsers. Or, you might not be able to support PDF in case an external conversion service is down. In which case, you won't want it on the list at all, and instead want content negotiation to choose a different format that the client supports, such as DVI.
So, building your content negotiation table via API gives you a lot flexibility, at no real expense: these API calls are very lightweight.
Note that handleInit is called even if your resource is cached (on the server), exactly because you need to set up content negotiation before casting the cache key template.

handleGet

Handles HTTP "GET" requests.
In a conventional resource-oriented architecture, clients will not be expecting the resource to be altered in any way by a GET operation.
What you'll usually do here is construct a representation of the resource, possibly according to specific parameters of the request, and then return this representation to the client, possibly with directions for client-side caching.
There are many kinds of payloads you can return to the client: they are discussed in depth in the web data chapter. However, here's a reference of the supported return types:
If your resource has been cached (on the server) then handleGet will not be called. The cache entry will be returned to the client instead.
Integrating Template Resources
It's possible to return template resources as your payload. This could be useful if you're implementing the Model-View-Controller (MVC) pattern. See the MVC chapter for complete examples.

handlePost

Handles HTTP "POST" requests.
In a conventional resource-oriented architecture, POST is the "update" operation (well, not exactly: see note below). Clients will expect the resource to already exist for the POST operation to succeed. That is, a call to GET before the POST may succeed. Clients expect you to return a modified representation, in the selected media type, if the POST succeeded. Subsequent GET operations would then return the same modified representation. A failed POST should not alter the resource: only a success status code should indicate a change. That means that ideally you should roll back changes if the entire operation fails along the way.
Note that the entity sent by the client does not have to be identical in format or content to what you return. In fact, it's likely that the client will send smaller delta updates in a POST, rather than a comprehensive representation.
What you'll usually do here is alter existing data according to data sent by the client.
The most important thing to realize is that POST is the only HTTP operation that is not "idempotent," which means that multiple identical POST operations on a resource may yield results that are different from that of a single POST operation. This is why web browsers warn you if you try to refresh or go back to a web page that is the result of a POST operation. As such, POST is the correct operation to use for manipulations of a resource that cannot be repeated. So, if you're thinking in terms of CRUD, POST can mean either "update" or "create": it depends on whether or not "create" is a repeatable operation in your specific data semantics. See this blog post by John Calcote for one explanation.
Return value behavior is identical to that in handleGet. In fact, you may want handlePost to share the same code path as handleGet for creating the representation.
Note that the default return status for successful operations, 200 ("ok"), is indeed OK. However, it is better to return a 201 ("created") status if indeed the resource was created, and also return the full representation. If you cannot handle the operation at the moment, you should return a 202 ("accepted") status, signifying that the operation has been queued for later.

handlePut

Handles HTTP "PUT" requests.
In a conventional resource-oriented architecture, PUT is the "create" operation (well, not exactly: see note below). Clients will expect whatever current data exists in the resource to be discarded, and for you to return a representation of the new resource in the selected media type. A failed PUT should not alter the resource.
Note that the entity sent by the client does not have to be identical in format or content to what you return.
What you'll usually do here is parse and store the data sent by the client, overwriting data if it already exists.
PUT, like most HTTP operations, is "idempotent," which means that multiple identical PUT operations on a resource are expected to yield the same result as a single PUT operation. PUT should thus overwrite any existing data. If you are implementing a "create" operation that cannot be repeated, then you should use POST instead. See note in POST.
See handleGet for supported return types. In fact, you may want handlePut to share the same code path as handleGet for creating the representation.
Note that the default return status for successful operations, 200 ("ok"), is indeed OK. However, it is better to return a 201 ("created") status if indeed the resource was created, and also return the full representation. If you cannot handle the operation at the moment, you should return a 202 ("accepted") status, signifying that the operation has been queued for later.

handleDelete

Handles HTTP "DELETE" requests.
In a conventional resource-oriented architecture, clients expect subsequent GET operations to fail with a 404 ("not found") code. A DELETE should fail with 404 if the resource is not already there; it should not silently succeed. A failed DELETE should not alter the resource.
What you'll usually do here is make sure the identified resource exists, and if it does, remove or mark it somehow as deleted
The following return types are supported:
Though some languages return null if no explicit return statement is used, others return the value of the last executed operation, which could be a number, which would in turn become an HTTP status code for the client. This can lead to some very bizarre bugs, as clients receive apparently random status codes! It's thus good practice to always explicitly return null in handleDelete, if only to add clarity to your code's intent.
If you cannot handle the operation at the moment, you should return a 202 ("accepted") status, signifying that the operation has been queued for later.

handleGetInfo

Handles HTTP "GET" requests before handleGet.
This entry point, if it exists, is called before handleGet in order to provide Prudence with information required for conditional HTTP requests. Only if conditions are not met—for example if our resource is newer than the version the client has cached, or the tag has changed—does Prudence continue to handleGet. Using handleGetInfo can thus improve on the gains of conditional requests: not only are you saving bandwidth, but you are also avoiding a potentially costly handleGet call. Note that if the client is not doing a conditional request, then handleGetInfo will not be called.
The use of handleGetInfo discussed in detail in the caching chapter. However, for the sake of completion, here's a reference of the supported return types:
Note that even though you can only return the modification date or the tag, it is possible set both together by returning one and setting the other via the APIs.
If you implement handleGetInfo, you should be returning the same conditional information in your handleGet implementation, so that the client would know how to tag the data. The return value from handleGetInfo does not, in fact, ever get to the client: it is only used internally by Prudence to process conditional requests.

Template Resources

Though especially suitable for web pages (HTML), template resources can be used for any kind of textual asset. They are indeed intended and optimized for arbitrary textual formats: HTML, XML, plain text, etc. The design goal is to make it as easy as possible to generate the text dynamically, by allowing developers and designers to mix static elements with dynamic elements into a single file.
Using the default "scriptlets" parser, this means that the file is static text optionally embedded with delimited programming source code—these are the scriptlets. There are a few built-in shortcut scriptlets for common tasks, and it's also easy to write plugins to implement your own custom shortcuts.
The "scriptlets" parser is intended to be as straightforward and flexible as possible, mimicking the familiar paradigm of PHP/ASP/JSP, which allows for raw code that is executed in-place. However, it's possible to replace this parser with your own should you desire. For example, you might prefer declarative rather than procedural templates (mimicking the structure of HTML/XML), and rather than have opaquely delimited areas, you might prefer structural parsing of XML attributes. The parser system is pluggable and easy to extend.
Whatever parser you use, it will compile the whole file into one or more "programs" that are executed in sequence. Thus, unlike manual resources, template resources have no "entry points," and work in quite a different execution environment, and indeed each "program" can be in a different programming language, allowing for mixed-language templates.

Configuration

Add support for template resources using the "templates" route type in your routing.js, mapping it to a URI template ending in a wildcard:
app.routes = {
	'/*': 'templates'
}
The default configuration for "templates" will map all files from your application's "/resources/" subdirectory with the ".t." pre-extension. Here is the above configuration with all the defaults fleshed out:
app.routes = {
	'/*': {
		type: 'templates',
		root: 'resources',
		includeRoot: ['libraries', 'includes'],
		passThroughs: [],
		preExtension: 't',
		trailingSlashRequired: true,
		defaultDocumentName: 'index',
		defaultExtension: 'html',
		clientCachingMode: 'conditional',
		maxClientCachingDuration: -1,
		compress: true
	}
}
General configuration for templates is in setting.js, as are the general configuration for code.

MIME Types and Compression

Prudence will handle HTTP content negotiation for your template resources, and will assume a single MIME type per resource. That MIME type is determined by the filename extension. For example, a resource named "profile.t.html" will have the "text/html" MIME type.
Prudence recognizes many common file types by default, but you can add your own mappings in you application's settings.js, using app.settings.mediaTypes.
When "compress" is true, Prudence will negotiate the best compression format (gzip and zip are supported) and compress on the fly. Compression can be configured in settings.js.

Scriptlets

By default, you can use either "<%…%>" (ASP/JSP-style) or "<?…?>" (PHP-style) scriptlet delimiters in your templates. Note that you can only use one or the other, though, in the same template.
The entire template is turned into a single program (or several programs if you are mixing languages: more on that below): the code between the delimiters is output as-is to the program, while the rest will be printed out. For example, the following template:
<% for (var x = 0; x < 10; x++) { %>
<p>This is a "line"</p>
<% } %>
Will become the following program behind the scenes:
for (var x = 0; x < 10; x++) {
print("<p>This is a \"line\"</p>")
}
You can see the programs generated behind the scenes by enabling debug mode.
It's important to emphasize that any code can be used in templates: you can import libraries, define functions and classes, etc. It's up to you to decide how much and what kind of programming logic to use in templates. There are indeed strict coding disciplines, such as MVC, that forbid anything but visual logic in template. See the MVC chapter for a complete discussion.
You can specify the language of the scriptlet in its opening delimiter:
<%ruby print 1 + 2 %>
Full language names are supported, as above, as well as shortcuts that are usually the common filename extensions for that language: "rb" for Ruby, "py" for Python, "js" for JavaScript, etc.
If the language of a scriptlet is not specified, it will default to the language of the previous scriptlet, so that you only need to specify the language if you are changing languages. If the first scriptlet does not specify a language, it will use the "defaultLanguageTag" setting. The default for that is JavaScript.

Built-In Shortcuts

Shortcuts use a special marker after the scriptlet's opening delimiter.
To output an expression:
<%= x*2 %>
The above is equivalent to:
<% print(x*2) %>
To include another template:
<%& '/header/' %>
The above is equivalent to:
<% document.include('/header/'); %>
A shortcut to print out conversation.base:
<%.%>
Scriptlet comments can be used for human-readable explanations, or to temporarily disable scriptlets:
<%# This scriptlet will be ignored by the parser. %>
All the above shortcuts work for all supported programming languages, generating source code in that language. To combine a language specification with a shortcut symbol, put the shortcut symbol first:
<%=rb x*2 %>
A few other built-in shortcuts are introduced under inheritance, and it's also possible create your own shortcuts.

Fragments

You can compose your templates out of reusable "fragments" by placing them in the "/libraries/includes/" directory, and then including them in other templates using the the "<%&…%>" shortcut (or the document.include API directly). For example, we can create this fragment in "/libraries/includes/lists/simple.t.html":
<li><%= line %></li>
And then use it like so:
<% for (int l in lines) { var line = lines[l] %>
<%& '/lists/simple/' %>
<% } %>
Fragments don't have to include scriptlets: they can be purely textual. On the other hand, they can contain sophisticated code to generate their HTML. Fragments can also be nested to any depth: a fragment can include others, those can include others, and so on.
Fragments in Prudence are not merely "server-side includes": in fact, each fragment is cached separately, with its own cache key and cache duration. This allows you to create sophisticated and extremely efficient fine-grained caching strategies. See the caching chapter.
To share fragments with all applications, put them in your container's "/libraries/prudence-includes/" directory. Files in your application's "/libraries/includes/" will always override the shared versions.

Blocks and Inheritance

This feature is very similar to fragments, but can be understood as its inverse: rather than inserting a fragment into the current location using "<%&…%>", you define blocks that will only later be inserted into a template. Unlike fragments, blocks cannot be individually cached, but they can otherwise provide additional flexibility in assembling your page. It's a good idea to use both: blocks when you need design flexibility and fragments when you need fine-grained caching.
There are special scriptlets for blocks. As an example, let's define a block and then include the actual template:
<%{ title %>
	<h1>My Title</h1>
<%}%>
<%& '/templates/main/' %>
The block definition is enclosed in "<%{…%>" and "<%}%>" scriptlets: instead of being printed out to the page, it will be saved for later use. Indeed, the template above generates no actual output in itself.
Now, let's see the actual template, in "/includes/templates/main.t.html":
<html>
<body>
<%== title %>
</body>
</html>
The "<%==…%>" scriptlet is a shortcut to print any conversation.local: indeed, our block was simply a temporary capturing of output into a conversation.local. Behind the scenes, blocks are simply calls to document.startCapture and document.endCapture.
But what if you want to give the block a default value in the template? There are special scriptlets for that, too. Let's change our "main.t.html":
<html>
<body>
<%[ title %>
	<h1>Default Title</h1>
<%]%>
</body>
</html>
The "<%[…%>" and "<%]%>" scriptlets are like a conditional "<%==…%>": the code between them will not be executed if the conversation.local is already defined. If it is defined, then it will simply be printed out.
Blocks with Arguments
You may need blocks that change their content according to external parameters. Nothing magical about these: they are simply functions! For example:
<% function header1(content) { %>
<h1><%= content %></h1>
<% } %>
To use it, just call it:
<% header1('Hello'); %>
You can send block content as an argument to the function:
<%{ myArgument %>
<a href="/">This HTML code will be sent as an argument</a>
<%}%>
<% header1(conversation.locals.get('myArgument')); %>

Templating Languages

Scriptlets can be used not only with programming languages, but also with templating languages. Succinct and Velocity are both supported. Here's an example using Velocity and JavaScript together:
<%js
conversation.locals.put('test', 'TEST')
%>
<%velocity
#macro(hello $name)
	<div>Hello, $name!</div>
#end
<div>
	#hello('Mozart')
	#hello('Bach')
	Here is a conversation local: $!conversation.locals.test
</div>
%>
As with programming languages, you will need to install the engine first:
sincerity add velocity : install
You might prefer to use templating engines independently of template resources, as MVC "views." See the MVC chapter for a guide.

HTML Markup Languages

You can also render the following HTML markup language via scriptlets: Markdown, Confluence, MediaWiki, TWiki, Trac and Textile. Here's a Markdown example:
<html>
<body>
<%md
​
Our Conference
==============
​
* The first item of business
* The second item of business
​
%>
</body>
</html>
As with programming languages, you will need to install the engine first:
sincerity add org.pegdown pegdown : install
Here's a list of package identifiers for all supported languages (note there are two implementation options for Markdown):
Language Identifier
Markdown org.pegdown pegdown
Markdown org.eclipse.mylyn wikitext-markdown
Confluence org.eclipse.mylyn wikitext-confluence
MediaWiki org.eclipse.mylyn wikitext-mediawiki
TWiki org.eclipse.mylyn wikitext-twiki
Trac org.eclipse.mylyn wikitext-trac
Textile org.eclipse.mylyn wikitext-textile

PHP

Of all the supported programming languages, PHP is special in that it already has a scriptlet parser. In Prudence, PHP code will work pretty much as is, as it mimics the PHP format. You actually have the choice of using the standard PHP-style delimiters, "<?…?>", or the ASP/JSP-style delimiters instead: "<%…%>".
For example:
<?php
for($i = 0; $i < 10; $i++) {
	print '<p>' . $i . '</p>';
}
?>
PHP is special also in that it is designed for server-side web programming. Thus, though you can use all of Prudence's APIs in PHP, Prudence also explicitly supports many of PHP's predefined variables as a more standard alternative:
<?php
print $_GET['id']
?>
The convention when programming in PHP is to use ".php" extensions for files, even though the MIME type is "text/html". This is easy to achieve in Prudence by using a ".t.php" for your files, while also mapping the extension to the MIME type in your settings.js:
app.settings = {
	...
	mediaTypes: {
		php: 'text/html'
	}
}

Scriptlet Plugins

The default "scriptlets" parser comes with various useful shortcuts, but it's easy to create your own.
Configure your scriptlet plugins in settings.js using a dict that maps the shortcut codes to the library that will handle them. For this tutorial, we'll define two shortcuts in the same library:
app.settings = {
	...
	templates: {
		plugins: {
			'_': '/plugins/custom/',
			'&?': '/plugins/custom/'
		}
	}
}
The "_" shortcut will be used to print out localized text strings. The "&?" shortcut will be a conditional include. Let's now implement them in "/libraries/plugins/custom.js":
function handleGetScriptlet(code, languageAdapter, content) {
	if (code == '_') {
		return "print(application.globals.get('text.' + conversation.locals.get('locale') + '." + content.trim() + "'));"
	}
	else if (code == '&?') {
		return "if(conversation.locals.get('include')===true) { document.include(" + content + ") }"
	}
	return ''
}
As you can see, the "handleGetScriptlet" function returns JavaScript source code that will be embedded into the generated program. You can optionally use the content of the scriptlet via the "content" param. If you wish to support multiple programming languages, you can test for them using "languageAdapter.attributes.get('language.name')".
Let's now use our shortcuts in a template resource:
<%
conversation.locals.put('locale', 'en')
conversation.locals.put('include', false)
%>
<p>
	How to say "hello" in your language: <%_ basic.hello %>
</p>
<p>
	This fragment will not be included: <%&? '/hello/' %>
</p>
Our "_" shortcut expects certain application.global definitions, so let's define them in our settings.js:
app.globals = {
	text: {
		en: {
			basic: {
				hello: 'Hi!'
			}
		},
		es: {
			basic: {
				hello: '¡Hola!'
			}
		}
	}
}
Some things to note about scriptlet plugins:

Static Resources

Prudence works fine as a static web server: it's fast, supports non-blocking chunking, and has many useful features detailed below.
Of course, there are servers out there that specialize in serving static files and might do a better job, but you might be surprised by how far Prudence can take you.
Note that if Internet scalability is really important to you, it's better to even not use a standard web server at all, but instead rely on a CDN (Content Delivery Network) product or service with true global reach.

Configuration

Add support for static resources using the "static" route type in your routing.js, mapping it to a URI template ending in a wildcard:
app.routes = {
	'/*': 'static'
}
The default configuration for "static" will map all files from your application's "/resources/" subdirectory, as well as the container's "/libraries/web/" directory. Here is the above configuration with all the defaults fleshed out:
app.routes = {
	'/*': {
		type: 'static',
		roots: [
			'resources',
			sincerity.container.getLibrariesFile('web')
		],
		listingAllowed: false,
		negotiate: true,
		compress: true
	}
}
Note that the "roots" (pluralized) param is a shortcut to create a chain of two "static" instances. The above is equivalent to:
app.routes = {
	'/*': [
		{type: 'static', root: 'resources'},
		{type: 'static', root: sincerity.container.getLibrariesFile('web')}
	]
}
If you want to also support manual and template resources, make sure to chain "static" after them, so it will catch whatever doesn't have the special ".m." and ".t." pre-extensions:
app.routes = {
	'/*': [
		'manual',
		'templates',
		'static'
	]
}

MIME Types and Compression

When "negotiate" is true, Prudence will handle HTTP content negotiation for your static resources, and will assume a single MIME type per resource. That MIME type is determined by the filename extension. For example, a resource named "logo.png" will have the "image/png" MIME type.
Prudence recognizes many common file types by default, but you can add your own mappings in you application's settings.js, using app.settings.mediaTypes.
When "compress" is also true, Prudence will negotiate the best compression format (gzip and zip are supported) and compress on the fly. Compression can be configured in settings.js.

Client-Side Caching

Prudence adds modification timestamp headers to all static resources, which allow clients, such as web browsers, to cache the contents and use conditional HTTP requests to later check if the cache needs to be refreshed.
Conditional HTTP is efficient and fast, but you can go one step further and tell clients to avoid even that check. Use the "cacheControl" filter before your "static" route type:
app.routes = {
	'/*': {
		type: 'cacheControl',
		mediaTypes: {
			'image/*': '10m',
			'text/css': '10m',
			'application/x-javascript': '10m'
		},
		next: 'static'
	}
}
With the above, Prudence will ask web browsers to cache common image types, CSS and JavaScript for 10 minutes before sending conditional HTTP requests.
Make sure you understand the implications of this: after the client's first hit, for 10 minutes it will not be able to see changes to that static resource. The client's web browser would continue using the older version of the resource until its cache expires.
For a full discussion of client-side caching, see the caching chapter.
Bypassing the Client Cache
There is a widely-used trick that lets you use client-side caching while still letting you propagate changes immediately. It makes use of the fact that the client cache uses the complete URL as the cache key, which includes the query matrix. If you use a query param with the URL, the "static" resource will ignore it, but the client will still consider it a new resource in terms of caching. For example, let's say you include an image in an HTML page:
<img src="/media/logo.png" />
If you made a change to the "logo.png" file, and you want to bypass the client cache, then just change the HTML to this:
<img src="/media/logo.png?_=1" />
Voila: it's a new URL, so older cached values will not be used. For Prudence, the query makes no difference. You can then simply increase the value of the "_" query param every time you make a change.
This trick works so well that, if you use it, it's recommended that you actually ask clients to cache these resources forever. "Forever" is not actually supported, but it's customary to use 10 years in the future as a practical equivalent. Use "farFuture" as a shortcut in "cacheControl":
app.routes = {
	'/*': {
		type: 'cacheControl',
		mediaTypes: {
			'image/*': 'farFuture'
		},
		next: 'static'
	}
}
Remembering to increase the query param in all uses of the resource might be too cumbersome and error-prone. Consider using the Diligence Assets service, or something similar, instead: it calculates digests for the resource file contents and use them as the query param. Thus, any change to the file contents will result in a new, unique URL.
What happens to cache entries that have been marked to expire in 10 years, but are no longer used by your site? They indeed will linger in your client's web browser cache. This isn't too bad: web browsers normally are configured with a maximum cache size and the disk space will be cleared and reused if needed. It's still an inelegant waste, for which unfortunately there is no solution in HTTP and HTML.

JavaScript and CSS Optimization

When writing JavaScript code, you likely want to use a lot of spacing, indentation and comments to keep the code clear and manageable. You would likely also want to divide a large code base among multiple files. Unfortunately, this is not so efficient, because clients must download these files.
Prudence's "javaScriptUnifyMinify" filter can help. To configure:
app.routes = {
	'/*': {
		type: 'javaScriptUnifyMinify',
		next: 'static'
	}
}
The filter will catch URLs ending in "/all.js" or "/all.min.js", the former being unified and the latter unified and minified. The contents to be used, by default, will be all the ".js" files under your application's "/resources/scripts/" subdirectory as well as those under your container's "/libraries/web/scripts/" directory. The filter writes out the generated "all.js" and "all.min.js" files to "/resources/scripts/", and makes sure to update these files (unifying and minifying again) if any one of the source files are changed.
Note that the files are unified in alphabetical order, so make sure to rename them accordingly if order of execution is important.
Here is the above configuration with all the defaults fleshed out:
app.routes = {
	'/*': {
		type: 'javaScriptUnifyMinify',
		roots: [
			'resources/scripts',
			sincerity.container.getLibrariesFile('web', 'scripts')
		],
		next: 'static'
	}
}
For a usage example, let's say we have the following three files under the application's subdirectory:
/resources/scripts/jquery.js
/resources/scripts/jquery.highlight.js
/resources/scripts/jquery.popup.js
Your HTML files can then include something like this:
<head>
	...
	<script src="/scripts/all.min.js"></script>
</head>
Note that the first entry in the "roots" array is where the generated "all.js" and "all.min.js" files are stored.
The "cssUnifyMinify" filter does the same for CSS files, with the default roots being the application's "/resources/style/" subdirectory and the container's "/libraries/web/style/" directory. The relevant files are "all.css" and "all.min.css". Note, however, that similar functionality is provided by using LESS.
Here's an example with both filters configured:
app.routes = {
	'/*': {
		type: 'javaScriptUnifyMinify',
		next: {
			type: 'cssUnifyMinify',
			next: 'static'
		}
	}
}
Usage in HTML:
<head>
	...
	<link rel="stylesheet" type="text/css" href="/style/all.min.css" />
</head>

LESS to CSS

LESS is an extended CSS language. It greatly increases the power of CSS by allowing for code re-usability, variables and expressions, as well as nesting CSS. Using the the "less" filter you can compile ".less" files to CSS, and also apply the same minifier used by "cssUnifyMinify".
To configure:
app.routes = {
	'/*': {
		type: 'less',
		next: 'static'
	}
}
The filter works by catching all URLs ending in ".css" or ".min.css". It will then try to find an equivalent ".less" file, and if it does, will compile it and produce the equivalent ".css" or ".min.css" file. It makes sure to recompile if the source ".less" file is changed.
For a usage example, let's say we have a "/resources/style/dark/main.less" file the application's subdirectory. Your HTML files can then include something like this:
<head>
	...
	<link rel="stylesheet" type="text/css" href="/style/dark/main.min.css" />
</head>
The "less" filter can be configured with a "roots" param similarly to the "javaScriptMinifyUnify" and "cssUnifyMinify".
See the FAQ as to why Prudence supports LESS but not SASS.

Other Effects

Because static resources don't allow for code (unlike manual and template resources), the way to program your own effects is to add filters.
For example, let's say we want to force all ".pdf" files to be downloadable (by default, web browsers might prefer to display the file using a browser plugin). We'll be using the technique described here to change the response's "disposition".
Here's our filter code, in "/libraries/filters/download-pdf.js":
function handleAfter(conversation) {
	var entity = conversation.response.entity
	if (entity.mediaType.name == 'application/pdf') {
		entity.disposition.type = 'attachment'
	}
}
To install it in routing.js:
app.routes = {
	'/*': {
		type: 'filter',
		library: '/filters/download-pdf/',
		next: 'static'
	}
}

On-the-Fly Resources

You can add support for on-the-fly resources to your application via the "execute" route type. This powerful—and dangerous—resource executes all POST payloads as if they were template resources in the application, and is very useful for debugging and maintenance.
Another possibly exciting use case is to allow an especially rich API: instead of exposing your facilities via a RESTful API, you can allow certain clients full access to, well, everything. It's hard to recommend this usage for most applications due to its severe security risks, as well as limitations to scalability, but for some internally running applications it could prove extremely useful.
Diligence comes with the console feature, which offers a user-friendly variation of this functionality: it's a web-based mini-IDE that features persistent programs, JavaScript syntax coloring, and log tailing/filtering.
To install it, modify your application's routing.js and create a route for the "execute" type:
app.routes = {
	...
	'/execute/': 'execute'
}
Because it allows execution of arbitrary code, you very likely do not want its URL publicly exposed. Make sure to protect its URL on publicly available machines!
Example use with cURL command line:
curl --data '<% println(1+2) %>' http://localhost:8080/myapp/execute/
Note that if you use cURL with a file, you need to send it as binary, otherwise curl will strip your newlines:
curl --data-binary @myscriptfile http://localhost:8080/myapp/execute/
Where "myscriptfile" could be something like this:
<%
document.require('/sincerity/templates/')
println(Hello, {0}'.cast('Linus'))
%>
Almost all the usual template resource APIs work (with the exception of caching, which isn't supported):
<%
document.require('/sincerity/templates/')
var name = conversation.query.get('name') || 'Linus'
println('Hello, {0}'.cast(name))
%>
For the above, you could then POST with a query param:
curl --data-binary @myscriptfile 'http://localhost:8080/myapp/execute/?name=Richard'
Note that you can, as usual, use scriptlets in any supported programming language:
<%python
name = conversation.query['name'] or 'Linus'
print 'Hello, %s' % name
%>
Also note that the default response MIME type is "text/plain", but you can modify it with the conversation.mediaType APIs:
<%
document.require('/sincerity/json/')
conversation.mediaTypeName = 'application/json'
println(Sincerity.JSON.to({greeting: 'Hello'}, true))
%>

Java Resources

You may prefer to implement some of your manual resources directly in Java, by inheriting ServerResource, or perhaps you are relying a JVM library that already comes with such resources. To use them, set them up in your routing.js via the "resource" route type.
Some notes:

Resource Type Comparison Table

Manual Template Static
Supports URI Mapping Yes Yes Yes
Supports URI Dispatching Yes No No
Filename Extension Determines programming language Determines MIME type Determines MIME type
Filename Pre-extension *.m.* *.t.* n/a
Programming Languages Determined by filename extension Determined by scriptlet tags (multiple languages possible per resource) n/a
Content Negotiation Manually determined in handleInit; multiple MIME types possible; multiple compression types automatically supported and cached Single MIME type determined by filename extension; multiple compression types automatically supported and cached Single MIME type determined by filename extension; multiple compression types automatically supported
Server-Side Caching Manual (via API) Automatic (determined by server-side caching) n/a
Client-Side Caching Manual (via API) Automatic (determined by server-side caching) Can be added with CacheControlFilter

The Prudence Manual is provided for you under the terms of the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. The complete manual is available for download as a PDF.

Download manual as PDF Creative Commons License