Persevere is an open source set of tools for persistence and distributed computing using simple intuitive JSON interchange using HTTP REST and JSON-RPC. The Persevere project includes a Persevere Server and Persevere JavaScript Client, but these interact through standard REST and JSON-RPC, and so both the client and server can be used with other client and server technologies. If you plan to use the Persevere client with the Persevere server, you may want to refer to the Persevere client documentation for more information about developing applications with Persevere. If you will be using alternate client technologies, you may want to refer to the HTTP API section for more information about interacting with Persevere using HTTP requests.

The Persevere Server is a JavaScript based data storage server (based on Java/Rhino) that provides persistent data storage of JSON data, as well as query capability through JSONQuery/JSONPath, and distributed computing capabilities through JSON-RPC. Persevere follows the JSPON convention for exposing persistent data storage as JSON REST web services, and with full capabilities for modification of persisted data, execution of remote/distributed JavaScript methods on the server, and data centric object level security.

Persevere updates can be found on the project page, and discussion and the mailing list can be found on the Persevere forum.

Requirements

Java 1.5

Installation

To run Persevere follow these steps:

  1. Unzip the downloaded file
  2. Ensure that Java 1.5 is installed on your system.
  3. Go to the directory where you unzipped the downloaded file and run:
    java -jar start.jar
    
    See running Jetty page for more information.
If you want to run Persevere as a web application in an existing J2EE server like Tomcat, follow these steps:
  1. Ensure that you have a web application server setup (such as Tomcat)
  2. If you have an existing web application, save a copy of your web.xml file
  3. Unzip the downloaded file into your desired web application directory
  4. Merge the filter and servlet configurations in the new Persevere web.xml file into your old web.xml file and put it your WEB-INF directory (Note, if you are using Tomcat and want Comet support, you should uncomment the Tomcat Comet support in the web.xml file)

Using Persevere Server

The Persevere Server is a server for various JSON uses. You can store, retrieve, and modify persisted data using standard HTTP REST. You can use the included REST Object browser (browser.html) to browse and modify persisted data in the Persevere server. You can use the included Persevere JavaScript framework to build JavaScript based applications that utilize the persisted data on the Persevere server.

Directory Structure

Example Application

You can view a demonstration of using Dojo with Persevere.

Persevere Storage Structure

Persevere stores persistent objects in it's tables. Tables and their objects are accessible through URLs. Tables are equivalent to classes in Persevere, where each item in the table is an instance of that class. There are several important URLs for accessing tables:

Extending/Subclassing Tables

Because tables are equivalent to classes, tables can "extend" other tables. A subclass table extends a superclass table, which means that all instances of the subclass table must be valid by any schema defined by the superclass table, and will be members of the superclass table. An object instance of the subclass table will exist in queries of both the supertype table and subclass table. However, objects that are direct instances of the supertype table will not appear in the subclass table. Subclassing also affects prototype chains, a subclass will have a prototype object that delegates to the prototype object of the superclass. In other words, If you define methods for the superclass's objects, those methods will be available on the subclass's objects as well (unless they are overriden).

Creating New Tables/Classes

You can create a new table from the object browser by clicking on the add new property button without selecting any objects. You may then choose the name of the table you wish to add and what class you wish to extend (normally you can just extend Object). You may also create new tables by doing an HTTP PUT to the path of the table you want to create. For example:

PUT /MyNewTable HTTP/1.1

{"extends":"Object"}

REST HTTP Interaction

The Persevere Server persisted data can be accessed and manipulated with a simple and intuitive JSON REST interface. You can store, retrieve, and modify persisted data using standard REST semantics with the following HTTP methods. The Persevere JavaScript Client communicates through these standard HTTP methods.

GET

The GET method can be used to retrieve an object by id, a value by path, or a result set by JSONQuery. To retrieve an object by id, simply use the url corresponding to the object. For example to retrieve the /Customer/1 object:

GET /Customer/1
-->
{"id":"0",
 "name","John",
...
}

To retrieve a value, simply use property path access appended to a starting id. For example:

GET /Customer/1.firstName
-->
"John"

You can use more complex paths:

GET /BlogPost/1.comments[0]
-->
{"id":"1",
"lastName":"customer",
"phoneNumber":"a phone?",
"address":"somewhere",
"created":"2007-10-23T14:40:18Z",
"firstName":"first",
"comment":"this is great"
}

You can also use JSONQuery queries to retrieve query result sets from the server:

GET /Customer/[%3F(@.firstName='John')]
-->
[
{"id":"1",
"lastName":"customer",
...
}]

