Repository: cayenne-website
Updated Branches:
  refs/heads/master ecbc2ebc5 -> b81e46fbc


http://git-wip-us.apache.org/repos/asf/cayenne-website/blob/b81e46fb/src/main/site/content/docs/3.1/getting-started-rop.html
----------------------------------------------------------------------
diff --git a/src/main/site/content/docs/3.1/getting-started-rop.html 
b/src/main/site/content/docs/3.1/getting-started-rop.html
new file mode 100644
index 0000000..7649588
--- /dev/null
+++ b/src/main/site/content/docs/3.1/getting-started-rop.html
@@ -0,0 +1,581 @@
+---
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you 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.
+
+title: "Cayenne Getting Started ROP"
+description: "Tutorial how to quick start new Cayenne ROP project"
+cayenneVersion: "3.1"
+docsMenuTitle: "Getting Started ROP"
+weight: 40
+---
+<div class="sect1"> 
+ <h2 id="prerequisites"><a class="anchor" href="#prerequisites"></a>1. 
Prerequisites</h2> 
+ <div class="sectionbody"> 
+  <div class="sect2"> 
+   <h3 id="prerequisites-2"><a class="anchor" href="#prerequisites-2"></a>1.1. 
Prerequisites</h3> 
+   <div class="paragraph"> 
+    <p>This tutorial starts where "Getting Started with Cayenne" left off. If 
you have gone through the previous tutorial, and have the "tutorial" project 
open in Eclipse, you can go directly to the next step. If not, here are the 
compressed instructions to prepare you for work with ROP:</p> 
+   </div> 
+   <div class="ulist"> 
+    <ul> 
+     <li> <p>Step 1 - Eclipse Setup</p> </li> 
+     <li> <p>Step 2 - Create a project</p> </li> 
+     <li> <p>Step 3 - Create Cayenne OR Mapping</p> </li> 
+     <li> <p>Step 4 - Create Java Classes</p> </li> 
+     <li> <p>Step 5 - Convert the project to webapp.</p> </li> 
+    </ul> 
+   </div> 
+   <div class="paragraph"> 
+    <p>Note that at "Step 5" you can skip the JSP creation part. Just setup 
web.xml and maven-jetty-plugin in the POM.</p> 
+   </div> 
+  </div> 
+ </div> 
+</div> 
+<div class="sect1"> 
+ <h2 id="remote-object-persistence-quick-start"><a class="anchor" 
href="#remote-object-persistence-quick-start"></a>2. Remote Object Persistence 
Quick Start</h2> 
+ <div class="sectionbody"> 
+  <div class="sect2"> 
+   <h3 id="starting-client-project"><a class="anchor" 
href="#starting-client-project"></a>2.1. Starting Client Project</h3> 
+   <div class="sect3"> 
+    <h4 id="create-an-rop-client-project-in-eclipse"><a class="anchor" 
href="#create-an-rop-client-project-in-eclipse"></a>Create an ROP Client 
Project in Eclipse</h4> 
+    <div class="paragraph"> 
+     <p>Creation of a new Eclipse project has been discussed in some details 
in "Getting Started with Cayenne" guide, so we will omit the screenshots for 
the common parts.</p> 
+    </div> 
+    <div class="paragraph"> 
+     <p>In Eclipse select "File &gt; New &gt; Other…​" and then "Maven 
&gt; Maven Project". Click "Next". On the following screen check "Create a 
simple project" checkbox and click "Next" again. In the dialog shown on the 
screenshot below, enter "org.example.cayenne" for the "Group Id" and 
"tutorial-rop-client" for the "Artifact Id" (both without the quotes) and click 
"Finish".</p> 
+    </div> 
+    <div class="paragraph"> 
+     <p>Now you should have a new empty project in the Eclipse workspace. 
Check that the project Java compiler settings are correct. Rightclick on the 
"tutorial-rop-client" project, select "Properties &gt; Java Compiler" and 
ensure that "Compiler compliance level" is at least 1.5 (some versions of Maven 
plugin seem to be setting it to 1.4 by default).</p> 
+    </div> 
+   </div> 
+   <div class="sect3"> 
+    <h4 id="create-client-java-classes"><a class="anchor" 
href="#create-client-java-classes"></a>Create Client Java Classes</h4> 
+    <div class="paragraph"> 
+     <p>The client doesn’t need the XML ORM mapping, as it is loaded from 
the server. However it needs the client-side Java classes. Let’s generate 
them from the existing mapping:</p> 
+    </div> 
+    <div class="ulist"> 
+     <ul> 
+      <li> <p>Start CayenneModeler and open cayenne.xml from the "tutorial" 
project (located under "tutorial/src/main/resources", unless it is already 
open.</p> </li> 
+      <li> <p>Select the "datamap" DataMap and check "Allow Client Entities" 
checkbox.</p> </li> 
+      <li> <p>Enter "org.example.cayenne.persistent.client" for the "Client 
Java Package" and click "Update.." button next to the field to refresh the 
client package of all entities.</p> </li> 
+     </ul> 
+    </div> 
+    <div class="imageblock" style="text-align: center"> 
+     <div class="content"> 
+      <img src="images/datamap-enableclient.png" alt="datamap enableclient"> 
+     </div> 
+    </div> 
+    <div class="ulist"> 
+     <ul> 
+      <li> <p>Select "Tools &gt; Generate Classes" menu.</p> </li> 
+      <li> <p>For "Type" select "Client Persistent Objects".</p> </li> 
+      <li> <p>For the "Output Directory" select 
"tutorial-rop-client/src/main/java" folder (as client classes should go in the 
client project).</p> </li> 
+      <li> <p>Click on "Classes" tab and check the "Check All Classes" 
checkbox (unless it is already checked and reads "Uncheck all Classes").</p> 
</li> 
+      <li> <p>Click "Generate".</p> </li> 
+     </ul> 
+    </div> 
+    <div class="paragraph"> 
+     <p>Now go back to Eclipse, right click on "tutorial-rop-client" project 
and select "Refresh" - you should see pairs of classes generated for each 
mapped entity, same as on the server. And again, we see a bunch of errors in 
those classes. Let’s fix it now by adding two dependencies, "cayenne-client" 
and "resin-hessian", in the bottom of the pom.xml file. We also need to add 
Caucho M2 repository to pull Hessian jar files. The resulting POM should look 
like this:</p> 
+    </div> 
+    <div class="listingblock"> 
+     <div class="content"> 
+      <pre class="highlight"><code class="language-XML XML" 
data-lang="XML">&lt;project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd"&gt;
+    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
+    &lt;groupId&gt;org.example.cayenne&lt;/groupId&gt;
+    &lt;artifactId&gt;tutorial-rop-client&lt;/artifactId&gt;
+    &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;
+
+    &lt;dependencies&gt;
+        &lt;dependency&gt;
+            &lt;groupId&gt;org.apache.cayenne&lt;/groupId&gt;
+            &lt;artifactId&gt;cayenne-client&lt;/artifactId&gt;
+            &lt;!-- Here specify the version of Cayenne you are actually using 
--&gt;
+            &lt;version&gt;3.1.3-SNAPSHOT&lt;/version&gt;
+        &lt;/dependency&gt;
+        &lt;dependency&gt;
+        &lt;groupId&gt;com.caucho&lt;/groupId&gt;
+            &lt;artifactId&gt;resin-hessian&lt;/artifactId&gt;
+            &lt;version&gt;3.1.6&lt;/version&gt;
+        &lt;/dependency&gt;
+    &lt;/dependencies&gt;
+
+   &lt;repositories&gt;
+           &lt;repository&gt;
+               &lt;id&gt;caucho&lt;/id&gt;
+               &lt;name&gt;Caucho Repository&lt;/name&gt;
+               &lt;url&gt;http://caucho.com/m2&lt;/url&gt;
+               &lt;layout&gt;default&lt;/layout&gt;
+               &lt;snapshots&gt;
+                   &lt;enabled&gt;false&lt;/enabled&gt;
+               &lt;/snapshots&gt;
+               &lt;releases&gt;
+                   &lt;enabled&gt;true&lt;/enabled&gt;
+               &lt;/releases&gt;
+           &lt;/repository&gt;
+       &lt;/repositories&gt;
+&lt;/project&gt;</code></pre> 
+     </div> 
+    </div> 
+    <div class="paragraph"> 
+     <p>Your computer must be connected to the internet. Once you save the 
pom.xml, Eclipse will download the needed jar files and add them to the project 
build path. After that all the errors should disappear.</p> 
+    </div> 
+    <div class="paragraph"> 
+     <p>Now let’s check the entity class pairs. They look almost identical 
to their server counterparts, although the superclass and the property access 
code are different. At this point these differences are somewhat academic, so 
let’s go on with the tutorial.</p> 
+    </div> 
+   </div> 
+  </div> 
+  <div class="sect2"> 
+   <h3 id="setting-up-hessian-web-service"><a class="anchor" 
href="#setting-up-hessian-web-service"></a>2.2. Setting up Hessian Web 
Service</h3> 
+   <div class="sect3"> 
+    <h4 id="setting-up-dependencies"><a class="anchor" 
href="#setting-up-dependencies"></a>Setting up Dependencies</h4> 
+    <div class="paragraph"> 
+     <p>Now lets get back to the "tutorial" project that contains a web 
application and set up dependencies. The only extra one that we don’t have 
yet is resin-hessian.jar, just like the client, so let’s add it (and the 
caucho repo declaration) to the pom.xml.</p> 
+    </div> 
+    <div class="listingblock"> 
+     <div class="content"> 
+      <pre class="highlight"><code class="language-XML XML" 
data-lang="XML">&lt;project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd"&gt;
+    ...
+    &lt;dependencies&gt;
+        ...
+        &lt;dependency&gt;
+            &lt;groupId&gt;com.caucho&lt;/groupId&gt;
+            &lt;artifactId&gt;resin-hessian&lt;/artifactId&gt;
+            &lt;version&gt;3.1.6&lt;/version&gt;
+        &lt;/dependency&gt;
+    &lt;/dependencies&gt;
+
+    &lt;build&gt;
+    ...
+    &lt;/build&gt;
+
+    &lt;repositories&gt;
+        &lt;repository&gt;
+            &lt;id&gt;caucho&lt;/id&gt;
+            &lt;name&gt;Caucho Repository&lt;/name&gt;
+            &lt;url&gt;http://caucho.com/m2&lt;/url&gt;
+            &lt;layout&gt;default&lt;/layout&gt;
+            &lt;snapshots&gt;
+                &lt;enabled&gt;false&lt;/enabled&gt;
+            &lt;/snapshots&gt;
+            &lt;releases&gt;
+                &lt;enabled&gt;true&lt;/enabled&gt;
+            &lt;/releases&gt;
+        &lt;/repository&gt;
+    &lt;/repositories&gt;
+    &lt;/project&gt;</code></pre> 
+     </div> 
+    </div> 
+    <div class="admonitionblock note"> 
+     <table> 
+      <tbody>
+       <tr> 
+        <td class="icon"> <i class="fa fa-info-circle fa-2x" title="Note"></i> 
</td> 
+        <td class="content"> <strong>Maven Optimization Hint</strong> On a 
real project both server and client modules will likely share a common parent 
pom.xml where common repository delcaration can be placed, with child pom’s 
"inheriting" it from parent. This would reduce build code duplication. </td> 
+       </tr> 
+      </tbody>
+     </table> 
+    </div> 
+   </div> 
+   <div class="sect3"> 
+    <h4 id="client-classes-on-the-server"><a class="anchor" 
href="#client-classes-on-the-server"></a>Client Classes on the Server</h4> 
+    <div class="paragraph"> 
+     <p>Since ROP web service requires both server and client persistent 
classes, we need to generate a second copy of the client classes inside the 
server project. This is a minor inconvenience that will hopefully go away in 
the future versions of Cayenne. Don’t forget to refresh the project in 
Eclipse after class generation is done.</p> 
+    </div> 
+   </div> 
+   <div class="sect3"> 
+    <h4 id="configuring-web-xml"><a class="anchor" 
href="#configuring-web-xml"></a>Configuring web.xml</h4> 
+    <div class="paragraph"> 
+     <p>Cayenne web service is declared in the web.xml. It is implemented as a 
servlet "org.apache.cayenne.rop.ROPServlet". Open 
tutorial/src/main/webapp/WEB-INF/web.xml in Eclipse and add a service 
declaration:</p> 
+    </div> 
+    <div class="listingblock"> 
+     <div class="content"> 
+      <pre class="highlight"><code class="language-XML XML" 
data-lang="XML">&lt;?xml version="1.0" encoding="utf-8"?&gt;
+ &lt;!DOCTYPE web-app
+   PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
+   "http://java.sun.com/dtd/web-app_2_3.dtd"&gt;
+&lt;web-app&gt;
+    &lt;display-name&gt;Cayenne Tutorial&lt;/display-name&gt;
+    &lt;servlet&gt;
+        &lt;servlet-name&gt;cayenne-project&lt;/servlet-name&gt;
+        
&lt;servlet-class&gt;org.apache.cayenne.configuration.rop.server.ROPHessianServlet&lt;/servlet-class&gt;
+        &lt;load-on-startup&gt;0&lt;/load-on-startup&gt;
+    &lt;/servlet&gt;
+    &lt;servlet-mapping&gt;
+        &lt;servlet-name&gt;cayenne-project&lt;/servlet-name&gt;
+        &lt;url-pattern&gt;/cayenne-service&lt;/url-pattern&gt;
+    &lt;/servlet-mapping&gt;
+    &lt;/web-app&gt;</code></pre> 
+     </div> 
+    </div> 
+    <div class="admonitionblock note"> 
+     <table> 
+      <tbody>
+       <tr> 
+        <td class="icon"> <i class="fa fa-info-circle fa-2x" title="Note"></i> 
</td> 
+        <td class="content"> <strong>Extending Server Behavior via 
Callbacks</strong> While no custom Java code is required on the server, just a 
service declaration, it is possible to customizing server-side behavior via 
callbacks and listeners (not shown in the tutorial). </td> 
+       </tr> 
+      </tbody>
+     </table> 
+    </div> 
+   </div> 
+   <div class="sect3"> 
+    <h4 id="running-rop-server"><a class="anchor" 
href="#running-rop-server"></a>Running ROP Server</h4> 
+    <div class="paragraph"> 
+     <p>Use previosly created Eclipse Jetty run configuration available via 
"Run &gt; Run Configurations…​" (or create a new one if none exists yet). 
You should see output in the Eclipse console similar to the following:</p> 
+    </div> 
+    <div class="listingblock"> 
+     <div class="content"> 
+      <pre class="highlight"><code>[INFO] Scanning for projects...
+[INFO]
+[INFO] ------------------------------------------------------------------------
+[INFO] Building tutorial 0.0.1-SNAPSHOT
+[INFO] ------------------------------------------------------------------------
+...
+[INFO] Starting jetty 6.1.22 ...
+INFO::jetty-6.1.22
+INFO::No Transaction manager found - if your webapp requires one, please 
configure one.
+INFO::Started SelectChannelConnector@0.0.0.0:8080
+[INFO] Started Jetty Server
+INFO: Loading XML configuration resource from file:cayenne-project.xml
+INFO: loading user name and password.
+INFO: Created connection pool: jdbc:derby:memory:testdb;create=true
+    Driver class: org.apache.derby.jdbc.EmbeddedDriver
+    Min. connections in the pool: 1
+    Max. connections in the pool: 1</code></pre> 
+     </div> 
+    </div> 
+    <div class="paragraph"> 
+     <p>Cayenne ROP service URL is <a 
href="http://localhost:8080/tutorial/cayenne-service"; 
class="bare">http://localhost:8080/tutorial/cayenne-service</a>. If you click 
on it, you will see "Hessian Requires POST" message, that means that the 
service is alive, but you need a client other than the web browser to access 
it.</p> 
+    </div> 
+   </div> 
+  </div> 
+  <div class="sect2"> 
+   <h3 
id="porting-existing-code-to-connect-to-a-web-service-instead-of-a-database"><a 
class="anchor" 
href="#porting-existing-code-to-connect-to-a-web-service-instead-of-a-database"></a>2.3.
 Porting Existing Code to Connect to a Web Service Instead of a Database</h3> 
+   <div class="sect3"> 
+    <h4 id="starting-command-line-client"><a class="anchor" 
href="#starting-command-line-client"></a>Starting Command Line Client</h4> 
+    <div class="paragraph"> 
+     <p>One of the benefits of ROP is that the client code is no different 
from the server code - it uses the same ObjectContext interface for access, 
same query and commit API. So the code below will be similar to the code 
presented in the first Cayenne Getting Started Guide, although with a few 
ROP-specific parts required to bootstrap the ObjectContext.</p> 
+    </div> 
+    <div class="paragraph"> 
+     <p>Let’s start by creating an empty Main class with the standard main() 
method in the client project:</p> 
+    </div> 
+    <div class="listingblock"> 
+     <div class="content"> 
+      <pre class="highlight"><code class="language-java java" 
data-lang="java">package org.example.cayenne.persistent.client;
+
+public class Main {
+
+    public static void main(String[] args) {
+
+    }
+}</code></pre> 
+     </div> 
+    </div> 
+    <div class="paragraph"> 
+     <p>Now the part that is actually different from regular Cayenne - 
establishing the server connection and obtaining the ObjectContext:</p> 
+    </div> 
+    <div class="listingblock"> 
+     <div class="content"> 
+      <pre class="highlight"><code class="language-java java" 
data-lang="java">ClientConnection connection = new 
HessianConnection("http://localhost:8080/tutorial/cayenne-service";);
+DataChannel channel = new ClientChannel(connection, false, new 
DefaultEventManager(), false);
+ObjectContext context = new CayenneContext(channel);</code></pre> 
+     </div> 
+    </div> 
+    <div class="paragraph"> 
+     <p>Note that the "channel" can be used to create as many peer 
ObjectContexts as needed over the same connection, while ObjectContext is a 
kind of isolated "persistence session", similar to the server-side context. A 
few more notes. Since we are using HTTP(S) to communicate with ROP server, 
there’s no need to explicitly close the connection (or channel, or 
context).</p> 
+    </div> 
+    <div class="paragraph"> 
+     <p>So now let’s do the same persistent operaions that we did in the 
first tutorial "Main" class. Let’s start by creating and saving some 
objects:</p> 
+    </div> 
+    <div class="listingblock"> 
+     <div class="content"> 
+      <pre class="highlight"><code class="language-java java" 
data-lang="java">// creating new Artist
+Artist picasso = context.newObject(Artist.class);
+picasso.setName("Pablo Picasso");
+
+// Creating other objects
+Gallery metropolitan = context.newObject(Gallery.class);
+metropolitan.setName("Metropolitan Museum of Art");
+
+Painting girl = context.newObject(Painting.class);
+girl.setName("Girl Reading at a Table");
+
+Painting stein = context.newObject(Painting.class);
+stein.setName("Gertrude Stein");
+
+// connecting objects together via relationships
+picasso.addToPaintings(girl);
+picasso.addToPaintings(stein);
+
+girl.setGallery(metropolitan);
+stein.setGallery(metropolitan);
+
+// saving all the changes above
+context.commitChanges();</code></pre> 
+     </div> 
+    </div> 
+    <div class="paragraph"> 
+     <p>Now let’s select them back:</p> 
+    </div> 
+    <div class="listingblock"> 
+     <div class="content"> 
+      <pre class="highlight"><code class="language-java java" 
data-lang="java">// SelectQuery examples
+SelectQuery select1 = new SelectQuery(Painting.class);
+List&lt;Painting&gt; paintings1 = context.performQuery(select1);
+
+Expression qualifier2 = ExpressionFactory.likeIgnoreCaseExp(
+        Painting.NAME_PROPERTY, "gi%");
+SelectQuery select2 = new SelectQuery(Painting.class, qualifier2);
+List&lt;Painting&gt; paintings2 = context.performQuery(select2);</code></pre> 
+     </div> 
+    </div> 
+    <div class="paragraph"> 
+     <p>Now, delete:</p> 
+    </div> 
+    <div class="listingblock"> 
+     <div class="content"> 
+      <pre class="highlight"><code class="language-java java" 
data-lang="java">Expression qualifier = 
ExpressionFactory.matchExp(Artist.NAME_PROPERTY,
+                "Pablo Picasso");
+SelectQuery selectToDelete = new SelectQuery(Artist.class, qualifier);
+Artist picasso = (Artist) DataObjectUtils.objectForQuery(context,
+        selectToDelete);
+
+if (picasso != null) {
+    context.deleteObject(picasso);
+    context.commitChanges();
+}</code></pre> 
+     </div> 
+    </div> 
+    <div class="paragraph"> 
+     <p>This code is exactly the same as in the first tutorial. So now let’s 
try running the client and see what happens. In Eclipse open main class and 
select "Run &gt; Run As &gt; Java Application" from the menu (assuming the ROP 
server started in the previous step is still running). You will some output in 
both server and client process consoles. Client:</p> 
+    </div> 
+    <div class="listingblock"> 
+     <div class="content"> 
+      <pre class="highlight"><code>INFO: Connecting to 
[http://localhost:8080/tutorial/cayenne-service] - dedicated session.
+INFO: === Connected, session: 
org.apache.cayenne.remote.RemoteSession@26544ec1[sessionId=17uub1h34r9x1] - 
took 111 ms.
+INFO: --- Message 0: Bootstrap
+INFO: === Message 0: Bootstrap done - took 58 ms.
+INFO: --- Message 1: flush-cascade-sync
+INFO: === Message 1: flush-cascade-sync done - took 1119 ms.
+INFO: --- Message 2: Query
+INFO: === Message 2: Query done - took 48 ms.
+INFO: --- Message 3: Query
+INFO: === Message 3: Query done - took 63 ms.
+INFO: --- Message 4: Query
+INFO: === Message 4: Query done - took 19 ms.
+INFO: --- Message 5: Query
+INFO: === Message 5: Query done - took 7 ms.
+INFO: --- Message 6: Query
+INFO: === Message 6: Query done - took 5 ms.
+INFO: --- Message 7: Query
+INFO: === Message 7: Query done - took 2 ms.
+INFO: --- Message 8: Query
+INFO: === Message 8: Query done - took 4 ms.
+INFO: --- Message 9: flush-cascade-sync
+INFO: === Message 9: flush-cascade-sync done - took 34 ms.</code></pre> 
+     </div> 
+    </div> 
+    <div class="paragraph"> 
+     <p>As you see client prints no SQL statmenets, just a bunch of query and 
flush messages sent to the server. The server side is more verbose, showing the 
actual client queries executed against the database:</p> 
+    </div> 
+    <div class="listingblock"> 
+     <div class="content"> 
+      <pre class="highlight"><code>...
+INFO: SELECT NEXT_ID FROM AUTO_PK_SUPPORT WHERE TABLE_NAME = ? FOR UPDATE 
[bind: 1:'ARTIST']
+INFO: SELECT NEXT_ID FROM AUTO_PK_SUPPORT WHERE TABLE_NAME = ? FOR UPDATE 
[bind: 1:'GALLERY']
+INFO: SELECT NEXT_ID FROM AUTO_PK_SUPPORT WHERE TABLE_NAME = ? FOR UPDATE 
[bind: 1:'PAINTING']
+INFO: INSERT INTO ARTIST (DATE_OF_BIRTH, ID, NAME) VALUES (?, ?, ?)
+INFO: [batch bind: 1-&gt;DATE_OF_BIRTH:NULL, 2-&gt;ID:200, 3-&gt;NAME:'Pablo 
Picasso']
+INFO: === updated 1 row.
+INFO: INSERT INTO GALLERY (ID, NAME) VALUES (?, ?)
+INFO: [batch bind: 1-&gt;ID:200, 2-&gt;NAME:'Metropolitan Museum of Art']
+INFO: === updated 1 row.
+INFO: INSERT INTO PAINTING (ARTIST_ID, GALLERY_ID, ID, NAME) VALUES (?, ?, ?, 
?)
+INFO: [batch bind: 1-&gt;ARTIST_ID:200, 2-&gt;GALLERY_ID:200, 3-&gt;ID:200, 
4-&gt;NAME:'Girl Reading at a Table']
+INFO: [batch bind: 1-&gt;ARTIST_ID:200, 2-&gt;GALLERY_ID:200, 3-&gt;ID:201, 
4-&gt;NAME:'Gertrude Stein']
+INFO: === updated 2 rows.
+INFO: +++ transaction committed.
+INFO: --- transaction started.
+INFO: SELECT t0.GALLERY_ID, t0.NAME, t0.ARTIST_ID, t0.ID FROM PAINTING t0
+INFO: === returned 2 rows. - took 14 ms.
+INFO: +++ transaction committed.
+INFO: --- transaction started.
+INFO: SELECT t0.GALLERY_ID, t0.NAME, t0.ARTIST_ID, t0.ID FROM PAINTING t0
+      WHERE UPPER(t0.NAME) LIKE UPPER(?) [bind: 1-&gt;NAME:'gi%']
+INFO: === returned 1 row. - took 10 ms.
+INFO: +++ transaction committed.
+INFO: --- transaction started.
+INFO: SELECT t0.DATE_OF_BIRTH, t0.NAME, t0.ID FROM ARTIST t0 WHERE t0.NAME = ? 
[bind: 1-&gt;NAME:'Pablo Picasso']
+INFO: === returned 1 row. - took 8 ms.
+INFO: +++ transaction committed.
+INFO: --- transaction started.
+INFO: DELETE FROM PAINTING WHERE ID = ?
+INFO: [batch bind: 1-&gt;ID:200]
+INFO: [batch bind: 1-&gt;ID:201]
+INFO: === updated 2 rows.
+INFO: DELETE FROM ARTIST WHERE ID = ?
+INFO: [batch bind: 1-&gt;ID:200]
+INFO: === updated 1 row.
+INFO: +++ transaction committed.</code></pre> 
+     </div> 
+    </div> 
+    <div class="paragraph"> 
+     <p>You are done with the basic ROP client!</p> 
+    </div> 
+   </div> 
+  </div> 
+  <div class="sect2"> 
+   <h3 id="adding-basic-authentication"><a class="anchor" 
href="#adding-basic-authentication"></a>2.4. Adding BASIC Authentication</h3> 
+   <div class="paragraph"> 
+    <p>You probably don’t want everybody in the world to connect to your 
service and access (and update!) arbitrary data in the database. The first step 
in securing Cayenne service is implementing client authentication. The easiest 
way to do it is to delegate the authentication task to the web container that 
is running the service. HessianConnection used in the previous chapter supports 
BASIC authentication on the client side, so we’ll demonstrate how to set it 
up here.</p> 
+   </div> 
+   <div class="sect3"> 
+    <h4 id="securing-rop-server-application"><a class="anchor" 
href="#securing-rop-server-application"></a>Securing ROP Server 
Application</h4> 
+    <div class="paragraph"> 
+     <p>Open web.xml file in the server project and setup security constraints 
with BASIC authentication for the ROP service:</p> 
+    </div> 
+    <div class="listingblock"> 
+     <div class="content"> 
+      <pre class="highlight"><code class="language-XML XML" 
data-lang="XML">&lt;security-constraint&gt;
+    &lt;web-resource-collection&gt;
+        &lt;web-resource-name&gt;CayenneService&lt;/web-resource-name&gt;
+        &lt;url-pattern&gt;/cayenne-service&lt;/url-pattern&gt;
+    &lt;/web-resource-collection&gt;
+    &lt;auth-constraint&gt;
+        &lt;role-name&gt;cayenne-service-user&lt;/role-name&gt;
+    &lt;/auth-constraint&gt;
+&lt;/security-constraint&gt;
+
+&lt;login-config&gt;
+    &lt;auth-method&gt;BASIC&lt;/auth-method&gt;
+    &lt;realm-name&gt;Cayenne Realm&lt;/realm-name&gt;
+&lt;/login-config&gt;
+
+&lt;security-role&gt;
+    &lt;role-name&gt;cayenne-service-user&lt;/role-name&gt;
+&lt;/security-role&gt;</code></pre> 
+     </div> 
+    </div> 
+   </div> 
+   <div class="sect3"> 
+    <h4 id="configuring-jetty-for-basic-authentication"><a class="anchor" 
href="#configuring-jetty-for-basic-authentication"></a>Configuring Jetty for 
BASIC Authentication</h4> 
+    <div class="admonitionblock note"> 
+     <table> 
+      <tbody>
+       <tr> 
+        <td class="icon"> <i class="fa fa-info-circle fa-2x" title="Note"></i> 
</td> 
+        <td class="content"> These instructions are specific to Jetty 6. Other 
containers (and versions of Jetty) will have different mechansims to achieve 
the same thing. </td> 
+       </tr> 
+      </tbody>
+     </table> 
+    </div> 
+    <div class="paragraph"> 
+     <p>Open pom.xml in the server project and configure a "userRealm" for the 
Jetty plugin:</p> 
+    </div> 
+    <div class="listingblock"> 
+     <div class="content"> 
+      <pre class="highlight"><code class="language-XML XML" 
data-lang="XML">&lt;plugin&gt;
+    &lt;groupId&gt;org.mortbay.jetty&lt;/groupId&gt;
+        &lt;artifactId&gt;maven-jetty-plugin&lt;/artifactId&gt;
+        &lt;version&gt;6.1.22&lt;/version&gt;
+        &lt;!-- adding configuration below: --&gt;
+        &lt;configuration&gt;
+            &lt;userRealms&gt;
+                &lt;userRealm 
implementation="org.mortbay.jetty.security.HashUserRealm"&gt;
+                    &lt;!-- this name must match the realm-name in web.xml 
--&gt;
+                    &lt;name&gt;Cayenne Realm&lt;/name&gt;
+                    &lt;config&gt;realm.properties&lt;/config&gt;
+                &lt;/userRealm&gt;
+            &lt;/userRealms&gt;
+        &lt;/configuration&gt;
+    &lt;/plugin&gt;
+&lt;/plugins&gt;</code></pre> 
+     </div> 
+    </div> 
+    <div class="paragraph"> 
+     <p>Now create a new file called {["realm.properties"}} at the root of the 
server project and put user login/password in there:</p> 
+    </div> 
+    <div class="listingblock"> 
+     <div class="content"> 
+      <pre class="highlight"><code>cayenne-user: 
secret,cayenne-service-user</code></pre> 
+     </div> 
+    </div> 
+    <div class="paragraph"> 
+     <p>Now let’s stop the server and start it again. Everything should 
start as before, but if you go to <a 
href="http://localhost:8080/tutorial/cayenne-service"; 
class="bare">http://localhost:8080/tutorial/cayenne-service</a>, your browser 
should pop up authentication dialog. Enter "cayenne-user/secret" for user name 
/ password, and you should see "Hessian Requires POST" message. So the server 
is now secured.</p> 
+    </div> 
+   </div> 
+   <div class="sect3"> 
+    <h4 id="running-client-with-basic-authentication"><a class="anchor" 
href="#running-client-with-basic-authentication"></a>Running Client with Basic 
Authentication</h4> 
+    <div class="paragraph"> 
+     <p>If you run the client without any changes, you’ll get the following 
error:</p> 
+    </div> 
+    <div class="listingblock"> 
+     <div class="content"> 
+      <pre 
class="highlight"><code>org.apache.cayenne.remote.hessian.HessianConnection 
connect
+INFO: Connecting to [http://localhost:8080/tutorial/cayenne-service] - 
dedicated session.
+org.apache.cayenne.remote.hessian.HessianConnection connect
+INFO: Error establishing remote session. URL - 
http://localhost:8080/tutorial/cayenne-service;
+      CAUSE - cannot retry due to server authentication, in streaming mode
+java.net.HttpRetryException: cannot retry due to server authentication, in 
streaming mode
+    at 
sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1257)
+    at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:379)
+    at com.caucho.hessian.client.HessianProxy.invoke(HessianProxy.java:168)
+    at $Proxy0.establishSession(Unknown Source)
+    at 
org.apache.cayenne.remote.hessian.HessianConnection.connect(HessianConnection.java:210)
+    at 
org.apache.cayenne.remote.hessian.HessianConnection.getServerEventBridge(HessianConnection.java:114)
+    at 
org.apache.cayenne.remote.ClientChannel.setupRemoteChannelListener(ClientChannel.java:337)
+    at 
org.apache.cayenne.remote.ClientChannel.&lt;init&gt;(ClientChannel.java:108)
+    at org.example.cayenne.Main.main(Main.java:25)
+Exception in thread "main" org.apache.cayenne.CayenneRuntimeException: 
[v.3.1M3 Sep 19 2011 07:12:41]
+Error establishing remote session. URL - 
http://localhost:8080/tutorial/cayenne-service;
+CAUSE - cannot retry due to server authentication, in streaming mode
+    at 
org.apache.cayenne.remote.hessian.HessianConnection.connect(HessianConnection.java:229)
+    at 
org.apache.cayenne.remote.hessian.HessianConnection.getServerEventBridge(HessianConnection.java:114)
+    at 
org.apache.cayenne.remote.ClientChannel.setupRemoteChannelListener(ClientChannel.java:337)
+    at 
org.apache.cayenne.remote.ClientChannel.&lt;init&gt;(ClientChannel.java:108)
+    at org.example.cayenne.Main.main(Main.java:25)
+Caused by: java.net.HttpRetryException: cannot retry due to server 
authentication, in streaming mode
+    at 
sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1257)
+    at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:379)
+    at com.caucho.hessian.client.HessianProxy.invoke(HessianProxy.java:168)
+    at $Proxy0.establishSession(Unknown Source)
+    at 
org.apache.cayenne.remote.hessian.HessianConnection.connect(HessianConnection.java:210)
+    ... 4 more</code></pre> 
+     </div> 
+    </div> 
+    <div class="paragraph"> 
+     <p>Which is exactly what you’d expect, as the client is not 
authenticating itself. So change the line in Main.java where we obtained an ROP 
connection to this:</p> 
+    </div> 
+    <div class="listingblock"> 
+     <div class="content"> 
+      <pre class="highlight"><code class="language-java java" 
data-lang="java">ClientConnection connection = new HessianConnection(
+        "http://localhost:8080/tutorial/cayenne-service";,
+        "cayenne-user", "secret", null);</code></pre> 
+     </div> 
+    </div> 
+    <div class="paragraph"> 
+     <p>Try running again, and everything should work as before. Obviously in 
production environment, in addition to authentication you’ll need to use 
HTTPS to access the server to prevent third-party eavesdropping on your 
password and data.</p> 
+    </div> 
+    <div class="paragraph"> 
+     <p>Congratulations, you are done with the ROP tutorial!</p> 
+    </div> 
+   </div> 
+  </div> 
+ </div> 
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne-website/blob/b81e46fb/src/main/site/content/docs/3.1/getting-started-rop.toc.html
----------------------------------------------------------------------
diff --git a/src/main/site/content/docs/3.1/getting-started-rop.toc.html 
b/src/main/site/content/docs/3.1/getting-started-rop.toc.html
new file mode 100644
index 0000000..4f76447
--- /dev/null
+++ b/src/main/site/content/docs/3.1/getting-started-rop.toc.html
@@ -0,0 +1,18 @@
+<div id="toc" class="toc toc-side"> 
+ <div id="toctitle">
+  Table of Contents
+ </div> 
+ <ul class="sectlevel1 nav"> 
+  <li><a href="#prerequisites" class="nav-link">1. Prerequisites</a> 
+   <ul class="sectlevel2 nav"> 
+    <li><a href="#prerequisites-2" class="nav-link">1.1. 
Prerequisites</a></li> 
+   </ul> </li> 
+  <li><a href="#remote-object-persistence-quick-start" class="nav-link">2. 
Remote Object Persistence Quick Start</a> 
+   <ul class="sectlevel2 nav"> 
+    <li><a href="#starting-client-project" class="nav-link">2.1. Starting 
Client Project</a></li> 
+    <li><a href="#setting-up-hessian-web-service" class="nav-link">2.2. 
Setting up Hessian Web Service</a></li> 
+    <li><a 
href="#porting-existing-code-to-connect-to-a-web-service-instead-of-a-database" 
class="nav-link">2.3. Porting Existing Code to Connect to a Web Service Instead 
of a Database</a></li> 
+    <li><a href="#adding-basic-authentication" class="nav-link">2.4. Adding 
BASIC Authentication</a></li> 
+   </ul> </li> 
+ </ul> 
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne-website/blob/b81e46fb/src/main/site/content/docs/3.1/getting-started-rop/images/datamap-enableclient.png
----------------------------------------------------------------------
diff --git 
a/src/main/site/content/docs/3.1/getting-started-rop/images/datamap-enableclient.png
 
