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 > New > Otherâ¦â" and then "Maven > 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 > 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 > 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"><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"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.example.cayenne</groupId> + <artifactId>tutorial-rop-client</artifactId> + <version>0.0.1-SNAPSHOT</version> + + <dependencies> + <dependency> + <groupId>org.apache.cayenne</groupId> + <artifactId>cayenne-client</artifactId> + <!-- Here specify the version of Cayenne you are actually using --> + <version>3.1.3-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>com.caucho</groupId> + <artifactId>resin-hessian</artifactId> + <version>3.1.6</version> + </dependency> + </dependencies> + + <repositories> + <repository> + <id>caucho</id> + <name>Caucho Repository</name> + <url>http://caucho.com/m2</url> + <layout>default</layout> + <snapshots> + <enabled>false</enabled> + </snapshots> + <releases> + <enabled>true</enabled> + </releases> + </repository> + </repositories> +</project></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"><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"> + ... + <dependencies> + ... + <dependency> + <groupId>com.caucho</groupId> + <artifactId>resin-hessian</artifactId> + <version>3.1.6</version> + </dependency> + </dependencies> + + <build> + ... + </build> + + <repositories> + <repository> + <id>caucho</id> + <name>Caucho Repository</name> + <url>http://caucho.com/m2</url> + <layout>default</layout> + <snapshots> + <enabled>false</enabled> + </snapshots> + <releases> + <enabled>true</enabled> + </releases> + </repository> + </repositories> + </project></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"><?xml version="1.0" encoding="utf-8"?> + <!DOCTYPE web-app + PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" + "http://java.sun.com/dtd/web-app_2_3.dtd"> +<web-app> + <display-name>Cayenne Tutorial</display-name> + <servlet> + <servlet-name>cayenne-project</servlet-name> + <servlet-class>org.apache.cayenne.configuration.rop.server.ROPHessianServlet</servlet-class> + <load-on-startup>0</load-on-startup> + </servlet> + <servlet-mapping> + <servlet-name>cayenne-project</servlet-name> + <url-pattern>/cayenne-service</url-pattern> + </servlet-mapping> + </web-app></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 > 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<Painting> paintings1 = context.performQuery(select1); + +Expression qualifier2 = ExpressionFactory.likeIgnoreCaseExp( + Painting.NAME_PROPERTY, "gi%"); +SelectQuery select2 = new SelectQuery(Painting.class, qualifier2); +List<Painting> 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 > Run As > 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->DATE_OF_BIRTH:NULL, 2->ID:200, 3->NAME:'Pablo Picasso'] +INFO: === updated 1 row. +INFO: INSERT INTO GALLERY (ID, NAME) VALUES (?, ?) +INFO: [batch bind: 1->ID:200, 2->NAME:'Metropolitan Museum of Art'] +INFO: === updated 1 row. +INFO: INSERT INTO PAINTING (ARTIST_ID, GALLERY_ID, ID, NAME) VALUES (?, ?, ?, ?) +INFO: [batch bind: 1->ARTIST_ID:200, 2->GALLERY_ID:200, 3->ID:200, 4->NAME:'Girl Reading at a Table'] +INFO: [batch bind: 1->ARTIST_ID:200, 2->GALLERY_ID:200, 3->ID:201, 4->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->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->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->ID:200] +INFO: [batch bind: 1->ID:201] +INFO: === updated 2 rows. +INFO: DELETE FROM ARTIST WHERE ID = ? +INFO: [batch bind: 1->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"><security-constraint> + <web-resource-collection> + <web-resource-name>CayenneService</web-resource-name> + <url-pattern>/cayenne-service</url-pattern> + </web-resource-collection> + <auth-constraint> + <role-name>cayenne-service-user</role-name> + </auth-constraint> +</security-constraint> + +<login-config> + <auth-method>BASIC</auth-method> + <realm-name>Cayenne Realm</realm-name> +</login-config> + +<security-role> + <role-name>cayenne-service-user</role-name> +</security-role></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"><plugin> + <groupId>org.mortbay.jetty</groupId> + <artifactId>maven-jetty-plugin</artifactId> + <version>6.1.22</version> + <!-- adding configuration below: --> + <configuration> + <userRealms> + <userRealm implementation="org.mortbay.jetty.security.HashUserRealm"> + <!-- this name must match the realm-name in web.xml --> + <name>Cayenne Realm</name> + <config>realm.properties</config> + </userRealm> + </userRealms> + </configuration> + </plugin> +</plugins></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.<init>(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.<init>(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