You may use the HTTP Range header to specify a range of items to retrieve. This is recommended for paging through results. Persevere supports a range unit "items" which identifies the items to be retrieved by index. For example one one could use the following request to retrieve the first twenty items of the Customer/ table:

GET /Customer/ HTTP/1.1
Range: items=0-20
Other range values could include:
Range: items=10-20  # items 10 through 20
Range: items=-50  # the first 50 items 
Range: items=100- # items at index 100 and above

POST

You can use the HTTP POST method to create new items in the table. For example:

POST /Customer/
{"firstName":"new",
"lastName":"customer"
}

This will add a new customer to the list of customers. If successful, the server will return the newly created object with the newly assigned id:

{"id":"4444",
"firstName":"new",
"lastName":"customer"
}

If the append was not successful, the HTTP status code will indicate the failure

PUT

You can modify an existing object by using PUT method to put a new set of values to existing object id. For example we could modify Customer/1 with this request:

PUT /Customer/1
{"id":"1",
"lastName":"new last name",
...
}

You can also use the PUT method to modify individual property values by using path references. For example we could just change the lastName property of the Customer/1 by using the following request:

PUT /Customer/1.lastName
"another new last name"

If the PUT was not successful, the HTTP status code will indicate the failure

DELETE

You can delete existing objects by using the DELETE method with the URL for the object. For example we can delete the /Customer/1 object by this request:

DELETE /Customer/1

You can also delete a single property by path. For example we could remove the comment property:

DELETE /BlogPost/1.comment

If the DELETE was not successful, the HTTP status code will indicate the failure

Object URL Determination

The URL for an object can be determined from the id property by using the standard rules for relative urls. For example if we request:

http://mydomain.com/Customer/
-->
[
 {"id":"1",
  "firstName":"first",
...
 }
]