b/src/main/site/content/docs/3.1/getting-started-rop/images/datamap-enableclient.png
new file mode 100644
index 0000000..62a2af2
Binary files /dev/null and 
b/src/main/site/content/docs/3.1/getting-started-rop/images/datamap-enableclient.png
 differ

http://git-wip-us.apache.org/repos/asf/cayenne-website/blob/b81e46fb/src/main/site/content/docs/3.1/upgrade-guide.html
----------------------------------------------------------------------
diff --git a/src/main/site/content/docs/3.1/upgrade-guide.html 
b/src/main/site/content/docs/3.1/upgrade-guide.html
new file mode 100644
index 0000000..193ac6b
--- /dev/null
+++ b/src/main/site/content/docs/3.1/upgrade-guide.html
@@ -0,0 +1,180 @@
+---
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you 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.
+
+title: "Guide to 3.1 Features"
+description: "This guide highlights the new features and changes introduced in 
Apache Cayenne 3.1"
+cayenneVersion: "3.1"
+docsMenuTitle: "Upgrade Guide"
+weight: 50
+---
+<div class="sect1"> 
+ <h2 id="guide-to-3-1-features"><a class="anchor" 
href="#guide-to-3-1-features"></a>1. Guide to 3.1 Features</h2> 
+ <div class="sectionbody"> 
+  <div class="paragraph"> 
+   <p>This guide highlights the new features and changes introduced in 3.1 
release. It is a high-level overview. For more details consult 
<strong>RELEASE-NOTES.txt</strong> file included in each release for the full 
list of changes, and UPGRADE.txt for the release-specific upgrade 
instructions.</p> 
+  </div> 
+  <div class="sect2"> 
+   <h3 id="distribution-contents-structure"><a class="anchor" 
href="#distribution-contents-structure"></a>1.1. Distribution Contents 
Structure</h3> 
+   <div class="paragraph"> 
+    <p>Cayenne distribution is made leaner and more modular:</p> 
+   </div> 
+   <div class="ulist"> 
+    <ul> 
+     <li> <p>"cayenne-modeler.jar" is no longer included in the "lib" folder, 
as it is no longer used for loading local JNDI overrides. Of course 
"CayenneModeler-the-app" is still included.</p> </li> 
+     <li> <p>Ashwood library used for commit operation sorting is no longer a 
third-party dependency. Instead a small subset of the relevant Ashwood classes 
got included in Cayenne core.</p> </li> 
+     <li> <p>The following helper modules are split away from Cayenne core: 
"cayenne-project" and "cayenne-wocompat". They are bundled in CayenneModeler, 
and are available from the source distribution. They are not included as 
standalone jars in the binary distribution.</p> </li> 
+    </ul> 
+   </div> 
+  </div> 
+  <div class="sect2"> 
+   <h3 id="cayenne-configuration"><a class="anchor" 
href="#cayenne-configuration"></a>1.2. Cayenne Configuration</h3> 
+   <div class="admonitionblock note"> 
+    <table> 
+     <tbody>
+      <tr> 
+       <td class="icon"> <i class="fa fa-info-circle fa-2x" title="Note"></i> 
</td> 
+       <td class="content"> The new DI-based bootstrap and configuration 
approach is not API-compatible with earlier versions of Cayenne. Make sure you 
read the <code>UPGRADE.txt</code> file for instructions how to upgrade the 
existing projects. </td> 
+      </tr> 
+     </tbody>
+    </table> 
+   </div> 
+   <div class="sect3"> 
+    <h4 id="dependency-injection-container"><a class="anchor" 
href="#dependency-injection-container"></a>Dependency Injection Container</h4> 
+    <div class="paragraph"> 
+     <p>Cayenne 3.1 runtime stack is built around the ideas of Dependency 
Injection (DI), making it extremely flexible and easy to extend. It bundles a 
small, flexible annotations-based DI container to configure its services. The 
container provides DI services and exposes Cayenne extension points, but does 
not interfere with other DI containers that may be present in the application. 
I.e. it is invisible to the users who do not care about advanced Cayenne 
customization.</p> 
+    </div> 
+   </div> 
+   <div class="sect3"> 
+    <h4 id="bootstrapping-cayenne-in-various-environments"><a class="anchor" 
href="#bootstrapping-cayenne-in-various-environments"></a>Bootstrapping Cayenne 
in Various Environments</h4> 
+    <div class="paragraph"> 
+     <p>Here is a simple example of starting a server-side Cayenne stack:</p> 
+    </div> 
+    <div class="listingblock"> 
+     <div class="content"> 
+      <pre class="highlight"><code class="language-java java" 
data-lang="java">ServerRuntime runtime = new 
ServerRuntime("cayenne-UntitledDomain.xml");</code></pre> 
+     </div> 
+    </div> 
+    <div class="paragraph"> 
+     <p>For more detailed examples check the tutorials and other 
documentation.</p> 
+    </div> 
+   </div> 
+   <div class="sect3"> 
+    <h4 id="configuring-local-datasources-removal-of-jndi-hack"><a 
class="anchor" 
href="#configuring-local-datasources-removal-of-jndi-hack"></a>Configuring 
Local DataSources, Removal of JNDI Hack</h4> 
+    <div class="paragraph"> 
+     <p>Cayenne 3.1 provides a property-based mechanism to override Modeler 
DataSource definitions, regardless of whether they are driver configurations, 
JNDI, DBCP, etc. A quick configuration example is shown below:</p> 
+    </div> 
+    <div class="listingblock"> 
+     <div class="content"> 
+      <pre class="highlight"><code>-Dcayenne.jdbc.driver=com.mysql.jdbc.Driver 
-Dcayenne.jdbc.url=jdbc:mysql://localhost/mydb \
+-Dcayenne.jdbc.username=user -Dcayenne.jdbc.password=password</code></pre> 
+     </div> 
+    </div> 
+    <div class="paragraph"> 
+     <p>For more details and configuration options see javadocs of 
<code>org.apache.cayenne.configuration.server.PropertyDataSourceFactory</code>.</p>
 
