velocity-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cbris...@apache.org
Subject svn commit: r1298906 [3/14] - in /velocity/sandbox/velosurf: ./ docs/ examples/ examples/ant-vpp/ examples/ant-vpp/lib/ examples/auth-l10n/ examples/auth-l10n/WEB-INF/ examples/auth-l10n/WEB-INF/lib/ examples/auth-l10n/WEB-INF/src/ examples/auth-l10n/e...
Date Fri, 09 Mar 2012 16:23:32 GMT
Added: velocity/sandbox/velosurf/docs/user-guide.html
URL: http://svn.apache.org/viewvc/velocity/sandbox/velosurf/docs/user-guide.html?rev=1298906&view=auto
==============================================================================
--- velocity/sandbox/velosurf/docs/user-guide.html (added)
+++ velocity/sandbox/velosurf/docs/user-guide.html Fri Mar  9 16:23:25 2012
@@ -0,0 +1,615 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+
+  <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">
+  <title>Velosurf - User Guide</title>
+
+
+  <link rel="stylesheet" href="./velosurf.css" type="text/css">
+
+</head>
+
+
+<body>
+
+<div id="container">
+<div id="header">
+<div id="logo1"><img style="height: 60px;" altforeign="Velosurf logo" src="logo.png" border="0"></div>
+
+<div id="logo3"><img alt="Velosurf title" src="title.png" border="0"></div>
+
+<div id="logo2"><a href="http://velocity.apache.org/"><img style="width: 80px;" src="powered-by-logo.gif" alt="Velocity" border="0"></a></div>
+
+</div>
+
+<div id="menu">
+<div class="menusection"><span class="menuheader">Velosurf</span>
+<ul>
+
+  <li><a href="./index.html">Home</a></li>
+
+  <li> <a href="./overview.html">Overview</a>
+  </li>
+
+  <li><a href="./download.html">Download</a>
+  </li>
+
+  <li> <a href="./faq.html">FAQ</a> </li>
+
+  <li> <a href="http://velocity.apache.org/contact.html">Mailing lists</a> </li>
+
+</ul>
+
+</div>
+
+<div class="menusection">
+<span class="menuheader">Docs</span>
+<ul>
+
+  <li><a href="./installation.html">Installation</a></li>
+
+  <li><a href="./configuration.html">Configuration</a></li>
+
+  <li><b>User Guide</b></li>
+
+  <li> <a href="./vtl-reference.html">VTL Reference</a> </li>
+
+  <li><a href="./api/index.html">Javadoc</a></li>
+
+  <li><a href="./architecture.html">Architecture</a></li>
+
+  <li><a href="./velosurf/docs/index.html">1.4.x Docs</a></li>
+
+  <li> <a href="./CHANGELOG">Change Log</a> </li>
+
+  <li> <a href="./LICENSE">License</a></li>
+
+</ul>
+
+</div>
+
+</div>
+
+<div id="body">
+
+<h1>Table of Contents</h1>
+<p>
+<ol>
+<li><a href="#settingup">Setting up and configuring Velosurf</a></li>
+<li><a href="#extparams">External Parameters</a></li>
+<li><a href="#pooling">Connections/statements pooling and recovery</a></li>
+<li><a href="#reverse">Reverse engineering</a></li>
+<li><a href="#fetching">Fetching instances and iterating</a></li>
+<li><a href="#obfuscation">IDs obfuscation</a></li>
+<li><a href="#caching">Caching instances</a></li>
+<li><a href="#mapping">Customizing Java mapping objects</a></li>
+<li><a href="#modifications">Issuing modifications to the database</a></li>
+<li><a href="#validation">Data validation</a></li>
+<li><a href="#foreign-keys">Imported and exported keys</a></li>
+<li><a href="#httpquery">HTTP Query parameters</a></li>
+<li><a href="#localization">Localization</a></li>
+<li><a href="#authentication">Authentication</a></li>
+<li><a href="#templatenamefilter">Template name filter</a></li>
+<li><a href="#filtering">Order of servlet filters</a></li>
+<li><a href="#fromjava">Using the Velosurf API from Java</a></li>
+</ol>
+</p>
+
+<a name="settingup"/>
+<h1>Setting up and Configuring Velosurf</h1>
+<p>Please refer to the <a href="./installation.html">Installation</a> page for how to set up Velosurf in you <a href="">Velocity-Tools</a> Webapp or in your Java application.</p>
+<p>It is possible to use several instances of Velosurf at the same time, each having its own configuration file, for instance
+if you want to use different context keys to refer to different schemas. Provided that the different configuration files use the same database login
+(apart from the schema name), you can cross-reference entities between configuration files.</p>
+<p>It is also possible to split the configuration file into several pieces using the <a href="http://www.w3.org/TR/2004/PR-xinclude-20040930/">XML Include</a> syntax:
+the root <code>&lt;database&gt;</code> tag must have the following attribute set: <code>xmlns:xi="http://www.w3.org/2001/XInclude"</code>.
+You can set include files using the syntax: <code>&lt;xi:include href="<i>included_file.xml</i>"/&gt;</code> (other features of the
+<a href="http://www.w3.org/TR/2004/PR-xinclude-20040930/">XML Include specification</a>, like fallback and XPointers, are not supported).
+</p>
+<p>The XML tree of the configuration file (plus optional reverse engineered data) defines everything that will be accessible under the <code>$db</code> (or whatever name you choosed) context key.
+The syntax of this configuration file is detailed on the <a href="./configuration.html">Configuration</a> page.</p>
+
+<p>An attribute is of any of the following types::
+<ul>
+<li><b>scalar</b>: when an attribute of this type is evaluated, Velosurf will return the first row of the first column in the result set.</li>
+<li><b>row</b>: only the first row of the result is considered.</li>
+<li><b>rowset</b>: the result is a set of rows.</li>
+</ul></p>
+<p>For the row and row set types, if the rows are instances of an entity, you can specify the name of the resulting entity. Doing so, you'll be able to invoke this resulting entity attributes and actions.
+<p>The former and now deprecated syntax for declaring attributes was: <code>&lt;attribute name="<i>myattribute</i>" result="scalar<b>|</b>row<b>|</b>rowset<b>[</b>/<i>resultEntity</i><b>]</b>"&gt;</code>. Now, you can use: <code>&lt;scalar name="<i>myScalar</i>"&gt;</code>, <code>&lt;row name="<i>myRow</i>" <b>[</b>result="<i>resultEntity</i>"<b>]</b>&gt;</code>, <code>&lt;rowset name="<i>myRow</i>" <b>[</b>result="<i>resultEntity</i>"<b>]</b>&gt;</p></code>
+You'll be able to call this entity's attributes directly on the returned row.</p>
+<p>Values of the current instance that are needed in the SQL query of an entity's attribute must appear as inline tags inside the SQL query:</p>
+<div class="source"><xmp>
+  <entity name="book">
+    <!-- let's suppose we want to manually define the foreign-key
+       towards the publisher table -->
+    <row name="publisher" result="publisher">
+      SELECT * FROM publisher WHERE id = <publisher_id/>
+    </row>
+  </entity></xmp></div>
+
+<p>Please note that the <code>$book.publisher</code> property will automagically be available, without any need to declare it, when using the full database reverse enginering mode (see later).</p>
+
+<p>Be careful when using quoted SQL strings in your queries: since XML parsers may add spaces here and there
+inside text data, it may break the syntax of such SQL queries. To remedy to this problem, you must use the XML attribute
+<code>xml-space=&quot;preserve&quot;</code> as an XML attribute of any XML entity containing such an SQL query.</p>
+
+<p>Remember also to escape XML special characters &lt; &gt; and &amp; with their XML equivalent (respectively <code>&amp;lt;</code>
+<code>&amp;gt;</code> and <code>&amp;amp;</code>) whenever they appear inside your queries.<br>
+
+<a name="extparams"/>
+<h1>External Parameters</h1>
+<p>Other parameters - called <i>external parameters</i> - can appear as inline tags in an attribute SQL query. For instance, let's say we want to define
+a root attribute listing all the books published in the given year. We'll define this attribute like this:</p>
+<div class="source"><xmp>  <rowset name="books_per_year" result="book">
+    SELECT * FROM book WHERE DATE(publication_date) = <publication_year/>
+  </rowset></xmp></div>
+<p>There are two ways to use external attributes from templates:</p>
+<p>The first one is to set their values as properties of the parent object (this method is now strongly discouraged, since the parent object can be shared), like this:</p>
+<div class="source">#set($db.publication_year = '2006')
+Books for year $db.publication_year:
+#foreach($book in $db.books_per_year)
+&nbsp;&nbsp;* $book.title
+#end</div>
+<p>The second -and now preferred- method is to specify the map of all external parameters values as argument of the attribute:</p>
+<div class="source">Books for year 2006:
+#foreach($book in $db.books_per_year({'publication_year':2006}))
+&nbsp;&nbsp;* $book.title
+#end</div>
+To be able to use this second method, you need to use the VelosurfUberspector:
+<div class="source">(excerpt from velocity.properties)
+# Use the Veltools' WebappUberspector to allow standard getters and setters on request, session and application
+# Use the VelosurfUberspector to allow parametrized getters
+runtime.introspector.uberspect = org.apache.velocity.util.introspection.UberspectImpl,org.apache.velocity.tools.view.WebappUberspector,velosurf.util.VelosurfUberspector
+</div>
+<p>Without using this customized uberspector, you can still use this method by doing:</p>
+<div class="source">Books for year 2006:
+#foreach($book in $db.getWithParams('books_per_year',{'publication_year':2006}))
+&nbsp;&nbsp;* $book.title
+#end</div>
+
+<!-- <p>Note that the name <code>publication_year</code> does not correspond to anything in the database:
+it is only a label that can be used as a prepared statement parameter. Note also that external parameters
+only retain their value within the scope of one VelosurfTool instance (which is the request scope by default).</p>
+-->
+
+<a name="pooling"/>
+<h1>Connections/Statements Pooling and Recovery</h1>
+<p>Connections and statements pooling is transparent. There are two connections pools, one with autocommit connections
+for queries and single statement updates and one without autocommit for transactions (actions containing several update requests). Those pools
+grow according to the rate of requests.</p>
+<p>The automatic connection recovery will transparently care for broken or timed out connections.</p>
+<p>Needed statements are created on the fly when needed, that is when there isn't any previous instance of a particular statement
+or when such an instance is already busy. The statements pool will thus grow as needed.</p>
+<p>Concurrent accesses are of course taken into account: Velosurf maintains a <i>busy</i> state for each connection.</p>
+
+<a name="reverse"/>
+<h1>Reverse Engineering</h1>
+<p>There are four reverse engineering modes proposed by Velosurf:
+<ul>
+<li><b>full</b> (default): all tables and foreign-keys of the current schema (if any) are reverse engineered.</li>
+<li><b>tables</b>: all tables of the current schema (if any) are reverse engineered.</li>
+<li><b>manual</b>: only entities listed in the configuration file are reverse engineered (only if they do correspond to an actual table).</li>
+<li><b>none</b>: no reverse engineering of any kind is achieved. Several features of Velosurf (like the <code><i>entity</i>.fetch</code> method) aren't available when using this mode.</li>
+</ul></p>
+
+<p>See the <a href="#foreign-keys">Imported and Exported Keys</a> section below for details on the reverse engineering of foreign keys.</p>
+
+<p>By default entity names are deduced from SQL table names and entity property names are deduced from SQL column names.</p>
+<p>Use the <code>table='<i>table name</i>'</code> if an entity is to have a different name than its corresponding table
+and use a <code>&lt;aliases <i>alias1</i>='<i>column1</i>' <i>alias2</i>='<i>column2</i>' &gt;</code> tag to declare aliases
+for SQL column names.</p>
+<p>When a table name or an SQL column name is aliased, you have to use the alias rather than the column name in whatever attribute or tag
+in the configuration file, except when the name appears as a keyword of an attribute SQL query.</p>
+<p>Example:</p>
+<div class="source"><xmp><entity name="person" table="tbl_person">
+  <aliases id="person_id" lastname="family_name"/>
+  <rowset name="related" result="person">
+    SELECT * FROM tbl_person WHERE family_name = <lastname/>
+  </rowset>
+  <scalar name="children">
+    SELECT count(*) FROM person WHERE person_id = <id/>
+  </scalar>
+</entity></xmp></div>
+
+<a name="fetching"/>
+<h1>Fetching instances and iterating</h1>
+
+<p>Unless reverse engineering is deactivated, primary keys of tables will be reverse engineered. You can then use the <code>fetch(key)</code> entity method
+to fetch a particular instance of this entity. The <code>key</code> parameter can be a scalar value, a list of values or a map of key-value pairs. The two last forms are adequate for multi-valued primary keys.</p>
+<p>For instance:</p>
+<div class="source">#set( $book = $db.book.fetch( $query.book_id ) )</div>
+<p>This example illustrate a common practice, which is to add hidden id fields to HTML forms so that target instances
+can be fetched using the HTTP query tool.</p>
+<p>Multivalued keyed rows can also be fetched the same way by providing a column&rarr;value map (like <code>$query</code> itself) or a list containing
+key values in their natural order.</p>
+
+<p>You can iterate on an entity or on a row set attribute by mean of the Velocity <code>#foreach</code> directive.</p>
+<p>Example:</p>
+<div class="source"><code><pre>List of books by publisher:
+#foreach($publisher in $db.publisher)
+  Books published by $publisher.name:
+    #foreach($book in $publisher.books)
+      - $book.title (author $book.author.firstname $book.author.lastname)
+    #end
+#end
+</pre></code></div>
+<p>While discouraged since it breaks SQL code isolation, you can control the rows order and add supplemental criteria
+by calling the <code>order("<i>SQL order clause</i>")</code> and <code>refine("<i>SQL condition</i>")</code> methods before issuing the <code>#foreach</code>, like this:
+</p>
+<div class="source"><code><pre>List of books by publisher:
+#set($db.publisher.refine('active=true')) ## only take into account active publishers
+#set($db.publisher.order('name')) ## order by name
+#foreach($publisher in $db.publisher)
+  Books published by $publisher.name:
+    #foreach($book in $publisher.books)
+      - $book.title (author $book.author.firstname $book.author.lastname)
+    #end
+#end
+</pre></code></div>
+<p>Refinment and ordering have the same scope than the velosurf.web.VelosurTool tool.</p>
+<a name="obfuscation"/>
+<h1>IDs obfuscation</h1>
+<p>Since in a Webapp the query part of URLs is likely to contain ID values, it is good practice to obfuscate those values
+if you want to protect the Webapp against manual editing of those URLs. Velosurf can automatically handle this obfuscation for you.
+You just need to provide a comma separated list of columns meant to be obfuscated in the <code>obfuscate</code> attribute of the <code>&lt;entity&gt;</code> tag.</p>
+<p>Remember that obfuscated IDs will be strings, never numbers.</p>
+
+<a name="caching"/>
+<h1>Caching instances</h1>
+<p>When very frequent fetch queries occur, you can tell Velosurf to cache corresponding instances in memory by mean of the <code>cache</code> attribute of the <code>&lt;entity&gt;</code> tag,
+which can take the following values:
+<ul>
+<li><code>no</code> (the default): no caching provided.</li>
+<li><code>yes</code>: caching of fetched instances with respect to memory. Instances are put into the cache
+when fetched for the first time, but the Java virtual machine can reclaim the memory they use if needed.</li>
+</ul></p>
+<p>Warning: Velosurf will invalidate cached entries on update/delete requests, but global updates are not
+taken into account, so be sure to empty the cache after global modifications.</p>
+ <p>This caching mechanism is meant for straightforward optimizations in simple situations, for instance to
+avoid re-fetching a specific instance at each HTTP request.</p>
+
+<a name="mapping"/>
+<h1>Customizing Java mapping objects</h1>
+<p>Using the <code>class</code> attribute of the entity tag, you can specify which class you'd like Velosurf to use to map instances of a particular entity.
+This class can be a POJO (Plain Old Java Object) or a class inheriting from <code><a href="api/velosurf.context.Instance.html">velosurf.context.Instance</a></code>.</p>
+<p>In both cases, the following methods will be taken into account by Velosurf when present in the POJO:
+<ul>
+<li>specific getter: <code>getFoo()</code>.</li>
+<li>generic getter: <code>get(<i>key</i>)</code></li>
+<li>specific setter: <code>setFoo(<i>value</i>)</code></li>
+<li>generic getter: <code>put(<i>key</i>,<i>value</i>)</code></li>
+<li>update row with current values: <code>update()</code> (boolean result type expected)</li>
+<li>update row with passed values: <code>update(<i>map</i>)</code> (boolean result type expected)</li>
+<li>insert row: <code>insert()</code> (boolean result type expected)</li>
+<li>delete row: <code>delete()</code> (boolean result type expected)</li>
+</ul>
+</p>
+<p>When using POJOs, you can choose to implement only some of fields getters and setters; other fields will still have their
+default getters and setters.</p>
+
+<a name="modifications"/>
+<h1>Issuing modifications to the database</h1>
+<p>By default, the database is opened in read-only mode, and thus forbidding the execution of any action, insert, update or delete.
+You need to set a <code>read-only="no"</code> attribute in the database tag to override this default behaviour.</p>
+<p>To enforce the MVC paradigm, database modifications should not be issued from inside templates
+but rather from a controller object, so as not to mix View and Controller layers. This controller object of your own can change programmatically the read-only flag of
+its connection before issuing the modifications, while still relying on the model defined in Velosurf configuration file via
+the Velosurf Java api. And to enforce security, you should also use different database users with different rights (see the <a href="./faq.html#mvc.login">FAQ</a> about how to do this).</p>
+<p>For each row-based update or delete, Velosurf ensures that the key values are known to avoid a wider accidental update or delete.</p>
+<p>After an insertion, the last inserted ID value can be fetched using <code>$db.<i>entity</i>.lastInsertID</code> (or from Java code by calling
+the <code>getLastInsertID()</code> method on the EntityReference). Note: this feature is not implemented in Velosurf for all databases (for now,
+only Cloudscape, DB2, HSqlDB, MySql and Sybase databases are supported - if you need this feature for your favorite RDBMS not listed here, please contribute!)</p>
+
+<a name="validation"/>
+<h1>Data validation</h1>
+<div style="background:gray">
+<center><b>Warning: the data validation module is currently not actively maintained - it may become depracated, evolve into something else, etc...</b></center>
+</div>
+<p>Velosurf provides a validation process on constraints defined in its configuration file. Those constraints
+don't replace SQL defined constraints, they are supplementary constraints provided by Velosurf which are enforced on a per-row basis
+and not checked on massive updates.</p>
+<p>You can define constraints on fields of an entity using a <code>&lt;constraint&gt;</code> tag per column. Each column constraint tag contains field constraints. Field constraints can be expressed in a short syntax form (as attributes of the column &lt;constraint&gt; tag)
+or in a long syntax form (as child tags of the column &lt;constraint&gt; tag), the long syntax form allowing some additional settings
+on the field constraint like the customization of the error message to be generated when the field constraint fails.</p>
+<p>The following field constraints are available (we only recall the short syntax here; please refer to <a href="./configuration.html">the Configuration page</a>
+or to the <a href="./api/velosurf/validation.html">javadoc</a>):
+<ul>
+<li><code>not-null="yes"</code> : data cannot be null.</li>
+<li><code>not-empty="yes"</code> : data cannot be null or an empty string.</li>
+<li><code>min-length="<i>integer</i>"</code> and/or <code>max-length="<i>integer</i>"</code> : data length must reside in the specified inclusive interval.</li>
+<li><code>one-of="<i>value1,value2,..."</i></code> : data must be one of the supplied values.</li>
+<li><code>references="<i>table.column</i>"</code> : data must reference a value found in <code><i>table.column</i></code> (a <code>select distinct</code> query is performed at validation time).</li>
+<li><code>regex="<i>pattern</i>"</code> : data must be matched by the supplied pattern.</li>
+<li><code>type="number"</code> : a numeric value is expected</li>
+<li><code>type="integer"</code> : an integer or long value is expected.</li>
+<li><code>min="<i>number</i>"</code> and/or <code>max="<i>number</i>"</code> : data must be in the specified inclusive interval (number type implied).</li>
+<li><code>type="date"</code> : data must be a parsable date. Some heuristics are provided to determine the locale and the format of the date; otherwise you can use the long syntax form and
+specify the format you expect here.</li>
+<li><code>after="<i>yyyymmdd"</i></code> and/or <code>before="<i>yyyymmdd</i>"</code> : data must be a date lying between the specified inclusive interval (date type implied).</li>
+<li><code>type="email"</code> : data is expected to have a valid email syntax. When using the long syntax form for this constraint, you can also ask for a DNS check
+(to validate the domain name) and for an SMTP check (to validate the user name).</li>
+</ul></p>
+<p>Apart from <code>not-empty</code> and <code>not-null</code>, all constraints are considered valid on a null or empty string.</p>
+<p>Validation occurs:
+<ul>
+<li>when <code>update()</code> or <code>insert()</code> is called on a row (boolean returned).</li>
+<li>when <code>validate()</code> is called on a row (boolean returned).</li>
+<li>when using the <code><a href="api/velosurf/validation/ValidationFilter.html">velosurf.validation.ValidationFilter</a></code> servlet filter, see below.</li>
+</ul></p>
+<p>In all cases, all validation error messages are then accessible in the <code>$db.validationErrors</code> list.</p>
+<p>The validation filter checks every request for a <code>velosurf.entity</code> query attribute that contains the name
+of the entity against which the data is to be validated. If found, it will check form data and either let the request pass through
+if data is valid or redirect back the client browser to the input form (using the referrer field) with <code>$db.validationErrors</code>
+populated if data is not valid.</p>
+<p>Once the filter in set up in you <code>/WEB-INF/web.xml</code> file with those lines:</p>
+<div class="source"><xmp>  <filter>
+    <filter-name>validation</filter-name>
+    <filter-class>velosurf.validation.ValidationFilter</filter-class>
+  </filter>
+  <filter-mapping>
+    <filter-name>validation</filter-name>
+    <!-- on a production site you can optimize this mapping with an <url-pattern> entry
+         per input form page if you have a 2.4+ servlet container -->
+    <url-pattern>/*</url-pattern>
+    <dispatcher>REQUEST</dispatcher>
+    <dispatcher>FORWARD</dispatcher>
+  </filter-mapping>
+</xmp></div>
+<p>then every input form can benefit of this mechanism provided:
+<ul>
+<li>you give the name of the entity to be validated in an input field:<br><code>&lt;input&nbsp;type="hidden" name="velosurf.entity" value="<i>entity name</i>"&gt; </code>.</li>
+<li>the name of each other input field correspond to the entity field name.</li>
+</ul></p>
+
+<a name="foreign-keys"/>
+<h1>Imported and Exported Keys</h1>
+<p>When reverse engineering foreign keys in <b>full</b> mode, each foreign key will produce two new attributes:
+<ul>
+<li>one attribute for the <i>imported key</i>, belonging to the importing table, named after the imported table name, with a row result type.</li>
+<li>one attribute for the <i>exported key</i>, belonging to the imported table, named after a rough pluralization ("s" or "es" added) of the importing table name, with a row set result type.</li>
+</ul></p>
+<p>Example: if the <code>book</code> table is importing the key of the <code>publisher</code> table, then the two generated attributes will be:
+<ul>
+<li><code>$book.publisher</code> (a single publisher)</li>
+<li><code>$publisher.books</code> (a set of books)</li></ul></p>
+<p>If this default behaviour is not the one you need, use a	lower reverse engineering mode and define manually the
+foreign keys you need using the <code>&lt;imported-key&gt;</code> and <code>&lt;exported-key&gt;</code> tags. You can
+still use those tags in <b>full</b> reverse engineering mode to customize the name of the generated attributes.</p>
+
+<div style="background:gray;">
+<a name="httpquery"/>
+<h1>HTTP Query parameters</h1>
+<center><b>Deprecated: those features are now directly accessible in VelocityTools 2.0+</b></center>
+<p>Velosurf provides an <a href="./api/velosurf/web/HttpQueryTool.html">HTTP query parameter parser</a>, traditionally mapped to the <code>$query</code> key in the toolbox. It is very similar to the <a href="http://velocity.apache.org/tools/releases/2.0/javadoc/org/apache/velocity/tools/view/ParameterTool.html">VelocityTools ParameterTool</a> (from which it inherits), but adds a few features:</p>
+<ul>
+<li>it adds a generic setter, this allows adding some key/value pairs in its map before using <code>$query</code> as an argument to one of the Velosurf methods expecting a map.</li>
+<li>it permits to gather in a submap all form parameters that share a common prefix. For instance, given the following form:
+<div class="source"><xmp>
+<form>
+	<input type=... name="foo.firstname" />
+	<input type=... name="foo.lastname" />	
+	...
+</form>
+</xmp></div>then <code>$query.foo</code> will return a map containing two keys, <i>firstname</i> and <i>lastname</i></li>
+</ul>
+</div>
+
+<a name="localization"/>
+<h1>Localization</h1>
+<div class="warning">this feature is still experimental</div>
+<p>Velosurf provides a localization mechanism. It consists of:
+<ul><li>a <code><a href="api/velosurf/web/l10n/Localizer.html">velosurf.web.l10n.Localizer</a></code> Java interface with a getter and a setter for the active locale, and two getters to obtain
+localized messages from their ID (the second one allowing the use of parameterized messages as in <code>"Found {0} match(es) for {1}."</code>).</li>
+<li>an abstract <code><a href="api/velosurf/web/l10n/HTTPLocalizerTool.html">velosurf.web.l10n.HTTPLocalizerTool</a></code> Java class implementing the <code>Localizer</code> interface.
+It will try to deduce the appropriate locale for incoming HTTP queries (from their "Accepted-Language" header). It is abstract because it does not make any assumption
+on how the localized data is stored.</li>
+<li>a <code><a href="api/velosurf/web/l10n/SimpleDBLocalizer.html">velosurf.web.l10n.SimpleDBLocalizer</a></code> Java class inheriting from <code>HttpLocalizerTool</code> that uses a configurable <code>localized(id,locale,string)</code> SQL table.</li>
+<li>an optional <code><a href="api/velosurf/web/l10n/LocalizationFilter.html">velosurf.web.l10n.LocalizationFilter</a></code> servlet filter meant to help the process of redirecting or
+forwarding incoming requests towards separate localized instances of a site (i.e. <code>/index.html</code> redirected
+or forwarded towards <code>/en/index.html</code> or <code>/fr/index.html</code>) based on browser locale. This rewriting mechanism is
+only implemented for the URI part of the URL at the moment (that is, you cannot yet change the hostname (&rarr;<code>en.mysite.com</code>) or the query string (&rarr;mysite.com?lang=fr)).</li>
+</ul>
+</p>
+<p>Please refer to the corresponding javadoc and look in the examples for how to configure those tools.</p>
+<p>Once the localizer is set up in the toolbox, the syntax used to display a localized message in a template will be like: <code>$local.welcomeMessage</code>. When localizing
+parameterized messages, the getter that takes parameters must be used: <code>$local.get('welcomeMessage',$user.name)</code></p>
+<p>Here is an example of configuration where we want the client browser redirected towards pages under <code>/en/</code>, <code>/fr/</code> or <code>/es/</code> if needed:</p>
+<ul><li>file <code>/WEB-INF/web.xml</code>:</li>
+<div class="source"><xmp>...
+  <filter>
+    <filter-name>localization</filter-name>
+    <filter-class>velosurf.web.l10n.LocalizationFilter</filter-class>
+    <init-param>
+      <param-name>localization-method</param-name>
+      <param-value>redirect</param-value>
+    </init-param>
+    <init-param>
+      <param-name>supported-locales</param-name>
+      <param-value>en,fe,es</param-value>
+    </init-param>
+    <init-param>
+      <param-name>inspect-uri</param-name>
+      <param-value>^/(.+)(?:/|$)</param-value>
+    </init-param>
+    <init-param>
+      <param-name>match-uri</param-name>
+      <param-value>^/(.*)$</param-value>
+    </init-param>
+    <init-param>
+      <param-name>rewrite-uri</param-name>
+      <param-value>/@/$1</param-value>
+    </init-param>
+  </filter>
+  ...
+  <filter-mapping>
+    <filter-name>localization</filter-name>
+    <url-pattern>/*</url-pattern>
+    <dispatcher>REQUEST</dispatcher>
+    <dispatcher>FORWARD</dispatcher>
+  </filter-mapping>
+  ...</xmp></div>
+<li>file <code>/WEB-INF/toolbox.xml</code> (VelocityTools 1.x):</li>
+<div class="source"><xmp>...
+  <tool>
+    <key>local</key>
+    <scope>session</scope>
+    <class>velosurf.web.l10n.SimpleDBLocalizer</class>
+  </tool>
+  ...</xmp></div>
+  <li>file <code>/WEB-INF/tools.xml</code> (VelocityTools 2.x):</li>
+  <div class="source"><xmp>...
+    <toolbox scope="session">
+      <tool key="local" class="velosurf.web.l10n.SimpleDBLocalizer"/>
+      ...
+    </toolbox>
+    ...</xmp></div>
+</ul>
+<p>Using the redirect method is more advised than using the forward method, since the forward method will let one
+URL correspond to different web pages, thus bugging search engines.</p>
+
+<a name="authentication"/>
+<h1>Authentication</h1>
+<p>Velosurf is shipped with some utility classes that allow one to easily plug a session based CRAM (Challenge Response Authentication Mechanism)
+in a Webapp. It consists of three classes and a javascript module:
+<ul>
+<li>a <code><a href="api/velosurf/web/auth/AuthenticationFilter.html">velosurf.web.auth.AuthenticationFilter</a></code> that is meant to be mapped to pages needing authentication.</li>
+<li>an abstract <code><a href="api/velosurf/web/auth/BaseAuthenticator.html">velosurf.web.auth.BaseAuthenticator</a></code> tool that takes a <code>method</code> configuration parameter
+(the encryption method to be used). Omitting this <code>method</code> parameter means that passwords will be transmitted in clear (which is
+not a problem if you use HTTPS, which you should really use if you want security).</li>
+<li>a simple implementation of this abstract tool, <code><a href="api/velosurf/web/auth/SimpleDBAuthenticator.html">velosurf.web.auth.SimpleDBAuthenticator</a></code>, that implements the two abstract
+methods <code>getUser(<i>login</i>)</code> and <code>getPassword(<i>login</i>)</code> using a configurable <code>user(id,login,password)</code> SQL table. If you use this authenticator, you'll have to define a root attribute that returns a user instance given its login, as detailed on the javadoc page.</li>
+<li>a Javascript <code>/src/javascript/md5.js</code> (BSD license) implementing the client-side encryption for the <code>HmacMD5</code> method.</li>
+</ul></p>
+<p>Please refer to the provided javadoc links for further information regarding the configuration parameters.</p>
+<p>Here is an example of configuration for a HmacMD5 autentication:</p>
+<ul><li>file <code>/WEB-INF/web.xml</code>:</li>
+<div class="source"><xmp> ...
+  <filter>
+    <filter-name>authentication</filter-name>
+    <filter-class>velosurf.web.auth.AuthenticationFilter</filter-class>
+    <init-param>
+      <param-name>index-page</param-name>
+      <param-value>/index.vhtml</param-value>
+    </init-param>
+    <init-param>
+      <param-name>max-inactive</param-name>
+      <param-value>600</param-value>
+    </init-param>
+    <init-param>
+      <param-name>login-page</param-name>
+      <param-value>/login.vhtml</param-value>
+    </init-param>
+    <init-param>
+      <param-name>authenticated-index-page</param-name>
+      <param-value>/auth/index.vhtml</param-value>
+    </init-param>
+  </filter>
+  ...
+  <filter-mapping>
+    <filter-name>authentication</filter-name>
+    <!-- 2.4 syntax allows several url-patterns per mapping -->
+    <url-pattern>/auth/*</url-pattern>
+    <url-pattern>*.do</url-pattern>
+    <dispatcher>REQUEST</dispatcher>
+    <dispatcher>FORWARD</dispatcher>
+  </filter-mapping>
+  ...
+</xmp></div>
+<li>file <code>/WEB-INF/toolbox.xml</code> (VelocityTools 1.x):</li>
+<div class="source"><xmp>  ...
+  <tool>
+    <key>auth</key>
+    <scope>session</scope>
+    <class>velosurf.web.auth.SimpleDBAuthenticator</class>
+    <parameter name="method" value="HmacMD5"/>
+  </tool>
+  ...
+</xmp></div>
+  <li>file <code>/WEB-INF/tools.xml</code> (VelocityTools 2.x):</li>
+  <div class="source"><xmp>...
+    <toolbox scope="session">
+      <tool key="auth" class="velosurf.web.auth.SimpleDBAuthenticator"/>
+      ...
+    </toolbox>
+    ...</xmp></div>
+</ul>
+<li>file <code>/login.vhtml</code>:</li>
+<div class="source"><xmp><html>
+<head>
+<title>Login</title>
+<script type="text/javascript" src="md5.js"></script>
+<script type="text/javascript">
+    function sendLogin() {
+        document.hidden.elements['login'].value = document.login.elements['login'].value;
+        document.hidden.elements['password'].value =
+          b64_hmac_md5(document.login.elements['password'].value,'$auth.challenge');
+        document.hidden.submit();
+    }
+</script>
+</head>
+<body>
+$!loginMessage<br>
+Identification:<br>
+<form name="login" action="javascript:sendLogin()" method="POST">
+    Login: <input type="text" name="login" size="25" maxlength="30"><br>
+    Password: <input type="password" name="password"  size="15" maxlenght="50"><br>
+    <input type=submit value="Ok"><br>
+</form>
+<form name="hidden" action="login.do" method=POST>
+  <input type=hidden name=login>
+  <input type=hidden name=password>
+</form>
+</body>
+</html></xmp></div>
+<li>loging out link: <code>&lt;a href="logout.do"&gt;Logout&lt;/a&gt;</code></li>
+</ul>
+<p>Once a user has logged on, $auth.loggedUser will contain the user's instance.</p>
+
+<div style="background:gray">
+<a name="templatenamefilter"/>
+  <h1>Template name filter</h1>
+<center><b>Deprecated: the good practice is to use .vhtml, .vjs, .vxml ... for template file extensions</b></center>
+<p>Velosurf comes with a <code><a href="api/velosurf/util/TemplateNameFilter">TemplateNameFilter</a></code> servlet filter
+that is used to mask the '.vtl' in URLs. The idea is to be able to change the status of an HTML file from plain HTML to templatized HTML
+without the need to update URLs. It supposes you follow the convention of suffixing '.vtl' to the name of template files (e.g. <code>index.html.vtl</code> or <code>toolkit.js.vtl</code>).</p>
+<p>Check the javadoc to see how you can customize the parameters of the filter.</p>
+</div>
+
+<a name="filtering"/>
+<h1>Order of servlet filters</h1>
+<p>When using several of the filters proposed by the library, one must be cautious to the order in which those filters
+are mapped to incoming HTTP requests in the <code>/WEB-INF/web.xml</code> application descriptor.</p>
+<p><span style="text-decoration:line-through">If used, the template name filter should appear first. Then, </span>if both the authentication and localization filters are
+used, they should appear in the same order as the hierarchical ordering of the corresponding directories (i.e. authentication first if you
+use paths like <code>/auth/en/</code> and localization first if you use paths like <code>/en/auth/</code>).</p>
+
+<a name="fromjava"/><h1>Using the Velosurf API from Java</h1>
+<p>The Velosurf API is a very convenient way to access to the database from Java while still centralizing your model
+in <code>model.xml</code>.</p>
+<p>The main classes you may have to use are the following ones:</p>
+<ul><li><a href="api/velosurf/Velosurf.html"><code>velosurf.Velosurf</code></a> to obtain a database connection with <code>velosurf.getDatabase()</code></li>
+<!--<li><a href="api/velosurf/sql/Database.html"><code>velosurf.sql.Database</code></a> to get a connection using one of the static <code>getInstance</code> method.</li>-->
+<li><a href="api/velosurf/model/Entity.html"><code>velosurf.model.Entity</code></a> obtained from <code>database.getEntity('<i>name</i>')</code>.</li>
+<li><a href="api/velosurf/model/Attribute.html"><code>velosurf.model.Attribute</code></a> obtained from <code>database.getAttribute('<i>name</i>')</code> or from <code>entity.getAttribute('<i>name</i>')</code>.
+Attributes can then be evaluated with the appropriate method depending on the result type of the attribute (<code>evaluate()</code>, <code>fetch()</code> or <code>query()</code>).
+<li><a href="api/velosurf/model/Action.html"><code>velosurf.model.Action</code></a> obtained from <code>database.getAction('<i>name</i>')</code> or from <code>entity.getAction('<i>name</i>')</code>.</li>
+<li><a href="api/velosurf/context/RowIterator.html"><code>velosurf.context.RowIterator</code></a> obtained from <code><i>entity</i>.iterator()</code> or from <code><i>attribute</i>.query()</code>.</li>
+<li><a href="api/velosurf/context/Instance.html"><code>velosurf.context.Instance</code></a> fetched by its key value or as the result of an attribute.</li>
+</ul>
+<p>But you can also stick to <code>velosurf.context</code> objects, that is use <a href="api/velosurf/context/EntityReference.html"><code>EntityReference</code></a> instead of velosurf.model.Entity
+and <a href="api/velosurf/context/AttributeReference.html"><code>velosurf.context.AttributeReference</code></a> instead of <code>velosurf.model.Attribute</code>. It all depends on your needs.</p>
+<p>Please note that to avoid sql connection timeouts, you should not declare Velosurf prepared statements
+as variables having a long lifecycle (like static members). You should only keep references to Velosurf connection
+objects on the long term (they do handle timeouts). Plus, they already do prepared statements caching and pooling for you.</p>
+
+</div>
+</div>
+
+</body>
+</html>
+
+
+
+

Added: velocity/sandbox/velosurf/docs/velosurf.css
URL: http://svn.apache.org/viewvc/velocity/sandbox/velosurf/docs/velosurf.css?rev=1298906&view=auto
==============================================================================
--- velocity/sandbox/velosurf/docs/velosurf.css (added)
+++ velocity/sandbox/velosurf/docs/velosurf.css Fri Mar  9 16:23:25 2012
@@ -0,0 +1,219 @@
+/* Generated by CaScadeS, a stylesheet editor for Mozilla Composer */
+
+  body { background-color: rgb(255, 255, 255);
+    color: rgb(0, 0, 0);
+    }
+
+  a:link, a:active, a:visited { color: rgb(82, 93, 118);
+    }
+
+  h1 { background-color: rgb(2, 73, 114);
+    color: rgb(255, 255, 255);
+    font-family: arial,helvetica,sanserif;
+    font-size: large;
+    padding-left: 2px;
+    }
+
+  h2 { background-color: rgb(130, 141, 166);
+    color: rgb(255, 255, 255);
+    font-family: arial,helvetica,sanserif;
+    font-size: medium;
+    padding-left: 2px;
+    }
+
+  h3 { background-color: rgb(180, 180, 220);
+    color: rgb(255, 255, 255);
+    font-family: arial,helvetica,sanserif;
+    font-size: medium;
+    padding-left: 2px;    
+    margin-left: 10px;
+    }
+
+  p { text-align:justify;
+    }
+
+  table { border: medium none ;
+    border-collapse: collapse;
+    }
+
+  img { border: 0px none ;
+    }
+
+  table#layout { width: 100%;
+    }
+
+  table#layout td { padding: 0px;
+    }
+
+  div#container { margin: 10px auto 10px 0pt;
+    padding: 10px;
+    width: 850px;
+    }
+
+  div#header { border-bottom: 1px solid rgb(51, 51, 51);
+    margin: 5px 0px;
+    padding: 5px;
+    height: 80px;
+    }
+
+  div#menu { margin: 10px 5px 0px 0px;
+    padding: 5px;
+    float: left;
+    width: 200px;
+    }
+
+  div#body { margin: 5px 0px 0px 215px;
+    padding: 5px;
+    }
+
+  div#footer { border-top: 1px solid rgb(51, 51, 51);
+    clear: both;
+    padding-top: 15px;
+    margin-top: 25px;
+    text-align: center;
+    color: rgb(82, 93, 118);
+    font-style: italic;
+    font-size: smaller;
+    }
+
+  div#logo1 { position:absolute;
+    left: 20px;
+    top: 30px;
+    }
+
+  div#logo2 { position:absolute;
+    left:790px;
+	top:50px;
+    }
+
+  div#logo3 { position:absolute;
+    left:320px;
+    top:30px;
+    }
+
+  div#body th { border: 1px solid rgb(255, 255, 255);
+    padding: 2px;
+    background-color: rgb(3, 154, 204);
+    color: rgb(0, 0, 0);
+    font-family: arial,helvetica,sanserif;
+    font-size: smaller;
+    vertical-align: top;
+    text-align: left;
+    }
+
+  div#body td { border: 1px solid rgb(255, 255, 255);
+    padding: 2px;
+    background-color: rgb(230, 230, 255);
+    color: rgb(0, 0, 0);
+    font-family: arial,helvetica,sanserif;
+    font-size: smaller;
+    vertical-align: top;
+    text-align: left;
+    }
+
+  div#body li { margin-top: 3px;
+    }
+
+  div.section { margin-left: 25px;
+    }
+
+  div.subsection { margin-left: 25px;
+    }
+
+  div.source { border: 1px solid rgb(51, 51, 51);
+    padding: 5px 4px 4px;
+    margin-left: 25px;
+    margin-top: 20px;
+    margin-bottom: 20px;
+/*    width: 600px; */
+    background-color: rgb(238, 238, 238);
+    color: rgb(51, 51, 51);
+    white-space: pre;
+    font-family: Courier;
+    font-size: smaller;
+    text-align: left;
+    overflow: auto;
+    }
+
+  div.frame { border: 1px solid rgb(51, 51, 51);
+    padding: 5px 4px 4px;
+    margin-left: 25px;
+    margin-top: 20px;
+    margin-bottom: 20px;
+    width: 600px;
+    background-color: rgb(238, 238, 238);
+    color: rgb(51, 51, 51);
+    font-size: smaller;
+    text-align: left;
+    overflow: auto;
+    }
+
+  div.license { border: 1px solid rgb(51, 51, 51);
+    padding: 5px;
+    margin-left: 0px;
+    margin-top: 20px;
+    margin-bottom: 20px;
+    background-color: rgb(238, 238, 238);
+    color: rgb(51, 51, 51);
+    text-align: left;
+    }
+
+  div.menusection { margin-bottom: 10px;
+    }
+
+  .menuheader { font-weight: bold;
+    margin-bottom: 0px;
+    }
+
+  div.menusection ul { margin-top: 5px;
+    }
+
+  div.menusection li {  }
+
+  .warning
+  {
+      color:red;
+      font-weight:bold;
+  }
+  
+  @media print {
+  div#container { width: 100%;
+    min-height: 0px;
+    }
+  div#menu { display: none;
+    }
+  div#header { display: none;
+    }
+  div#body { margin-left: 5px;
+    }
+  div.source { width: 95%;
+    margin-left: 0px;
+    }
+  div.section { margin-left: 0px;
+    }
+  div.subsection { margin-left: 0px;
+    }
+  h1 { background-color: rgb(255, 255, 255);
+    color: rgb(0, 0, 0);
+    }
+  h2 { background-color: rgb(255, 255, 255);
+    color: rgb(0, 0, 0);
+    }
+  
+  div#body td { border: 1px solid rgb(51, 51, 51);
+    background-color: rgb(255, 255, 255);
+    color: rgb(0, 0, 0);
+    }
+  div#body th { border: 1px solid rgb(51, 51, 51);
+    background-color: rgb(255, 255, 255);
+    color: rgb(0, 0, 0);
+    }
+
+  .warning
+  {
+      color:red;
+      font-weight:bold;
+  }
+  
+}
+