We can determine the URL for the first object from id property (which has a value "1") in combination with the context of the requested URL (http://mydomain.com/Customer/). The inferred URL would therefore be http://mydomain.com/Customer/1.

Referencing

If an object is lazy loaded, circularly referenced, multiply referenced, or on a foreign site, Persevere will use a reference to the object. References are defined as an object with a property "$ref" with a value that represents the id or path of the target object. References follow the same rules as ids for relative URL inference and path resolution. Therefore a reference to an object that has not been transferred in the current response could be denoted:

GET /Customer/1
-->
{"id":"1",
 "address":{"$ref":"1"},
 ...
}

This denotes that the address property should have a value of the object with the id of Customer/1 (using relative URL inference). A client could do a GET on /Customer/1 to retrieve this object. Circular reference are also described using references:

{"id":"1",
 "referenceToSelf":{"$ref":"1"},
}

References can also have paths in them, which are used by default to reference arrays:

{"id":"1",
 "myArray":[1,2],
 "duplicateReferenceToMyArray":{"$ref":"1.myArray"}
}

References can be made to absolute URLs as well:

{"id":"1",
 "foreignReference":{"$ref":"http://otherdomain.com/Table/1"}
}

Example Client/HTTP Interaction

Here is an example of some ways you can interact with the Persevere Server.
Persevere client JavaScript actions
Resulting HTTP communication
 
 
// get the root of the object database
root=pjs.load('root');
 
GET /root
<---
{... root data...}
 
// query the example SQL database table
customer=pjs.load("Customer/?firstName='Jim'")[0]; // query using JSONQuery
GET Customer/[%3F(@.firstName='Jim')]
<---
[{"id":"Customer/2",
 "name":"Jim",
...}]
...
projects = pjs.load("/Project/");
newTask = {tasks:[{name:"build a sample application",price:10}, customer:customer};
projects.push(newTask);
POST /Project/
{[{"tasks":[{"name":"build a sample application","price":10}],{"$ref":"Customer/2"}}
 
Project = pjs.load("/Project");
Project.calcEstimate=function(project) {
    var price = 0;
    project.tasks.forEach(
        function(task){
            price+=task.price;
        });
   return price; }
projectApp.calcEstimate.runAt="server";
root.projectApp = projectApp; //attaching it to a persistent object will persist it
PUT /root.projectApp
{"calcEstimate":{"function":"function(project){....","runAt":"server"}}
(this is the convention that is used to pass functions so that it stays pure JSON)
 
var sampleEstimate = projectApp.calcEstimate(newOrder); // this executes the RPC, the function will be executed on the server (in Rhino)
sampleEstimate --> 10
POST /root.projectApp
{"id":"call1","method":"calcEstimate","params":[{"$ref":"/root.projects[0]"}]}
<---
{"id":"call1","response":10, "error":null}
// lets load a project from a different server, we are now a mashup!
foreignProject = pjs.load('http://foreignprojects.com/33');
http://foreignprojects.com:  GET /33
<---
{"tasks":[....]}
 
//and stick it in our array/table of projects
projects.push(foreignProject);
POST /Project/
{"$ref":"http://foreignprojects.com/33"}
 
a get on /Project/ might now return
[{.. first po ...},{"$ref":"http://foreignprojects.com/33"}]

Sequencing Control

HTTP is a non-deterministic protocol in regards to ordering. If you want to ensure that you requests are sequentially processed in the correct order, you should include an X-Seq-Id header with each request. For each request, the header value should be incremented one. It is recommended that you use this header in conjunction with the X-Client-Id header which indicates which page the request is made from. The X-Client-Id should be randonly generated string. For example:

X-Client-Id: 35523532
X-Seq-Id: 3
This would indicate that the request should be processed after the request with a sequence id of 2 and before the request with a sequence id of 4 for the client with the given id.

Transactions

To indicate transactional processing, the X-Transaction header is used. If the X-Transaction header is omitted it is always assumed that the modifications made by the current will be committed. If you want the current modification to be included in a transaction set, and you do not want the transaction to be committed until a later request, you should set the X-Transaction header to "open" like:

X-Transaction: open
It is highly recommended that you use the X-Transaction header in conjunction with the X-Seq-Id and X-Client-Id headers for deterministic ordering so that the commit takes place after the correct modification.

Data Integrity/Optimistic Locking

With Persevere you can make conditional requests in order to assert the data state assumptions prior to modifying data. This can be used to provide simple optimistic locking, preventing inadvertent modification of the wrong version of an object. Or it can be used for more sophisticated assertions based on knowledge of the current state of various objects. To make a conditional request, you put a JSONQuery expression in an X-If-Condition header. If the expression in the X-If-Condition evaluates to false, the request will be rejected with a 412 status code. For example:

PUT /Customer/1 HTTP/1.1
X-If-Condition: Customer/1.version=3
This PUT would be rejected if the version property does not equal 3.

RPCs and custom REST handlers

With Persevere, methods on objects may be executed using the HTTP requests. Persevere supports both RPCs via HTTP methods and JSON-RPC. Every HTTP request with a URI that can be resolved to a persisted object is treated as an RPC. The HTTP method is used as the method name in the RPC call. For example if Persevere receives the following HTTP request:
POST /Person/5 HTTP/1.1
Persevere will call the post method on the object with an id of /Person/5. Persevere will provide two arguments to the call. The first argument is an object with properties that represent the headers and parameters from the query string of the url (if it exists). The second argument represents body of the HTTP request. Therefore the following HTTP request and JavaScript code would have identical effects:
POST /Person/5?param1=value HTTP/1.1
Content-Length: 11

{foo:"bar"}

would be the same as running this on the server:

var obj = pjs.load("/Person/5");
obj.post({"Content-Length":"10",param1:"value"},{foo:"bar"});
Persevere provides a default implementation of get, put, and delete methods on Object.prototype and post method on Array.prototype, in order to implement to provide REST capability. However, any object may define it's own implementation of these methods and override the default implementation provided by Persevere. The following are approximately the default implementation of REST methods provided by Persevere (they are actually implemented in Java for performance):
Object.prototype.get = function(args) {
	return this; // just returns this object, Persevere internally handles the serialization for the HTTP response
}
Array.prototype.post = function(args,data) {
	this.push(data); // append the data to the list
	return data;
}
Object.prototype.put = function(args,data) { //Persevere internally handle the property changes indicated by the PUT request
	return this;
}
Object.prototype['delete'] = function(args) { // Persevere has a native implementation for this
	return persevere.NO_CONTENT;
}

You can override the default handlers by modifying the prototype object for a class. For example, to define a new GET handler for the Person table by executing:

Person.prototype.get=function(){
	return {test:this};
}

A GET request would then have a response like:

{test:{... action object ... }}

Custom REST handlers could also be installed by doing this:

PUT Person.prototype.get

function(){
	return {test:this};
}

It is not recommended you override the put method, because the API for put may change.

JSONQuery/JSONPath

JSONQuery/JSONPath support is based on Stefan Goessner’s specification for JSONPath and has been greatly expanded with numerous additional features for more powerful querying capabilities. This expanded set of functionality is called JSONQuery. A JSONQuery starts with object URL that is indicates the list being queried. JSONQuery can then be used to find objects by different property values using various operators. For example:

/Customer/?lastName='Smith'
This will find all the customers that have a last name of "Smith". We could do more sophisticated queries as well:
/Product/?price<15.00 & rating>3

This will find all the products with a price less than 15.00 and a rating more than 3. You can enclose queries in brackets to perform successive operations:

/Product/[?price<15.00][0:10]

This will return the first ten products that have a price less than 15.00. JSONQuery can also extract properties from a list of objects to return a set of property values:

/Product/[?price<15.00][=name]
This will return a list of the names of the products less than 15.00. This is called mappings, and you can do more sophisticated mappings as well:
/Customer/[={name:firstName + ' ' + lastName, address: street + state}]

This will return a list of objects that where the name is the first name plus the last name, and the address is the street plus the state.

We can also sort results:

/Product/[\rating]
This would return a list of products sorted in descending order by their rating. [/expr] indicates ascending and [\expr] indicates descending. You can also use multiple sort orders:
/Product/[\rating, /price]
This would sort by descending order for rating, and ties would be sorted by ascending order by price.

Another capability of JSONQuery is the recursive decent operator, “..”. One can recursively search data with the recursive operator. For example the query:

/Customer/objectid..name
This would search through all the children of the provided object, as well as the sub children and so on for the name properties and return their values.

The full set of operators that can be used in JSONQuery expressions are:

Operator Meaning
.propertyThis will return the provided property of the object, behaving exactly like JavaScript.
[expression]This returns the property name/index defined by the evaluation of the provided expression, behaving exactly like JavaScript.
[?expression]This will perform a filter operation on an array, returning all the items in an array that match the provided expression. This operator does not need to be in brackets, you can simply use ?expression, but since it does not have any containment, no operators can be used afterwards when used without brackets.
[/expression], [\expression], [/expression, /expression]This performs a sort operation on an array, with sort based on the provide expression. Multiple comma delimited sort expressions can be provided for multiple sort orders (first being highest priority).
[=expression]This performs a map operation on an array, creating a new array with each item being the evaluation of the expression for each item in the source array.
[start:end:step]This performs an array slice/range operation, returning the elements from the optional start index to the optional end index, stepping by the optional step number.
[expr,expr]This a union operator, returning an array of all the property/index values from the evaluation of the comma delimited expressions.
.* or [*]This returns the values of all the properties of the current object.
$This is the root object, If a JSONQuery expression does not being with a $, it will be auto-inserted at the beginning.
@This is the current object in filter, sort, and map expressions. This is generally not necessary, names are auto-converted to property references of the current object in expressions.
..propertyPerforms a recursive search for the given property name, returning an array of all values with such a property name in the current object and any subobjects
expr = exprPerforms a comparison (like JS's ==). When comparing to a string, the comparison string may contain wildcards * (matches any number of characters) and ? (matches any single character).
+, -, /, *, &, |, %, (, ), <, >, <=, >=, !=These operators behave just as they do in JavaScript.
.method()Performs a method call
.distinct()Removes duplicates from the current result set

Remember to always properly encode your JSONQuery queries when using them in URLs, leaving queries unencoded is a very common mistake.

Result-Based Evaluation

Persevere's JSONQuery is based on JSONPath. However, JSONQuery uses result-based evaluation instead of JSONPath’s item-based evaluation. Result-based evaluation follows general JavaScript evaluation (where possible) much more closely than item-based evaluation, which always attempts to return an array for valid results. Any JavaScript expression that evaluates to a defined value (not undefined) and is also a valid JSONQuery expression will have identical results in result-based JSONQuery evaluation as it would in JavaScript.

Result-based evaluation also allows successive narrowing operations to be performed on an array. The evaluation technique does not affect the query syntax. Result-based evaluation performs each operation on the result of the last operation. Item-based evaluation performs each operation on each item from the last result set. The following table compares some examples of result-based and item-based evaluation. For these examples we will assume that we are querying this object:

{
	name:"My Object",
	numbers:[2,4,6,8,10,12,14,16,18,20]

}
Query Item-based Result-based
obj.name [”My Object”] “My Object”
obj.numbers[1] [4] 4
obj.numbers[?(@>10)][0:3] false [12,14,16]

Note that it is recommended that you use the HTTP Range header for paging rather than the slice operator.

Safe-Evaluation

The original JSONPath did not provide any stipulation about the extent of allowable sub-expressions, instead just stating that sub-expressions could be anything that the underlying script engine can handle. However, this is not a portable solution (not all implementations have a JavaScript VM available), and it is also not safe since it allows for the arbitrary execution of code on the server. Therefore we use a safe subset of the sub-expressions which is highly portable and is safe from arbitrary code execution. The following operators (separated by commas) may be used in sub-expressions with safe-evaluation enabled:

&, |, =, !=, >=, <=, +, -, /, *, ?, :

Persisting Methods/Functions

In Persevere, you can use functions like any other value and they can be stored in properties just like any other value as long as the object is backed by a store that supports functions, and the default dynamic object database in Persevere does support functions. Typically, you will want to add functions/methods to the prototype object for a class/table. For example you could create a method getFullName that is available for all Customer objects by sending:

PUT /Customer.prototype HTTP/1.1
Content-Length: 30

{getFullName:function() { return this.firstName + " " + this.lastName; }}

It may also be useful to create "static" functions directly on the class object. You can view an example of persisted methods on this object.

JSON-RPC

Once you have created methods in Persevere, you can invoke the methods using JSON-RPC, which supports a wide range of arguments. JSON-RPC requests can be issued by sending a POST request with the body being a JSON-RPC request. The URI for the request is used to resolve the target object for the method call. For example, in order to call the getFullName method of /Customer/1 with no arguments, you could make the following HTTP request:
POST /person/4 HTTP/1.1
Content-Length: 30

{method:"getFullName", id:"1", params:[]}

Server Side JavaScript Environment

Persevere is designed to allow developers write JavaScript on both the server and client, and provide easy interaction between the two. On the server, Persevere runs Rhino 1.7 (JavaScript 1.7) and implements the Persistent JavaScript API in order to facilitate access to the persisted data. Once you have executed a query you may interact with objects using normal JavaScript syntax; property reads automatically dereference references and properties modifications are automatically persisted. Tables also are automatically entered into the JavaScript environment as class constructors. Therefore if you have a table called Customer, you can create a new customer by calling:

myNewCustomer = new Customer();

Server Side JavaScript Library

Server side JavaScript can utilize the including Persevere library functions:

You can also include your own libraries in the Persevere server side environment by including them on startup.

Using Persevere With Apache

Persevere can easily be used with Apache. You may use the same web directory for Apache and Persevere. Persevere comes with .htaccess file in the root directory that will route appropriate requests to the Persevere server for processing. You must have mod-proxy installed to use this feature.

Setting up Security

When Persevere is first setup, there are no users in the system and so it does not enforce any security. When the first user is created, this user is setup to be the super user for the system, and from then on, all secured access will require a login. This simplest way to create a user is with the REST Object browser. From the browser, click on sign in, and you can create a new user. Once this user is created, only this user can modify data, and all data will be readonly for all other users. You can modify the access levels for different objects, and add new users to groups to allow access for modification of data.

You can also add users programmatically. The User class provides a createUser method that can be called with JSON-RPC (or directly called from the server side) with a username and password to create a user.

Granting Access to Objects

From the Object browser you can grant access to resources to other users (or to the public). Simply choose an object and click the grant access button.

You can also grant access programmatically. The User class provides a grantAccess method that can be called with JSON-RPC (or directly called from the server side) with a username and an object reference to grant access to a resource. All the children of that object will inherit the access level of that object that was granted access.

Capabilities

You can also create a set of access with capabilities. A capability can be created that includes access to several objects. A capability can then be granted to a user or even another capability. You can use Capability.grantAccess to add objects or other capabilities to the set of objects that have been granted access through this capability.

Implementing Custom User Management and Security

Persevere can also be integrated into existing user management and security infrastructures. You can define your security manager in a configuration file (like core.json) by defining your own class for the "security" property. The class must implement org.persvr.security.SecurityHandler. With your custom security handler you can define your method for authenticating users and create your own user class (that implements org.persvr.security.User), to handle access to resources.

Incorporating Persevere with J2EE Applications

Persevere uses a filter to add persistence and referencing capabilities to Java Servlets. With this capability, clients can go beyond just passing strings as parameters, but can pass any value and the servlet can access the parameter values as as Strings, Booleans, Dates, Numbers, Objects, and more. There are two primary ways to utilize this capability:

Please see the Javadocs for more information.

Configuring Persevere

Data Sources

Persevere should be ready to use out of the box. However, the main configuration that may be desired is to setup new data sources. Existing databases or data sources can be exposed through Persevere. The configuration are found in WEB-INF/config. These files contains examples of various data sources and how to configure them.

Configuring Relational Databases

Persevere is designed to allow existing databases to be exposed through the JSON REST interface. To plugin an existing database table, you can use the DatabaseTableDataSource. A database table is configured by adding the following entry into the list of data sources:
	 {name:"Data source name",
		sourceClass:"org.persvr.datasource.DatabaseTableDataSource",
		connection:"Connection string",
		driver:"JDBC driver class",
		table:"Table name",
		idColumn:"Column name of the unique id for the table",
		dataColumns:[[Column name,Column configuration],...]
		},
The data columns can be column names (just a string) or column configuration. A column configuration object can be used to define relational columns. To define a one to many relationship, the following configuration object can be used:
 
{foreignSource:"Name of foreign database data source",
foreignColumn:"Name of foreign database key column",
foreignObjectColumn:"If the foreign table is mapped to this object, this is the name of mapped object property",
relationshipType:"one-to-many",
objectColumn:"Name of object property to map to"}
To define a many to one relationship, the following configuration object can be used:
 
{foreignSource:"Name of foreign database data source",
databaseColumn:"Name of foreign key column",
relationshipType:"many-to-one",
objectColumn:"Name of object property to map to"}
In WEB-INF/config/examples.json there is an example of relational tables in the project and task data sources.

Creating Custom Data Sources

You may also create new data sources by implementing org.persvr.datasource.DataSource. org.persvr.datasource.BaseDataSource provides a good starting abstract implementation for data sources, and org.persvr.datasource.DatabaseTableDataSource provides a good example of database data source. Please see the Javadocs for more information.

Custom Java Class For Object Instances

Persevere allows you to assign classes for objects from a table. This allows you to write custom Java model objects that can provide custom behavior. Model classes should implement org.persvr.data.Persistable which is most easily done by extending org.mozilla.javascript.NativeObject or org.mozilla.javascript.NativeArray. To register a custom class, define the "objectsClass" property in the configuration file for the data sources in WEB-INF/config.

Reseting the Database

During development it may be useful to occasionally "reset" the database to the initial conditions. This can be done by deleting the directories within /WEB-INF/data. When these are deleted and Persevere is restarted, Persevere will automatically recreate the database to the initial state.

Server Side Scripts on Startup

Persevere may be configured to include server scripts in the server JavaScript environment. A JavaScript library may be included in the server environment by adding to the serverScripts array in the configuration files in WEB-INF/config.

Dojo Support

Dojo has a unified data API that is well equipped for interacting with Persevere. Persevere comes with dojo.data implementation for connecting to Persevere, which can be found in jsclient/dojox/data/JsonRestStore.js. Using the dojo.data Persevere implementation, you can easily use Persevere storage as data model for dojo grid widget, which makes it very simple and easy to build a powerful user interface for the Persevere database. You can view a demonstration of the dojo grid connecting to Persevere in jsclient/dojox/grid/tests/test_dojo_data_model_persevere.html.

Live Data - Comet Support

Persevere supports Comet style connections for live data updates and for reverse RPC calls (from the server to the client). Persevere supports two forms of Comet communication. The recommended communication is through HTTP Channels. To use the HTTP Channels, you connect to Channels servlet (/channels by default), providing a connection id with the Create-Connection header. The response will be of the content type "application/http" and messages sent from the server will be sent as the content of the response in the form of HTTP response messages. Monitored/subscribed data that is modified will be sent as these messages. The inner HTTP message will include a "Content-Location" header which will identify the resource that was modified. The content of the inner HTTP message will be the new data for the modified resource. The HTTP message will also include a "X-Event" header that indicates what action took place (PUT, POST, or DELETE). When a post takes place, the only the posted data is included (not the resulting list/resource). Please see the HTTP Channels documentation for more information.

Persevere also supports Bayeux. When using Bayeux, subscription requests will be treated by resource subscriptions where the channel indicates the resource. Publish messages through Bayeux is funtionally equivalent to appending data to a resource as is done with a POST request. Therefore list/array resources can facilitate a pub/sub mechanism where messages can be published to resources and subscribers will receive the new messages.

SMD Support

You may get an Service Mapping Description (SMD) of the available data sources from the SMD servlet (which is /SMD by default). The SMD can be used for auto-configuration of services.

JSON Schema Support

Persevere supports JSON Schema for validating and providing integrity for persisted objects, which follows this format. The root table object is the schema for all object instances of the table. The schema can be used to constrain property value types for all the object instances on a table. For information on how to define the properties see the JSON Schema proposal.

In addition to the standard JSON Schema attributes, Persevere also supports a "lazy" attribute and a "validator" attribute. The lazy attribute indicates that the given property value should be lazy loaded. When objects are serialized, only a reference to the value will be provided.

The "validator" property can be used for custom validation logic. If you provide a function for the "validator" property of a property definition, that function will be called whenever the instance property is modified. The validator can will be passed the new value and the name of property. The validator can throw an exception to reject the change.

Creating Methods on Object Instances

All table schemas should have a prototype property that is the prototype for all the object instances from this table. You can add JavaScript functions on this prototype object and they will then be inherited by the object instances, and can be called as methods. These functions can be requested by clients and used as methods for the objects on the client side or they may be executed on the objects using JSON-RPC.

Cross-Site Data Access

JSONP

Persevere can provide access to the persisted data to other websites through JSONP. Authentication for cross-site requests is verified against the Referer header. If a user has authenticated against one website, another website will not be able to automatically use authentication to gain access to the user's data. This prevents cross-site request forgery (CSRF) attacks. Cross-site requests must be properly authenticated on their own in order to gain access to protected resources. To request an object from another site, include a "callback" parameter with the value indicating the name of the callback function to call with the data.

In many situations, it may be necessary to transmit and receive additional meta data which would otherwise be sent in HTTP headers. JSONP doesn't support headers. However, you can supply this header/metadata information using the JSONP metadata proposal.

XDomainRequest and Cross-Site XHR

Persevere also supports IE8's XDomainRequest and W3C Cross-Site Access Control. Requests can be made from other sites, and Persevere will apply the proper headers for use with these mechanisms. Persevere's security system still protects against CSRF with these modes of access.

Content Negotiation

Persevere supports content negotiation. Currently, Persevere supports JSON (pure JSON), JavaScript (basically JSON, but also allows functions), and Persevere Client specific format (basically JSON, but including a compiled version of functions).

License

Persevere Server is available under *either* the terms of the modified BSD license *or* the Academic Free License version 2.1. As a recipient of Persevere, you may choose which license to receive this code under (except as noted in per-module LICENSE files). Persevere is distributed with several libraries which were produced with their own license including Rhino (MPL, LGPL, or GPL), JSON.org's Java library (public domain), Derby (Apache license), Persevere JavaScript Client (MPL, LGPL, or GPL),and Apache Commons (Apache license), however, none of these libraries have been modified, the standard binary distributions are included for setup convenience. The Persevere Server comes with the Persevere JavaScript Client which uses the MPL 1.1, GPL 2.0, or LGPL 2.1 license and can be used as MPL (the most permissive of the three). The client library is included as an unmodified component, and therefore does not restrict the license of the Persevere Server and the server code.

The text of the AFL and BSD licenses are reproduced below:



-------------------------------------------------------------------------------
The "New" BSD License:
**********************

Copyright (c) 2008, SitePen
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright notice, this
    list of conditions and the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
  * Neither the name of the SitePen nor the names of its contributors
    may be used to endorse or promote products derived from this software
    without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-------------------------------------------------------------------------------
The Academic Free License, v. 2.1:
**********************************

This Academic Free License (the "License") applies to any original work of
authorship (the "Original Work") whose owner (the "Licensor") has placed the
following notice immediately following the copyright notice for the Original
Work:

Licensed under the Academic Free License version 2.1

1) Grant of Copyright License. Licensor hereby grants You a world-wide,
royalty-free, non-exclusive, perpetual, sublicenseable license to do the
following:

a) to reproduce the Original Work in copies;

b) to prepare derivative works ("Derivative Works") based upon the Original
Work;

c) to distribute copies of the Original Work and Derivative Works to the
public;

d) to perform the Original Work publicly; and