+    </div> 
+    <div class="paragraph"> 
+     <p>This feature supersedes what was formerly known as "JNDI hack", i.e. 
JNDI DataSource failover load strategy based on CayenneModeler preferences 
database. The problem with JNDI hack was unstable and frequently corrupted 
preferences database, and the need to include hsqldb and cayenne-modeler jars 
in the runtime.</p> 
+    </div> 
+   </div> 
+  </div> 
+  <div class="sect2"> 
+   <h3 id="framework-api"><a class="anchor" href="#framework-api"></a>1.3. 
Framework API</h3> 
+   <div class="paragraph"> 
+    <p>See UPGRADE.txt for the full list of changes</p> 
+   </div> 
+   <div class="sect3"> 
+    <h4 id="lifecycle-listener-annotations"><a class="anchor" 
href="#lifecycle-listener-annotations"></a>Lifecycle Listener Annotations</h4> 
+    <div class="paragraph"> 
+     <p>Cayenne 3.1 features support for annotations on lifecycle listeners 
(but not yet on entity callback methods) that simplifies registering listeners 
via API. Our experience with Cayenne 3.0 shows that mapping listeners in the 
Modeler doesn’t scale well to complex applications, and 3.0 API for mapping 
the listeners is hard to use. In 3.1 you can annotate listener methods and 
register multiple callback methods with a single call.</p> 
+    </div> 
+    <div class="listingblock"> 
+     <div class="content"> 
+      <pre class="highlight"><code class="language-java java" 
data-lang="java">// declare a listener with annotated methods
+class MyListener {
+    @PostLoad(Entity1.class)
+    @PostPersist(Entity1.class)
+    void postLoad(Object object) {
+        ....
+    }
+}
+
+// register a listener
+ServerRuntime runtime = ..
+MyListener listener = new MyListener();
+runtime.getChannel().getEntityResolver().getCallbackRegistry().addListener(listener);</code></pre>
 