Added: velocity/sandbox/velosurf/docs/velosurf.dtd
URL: http://svn.apache.org/viewvc/velocity/sandbox/velosurf/docs/velosurf.dtd?rev=1298906&view=auto
==============================================================================
--- velocity/sandbox/velosurf/docs/velosurf.dtd (added)
+++ velocity/sandbox/velosurf/docs/velosurf.dtd Fri Mar  9 16:23:25 2012
@@ -0,0 +1,107 @@
+<!ELEMENT database (entity*,attribute*,action*)>
+
+<!ATTLIST database user CDATA #REQUIRED>
+<!ATTLIST database password CDATA #REQUIRED>
+<!ATTLIST database url CDATA #REQUIRED>
+<!ATTLIST database driver CDATA #IMPLIED>
+<!ATTLIST database schema CDATA #IMPLIED>
+<!ATTLIST database read-only ( yes | no ) "yes">
+<!ATTLIST database caching ( none | soft | full ) "none">
+<!ATTLIST database reverse ( none | partial | full ) "full">
+<!ATTLIST database case ( sensitive | uppercase | lowercase ) #IMPLIED>
+<!ATTLIST database loglevel ( trace | debug | info | warn | error ) "info">
+<!ATTLIST database min-connections CDATA #IMPLIED>
+<!ATTLIST database max-connections CDATA #IMPLIED>
+<!ATTLIST database seed CDATA #IMPLIED>
+
+<!ELEMENT entity (attribute*,action*,constraint*)>
+
+<!ATTLIST entity name CDATA #REQUIRED>
+<!ATTLIST entity table CDATA #IMPLIED>
+<!ATTLIST entity read-only ( yes | no ) "yes">
+<!ATTLIST entity class CDATA #IMPLIED>
+<!ATTLIST entity caching ( none | soft | full) "none">
+<!ATTLIST entity obfuscate CDATA #IMPLIED>
+
+<!ELEMENT attribute (#PCDATA)> <!-- where #PCDATA is an SQL query with column tags -->
+
+<!ATTLIST attribute name CDATA #REQUIRED>
+<!ATTLIST attribute result CDATA #IMPLIED>
+
+<!ELEMENT action (#PCDATA)> <!-- where #PCDATA is an SQL query (or a set of queries) with column tags -->
+
+<!ATTLIST action name CDATA #REQUIRED>
+
+<!ELEMENT constraint (email?,min-len?,max-len?,integer?,number?,date?,not-null?,not-empty?,one-of?,reference?,regex?)>
+ 
+<!ATTLIST constraint column CDATA #REQUIRED>
+<!ATTLIST constraint type ( integer | number | date | email ) #IMPLIED>
+<!ATTLIST constraint min-len CDATA #IMPLIED>
+<!ATTLIST constraint max-men CDATA #IMPLIED>
+<!ATTLIST constraint min CDATA #IMPLIED>
+<!ATTLIST constraint max CDATA #IMPLIED>
+<!ATTLIST constraint after CDATA #IMPLIED>
+<!ATTLIST constraint before CDATA #IMPLIED>
+<!ATTLIST constraint not-empty CDATA #IMPLIED>
+<!ATTLIST constraint not-null CDATA #IMPLIED>
+<!ATTLIST constraint one-of CDATA #IMPLIED>
+<!ATTLIST constraint reference CDATA #IMPLIED>
+<!ATTLIST constraint regex CDATA #IMPLIED>
+
+<!ELEMENT email>
+
+<!ATTLIST email dns-check ( yes | no ) "no">
+<!ATTLIST email sptm-check ( yes | no ) "no">
+<!ATTLIST email message CDATA #IMPLIED>
+
+<!ELEMENT min-len>
+
+<!ATTLIST min-len value CDATA #REQUIRED>
+<!ATTLIST min-len message CDATA #IMPLIED>
+
+<!ELEMENT max-len>
+
+<!ATTLIST max-len value CDATA #REQUIRED>
+<!ATTLIST max-len message CDATA #IMPLIED>
+
+<!ELEMENT integer>
+
+<!ATTLIST integer min CDATA #IMPLIED>
+<!ATTLIST integer max CDATA #IMPLIED>
+<!ATTLIST integer message CDATA #IMPLIED>
+
+<!ELEMENT number>
+
+<!ATTLIST number min CDATA #IMPLIED>
+<!ATTLIST number max CDATA #IMPLIED>
+<!ATTLIST number message CDATA #IMPLIED>
+
+<!ELEMENT date>
+
+<!ATTLIST date before CDATA #IMPLIED>
+<!ATTLIST date after CDATA #IMPLIED>
+<!ATTLIST date message CDATA #IMPLIED>
+
+<!ELEMENT not-null>
+
+<!ATTLIST not-null message CDATA #IMPLIED>
+
+<!ELEMENT not-empty>
+
+<!ATTLIST not-empty message CDATA #IMPLIED>
+
+<!ELEMENT one-of (value+)>
+
+<!ATTLIST one-of message CDATA #IMPLIED>
+
+<!ELEMENT value (#PCDATA)>
+
+<!ELEMENT reference>
+
+<!ATTLIST reference foreign-key CDATA #REQUIRED>
+<!ATTLIST reference message CDATA #IMPLIED>
+
+<!ELEMENT regex>
+
+<!ATTLIST regex pattern CDATA #REQUIRED>
+<!ATTLIST regex message CDATA #IMPLIED>

Added: velocity/sandbox/velosurf/docs/vtl-reference.html
URL: http://svn.apache.org/viewvc/velocity/sandbox/velosurf/docs/vtl-reference.html?rev=1298906&view=auto
==============================================================================
--- velocity/sandbox/velosurf/docs/vtl-reference.html (added)
+++ velocity/sandbox/velosurf/docs/vtl-reference.html Fri Mar  9 16:23:25 2012
@@ -0,0 +1,569 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+
+  <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">
+  <title>Velosurf - VTL Reference</title>
+
+
+  <link rel="stylesheet" href="./velosurf.css" type="text/css">
+
+</head>
+
+
+<body>
+
+<div id="container">
+<div id="header">
+<div id="logo1"><img style="height: 60px;" alt="Velosurf logo" src="logo.png" border="0"></div>
+
+<div id="logo3"><img alt="Velosurf title" src="title.png" border="0"></div>
+
+<div id="logo2"><a href="http://jakarta.apache.org/velocity/"><img style="width: 80px;" src="powered-by-logo.gif" alt="Velocity" border="0"></a></div>
+
+</div>
+
+<div id="menu">
+<div class="menusection"><span class="menuheader">Velosurf</span>
+<ul>
+
+  <li><a href="./index.html">Home</a> </li>
+
+  <li> <a href="./overview.html">Overview</a>
+  </li>
+
+  <li><a href="./download.html">Download</a>
+  </li>
+
+  <li> <a href="./faq.html">FAQ</a> </li>
+
+  <li> <a href="http://velocity.apache.org/contact.html">Mailing lists</a> </li>
+
+</ul>
+
+</div>
+
+<div class="menusection">
+<span class="menuheader">Docs</span>
+<ul>
+
+  <li><a href="./installation.html">Installation</a></li>
+
+  <li><a href="./configuration.html">Configuration</a></li>
+
+  <li><a href="./user-guide.html">User Guide</a></li>
+
+  <li> <b>VTL Reference</b></li>
+
+  <li><a href="./api/index.html">Javadoc</a></li>
+
+  <li><a href="./architecture.html">Architecture</a></li>
+
+  <li><a href="./velosurf/docs/index.html">1.4.x Docs</a></li>
+
+  <li> <a href="./CHANGELOG">Change Log</a> </li>
+
+  <li> <a href="./LICENSE">License</a></li>
+
+</ul>
+
+</div>
+
+</div>
+
+<div id="body">
+			<H1>VTL Velosurf reference</H1>
+			<h2>Table of content</h2>
+			<ol>
+			<li><a href="#introduction">Introduction</a></li>
+			<li><a href="#database">Database attributes and methods</a></li>
+			<li><a href="#entity">Entity attributes and methods</a></li>
+			<li><a href="#attribute">Attribute attributes and methods</a></li>
+			<li><a href="#action">Action attributes and methods</a></li>
+			<li><a href="#instance">Instance attributes and methods</a></li>
+			<li><a href="#query">HTTPQuery attributes and methods</a></li>
+			<li><a href="#local">Localizer attributes and methods</a></li>
+			<li><a href="#auth">Authenticator attributes and methods</a></li>
+			</ol>
+			<a name="introduction"/>
+			<h2>Introduction</h2>
+			<p>You should have some knowledge of the <a href="http://velocity.apache.org/engine/releases/velocity-1.7/vtl-reference-guide.html">Velocity Template Language</a> before reading this page.</p>
+
+			<p>In a MVC Webapp, operations that issue changes to the database should not be done from inside
+			the templates but from a separate controller. One way to enforce this is to set the read-only
+			flag on in Velosurf configuration file (the controller can change this flag programmatically
+			for its own connection).</p>
+
+			<P>All methods that take a "<CODE>Map <i>values</i></CODE>"
+			argument expect column names as keys. They are quite convenient to use with the <CODE>$query</CODE>
+			variable (that contains all the HTTP query parameters) when coming
+			from an HTML form: you only have to ensure that the names of HTML
+			input fields map correctly to the names of the corresponding table
+			columns, by using <a href="user-guide.html#reverse">column aliases</a> if necessary.</P>
+			<P>Plain keywords represent actual names of properties
+			or methods, while keywords in italic stand for user properties or variables.</P>
+
+			<a name="database"/>
+			<H2>Database attributes and methods</H2>
+<div class="section">
+<table>
+<tr><td><a href="#db.entity"><code>$db.<i>entity</i></code></a></td><td>returns an entity</td></tr>
+<tr><td><a href="#db.attribute"><code>$db.<i>attribute</i></code></a></td><td>gets an attribute, returns a scalar, an instance, or an iterable attribute</td></tr>
+<tr><td><a href="#db.action"><code>$db.<i>action</i></code></a></td><td>executes an action, returns the number of affected rows</td></tr>
+<tr><td><a href="#db.external-parameter"><code>$db.<i>external-parameter</i></code></a></td><td>gets or sets an external parameter</td></tr>
+<tr><td><a href="#db.error"><code>$db.error</code></a></td><td>returns the last encountered error, if any</td></tr>
+<tr><td><a href="#db.locale"><code>$db.locale</code></a></td><td>returns the current locale</td></tr>
+</table>
+</div>
+			<h3><a name="db.entity">$db.<i>entity</i></a></h3>
+			<div class="section">
+			Returns an entity.
+<div class="source">#foreach($u in $db.user)
+ user name : $u.name
+#end
+<hr>#set( $current_user = $db.user.fetch($query.user_id) )</div></div>
+<h3><a name="db.attribute">$db.<i>attribute</i></a></h3>
+<div class="section">
+Returns an attribute, or directly the resulting value of the attribute for scalar or row attributes.
+<div class="source">Today, there are $db.today_events_count events.
+<hr/>#foreach($event in $db.today_events)
+  Today event: $event
+#end
+</div>
+You can optionally directly specify <a href="user-guide.html#extparams">external parameters values</a>:
+<div class="source">## requires the Velosurf uberspector
+Number of events for $date: $db.events_count({'day':$date})
+## without the Velosurf uberspector
+Number of events for $date: $db.getWithParams('events_count',{'day':$date})</div>
+</div>
+<h3><a name="db.action">$db.<i>action</i></a></h3>
+<div class="section">Executes a root action, returns the number of affected rows.
+<div class="source">#set( $nb = $db.cleanEvents )
+Deleted $nb event(s).</div>
+You can optionally directly specify <a href="user-guide.html#extparams">external parameters values</a>:
+<div class="source">## requires the Velosurf uberspector
+#set( $nb = $db.cleanDailyEvents({'date':$date}) )
+Deleted $nb event(s).
+## without the Velosurf uberspector
+#set( $nb = $db.getWithParams('cleanDailyEvents',{'date':$date}) )
+Deleted $nb event(s).</div>
+</div>
+<h3><a name="db.external-parameter">$db.<i>external-parameter</i></a></h3>
+<div class="section">
+Sets or returns the named external parameter, for use within a root attribute or action.
+<div class="source">#set( $db.publicationYear = 2006 )
+Number of published books for year $db.publicationYear: $db.countBooks</div></div>
+Note that you can specify external parameters <a href="user-guide.html#extparams">directly when calling attributes or actions</a>.
+<h3><a name="db.error">$db.error</a></h3>
+<div class="section">Returns the last encountered SQL error message, if any.
+<div class="source">#set( $nb = $db.myAction )
+#if($nb == 0 && $db.error)Error: $db.error</div></div>
+<a name="db.locale"/><h3>$db.locale</h3>
+<div class="section">Returns the current locale.
+<div class="source">Current locale: $db.locale.displayName</div></div>
+
+			<a name="entity"/>
+			<H2>Entity attributes and&nbsp;methods</H2>
+<div id="section">
+<div class="section">
+<table>
+<tr><td><a href="#entity.name"><code>$<i>entity</i>.name</code></a></td><td>returns the name of this entity</td></tr>
+<tr><td><a href="#entity.columns"><code>$<i>entity</i>.columns</code></a></td><td>returns the column names of this entity</td></tr>
+<tr><td><a href="#entity.fetch"><code>$<i>entity</i>.fetch(<i>key</i>)</code></a></td><td>returns the instance uniquely identified by <i>key</i> if it does exist, null otherwise</td></tr>
+<tr><td><a href="#entity.iterate"><code>#foreach(&nbsp;$<i>instance</i>&nbsp;in&nbsp;$<i>entity</i>&nbsp;)</code></a></td><td>iterates over this entity's instances</td></tr>
+<tr><td><a href="#entity.rows"><code>$<i>entity</i>.rows</code></a></td><td>returns the list of this entity's instances</td></tr>
+<tr><td><a href="#entity.order"><code>#set( $<i>entity</i>.order = '<i>order</i>' )</code></a></td><td>specifies how to order this entity's instances</td></tr>
+<tr><td><a href="#entity.refine"><code>$<i>entity</i>.refine( '<i>condition</i>' )</code></a></td><td>adds a filtering condition on this entity's instances</td></tr>
+<tr><td><a href="#entity.clearrefinement"><code>$<i>entity</i>.clearRefinement()</code></a></td><td>clears any previously set refinement</td></tr>
+<tr><td><a href="#entity.newinstance"><code>$<i>entity</i>.newInstance()</code></a></td><td>returns a new empty instance for this entity</td></tr>
+<tr><td><a href="#entity.newinstance2"><code>$<i>entity</i>.newInstance(Map <i>values</i>)</code></a></td><td>returns a new instance for this entity, initialized with the given values</td></tr>
+<tr><td><a href="#entity.validate"><code>$<i>entity</i>.validate(Map <i>values</i>)</code></a></td><td>validate data against this entity's constraints, returns the boolean success status</td></tr>
+<tr><td><a href="#entity.insert"><code>$<i>entity</i>.insert(Map <i>values</i>)</code></a></td><td>inserts an instance of the entity, returns the boolean success status</td></tr>
+<tr><td><a href="#entity.lastinsertid"><code>$<i>entity</i>.lastInsertID</code></a></td><td>returns the last inserted ID for this entity's autoincremented primary key</td></tr>
+<tr><td><a href="#entity.update"><code>$<i>entity</i>.update(Map <i>values</i>)</code></a></td><td>updates an instance of the entity, returns the boolean success status</td></tr>
+<tr><td><a href="#entity.delete"><code>$<i>entity</i>.delete(Map <i>values</i>)</code></a></td><td>delete an instance of the entity, returns the boolean success status</td></tr>
+<tr><td><a href="#entity.delete2"><code>$<i>entity</i>.delete(<i>key</i>)</code></a></td><td>delete the instance uniquely identified by <i>key</i>, return true if it did exist</td></tr>
+<tr><td><a href="#entity.upsert"><code>$<i>entity</i>.upsert(Map <i>values</i>)</code></a></td><td>upsert (update or insert) an instance of the entity, returns the boolean success status</td></tr>
+<tr><td><a href="#entity.count"><code>$<i>entity</i>.count</code></a></td><td>returns the number of rows in this entity's table</td></tr>
+</table>
+</div>
+</div>
+
+<h3><a name="entity.name">$<i>entity</i>.name</a></h3>
+<div class="section"><p>Returns the name of this entity.</p></div>
+
+<h3><a name="entity.columns">$<i>entity</i>.columns</a></h3>
+<div class="section"><p>Returns the column names of this entity.</p>
+<div class="source">#foreach($col in $user.entity.column)
+  column $col = $user.get($col)
+#end
+</div>
+</div>
+
+<h3><a name="entity.fetch">$<i>entity</i>.fetch(<i>key</i>)</a></h3>
+<div class="section"><p>Returns the instance uniquely identified by <i>key</i> if it does exist, null otherwise.
+<i>key</i> specifies this <i>entity</i>'s primary key value and can be a scalar value
+(string or number, for single-column keys), a list of values (for multi-column keys), or a map (where
+key values are stored under their column name).</p>
+<div class="source">#set( $book = $db.book.fetch( $query.book_id ) )
+<i>or:</i> #set( $book = $db.book.fetch( $query ) )
+<hr>#set( $resp = $db.responsability.fetch( [$user_id,$role_id]) )</div></div>
+<a name="entity.itetator"/><h3>#foreach( $<i>instance</i> in $<i>entity</i> )</h3>
+<div class="section">Iterates over this entity's instances. Concerned instances may have previously refined
+or ordered using the <code>refine()</code> and <code>order()</code> methods.
+<div class="source">All our books:
+#foreach($book in $db.book)
+  $book.title ($book.author.name)
+#end</div></div>
+<h3><a name="entity.rows">$<i>entity</i>.rows</a></h3>
+<div class="section">Returns the list of this entity's instances.  Concerned instances may have previously refined
+or ordered using the <code>refine()</code> and <code>order()</code> methods.</div>
+<h3><a name="entity.order">#set( $<i>entity</i>.order = '<i>order</i>' )</a></h3>
+<div class="section"><p>Sets the column(s) to be used for ordering this entity's instances when issuing a <code>#foreach</code>.
+This setting is local to the current Velocity context. The argument follows the syntax of a standard SQL ORDER BY clause, that is,
+several columns can be present in a comma separated list, and when postfixed to a column name the DESC keyword means descending order.</p>
+<!--<p>Use of this method is not encouraged, as it breaks the principle of SQL code isolation. It may be removed from future versions of Velosurf.</p>-->
+<div class="source">#set( $db.user.order = "lastname" )
+#foreach($user in $db.user) ... #end</div></div>
+
+<h3><a name="entity.refine">$<i>entity</i>.refine( '<i>condition</i>' )</a></h3>
+<div class="section"><p>Specifies an additional SQL condition before issuing a <code>#foreach</code> on this entity.
+This method can be called several times to accumulate conditions. The refinement is local to the current Velocity context.</p>
+<p>Refinements can be reset using the <code>clearRefinement()</code> method.</p>
+<p>Use of this method is not encouraged, as it breaks the principle of SQL code isolation. It may be removed from future versions of Velosurf.</p>
+<div class="source">Books written by $author:
+$db.book.refine("author_id = $autor.author_id")
+#foreach($book in $db.books) $book.title #end</div>
+</div>
+
+<h3><a name="entity.clearrefinement">$<i>entity</i>.clearRefinement()</a></h3>
+<div class="section">clears any previously set refinement.</div>
+
+<h3><a name="entity.newinstance">$<i>entity</i>.newInstance()</a></h3>
+<div class="section">Creates a new instance for this entity, meant for later insertion.
+<div class="source">#set( $user = $db.user.newInstance() )
+#set( $user.firstname = 'Joe' )
+#set( $user.lastname = 'Smith' )
+$db.user.insert( $user )</div></div>
+
+<a name="entity.newinstance2"/><h3>$<i>entity</i>.newInstance(Map <i>values</i>)</h3>
+<div class="section">Creates a new instance for this entity, meant for later insertion. It is initialized with the values given in the provided Map.
+<div class="source">#set( $user = $db.user.newInstance($query) )
+$db.user.insert( $user )</div></div>
+
+<h3><a name="entity.validate">$<i>entity</i>.validate(Map <i>values</i>)</a></h3>
+<div class="section">Validates <i>values</i> against this entity's constraints, returns a boolean.</div>
+
+<h3><a name="entity.insert">$<i>entity</i>.insert(Map <i>values</i>)</a></h3>
+<div class="section"><p>Inserts the given values as a new instance of this entity and returns the boolean success status of the operation.
+Unless auto-incremented, primary key values must be present in the map.
+If this entity's primary key is an auto-incremented index, its value can be retrieved using <code>$<i>entity</i>.lastInsertID</code>.</p>
+<p>If there are validation constraints for this entity, values are validated against them before the insertion.</p>
+<div class="source">#set( $success = $db.author.insert($query) )
+#if(!$success)
+  insertion failed:
+  ## display validation errors
+  for($error in $db.author.validationErrors) $error #end
+  ## display SQL error
+  $!db.error
+#end</div>
+</div>
+
+<h3><a name="entity.lastinsertid">$<i>entity</i>.lastInsertID</a></h3>
+<div class="section"><p>Returns the last inserted ID value for this entity's autoincremented primary key.</p></div>
+
+<h3><a name="entity.update">$<i>entity</i>.update(Map <i>values</i>)</a></h3>
+<div class="section"><p>Updates the values of an instance of this entity and returns the boolean success status of the operation.
+Primary key values must be present in the map along with
+values to be updated.</p>
+<p>Note that this method cannot be used to update the values of the primary key itself (use <code>insert(<i>new key</i>)</code> plus <code>delete(<i>old key</i>)</code>).</p>
+<p>If there are validation constraints for this entity, values are validated against them before the update.</p>
+<div class="source">#set( $success = $db.profile.update($query) )
+#if(!$success)
+  update failed:
+  ## display validation errors
+  for($error in $db.author.validationErrors) $error #end
+  ## display SQL error
+  $!db.error
+#end</div>
+</div>
+
+<h3><a name="entity.delete">$<i>entity</i>.delete(Map <i>values</i>)</a></h3>
+<div class="section"><p>Deletes an instance of the entity and returns the boolean success status of the operation.
+Primary key values must be present in the map.</p>
+<div class="source">
+#set($db.book.delete( $query ))
+#if(!$success)
+  delete failed:
+  $!db.error
+#end</div>
+</div>
+
+<h3><a name="entity.delete2">$<i>entity</i>.delete(<i>key</i>)</a></h3>
+<div class="section"><p>Deletes the instance uniquely identified by its primary key. Returns true if it did exist and was sucessfully deleted.</p>
+<div class="source">
+#set($db.book.delete( $query ))
+#if(!$success)
+  delete failed:
+  $!db.error
+#end</div>
+</div>
+
+<h3><a name="entity.upsert">$<i>entity</i>.upsert(Map <i>values</i>)</a></h3>
+<div class="section"><p>Upserts (updates or inserts) the values of an instance of this entity and returns the boolean success status of the operation.
+Primary key values must be present in the map along with
+values. If a row with this key already exists then the instance is updated, otherwise a new instance is inserted.</p>
+<p>If there are validation constraints for this entity, values are validated against them before the upsert.</p>
+<div class="source">#set( $success = $db.profile.upsert($query) )
+#if(!$success)
+  upsert failed:
+  ## display validation errors
+  for($error in $db.author.validationErrors) $error #end
+  ## display SQL error
+  $!db.error
+#end</div>
+</div>
+
+<h3><a name="entity.count">$<i>entity</i>.count</a></h3>
+<div class="section"><p>Returns the number of rows in this entity's table. Takes into account the current refinement.</p></div>
+
+<H2><a name="attribute">Attribute attributes and methods</a></H2>
+<div class="section">
+<table>
+<tr><td><a href="#attribute.iterator"><code>#foreach( $<i>instance</i> in $<i>attribute</i> )</code></a></td><td>iterates over the instances of this attribute</td></tr>
+<tr><td><a href="#attribute.rows"><code>$<i>attribute</i>.rows</code></a></td><td>returns the list of this attribute's resulting instances</td></tr>
+<tr><td><a href="#attribute.scalars"><code>$<i>attribute</i>.scalars</code></a></td><td>returns a list of this attribute's first resulting column</td></tr>
+<tr><td><a href="#attribute.map"><code>$<i>attribute</i>.map</code></a></td><td>returns a map built with this attribute's first two resulting columns</td></tr>
+<tr><td><a href="#attribute.instancemap"><code>$<i>attribute</i>.instanceMap</code></a></td><td>returns a map of all resulting instances indexed by their primary key</td></tr>
+<tr><td><a href="#attribute.order"><code>#set( $<i>attribute</i>.order = '<i>order</i>' )</code></a></td><td>specifies how to order this attribute's resulting instances</td></tr>
+<tr><td><a href="#attribute.refine"><code>$<i>attribute</i>.refine( '<i>condition</i>' )</code></a></td><td>adds a filtering condition on this entity's instances</td></tr>
+<tr><td><a href="#attribute.clearrefinement"><code>$<i>attribute</i>.clearRefinement()</code></a></td><td>clears any previously set refinement</td></tr>
+</table>
+</div>
+			<div class="section"><p>Only multivalued attributes (attributes that return a row set) can be referenced from
+			templates. Others are directly evaluated when referenced.</p></div>
+<h3><a name="attribute.iterator">#foreach( $<i>instance</i> in $<i>attribute</i> )</a></h3>
+<div class="section">Iterates over this attribute's resulting instances. Concerned instances may have previously refined
+or ordered using the <code>refine()</code> and <code>order()</code> methods.
+<div class="source">Logged users:
+#foreach( $user in $db.logged_users )
+  $user.login
+#end</div>
+</div>
+
+<h3><a name="attribute.rows">$<i>attribute</i>.rows</a></h3>
+<div class="section">Returns the list of this attribute's resulting instances. Concerned instances may have previously refined
+or ordered using the <code>refine()</code> and <code>order()</code> methods.</div>
+
+<h3><a name="attribute.scalars">$<i>attribute</i>.scalars</a></h3>
+<div class="section">Returns the list of this attribute's first resulting column. Concerned instances may have previously refined
+or ordered using the <code>refine()</code> and <code>order()</code> methods.</div>
+
+<h3><a name="attribute.map">$<i>attribute</i>.map</a></h3>
+<div class="section">Returns a map built with this attribute's first two resulting columns. Concerned instances may have previously refined
+or ordered using the <code>refine()</code> and <code>order()</code> methods.</div>
+
+<h3><a name="attribute.instancemap">$<i>attribute</i>.instanceMap</a></h3>
+<div class="section">Returns a map of all resulting instances indexed by their primary key.
+Concerned instances may have previously refined
+or ordered using the <code>refine()</code> and <code>order()</code> methods.</div>
+
+<h3><a name="attribute.order">#set( $<i>attribute</i>.order = '<i>order</i>' )</a></h3>
+<div class="section"><p>Sets the column(s) to be used for ordering this attributes's resulting instances when issuing a <code>#foreach</code>.
+This setting is local to the current Velocity context. The argument follows the syntax of a standard SQL ORDER BY clause, that is,
+several columns can be present in a comma separated list, and when postfixed to a column name the DESC keyword means descending order.</p>
+<!--<p>Use of this method is not encouraged, as it breaks the principle of SQL code isolation. It may be removed from future versions of Velosurf.</p>-->
+<div class="source">logged users:
+#set( $db.logged_users.order = 'login' )
+#foreach( $user in $db.logged_users )
+  $user.login
+#end</div></div>
+
+<h3><a name="attribute.refine">$<i>attribute</i>.refine( '<i>condition</i>' )</a></h3>
+<div class="section"><p>Specifies an additional SQL condition before issuing a <code>#foreach</code> on this attribute.
+This method can be called several times to accumulate conditions. The refinement is local to the current Velocity context.</p>
+<p>Refinements can be reset using the <code>clearRefinement()</code> method.</p>
+<p>Use of this method is not encouraged, as it breaks the principle of SQL code isolation. It may be removed from future versions of Velosurf.</p>
+<div class="source">Logged users for country $country.name:
+$db.logged_users.refine( "country = $country.id" )
+#foreach( $user in $db.logged_users )
+  $user.login
+#end</div>
+</div>
+
+<h3><a name="attribute.clearrefinement">$<i>attribute</i>.clearRefinement()</a></h3>
+<div class="section">Clears any previously set refinement.</div>
+
+
+<H2><a name="action">Action attributes and methods</a></H2>
+<div class="section">
+			<P>An action has no attribute and no method. It is
+			executed when referenced, and returns the number of affected rows.</P>
+</div>
+
+<H2><a name="instance">Instance attributes and methods</a></H2>
+<div class="section">
+<table>
+<tr><td><a href="#instance.column"><code>$<i>instance</i>.<i>column</i></code></a></td><td>Gets or sets the value of the specified column</td></tr>
+<tr><td><a href="#instance.attribute"><code>$<i>instance</i>.<i>attribute</i></code></a></td><td>calls an attribute of this instance, returned value depend on the attribute result type</td></tr>
+<tr><td><a href="#instance.action"><code>$<i>instance</i>.<i>action</i></code></a></td><td>executes an action of this instance and returns the number of affected rows</td></tr>
+<tr><td><a href="#instance.entity"><code>$<i>instance</i>.entity</code></a></td><td>returns this instance's entity or <code>null</code> for a generic instance</td></tr>
+<tr><td><a href="#instance.primarykey"><code>$<i>instance</i>.primaryKey</code></a></td><td>returns a list of two-elements maps ('name'&rarr;name and 'value'&rarr;value) of this instance's key column(s)</td></tr>
+<tr><td><a href="#instance.validate"><code>$<i>instance</i>.validate()</code></a></td><td>validates this instance's data</td></tr>
+<tr><td><a href="#instance.putall"><code>$<i>instance</i>.putAll(Map <i>values</i>)</code></a></td><td>put all the key/value pairs of the provided Map in this instance</td></tr>
+<tr><td><a href="#instance.setcolumnvalues"><code>$<i>instance</i>.setColumnValues(Map <i>values</i>)</code></a></td><td>put all the key/value pairs of the provided Map whose key resolves into a column of this instance into it</td></tr>
+<tr><td><a href="#instance.insert"><code>$<i>instance</i>.insert()</code></a></td><td>inserts this instance in the database</td></tr>
+<tr><td><a href="#instance.update"><code>$<i>instance</i>.update()</code></a></td><td>updates this instance with current values and return the boolean success state of the operation</td></tr>
+<tr><td><a href="#instance.update2"><code>$<i>instance</i>.update(&nbsp;Map&nbsp;<i>values</i>&nbsp;)</code></a></td><td>updates this instance with values in <i><code>values</code></i> and return the boolean success state of the operation</td></tr>
+<tr><td><a href="#instance.delete"><code>$<i>instance</i>.delete()</code></a></td><td>deletes this instance from the database</td></tr>
+<tr><td><a href="#instance.upsert"><code>$<i>instance</i>.upsert()</code></a></td><td>upserts (updates or inserts) this instance with current values and return the boolean success state of the operation</td></tr>
+<tr><td><a href="#instance.upsert2"><code>$<i>instance</i>.upsert(&nbsp;Map&nbsp;<i>values</i>&nbsp;)</code></a></td><td>upserts (updates or inserts) this instance with values in <i><code>values</code></i> and return the boolean success state of the operation</td></tr>
+</table>
+</div>
+<h3><a name="instance.column">$<i>instance</i>.<i>column</i></a></h3>
+<div class="section">Gets or sets the value of the specified column.
+<div class="source">Previous title was: $book.title
+#set($book.title = $newtitle )
+New title is: $book.title</div></div>
+
+<h3><a name="instance.attribute">$<i>instance</i>.<i>attribute</i></a></h3>
+<div class="section">Returns an attribute of this instance. Scalar and row attributes are evaluated directly
+while row set attributes must be evaluated later using <code>#foreach</code>.
+You can optionally directly specify <a href="user-guide.html#extparams">external parameters values</a>:
+<div class="source">## requires the Velosurf uberspector
+Number of events for user $user.name for $date: $user.events_count({'day':$date})
+## without the Velosurf uberspector
+Number of events for user $user.name for $date: $user.getWithParams('events_count',{'day':$date})</div>
+</div>
+
+<h3><a name="instance.action">$<i>instance</i>.<i>action</i></a></h3>
+<div class="section">Executes an action of this instance and returns the number of affected rows.
+<div class="source">$book.setOutOfStock</div>
+You can optionally directly specify <a href="user-guide.html#extparams">external parameters values</a>:
+<div class="source">## requires the Velosurf uberspector
+$book.setOutOfStock({'sold_out',$date})
+## without the Velosurf uberspector
+$book.getWithParams('setOutOfStock',{'sold_out',$date})
+</div>
+
+<h3><a name="instance.entity">$<i>instance</i>.entity</a></h3>
+<div class="section">Returns this instance's entity or <code>null</code> for a generic instance.</div>
+
+
+<h3><a name="instance.primarykey">$<i>instance</i>.primaryKey</a></h3>
+<div class="section"><p>Returns a list of two-elements maps ('name'&rarr;name and 'value'&rarr;value) of this instance's key column(s).</p>
+<div class="source">#foreach($key in $instance.primaryKey)
+  &lt;input type="hidden" name="$key.name" value="$key.value"
+#end</div></div>
+
+<h3><a name="instance.validate">$<i>instance</i>.validate()</a></h3>
+<div class="section"><p>Validates the data currently set in the instance.</p></div>
+
+<h3><a name="instance.putall">$<i>instance</i>.putAll(Map <i>values</i>)</a></h3>
+<div class="section"><p>Put all the key/value pairs of the provided Map in this instance.</p></div>
+
+<h3><a name="instance.setcolumnvalues">$<i>instance</i>.setColumnValues(Map <i>values</i>)</a></h3>
+<div class="section"><p>Put the key/value pairs of the provided Map whose key resolve to a column name of this instance into it, and ignore other values.</p></div>
+
+<h3><a name="instance.insert">$<i>instance</i>.insert()</a></h3>
+<div class="section"><p>Inserts this instance in the database and returns the boolean success status of the operation.</p>
+<p>Data is validated against constraints present in this instance's entity, if any.</p>
+<div class="source">#set( $book = $db.book.newInstance() )
+#set( $book.title = 'Bacmeth' )
+#set( $book.author = 'Shark Spear' )
+$book.insert()</div></div>
+
+<h3><a name="instance.update">$<i>instance</i>.update()</a></h3>
+<div class="section"><p>Updates this instance using current values. Returns the boolean success status of the operation.</p>
+<p>Data is validated against constraints present in this instance's entity, if any.</p>
+<div class="source">#set( $book.price='5.5' )
+$book.update()</div>
+</div>
+
+<h3><a name="instance.update2">$<i>instance</i>.update( Map <i>values</i> )</a></h3>
+<div class="section"><p>Updates this instance using values in the map (or current values for columns not present in the map). Returns the boolean success status of the operation.</p>
+<p>Data is validated against constraints present in this instance's entity, if any.</p>
+<div class="source">$book.update( $query )</div></div>
+
+<h3><a name="instance.delete">$<i>instance</i>.delete()</a></h3>
+<div class="section"><p>Removes this instance from the database, and returns the boolean success status of the operation.</p></div>
+
+<h3><a name="instance.upsert">$<i>instance</i>.upsert()</a></h3>
+<div class="section"><p>Upserts (updates or inserts) this instance using current values. Returns the boolean success status of the operation.</p>
+<p>Data is validated against constraints present in this instance's entity, if any.</p>
+<div class="source">#set($book = $db.find_book($params))
+#if(!$book)
+  #set($book = $db.book.newInstance($params))
+#end
+#set( $book.price='5.5' )
+$book.upsert()</div>
+</div>
+
+<h3><a name="instance.upsert2">$<i>instance</i>.upsert( Map <i>values</i> )</a></h3>
+<div class="section"><p>Upserts (updates or inserts) this instance using provided values. Returns the boolean success status of the operation.</p>
+<p>Data is validated against constraints present in this instance's entity, if any.</p>
+<div class="source">$book.upsert( $params )</div>
+</div>
+
+<h2><a name="query">HTTPQueryTool attributes and methods</a></h2>
+<div style="background:gray;">
+<center><b>Deprecated: please use the velocity-tools <a href="http://velocity.apache.org/tools/releases/2.0/javadoc/org/apache/velocity/tools/view/ParameterTool.html">Parameter Tool</a></b></center>
+</div>
+<div class="section">For a full survey of all supported methods, please check <a href="http://velocity.apache.org/tools/releases/1.7/javadoc/index.html">VelocityTools ParameterParser javadoc</a> and <a href="./api/velosurf/web/HttpQueryTool.html">Velosurf HttpQueryTool javadoc</a>.</div>
+<br/>
+<div class="section">
+<table>
+<tr><td><a href="#query"><code>$query</code></a></td><td>map of all query parameters</td></tr>
+<tr><td><a href="#query.param"><code>$query.<i>parameterName</i></code></a></td><td>returns the corresponding parameter (as a string)</td></tr>
+<tr><td><a href="#query.getint"><code>$query.getInt('<i>parameterName</i>')</code></a></td><td>returns the corresponding parameter (as an integer)</td></tr>
+<tr><td><a href="#query.getnumber"><code>$query.getNumber('<i>parameterName</i>')</code></a></td><td>returns the corresponding parameter (as a number)</td></tr>
+</table>
+</div>
+<div class="section">(examples yet to come...)</div>
+
+<h2><a name="local">Localizer attributes and methods</a></h2>
+
+<div class="section">
+<table>
+<tr><td><a href="#local.locale"><code>$local.locale</code></a></td><td>returns the current locale</td></tr>
+<tr><td><a href="#local.messageid"><code>$local.<i>message-id</i></code></a></td><td>returns the message corresponding to the specified id and the current locale</td></tr>
+<tr><td><a href="#local.get"><code>$local.get('<i>message-id</i>',...)</code></a></td><td>returns the message corresponding to the given id and the current locale, using the supplied parameters</td></tr>
+</table>
+</div>
+
+<h3><a name="local.locale">$local.locale</a></h3>
+<div class="section"><p>Returns the current locale used by the localizer</p></div>
+
+<h3><a name="local.messageid">$local.<i>message-id</i></a></h3>
+<div class="section"><p>Returns the message corresponding to the given id and using the current locale.</p>
+<div class="source">## display a welcome message in the user's language,
+## like "Hello, Robert!"
+$local.welcomeMessage, $user.name!</div></div>
+
+<h3><a name="local.get">$local.get('<i>message-id</i>',...)</a></h3>
+<div class="section"><p>Returns the message corresponding to the given id and the current locale, using the supplied parameters.
+The message must contain {0}, {1}, ... tags at the places where supplied parameters are to be inserted.</p>
+<div class="source">## display a welcome message using the user's name
+$local.get('welcomeMessage',$user.firstname)
+</div></div>
+
+<h2><a name="auth">Authenticator attributes and methods</a></h2>
+<div class="section">
+<table>
+<tr><td><a href="#auth.challenge"><code>$auth.challenge</code></a></td><td>returns a new challenge for CRAM authentication</td></tr>
+<tr><td><a href="#auth.loggeduser"><code>$auth.loggedUser</code></a></td><td>returns the logged user, if any</td></tr>
+</table>
+</div>
+</a>
+
+<h3><a name="auth.challenge">$auth.challenge</a></h3>
+<div class="section"><p>Returns a new challenge for CRAM authentication. See <a href="./user-guide.html#authentication">this section</a> in the user guide
+for more details.</p>
+</div>
+
+<h3><a name="auth.loggeduser">$auth.logguedUser</a></h3>
+<div class="section"><p>Returns the logged user, if any.
+</div>
+
+</div></div></body>
+</html>

Added: velocity/sandbox/velosurf/examples/ant-vpp/README
URL: http://svn.apache.org/viewvc/velocity/sandbox/velosurf/examples/ant-vpp/README?rev=1298906&view=auto
==============================================================================
--- velocity/sandbox/velosurf/examples/ant-vpp/README (added)
+++ velocity/sandbox/velosurf/examples/ant-vpp/README Fri Mar  9 16:23:25 2012
@@ -0,0 +1,18 @@
+This example show how to use Velosurf in the VPP Ant preprocessor.
+
+To run it you need to have Ant installed and to be running an unix-like
+shell (otherwise you'll have to adapt the provided script).
+
+Just enter this directory and type "./demo.sh"
+
+The script will:
+ - download needed libraries from the net
+ - launch "ant start-hsqldb" from the build directory of the release
+   to start the hsqldb demo database server.
+ - launch "ant demo" in this directory (the real part of the demo)
+ - launch "ant stop-hsqldb" from the build directory of the release
+   to stop the hsqldb demo database server.
+
+
+Thanks to Mike Kienenberger for the initial version of this example.
+

Added: velocity/sandbox/velosurf/examples/ant-vpp/build.xml
URL: http://svn.apache.org/viewvc/velocity/sandbox/velosurf/examples/ant-vpp/build.xml?rev=1298906&view=auto
==============================================================================
--- velocity/sandbox/velosurf/examples/ant-vpp/build.xml (added)
+++ velocity/sandbox/velosurf/examples/ant-vpp/build.xml Fri Mar  9 16:23:25 2012
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="iso-8859-1" ?>
+
+<!--
+ Copyright 2000-2006 The Apache Software Foundation.
+
+ Licensed under the Apache License, Version 2.0 (the "License")
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<project name="ant-vpp-demo" basedir="." xmlns:vpp="antlib:foundrylogic.vpp">
+
+  <!-- DOWNLOAD PROPERTIES -->
+  <property name="repo.url"          value="http://www.ibiblio.org/maven"/>
+  <property name="proxy.host"        value=""/>
+  <property name="proxy.port"        value="80"/>
+
+  <!-- demo -->
+
+  <!-- necessary if you want to customize the config file
+       (otherwise just specify the Velosurf class in the vpp context tool) -->
+  <typedef name="velosurf" className="velosurf.Velosurf"/>
+  <velosurf id="velosurf" configFile="./model.xml"/>
+
+  <vpp:config id="vppconfig">
+    <context>
+      <tool key="logger" classname="velosurf.util.Logger" />
+      <tool key="db" refid="velosurf" />
+      <property key="whatever" value="whatever" />
+    </context>
+  </vpp:config>
+
+  <target name="demo">
+    <vpp:copy todir="." overwrite="true">
+      <fileset dir="." includes="*.java.vtl"/>
+      <mapper type="glob" from="*.java.vtl" to="*.java"/>
+      <config refid="vppconfig"/>
+    </vpp:copy>
+  </target>
+
+</project>
+

Added: velocity/sandbox/velosurf/examples/ant-vpp/demo.sh
URL: http://svn.apache.org/viewvc/velocity/sandbox/velosurf/examples/ant-vpp/demo.sh?rev=1298906&view=auto
==============================================================================
--- velocity/sandbox/velosurf/examples/ant-vpp/demo.sh (added)
+++ velocity/sandbox/velosurf/examples/ant-vpp/demo.sh Fri Mar  9 16:23:25 2012
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+if [ "$0" == "./demo.sh" ] ; then
+
+  pushd .
+  cd ../../build
+  ant download
+  ant test-download
+  ant start-hsqldb
+  popd
+
+  if [ ! -e lib/commons-collections-3.2.jar ]; then cp ../../lib/commons-collections-3.2.jar lib; fi
+  if [ ! -e lib/commons-lang-2.2.jar ]; then cp ../../lib/commons-lang-2.2.jar lib; fi
+  if [ ! -e lib/crimson-1.1.3.jar ]; then cp ../../lib/crimson-1.1.3.jar lib; fi
+  if [ ! -e lib/hsqldb-1.8.0.5.jar ]; then cp ../../test/lib/hsqldb-1.8.0.5.jar lib; fi
+  if [ ! -e lib/jdom-1.0.jar ]; then cp ../../lib/jdom-1.0.jar lib; fi
+  if [ ! -e lib/velocity-1.4.jar ]; then cp ../../lib/velocity-1.4.jar lib; fi
+  if [ ! -e lib/oro-2.0.8.jar ]; then
+    echo Downloading oro-2.0.8.jar....
+    wget http://www.ibiblio.org/maven/oro/jars/oro-2.0.8.jar -O lib/oro-2.0.8.jar;
+  fi
+ 
+  cp ../../velosurf-*.jar lib
+
+  OLDCLASSPATH=$CLASSPATH
+  for lib in lib/*.jar; do CLASSPATH=$CLASSPATH:$lib; done;
+  echo CLASSPATH=$CLASSPATH
+  export CLASSPATH=$CLASSPATH
+  ant demo
+  CLASSPATH=$OLDCLASSPATH
+  export CLASSPATH
+
+  pushd .
+  cd ../../build
+  ant stop-hsqldb
+  popd
+
+else
+  echo "demo.sh must be launched in its directory!"
+fi
+

Propchange: velocity/sandbox/velosurf/examples/ant-vpp/demo.sh
------------------------------------------------------------------------------
    svn:executable = *

Added: velocity/sandbox/velosurf/examples/ant-vpp/foo.java.vtl
URL: http://svn.apache.org/viewvc/velocity/sandbox/velosurf/examples/ant-vpp/foo.java.vtl?rev=1298906&view=auto
==============================================================================
--- velocity/sandbox/velosurf/examples/ant-vpp/foo.java.vtl (added)
+++ velocity/sandbox/velosurf/examples/ant-vpp/foo.java.vtl Fri Mar  9 16:23:25 2012
@@ -0,0 +1,10 @@
+## used to debug...
+## $logger.log2File("/tmp/vpp.log")
+
+public class foo {
+
+    public static void main(String args[]) {
+      System.out.println("${db.localized.fetch(['welcome','en']).string}");
+    }
+
+}

Added: velocity/sandbox/velosurf/examples/ant-vpp/lib/vpp-2.2.1.jar
URL: http://svn.apache.org/viewvc/velocity/sandbox/velosurf/examples/ant-vpp/lib/vpp-2.2.1.jar?rev=1298906&view=auto
==============================================================================
Binary file - no diff available.

Propchange: velocity/sandbox/velosurf/examples/ant-vpp/lib/vpp-2.2.1.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: velocity/sandbox/velosurf/examples/ant-vpp/model.xml
URL: http://svn.apache.org/viewvc/velocity/sandbox/velosurf/examples/ant-vpp/model.xml?rev=1298906&view=auto
==============================================================================
--- velocity/sandbox/velosurf/examples/ant-vpp/model.xml (added)
+++ velocity/sandbox/velosurf/examples/ant-vpp/model.xml Fri Mar  9 16:23:25 2012
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<database user="sa" password="" url="jdbc:hsqldb:hsql://127.0.0.1/test"
+	read-only="false" loglevel="trace" reverse="full" xmlns:xi="http://www.w3.org/2001/XInclude">
+
+<!--  <xi:include href="included.xml"/> -->
+
+</database>

Added: velocity/sandbox/velosurf/examples/auth-l10n/README
URL: http://svn.apache.org/viewvc/velocity/sandbox/velosurf/examples/auth-l10n/README?rev=1298906&view=auto
==============================================================================
--- velocity/sandbox/velosurf/examples/auth-l10n/README (added)
+++ velocity/sandbox/velosurf/examples/auth-l10n/README Fri Mar  9 16:23:25 2012
@@ -0,0 +1,25 @@
+This Webapp example demonstrates:
+
+ - the use of the localization filter (see javadoc for the velosurf.web.l10n.LocalizationFilter)
+
+ - the use of the authentication filter (see javadoc for the velosurf.web.auth.AuthenticationFilter)
+
+To install it:
+
+1. Create an empty Webapp in your Servlet container.
+
+2. Copy the content of the auth-l10n directory to your Webapp folder.
+
+3. Copy the necessary libraries to WEB-INF/lib (Velosurf dependencies plus
+   your JDBC driver lib should be a good first guess).
+
+4. Adapt the database login informations in model.xml
+
+Some remarks:
+
+ - the provided deployment descriptor (web.xml) is for a 2.4 servlet container.
+
+ - the empty index.html file at root is here to fool the servlet container in
+   letting him find a welcome file whereas we will redirect the user later on
+   to a localized welcome file.
+



Mime
View raw message