e) to display the Original Work publicly.

2) Grant of Patent License. Licensor hereby grants You a world-wide,
royalty-free, non-exclusive, perpetual, sublicenseable license, under patent
claims owned or controlled by the Licensor that are embodied in the Original
Work as furnished by the Licensor, to make, use, sell and offer for sale the
Original Work and Derivative Works.

3) Grant of Source Code License. The term "Source Code" means the preferred
form of the Original Work for making modifications to it and all available
documentation describing how to modify the Original Work. Licensor hereby
agrees to provide a machine-readable copy of the Source Code of the Original
Work along with each copy of the Original Work that Licensor distributes.
Licensor reserves the right to satisfy this obligation by placing a
machine-readable copy of the Source Code in an information repository
reasonably calculated to permit inexpensive and convenient access by You for as
long as Licensor continues to distribute the Original Work, and by publishing
the address of that information repository in a notice immediately following
the copyright notice that applies to the Original Work.

4) Exclusions From License Grant. Neither the names of Licensor, nor the names
of any contributors to the Original Work, nor any of their trademarks or
service marks, may be used to endorse or promote products derived from this
Original Work without express prior written permission of the Licensor. Nothing
in this License shall be deemed to grant any rights to trademarks, copyrights,
patents, trade secrets or any other intellectual property of Licensor except as
expressly stated herein. No patent license is granted to make, use, sell or
offer to sell embodiments of any patent claims other than the licensed claims
defined in Section 2. No right is granted to the trademarks of Licensor even if
such marks are included in the Original Work. Nothing in this License shall be
interpreted to prohibit Licensor from licensing under different terms from this
License any Original Work that Licensor otherwise would have a right to
license.