+     </div> 
+    </div> 
+    <div class="paragraph"> 
+     <p>Moreover, unlike JPA annotations, Cayenne allows to attach a listener 
to a set of entities not known to the listener upfront, but that are all 
annotated with some custom annotation:</p> 
+    </div> 
+    <div class="listingblock"> 
+     <div class="content"> 
+      <pre class="highlight"><code class="language-java java" 
data-lang="java">class MyListener {
+    @PostLoad(entityAnnotations = CustomAnnotation.class)
+    void postLoad(Object object) {
+        ....
+    }
+}</code></pre> 
+     </div> 
+    </div> 
+   </div> 
+   <div class="sect3"> 
+    <h4 id="datachannelfilter-for-intercepting-datadomain-operations"><a 
class="anchor" 
href="#datachannelfilter-for-intercepting-datadomain-operations"></a>DataChannelFilter
 for Intercepting DataDomain Operations</h4> 
+    <div class="paragraph"> 
+     <p>Cayenne now features a DataChannelFilter interface that allows to 
intercept and alter all DataChannel traffic (i.e. selects and commits between a 
DataContext and DataDomain). It provides a chain of command API very similar to 
servlet filters. Filters are widely used by "cayenne-lifecyle" extensions and 
allow to build powerful custom object lifecycle-aware code. To install a 
filter, the following API is used:</p> 
+    </div> 
+    <div class="listingblock"> 
+     <div class="content"> 
+      <pre class="highlight"><code class="language-java java" 
data-lang="java">class MyFilter implement DataChannelFilter { .. }
+
+MyFilter filter = new MyFilter();
+ServerRuntime runtime = ..
+runtime.getDataDomain().addFilter(filter);</code></pre> 
+     </div> 
+    </div> 
+    <div class="paragraph"> 
+     <p>Very often filters mark some of their own methods with lifecycle 
annotations so that certain operations can be triggered by Cayenne inside the 
scope of filter’s onQuery() or onSync() methods. To ensure annotated methods 
are invoked, filter registration should be combined with listener 
registration:</p> 
+    </div> 
+    <div class="listingblock"> 
+     <div class="content"> 
+      <pre class="highlight"><code class="language-java java" 
data-lang="java">MyFilter filter = new MyFilter();
+ServerRuntime runtime = ..
+runtime.getDataDomain().addFilter(filter);
+runtime.getDataDomain().getEntityResolver().getCallbackRegistry().addListener(filter);
+// noticed that by default runtime.getDataDomain() is equivalent to 
runtime.getChannel()</code></pre> 
+     </div> 
+    </div> 
+   </div> 
+  </div> 
+  <div class="sect2"> 
+   <h3 id="cayennemodeler"><a class="anchor" href="#cayennemodeler"></a>1.4. 
CayenneModeler</h3> 
+   <div class="sect3"> 
+    <h4 id="java-preferences-api"><a class="anchor" 
href="#java-preferences-api"></a>Java Preferences API</h4> 
+    <div class="paragraph"> 
+     <p>We got rid of HSQLDB-based preferences storage, and are using standard 
Java Preferences API for the Modeler preferences. This solved a long-standing 
stability issue with Modeler preferences. So no more lost user preferences.</p> 
+    </div> 
+   </div> 
+  </div> 
+  <div class="sect2"> 
+   <h3 id="lifecycle-extensions"><a class="anchor" 
href="#lifecycle-extensions"></a>1.5. Lifecycle Extensions</h3> 
+   <div class="paragraph"> 
+    <p>Cayenne 3.1 includes an optional cayenne-lifecyle module that 
implements a few useful extensions based on DataChannelFilters and lifecycle 
annotations. Those include a concept of a String ID (which is a String 
URL-friendly representation of ObjectId), support for (de)referencing objects 
by String ID, String ID-based relationships, annotation-based cache groups 
invalidation, annotation-based audit of object changes, etc.</p> 
+   </div> 
+  </div> 
+ </div> 
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne-website/blob/b81e46fb/src/main/site/content/docs/3.1/upgrade-guide.toc.html
----------------------------------------------------------------------
diff --git a/src/main/site/content/docs/3.1/upgrade-guide.toc.html 
b/src/main/site/content/docs/3.1/upgrade-guide.toc.html
new file mode 100644
index 0000000..a7fe2ae
--- /dev/null
+++ b/src/main/site/content/docs/3.1/upgrade-guide.toc.html
@@ -0,0 +1,15 @@
+<div id="toc" class="toc toc-side"> 
+ <div id="toctitle">
+  Table of Contents
+ </div> 
+ <ul class="sectlevel1 nav"> 
+  <li><a href="#guide-to-3-1-features" class="nav-link">1. Guide to 3.1 
Features</a> 
+   <ul class="sectlevel2 nav"> 
+    <li><a href="#distribution-contents-structure" class="nav-link">1.1. 
Distribution Contents Structure</a></li> 
+    <li><a href="#cayenne-configuration" class="nav-link">1.2. Cayenne 
Configuration</a></li> 
+    <li><a href="#framework-api" class="nav-link">1.3. Framework API</a></li> 
+    <li><a href="#cayennemodeler" class="nav-link">1.4. 
CayenneModeler</a></li> 
+    <li><a href="#lifecycle-extensions" class="nav-link">1.5. Lifecycle 
Extensions</a></li> 
+   </ul> </li> 
+ </ul> 
+</div>
\ No newline at end of file

Reply via email to