5) This section intentionally omitted.

6) Attribution Rights. You must retain, in the Source Code of any Derivative
Works that You create, all copyright, patent or trademark notices from the
Source Code of the Original Work, as well as any notices of licensing and any
descriptive text identified therein as an "Attribution Notice." You must cause
the Source Code for any Derivative Works that You create to carry a prominent
Attribution Notice reasonably calculated to inform recipients that You have
modified the Original Work.

7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that
the copyright in and to the Original Work and the patent rights granted herein
by Licensor are owned by the Licensor or are sublicensed to You under the terms
of this License with the permission of the contributor(s) of those copyrights
and patent rights. Except as expressly stated in the immediately proceeding
sentence, the Original Work is provided under this License on an "AS IS" BASIS
and WITHOUT WARRANTY, either express or implied, including, without limitation,
the warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU.
This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No
license to Original Work is granted hereunder except under this disclaimer.

8) Limitation of Liability. Under no circumstances and under no legal theory,
whether in tort (including negligence), contract, or otherwise, shall the
Licensor be liable to any person for any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License
or the use of the Original Work including, without limitation, damages for loss
of goodwill, work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses. This limitation of liability shall not
apply to liability for death or personal injury resulting from Licensor's
negligence to the extent applicable law prohibits such limitation. Some
jurisdictions do not allow the exclusion or limitation of incidental or
consequential damages, so this exclusion and limitation may not apply to You.

9) Acceptance and Termination. If You distribute copies of the Original Work or
a Derivative Work, You must make a reasonable effort under the circumstances to
obtain the express assent of recipients to the terms of this License. Nothing
else but this License (or another written agreement between Licensor and You)
grants You permission to create Derivative Works based upon the Original Work
or to exercise any of the rights granted in Section 1 herein, and any attempt
to do so except under the terms of this License (or another written agreement
between Licensor and You) is expressly prohibited by U.S. copyright law, the
equivalent laws of other countries, and by international treaty. Therefore, by
exercising any of the rights granted to You in Section 1 herein, You indicate
Your acceptance of this License and all of its terms and conditions.

10) Termination for Patent Action. This License shall terminate automatically
and You may no longer exercise any of the rights granted to You by this License
as of the date You commence an action, including a cross-claim or counterclaim,
against Licensor or any licensee alleging that the Original Work infringes a
patent. This termination provision shall not apply for an action alleging
patent infringement by combinations of the Original Work with other software or
hardware.

11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this
License may be brought only in the courts of a jurisdiction wherein the
Licensor resides or in which Licensor conducts its primary business, and under
the laws of that jurisdiction excluding its conflict-of-law provisions. The
application of the United Nations Convention on Contracts for the International
Sale of Goods is expressly excluded. Any use of the Original Work outside the
scope of this License or after its termination shall be subject to the
requirements and penalties of the U.S. Copyright Act, 17 U.S.C. § 101 et
seq., the equivalent laws of other countries, and international treaty. This
section shall survive the termination of this License.

12) Attorneys Fees. In any action to enforce the terms of this License or
seeking damages relating thereto, the prevailing party shall be entitled to
recover its costs and expenses, including, without limitation, reasonable
attorneys' fees and costs incurred in connection with such action, including
any appeal of such action. This section shall survive the termination of this
License.

13) Miscellaneous. This License represents the complete agreement concerning
the subject matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent necessary to
make it enforceable.

14) Definition of "You" in This License. "You" throughout this License, whether
in upper or lower case, means an individual or a legal entity exercising rights
under, and complying with all of the terms of, this License. For legal
entities, "You" includes any entity that controls, is controlled by, or is
under common control with you. For purposes of this definition, "control" means
(i) the power, direct or indirect, to cause the direction or management of such
entity, whether by contract or otherwise, or (ii) ownership of fifty percent
(50%) or more of the outstanding shares, or (iii) beneficial ownership of such
entity.

15) Right to Use. You may use the Original Work in all ways not otherwise
restricted or conditioned by this License or by law, and Licensor promises not
to interfere with or be responsible for such uses by You.

This license is Copyright (C) 2003-2004 Lawrence E. Rosen. All rights reserved.
Permission is hereby granted to copy and distribute this license without
modification. This license may not be modified without the express written
permission of its copyright owner.

Included Libraries

The following libraries are included with the Persevere distribution (in binary library form):

Notes

Persevere is still in beta, so there may be some minor API changes before it is fully released.