cayenne-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ntimof...@apache.org
Subject [09/11] cayenne git commit: CAY-2371 Switch documentation from Docbook to Asciidoctor format
Date Fri, 05 Jan 2018 14:21:37 GMT
http://git-wip-us.apache.org/repos/asf/cayenne/blob/7783cd34/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/queries.adoc
----------------------------------------------------------------------
diff --git a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/queries.adoc b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/queries.adoc
new file mode 100644
index 0000000..f146ba2
--- /dev/null
+++ b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/queries.adoc
@@ -0,0 +1,691 @@
+// 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.
+
+=== Queries
+
+Queries are Java objects used by the application to communicate with the database. Cayenne knows how to translate queries into SQL statements appropriate for a particular database engine. Most often queries are used to find objects matching certain criteria, but there are other types of queries too. E.g. those allowing to run native SQL, call DB stored procedures, etc. When committing objects, Cayenne itself creates special queries to insert/update/delete rows in the database.
+
+There is a number of built-in queries in Cayenne, described later in this chapter. Most of the newer queries use fluent API and can be created and executed as easy-to-read one-liners. Users can define their own query types to abstract certain DB interactions that for whatever reason can not be adequately described by the built-in set.
+
+Queries can be roughly categorized as "object" and "native". Object queries (most notably ObjectSelect, SelectById, and EJBQLQuery) are built with abstractions originating in the object model (the "object" side in the "object-relational" divide). E.g. ObjectSelect is assembled from a Java class of the objects to fetch, a qualifier expression, orderings, etc. - all of this expressed in terms of the object model.
+
+Native queries describe a desired DB operation as SQL code (SQLSelect, SQLTemplate query) or a reference to a stored procedure (ProcedureQuery), etc. The results of native queries are usually presented as Lists of Maps, with each map representing a row in the DB (a term "data row" is often used to describe such a map). They can potentially be converted to objects, however it may take a considerable effort to do so. Native queries are also less (if at all) portable across databases than object queries.
+[[select]]
+==== SelectQuery
+
+SelectQuery is the most commonly used query in user applications. This may be the only query you will need in most appplications. It returns a list of persistent objects of a certain type specified in the query:
+
+[source, java]
+----
+SelectQuery query = new SelectQuery(Artist.class);
+List<Artist> objects = context.performQuery(query);
+----
+
+This returned all rows in the "ARTIST" table. If the logs were turned on, you might see the following SQL printed:
+
+----
+INFO: SELECT t0.DATE_OF_BIRTH, t0.NAME, t0.ID FROM ARTIST t0
+INFO: === returned 5 row. - took 5 ms.
+----
+
+This SQL was generated by Cayenne from the SelectQuery above. SelectQuery can have a qualifier to select only the data that you care about. Qualifier is simply an Expression (Expressions where discussed in the previous chapter). If you only want artists whose name begins with 'Pablo', you might use the following qualifier expression:
+
+[source, java]
+----
+SelectQuery query = new SelectQuery(Artist.class,
+        ExpressionFactory.likeExp(Artist.NAME_PROPERTY, "Pablo%"));
+List<Artist> objects = context.performQuery(query);
+----
+
+The SQL will look different this time:
+
+----
+INFO: SELECT t0.DATE_OF_BIRTH, t0.NAME, t0.ID FROM ARTIST t0 WHERE t0.NAME LIKE ?
+[bind: 1->NAME:'Pablo%']
+INFO: === returned 1 row. - took 6 ms.
+----
+
+SelectQuery allows to append parts of qualifier to self:
+
+[source, java]
+----
+SelectQuery query = new SelectQuery(Artist.class);
+query.setQualifier(ExpressionFactory.likeExp(Artist.NAME_PROPERTY, "A%"));
+query.andQualifier(ExpressionFactory.greaterExp(Artist.DATE_OF_BIRTH_PROPERTY, someDate));
+----
+
+To order the results of SelectQuery, one or more Orderings can be applied. Ordering were already discussed earlier. E.g.:
+
+[source, java]
+----
+SelectQuery query = new SelectQuery(Artist.class);
+
+// create Ordering object explicitly
+query.addOrdering(new Ordering(Artist.DATE_OF_BIRTH_PROPERTY, SortOrder.DESCENDING));
+
+// or let SelectQuery create it behind the scenes
+query.addOrdering(Artist.NAME_PROPERTY, SortOrder.ASCENDING);
+----
+
+There's a number of other useful properties in SelectQuery that define what to select and how to optimize database interaction (prefetching, caching, fetch offset and limit, pagination, etc.). Some of them are discussed in separate chapters on caching and performance optimization. Others are fairly self-explanatory. Please check the API docs for the full extent of the SelectQuery features.
+
+[[ejbql]]
+==== EJBQLQuery
+
+EJBQLQuery was created as a part of an experiment in adopting some of Java Persistence API (JPA) approaches in Cayenne. It is a parameterized object query that is created from query String. A String used to build EJBQLQuery must conform to JPQL (JPA query language):
+
+
+[source, java]
+----
+EJBQLQuery query = new EJBQLQuery("select a FROM Artist a");
+----
+
+JPQL details can be found in any JPA manual. Here we'll mention only how this fits into Cayenne and what are the differences between EJBQL and other Cayenne queries.
+
+Although most frequently EJBQLQuery is used as an alternative to SelectQuery, there are also DELETE and UPDATE varieties available.
+
+NOTE: As of this version of Cayenne, DELETE and UPDATE do not change the state of objects in the ObjectContext. They are run directly against the database instead.
+
+
+[source, java]
+----
+EJBQLQuery select = new EJBQLQuery("select a FROM Artist a WHERE a.name = 'Salvador Dali'");
+List<Artist> artists = context.performQuery(select);
+----
+
+[source, java]
+----
+EJBQLQuery delete = new EJBQLQuery("delete from Painting");
+context.performGenericQuery(delete);
+----
+
+[source, java]
+----
+EJBQLQuery update = new EJBQLQuery("UPDATE Painting AS p SET p.name = 'P2' WHERE p.name = 'P1'");
+context.performGenericQuery(update);
+----
+
+
+In most cases SelectQuery is preferred to EJBQLQuery, as it is API-based, and provides you with better compile-time checks. However sometimes you may want a completely scriptable object query. This is when you might prefer EJBQL. A more practical reason for picking EJBQL over SelectQuery though is that the former offers some extra selecting capabilities, namely aggregate functions and subqueries:
+
+[source, java]
+----
+EJBQLQuery query = new EJBQLQuery("select a, COUNT(p) FROM Artist a JOIN a.paintings p GROUP BY a");
+List<Object[]> result = context.performQuery(query);
+for(Object[] artistWithCount : result) {
+    Artist a = (Artist) artistWithCount[0];
+    int hasPaintings = (Integer) artistWithCount[1];
+}
+----
+
+This also demonstrates a previously unseen type of select result - a List of Object[] elements, where each entry in an Object[] is either a DataObject or a scalar, depending on the query SELECT clause. A result can also be a list of scalars:
+
+[source, java]
+----
+EJBQLQuery query = new EJBQLQuery("select a.name FROM Artist a");
+List<String> names = context.performQuery(query);
+----
+
+While Cayenne Expressions discussed previously can be thought of as identical to JPQL WHERE clause, and indeed they are very close, there are a few noteable differences:
+
+- Null handling: SelectQuery would translate the expressions matching NULL values to the corresponding "X IS NULL" or "X IS NOT NULL" SQL syntax. EJBQLQuery on the other hand requires explicit "IS NULL" (or "IS NOT NULL") syntax to be used, otherwise the generated SQL will look like "X = NULL" (or "X <> NULL"), which will evaluate differently.
+
+- Expression Parameters: SelectQuery uses "$" to denote named parameters (e.g. "$myParam"), while EJBQL uses ":" (e.g. ":myParam"). Also EJBQL supports positional parameters denoted by the question mark: "?3".
+
+[[sqltemplate]]
+==== SQLTemplate
+SQLTemplate is a query that allows to run native SQL from a Cayenne application. It comes handy when the standard ORM concepts are not sufficient for a given query or an update. SQL is too powerful and allows to manipulate data in ways that are not easily described as a graph of related entities. Cayenne acknowledges this fact and provides this facility to execute SQL, mapping the result to objects when possible. Here are examples of selecting and non-selecting SQLTemplates:
+
+
+[source, java]
+----
+SQLTemplate select = new SQLTemplate(Artist.class, "select * from ARTIST");
+List<Artist> result = context.performQuery(select);
+----
+
+[source, java]
+----
+SQLTemplate update = new SQLTemplate(Artist.class, "delete from ARTIST");
+QueryResponse response = context.performGenericQuery(update);
+----
+
+Cayenne doesn't make any attempt to make sense of the SQL semantics, so it doesn't know whether a given query is performing a select or update, etc. It is the the user's decision to run a given query as a selecting or "generic".
+
+NOTE: Any data modifications done to DB as a result of SQLTemplate execution do not change the state of objects in the ObjectContext. So some objects in the context may become stale as a result.
+
+Another point to note is that the first argument to the SQLTemplate constructor - the Java class - has the same meaning as in SelectQuery only when the result can be converted to objects (e.g. when this is a selecting query and it is selecting all columns from one table). In this case it denotes the "root" entity of this query result. If the query does not denote a single entity result, this argument is only used for query routing, i.e. determining which database it should be run against. You are free to use any persistent class or even a DataMap instance in such situation. It will work as long as the passed "root" maps to the same database as the current query.
+
+To achieve interoperability between mutliple RDBMS a user can specify multiple SQL statements for the same SQLTemplate, each corresponding to a native SQL dialect. A key used to look up the right dialect during execution is a fully qualified class name of the corresponding DbAdapter. If no DB-specific statement is present for a given DB, a default generic statement is used. E.g. in all the examples above a default statement will be used regardless of the runtime database. So in most cases you won't need to explicitly "translate" your SQL to all possible dialects. Here is how this works in practice:
+
+[source, java]
+----
+SQLTemplate select = new SQLTemplate(Artist.class, "select * from ARTIST");
+
+// For Postgres it would be nice to trim padding of all CHAR columns.
+// Otherwise those will be returned with whitespace on the right.
+// assuming "NAME" is defined as CHAR...
+String pgSQL = "SELECT ARTIST_ID, RTRIM(NAME), DATE_OF_BIRTH FROM ARTIST";
+query.setTemplate(PostgresAdapter.class.getName(), pgSQL);
+----
+
+===== Scripting SQLTemplate with Velocity
+
+The most interesting aspect of SQLTemplate (and the reason why it is called a "template") is that a SQL string is treated by Cayenne as an Apache Velocity template. Before sending it to DB as a PreparedStatement, the String is evaluated in the Velocity context, that does variable substitutions, and performs special callbacks in response to various directives, thus controlling query interaction with the JDBC layer.
+
+Check Velocity docs for the syntax details. Here we'll just mention the two main scripting elements - "variables" (that look like `$var`) and "directives" (that look like `#directive(p1 p2 p3)`). All built-in Velocity directives are supported. Additionally Cayenne defines a number of its own directives to bind parameters to PreparedStatements and to control the structure of the ResultSet. These directives are described in the following sections.
+
+
+===== Variable Substitution
+
+All variables in the template string are replaced from query parameters:
+
+
+[source, java]
+----
+SQLTemplate query = new SQLTemplate(Artist.class, "delete from $tableName");
+query.setParameters(Collections.singletonMap("tableName", "mydb.PAINTING"));
+
+// this will generate SQL like this: "delete from mydb.PAINTING"
+----
+
+The example above demonstrates the point made earlier in this chapter - even if we don't know upfront which table the query will run against, we can still use a fixed "root" in constructor (`Artist.class` in this case) , as we are not planning on converting the result to objects.
+
+Variable substitution within the text uses `"object.toString()"` method to replace the variable value. Keep in mind that this may not be appropriate in all situations. E.g. passing a date object in a WHERE clause expression may be converted to a String not understood by the target RDBMS SQL parser. In such cases variable should be wrapped in `#bind` directive as described below.
+
+[[directives]]
+===== Directives
+
+These are the Cayenne directives used to customize SQLTemplate parsing and integrate it with the JDBC layer:
+
+====== #bind
+
+Creates a PreparedStatement positional parameter in place of the directive, binding the value to it before statement execution. `#bind` is allowed in places where a "?" would be allowed in a PreparedStatement. And in such places it almost always makes sense to pass objects to the template via this or other forms of #bind instead of inserting them inline.
+
+Semantics:
+
+[source]
+----
+#bind(value)
+#bind(value jdbcType)
+#bind(value jdbcType scale)
+----
+
+Arguments:
+
+- `value` - can either be a char constant or a variable that is resolved from the query parameters. Note that the variable can be a collection, that will be automatically expanded into a list of individual value bindings. This is useful for instance to build IN conditions.
+
+- `jdbcType` - is a JDBC data type of the parameter as defined in `java.sql.Types`.
+
+- `scale` - An optional scale of the numeric value. Same as "scale" in PreparedStatement.
+
+Usage:
+
+[source]
+----
+#bind($xyz)
+#bind('str')
+#bind($xyz 'VARCHAR')
+#bind($xyz 'DECIMAL' 2)
+----
+
+Full example:
+
+[source, SQL]
+----
+update ARTIST set NAME = #bind($name) where ID = #bind($id)
+----
+
+
+====== #bindEqual
+
+Same as #bind, but also includes the "=" sign in front of the value binding. Look at the example below - we took the #bind example and replaced `"ID = #bind(..)"` with `"ID #bindEqual(..)"`. While it looks like a clumsy shortcut to eliminate the equal sign, the actual reason why this is useful is that it allows the value to be null. If the value is not null, `"= ?"` is generated, but if it is, the resulting chunk of the SQL would look like `"IS NULL"` and will be compilant with what the DB expects.
+
+Semantics:
+
+
+[source]
+----
+#bindEqual(value)
+#bindEqual(value jdbcType)
+#bindEqual(value jdbcType scale)
+----
+
+Arguments: (same as #bind)
+
+Usage:
+
+[source]
+----
+#bindEqual($xyz)
+#bindEqual('str')
+#bindEqual($xyz 'VARCHAR')
+#bindEqual($xyz 'DECIMAL' 2)
+----
+
+
+Full example:
+
+
+[source, SQL]
+----
+update ARTIST set NAME = #bind($name) where ID #bindEqual($id)
+----
+
+====== #bindNotEqual
+
+This directive deals with the same issue as `#bindEqual` above, only it generates "not equal" in front of the value (or IS NOT NULL).
+
+Semantics:
+
+[source]
+----
+#bindNotEqual(value)
+#bindNotEqual(value jdbcType)
+#bindNotEqual(value jdbcType scale)
+----
+
+Arguments: (same as #bind)
+
+Usage:
+
+[source]
+----
+#bindNotEqual($xyz)
+#bindNotEqual('str')
+#bindNotEqual($xyz 'VARCHAR')
+#bindNotEqual($xyz 'DECIMAL' 2)
+----
+
+Full example:
+
+
+[source, SQL]
+----
+update ARTIST set NAME = #bind($name) where ID #bindEqual($id)
+----
+
+====== #bindObjectEqual
+
+It can be tricky to use a Persistent object or an ObjectId in a binding, especially for tables with compound primary keys. This directive helps to handle such binding. It maps columns in the query to the names of Persistent object ID columns, extracts ID values from the object, and generates SQL like "COL1 = ? AND COL2 = ? ..." , binding positional parameters to ID values. It can also correctly handle null object. Also notice how we are specifying a Velocity array for multi-column PK.
+
+Semantics:
+
+[source]
+----
+#bindObjectEqual(value columns idColumns)
+----
+
+Arguments:
+
+- `value` - must be a variable that is resolved from the query parameters to a Persistent or ObjectId.
+
+- `columns` - the names of the columns to generate in the SQL.
+
+- `idColumn` - the names of the ID columns for a given entity. Must match the order of "columns" to match against.
+
+Usage:
+
+[source]
+----
+#bindObjectEqual($a 't0.ID' 'ID')
+#bindObjectEqual($b ['t0.FK1', 't0.FK2'] ['PK1', 'PK2'])
+----
+
+Full example:
+
+[source, java]
+----
+String sql = "SELECT * FROM PAINTING t0 WHERE #bindObjectEqual($a 't0.ARTIST_ID' 'ARTIST_ID' ) ORDER BY PAINTING_ID";
+SQLTemplate select = new SQLTemplate(Artist.class, sql);
+
+Artist a = ....
+select.setParameters(Collections.singletonMap("a", a));
+----
+
+====== #bindObjectNotEqual
+
+Same as #bindObjectEqual above, only generates "not equal" operator for value comparison (or IS NOT NULL).
+
+Semantics:
+
+[source]
+----
+#bindObjectNotEqual(value columns idColumns)
+----
+
+Arguments: (same as #bindObjectEqual)
+
+Usage:
+
+[source]
+----
+#bindObjectNotEqual($a 't0.ID' 'ID')
+#bindObjectNotEqual($b ['t0.FK1', 't0.FK2'] ['PK1', 'PK2'])
+----
+
+Full example:
+
+[source, java]
+----
+String sql = "SELECT * FROM PAINTING t0 WHERE #bindObjectNotEqual($a 't0.ARTIST_ID' 'ARTIST_ID' ) ORDER BY PAINTING_ID";
+SQLTemplate select = new SQLTemplate(Artist.class, sql);
+
+Artist a = ....
+select.setParameters(Collections.singletonMap("a", a));
+----
+
+====== #result
+
+Renders a column in SELECT clause of a query and maps it to a key in the result DataRow. Also ensures the value read is of the correct type. This allows to create a DataRow (and ultimately - a persistent object) from an arbitrary ResultSet.
+
+Semantics:
+
+[source]
+----
+#result(column)
+#result(column javaType)
+#result(column javaType alias)
+#result(column javaType alias dataRowKey)
+----
+
+Arguments:
+
+- `column` - the name of the column to render in SQL SELECT clause.
+
+- `javaType` - a fully-qualified Java class name for a given result column. For simplicity most common Java types used in JDBC can be specified without a package. These include all numeric types, primitives, String, SQL dates, BigDecimal and BigInteger. So `"#result('A' 'String')"`, `"#result('B' 'java.lang.String')"` and `"#result('C' 'int')"` are all valid
+
+- `alias` - specifies both the SQL alias of the column and the value key in the DataRow. If omitted, "column" value is used.
+
+- `dataRowKey` - needed if SQL 'alias' is not appropriate as a DataRow key on the Cayenne side. One common case when this happens is when a DataRow retrieved from a query is mapped using joint prefetch keys (see below). In this case DataRow must use database path expressions for joint column keys, and their format is incompatible with most databases alias format.
+
+Usage:
+
+[source]
+----
+#result('NAME')
+#result('DATE_OF_BIRTH' 'java.util.Date')
+#result('DOB' 'java.util.Date' 'DATE_OF_BIRTH')
+#result('DOB' 'java.util.Date' '' 'artist.DATE_OF_BIRTH')
+#result('SALARY' 'float')
+----
+
+Full example:
+
+
+[source, SQL]
+----
+SELECT #result('ID' 'int'), #result('NAME' 'String'), #result('DATE_OF_BIRTH' 'java.util.Date') FROM ARTIST
+----
+
+====== #chain and #chunk
+
+`#chain` and `#chunk` directives are used for conditional inclusion of SQL code. They are used together with `#chain` wrapping multiple `#chunks`. A chunk evaluates its parameter expression and if it is NULL suppresses rendering of the enclosed SQL block. A chain renders its prefix and its chunks joined by the operator. If all the chunks are suppressed, the chain itself is suppressed. This allows to work with otherwise hard to script SQL semantics. E.g. a WHERE clause can contain multiple conditions joined with AND or OR. Application code would like to exclude a condition if its right-hand parameter is not present (similar to Expression pruning discussed above). If all conditions are excluded, the entire WHERE clause should be excluded. chain/chunk allows to do that.
+
+Semantics:
+
+[source]
+----
+#chain(operator) ... #end
+#chain(operator prefix) ... #end
+#chunk() ... #end
+#chunk(param) ... #end
+----
+
+Full example:
+
+[source]
+----
+#chain('OR' 'WHERE')
+	#chunk($name) NAME LIKE #bind($name) #end"
+	#chunk($id) ARTIST_ID > #bind($id) #end"
+#end"
+----
+
+====== Mapping SQLTemplate Results
+
+Here we'll discuss how to convert the data selected via SQLTemplate to some useable format, compatible with other query results. It can either be very simple or very complex, depending on the structure of the SQL, JDBC driver nature and the desired result structure. This section presents various tips and tricks dealing with result mapping.
+
+By default SQLTemplate is expected to return a List of Persistent objects of its root type. This is the simple case:
+
+[source, Java]
+----
+SQLTemplate query = new SQLTemplate(Artist.class, "SELECT * FROM ARTIST");
+
+// List of Artists
+List<Artist> artists = context.performQuery(query);
+----
+
+Just like SelectQuery, SQLTemplate can fetch DataRows. In fact DataRows option is very useful with SQLTemplate, as the result type most often than not does not represent a Cayenne entity, but instead may be some aggregated report or any other data whose object structure is opaque to Cayenne:
+
+[source, Java]
+----
+String sql = "SELECT t0.NAME, COUNT(1) FROM ARTIST t0 JOIN PAINTING t1 ON (t0.ID = t1.ARTIST_ID) "
+    + "GROUP BY t0.NAME ORDER BY COUNT(1)";
+SQLTemplate query = new SQLTemplate(Artist.class, sql);
+
+// ensure we are fetching DataRows
+query.setFetchingDataRows(true);
+
+// List of DataRow
+List<DataRow> rows = context.performQuery(query);
+----
+
+In the example above, even though the query root is Artist. the result is a list of artist names with painting counts (as mentioned before in such case "root" is only used to find the DB to fetch against, but has no bearning on the result). The DataRows here are the most appropriate and desired result type.
+
+In a more advanced case you may decide to fetch a list of scalars or a list of Object[] with each array entry being either an entity or a scalar. You probably won't be doing this too often and it requires quite a lot of work to setup, but if you want your SQLTemplate to return results similar to EJBQLQuery, it is doable using SQLResult as described below:
+
+[source, Java]
+----
+SQLTemplate query = new SQLTemplate(Painting.class, "SELECT ESTIMATED_PRICE P FROM PAINTING");
+
+// let Cayenne know that result is a scalar
+SQLResult resultDescriptor = new SQLResult();
+resultDescriptor.addColumnResult("P");
+query.setResult(resultDescriptor);
+
+// List of BigDecimals
+List<BigDecimal> prices = context.performQuery(query);
+----
+
+[source, Java]
+----
+SQLTemplate query = new SQLTemplate(Artist.class, "SELECT t0.ID, t0.NAME, t0.DATE_OF_BIRTH, COUNT(t1.PAINTING_ID) C " +
+      "FROM ARTIST t0 LEFT JOIN PAINTING t1 ON (t0.ID = t1.ARTIST_ID) " +
+      "GROUP BY t0.ID, t0.NAME, t0.DATE_OF_BIRTH");
+
+// let Cayenne know that result is a mix of Artist objects and the count of their paintings
+EntityResult artistResult = new EntityResult(Artist.class);
+artistResult.addDbField(Artist.ID_PK_COLUMN, "ARTIST_ID");
+artistResult.addObjectField(Artist.NAME_PROPERTY, "NAME");
+artistResult.addObjectField(Artist.DATE_OF_BIRTH_PROPERTY, "DATE_OF_BIRTH");
+
+SQLResult resultDescriptor = new SQLResult();
+resultDescriptor.addEntityResult(artistResult);
+resultDescriptor.addColumnResult("C");
+query.setResult(resultDescriptor);
+
+// List of Object[]
+List<Object[]> data = context.performQuery(query);
+----
+
+Another trick related to mapping result sets is making Cayenne recognize prefetched entities in the result set. This emulates "joint" prefetching of SelectQuery, and is achieved by special column naming. Columns belonging to the "root" entity of the query should use unqualified names corresponding to the root DbEntity columns. For each related entity column names must be prefixed with relationship name and a dot (e.g. "toArtist.ID"). Column naming can be controlled with "#result" directive:
+
+[source, Java]
+----
+String sql = "SELECT distinct "
+    + "#result('t1.ESTIMATED_PRICE' 'BigDecimal' '' 'paintings.ESTIMATED_PRICE'), "
+    + "#result('t1.PAINTING_TITLE' 'String' '' 'paintings.PAINTING_TITLE'), "
+    + "#result('t1.GALLERY_ID' 'int' '' 'paintings.GALLERY_ID'), "
+    + "#result('t1.ID' 'int' '' 'paintings.ID'), "
+    + "#result('NAME' 'String'), "
+    + "#result('DATE_OF_BIRTH' 'java.util.Date'), "
+    + "#result('t0.ID' 'int' '' 'ID') "
+    + "FROM ARTIST t0, PAINTING t1 "
+    + "WHERE t0.ID = t1.ARTIST_ID";
+
+SQLTemplate q = new SQLTemplate(Artist.class, sql);
+q.addPrefetch(Artist.PAINTINGS_PROPERTY)
+List<Artist> objects = context.performQuery(query);
+----
+
+And the final tip deals with capitalization of the DataRow keys. Queries like `"SELECT * FROM..."` and even `"SELECT COLUMN1, COLUMN2, ... FROM ..."` can sometimes result in Cayenne exceptions on attempts to convert fetched DataRows to objects. Essentially any query that is not using a `#result` directive to describe the result set is prone to this problem, as different databases may produce different capitalization of the java.sql.ResultSet columns.
+
+The most universal way to address this issue is to describe each column explicitly in the SQLTemplate via `#result`, e.g.: `"SELECT #result('column1'), #result('column2'), .."`. However this quickly becomes impractical for tables with lots of columns. For such cases Cayenne provides a shortcut based on the fact that an ORM mapping usually follows some naming convention for the column names. Simply put, for case-insensitive databases developers normally use either all lowercase or all uppercase column names. Here is the API that takes advantage of that user knowledge and forces Cayenne to follow a given naming convention for the DataRow keys (this is also available as a dropdown in the Modeler):
+
+[source, Java]
+----
+SQLTemplate query = new SQLTemplate("SELECT * FROM ARTIST");
+query.setColumnNamesCapitalization(CapsStrategy.LOWER);
+List objects = context.performQuery(query);
+----
+
+or
+
+[source, Java]
+----
+SQLTemplate query = new SQLTemplate("SELECT * FROM ARTIST");
+query.setColumnNamesCapitalization(CapsStrategy.UPPER);
+List objects = context.performQuery(query);
+----
+
+None of this affects the generated SQL, but the resulting DataRows are using correct capitalization. Note that you probably shouldn't bother with this unless you are getting CayenneRuntimeExceptions when fetching with SQLTemplate.
+
+==== ProcedureQuery
+
+Stored procedures are mapped as separate objects in CayenneModeler. ProcedureQuery provides a way to execute them with a certain set of parameters. Just like with SQLTemplate, the outcome of a procedure can be anything - a single result set, mutliple result sets, some data modification (returned as an update count), or a combination of these. So use "performQuery" to get a single result set, and use "performGenericQuery" for anything else:
+
+[source, java]
+----
+ProcedureQuery query = new ProcedureQuery("my_procedure", Artist.class);
+
+// Set "IN" parameter values
+query.addParam("p1", "abc");
+query.addParam("p2", 3000);
+
+List<Artist> result = context.performQuery(query);
+----
+
+[source, java]
+----
+// here we do not bother with root class.
+// Procedure name gives us needed routing information
+ProcedureQuery query = new ProcedureQuery("my_procedure");
+
+query.addParam("p1", "abc");
+query.addParam("p2", 3000);
+
+QueryResponse response = context.performGenericQuery(query);
+----
+A stored procedure can return data back to the application as result sets or via OUT parameters. To simplify the processing of the query output, QueryResponse treats OUT parameters as if it was a separate result set. If a stored procedure declares any OUT or INOUT parameters, QueryResponse will contain their returned values in the very first result list:
+
+[source, java]
+----
+ProcedureQuery query = new ProcedureQuery("my_procedure");
+QueryResponse response = context.performGenericQuery(query);
+
+// read OUT parameters
+List out = response.firstList();
+
+if(!out.isEmpty()) {
+    Map outParameterValues = (Map) outList.get(0);
+}
+----
+
+There maybe a situation when a stored procedure handles its own transactions, but an application is configured to use Cayenne-managed transactions. This is obviously conflicting and undesirable behavior. In this case ProcedureQueries should be executed explicitly wrapped in an "external" Transaction. This is one of the few cases when a user should worry about transactions at all. See Transactions section for more details.
+
+==== NamedQuery
+
+NamedQuery is a query that is a reference to another query stored in the DataMap. The actual stored query can be SelectQuery, SQLTemplate, EJBQLQuery, etc. It doesn't matter - the API for calling them is the same - via a NamedQuery:
+
+[source, java]
+----
+String[] keys = new String[] {"loginid", "password"};
+Object[] values = new String[] {"joe", "secret"};
+
+NamedQuery query = new NamedQuery("Login", keys, values);
+
+List<User> matchingUsers = context.performQuery(query);
+----
+
+==== Custom Queries
+
+If a user needs some extra functionality not addressed by the existing set of Cayenne queries, he can write his own. The only requirement is to implement `org.apache.cayenne.query.Query` interface. The easiest way to go about it is to subclass some of the base queries in Cayenne.
+
+E.g. to do something directly in the JDBC layer, you might subclass AbstractQuery:
+
+[source, java]
+----
+public class MyQuery extends AbstractQuery {
+
+    @Override
+    public SQLAction createSQLAction(SQLActionVisitor visitor) {
+        return new SQLAction() {
+
+            @Override
+            public void performAction(Connection connection, OperationObserver observer) throws SQLException, Exception {
+                // 1. do some JDBC work using provided connection...
+                // 2. push results back to Cayenne via OperationObserver
+            }
+        };
+    }
+}
+----
+
+To delegate the actual query execution to a standard Cayenne query, you may subclass IndirectQuery:
+
+[source, java]
+----
+public class MyDelegatingQuery extends IndirectQuery {
+
+    @Override
+    protected Query createReplacementQuery(EntityResolver resolver) {
+        SQLTemplate delegate = new SQLTemplate(SomeClass.class, generateRawSQL());
+        delegate.setFetchingDataRows(true);
+        return delegate;
+    }
+
+    protected String generateRawSQL() {
+        // build some SQL string
+    }
+}
+----
+
+In fact many internal Cayenne queries are IndirectQueries, delegating to SelectQuery or SQLTemplate after some preprocessing.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

http://git-wip-us.apache.org/repos/asf/cayenne/blob/7783cd34/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/starting.adoc
----------------------------------------------------------------------
diff --git a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/starting.adoc b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/starting.adoc
new file mode 100644
index 0000000..aff8b91
--- /dev/null
+++ b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/starting.adoc
@@ -0,0 +1,120 @@
+// 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.
+
+=== Starting Cayenne
+
+==== Starting and Stopping ServerRuntime
+
+In runtime Cayenne is accessed via `org.apache.cayenne.configuration.server.ServerRuntime`. ServerRuntime is created by calling a convenient builder:
+
+[source, java]
+----
+ServerRuntime runtime = new ServerRuntime("com/example/cayenne-project.xml");
+----
+
+The parameter you pass to the builder is a location of the main project file. Location is a '/'-separated path (same path separator is used on UNIX and Windows) that is resolved relative to the application classpath. The project file can be placed in the root package or in a subpackage (e.g. in the code above it is in "com/example" subpackage).
+
+ServerRuntime encapsulates a single Cayenne stack. Most applications will just have one ServerRuntime using it to create as many ObjectContexts as needed, access the Dependency Injection (DI) container and work with other Cayenne features. Internally ServerRuntime is just a thin wrapper around the DI container. Detailed features of the container are discussed in xref:customize["Customizing Cayenne Runtime"] chapter. Here we'll just show an example of how an application might turn on external transactions:
+
+[source, java]
+----
+public class MyExtensionsModule implements Module {
+    public void configure(Binder binder) {
+        binder.bind(QueryCache.class).to(EhCacheQueryCache.class);
+    }
+}
+----
+
+[source, java]
+----
+Module extensions = new MyExtensionsModule();
+ServerRuntime runtime = new ServerRuntime("com/example/cayenne-project.xml", extensions);
+----
+
+It is a good idea to shut down the runtime when it is no longer needed, usually before the application itself is shutdown:
+
+[source, java]
+----
+runtime.shutdown();
+----
+
+When a runtime object has the same scope as the application, this may not be always necessary, however in some cases it is essential, and is generally considered a good practice. E.g. in a web container hot redeploy of a webapp will cause resource leaks and eventual OutOfMemoryError if the application fails to shutdown CayenneRuntime.
+
+==== Merging Multiple Projects
+
+ServerRuntime requires at least one mapping project to run. But it can also take multiple projects and merge them together in a single configuration. This way different parts of a database can be mapped independenlty from each other (even by different software providers), and combined in runtime when assembling an application. Doing it is as easy as passing multiple project locations to ServerRuntime constructor:
+
+[source, java]
+----
+ServerRuntime runtime = new ServerRuntime(new String[] {
+        "com/example/cayenne-project.xml",
+        "org/foo/cayenne-library1.xml",
+        "org/foo/cayenne-library2.xml"
+    }
+);
+----
+
+When the projects are merged, the following rules are applied:
+
+
+- The order of projects matters during merge. If there are two conflicting metadata objects belonging to two projects, an object from the last project takes precedence over the object from the first one. This makes possible to override pieces of metadata. This is also similar to how DI modules are merged in Cayenne.
+
+- Runtime DataDomain name is set to the name of the last project in the list.
+
+- Runtime DataDomain properties are the same as the properties of the last project in the list. I.e. properties are not merged to avoid invalid combinations and unexpected runtime behavior.
+
+- If there are two or more DataMaps with the same name, only one DataMap is used in the merged project, the rest are discarded. Same precedence rules apply - DataMap from the project with the highest index in the project list overrides all other DataMaps with the same name.
+
+- If there are two or more DataNodes with the same name, only one DataNode is used in the merged project, the rest are discarded. DataNode coming from project with the highest index in the project list is chosen per precedence rule above.
+
+- There is a notion of "default" DataNode. After the merge if any DataMaps are not explicitly linked to DataNodes, their queries will be executed via a default DataNode. This makes it possible to build mapping "libraries" that are only associated with a specific database in runtime. If there's only one DataNode in the merged project, it will be automatically chosen as default. A possible way to explicitly designate a specific node as default is to override `DataDomainProvider.createAndInitDataDomain()`.
+
+==== Web Applications
+
+Web applications can use a variety of mechanisms to configure and start the "services" they need, Cayenne being one of such services. Configuration can be done within standard Servlet specification objects like Servlets, Filters, or ServletContextListeners, or can use Spring, JEE CDI, etc. This is a user's architectural choice and Cayenne is agnostic to it and will happily work in any environment. As described above, all that is needed is to create an instance of ServerRuntime somewhere and provide the application code with means to access it. And shut it down when the application ends to avoid container leaks.
+
+Still Cayenne includes a piece of web app configuration code that can assist in quickly setting up simple Cayenne-enabled web applications. We are talking about CayenneFilter. It is declared in web.xml:
+
+[source, XML]
+----
+<web-app>
+    ...
+    <filter>
+        <filter-name>cayenne-project</filter-name>
+        <filter-class>org.apache.cayenne.configuration.web.CayenneFilter</filter-class>
+    </filter>
+     <filter-mapping>
+        <filter-name>cayenne-project</filter-name>
+        <url-pattern>/*</url-pattern>
+     </filter-mapping>
+    ...
+ </web-app>
+----
+
+
+When started by the web container, it creates a instance of ServerRuntime and stores it in the ServletContext. Note that the name of Cayenne XML project file is derived from the "filter-name". In the example above CayenneFilter will look for an XML file "cayenne-project.xml". This can be overridden with "configuration-location" init parameter.
+
+When the application runs, all HTTP requests matching the filter url-pattern will have access to a session-scoped ObjectContext like this:
+
+[source, java]
+----
+ ObjectContext context = BaseContext.getThreadObjectContext();
+----
+
+Of course the ObjectContext scope, and other behavior of the Cayenne runtime can be customized via dependency injection. For this another filter init parameter called "extra-modules" is used. "extra-modules" is a comma or space-separated list of class names, with each class implementing Module interface. These optional custom modules are loaded after the the standard ones, which allows users to override all standard definitions.
+
+For those interested in the DI container contents of the runtime created by CayenneFilter, it is the same ServerRuntime as would've been created by other means, but with an extra `org.apache.cayenne.configuration.web.WebModule` module that provides `org.apache.cayenne.configuration.web.RequestHandler` service. This is the service to override in the custom modules if you need to provide a different ObjectContext scope, etc.
+
+NOTE: You should not think of CayenneFilter as the only way to start and use Cayenne in a web application. In fact CayenneFilter is entirely optional. Use it if you don't have any special design for application service management. If you do, simply integrate Cayenne into that design.
+

http://git-wip-us.apache.org/repos/asf/cayenne/blob/7783cd34/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/tuning.adoc
----------------------------------------------------------------------
diff --git a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/tuning.adoc b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/tuning.adoc
new file mode 100644
index 0000000..e9316b1
--- /dev/null
+++ b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/tuning.adoc
@@ -0,0 +1,269 @@
+// 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.
+
+=== Performance Tuning
+
+==== Prefetching
+
+Prefetching is a technique that allows to bring back in one query not only the queried objects, but also objects related to them. In other words it is a controlled eager relationship resolving mechanism. Prefetching is discussed in the "Performance Tuning" chapter, as it is a powerful performance optimization method. However another common application of prefetching is to refresh stale object relationships, so more generally it can be viewed as a technique for managing subsets of the object graph.
+
+Prefetching example:
+
+[source, Java]
+----
+SelectQuery query = new SelectQuery(Artist.class);
+
+// this instructs Cayenne to prefetch one of Artist's relationships
+query.addPrefetch("paintings");
+
+// query is expecuted as usual, but the resulting Artists will have
+// their paintings "inflated"
+List<Artist> artists = context.performQuery(query);
+----
+
+All types of relationships can be preftetched - to-one, to-many, flattened.
+
+A prefetch can span multiple relationships:
+
+[source, Java]
+----
+ query.addPrefetch("paintings.gallery");
+----
+
+A query can have multiple prefetches:
+
+[source, Java]
+----
+query.addPrefetch("paintings");
+query.addPrefetch("paintings.gallery");
+----
+
+If a query is fetching DataRows, all "disjoint" prefetches are ignored, only "joint" prefetches are executed (see prefetching semantics discussion below for what disjoint and joint prefetches mean).
+
+===== Prefetching Semantics
+
+Prefetching semantics defines a strategy to prefetch relationships. Depending on it, Cayenne would generate different types of queries. The end result is the same - query root objects with related objects fully resolved. However semantics can affect preformance, in some cases significantly. There are 3 types of prefetch semantics, all defined as constants in `org.apache.cayenne.query.PrefetchTreeNode`:
+
+[source]
+----
+PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS
+PrefetchTreeNode.DISJOINT_PREFETCH_SEMANTICS
+PrefetchTreeNode.DISJOINT_BY_ID_PREFETCH_SEMANTICS
+----
+
+Each query has a default prefetch semantics, so generally users do not have to worry about changing it, except when performance is a concern, or a few special cases when a default sematics can't produce the correct result. SelectQuery uses DISJOINT_PREFETCH_SEMANTICS by default. Semantics can be changed as follows:
+
+[source, java]
+----
+SelectQuery query = new SelectQuery(Artist.class);
+query.addPrefetch("paintings").setSemantics(
+                PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
+----
+
+There's no limitation on mixing different types of semantics in the same SelectQuery. Multiple prefetches each can have its own semantics.
+
+SQLTemplate and ProcedureQuery are both using JOINT_PREFETCH_SEMANTICS and it can not be changed due to the nature of these two queries.
+
+
+===== Disjoint Prefetching Semantics
+
+This semantics results in Cayenne generatiing one SQL statement for the main objects, and a separate statement for each prefetch path (hence "disjoint" - related objects are not fetched with the main query). Each additional SQL statement uses a qualifier of the main query plus a set of joins traversing the preftech path between the main and related entity.
+
+This strategy has an advantage of efficient JVM memory use, and faster overall result processing by Cayenne, but it requires (1+N) SQL statements to be executed, where N is the number of prefetched relationships.
+
+===== Disjoint-by-ID Prefetching Semantics
+
+This is a variation of disjoint prefetch where related objects are matched against a set of IDs derived from the fetched main objects (or intermediate objects in a multi-step prefetch). Cayenne limits the size of the generated WHERE clause, as most DBs can't parse arbitrary large SQL. So prefetch queries are broken into smaller queries. The size of is controlled by the DI property Constants.SERVER_MAX_ID_QUALIFIER_SIZE_PROPERTY (the default number of conditions in the generated WHERE clause is 10000). Cayenne will generate (1 + N * M) SQL statements for each query using disjoint-by-ID prefetches, where N is the number of relationships to prefetch, and M is the number of queries for a given prefetch that is dependent on the number of objects in the result (ideally M = 1).
+
+The advantage of this type of prefetch is that matching database rows by ID may be much faster than matching the qualifier of the original query. Moreover this is *the only type of prefetch* that can handle SelectQueries with *fetch* limit. Both joint and regular disjoint prefetches may produce invalid results or generate inefficient fetch-the-entire table SQL when fetch limit is in effect.
+
+The disadvantage is that query SQL can get unwieldy for large result sets, as each object will have to have its own condition in the WHERE clause of the generated SQL.
+
+===== Joint Prefetching Semantics
+
+Joint semantics results in a single SQL statement for root objects and any number of jointly prefetched paths. Cayenne processes in memory a cartesian product of the entities involved, converting it to an object tree. It uses OUTER joins to connect prefetched entities.
+
+Joint is the most efficient prefetch type of the three as far as generated SQL goes. There's always just 1 SQL query generated. Its downsides are the potentially increased amount of data that needs to get across the network between the application server and the database, and more data processing that needs to be done on the Cayenne side.
+
+==== Data Rows
+
+Converting result set data to Persistent objects and registering these objects in the ObjectContext can be an expensive operation compareable to the time spent running the query (and frequently exceeding it). Internally Cayenne builds the result as a list of DataRows, that are later converted to objects. Skipping the last step and using data in the form of DataRows can significantly increase performance.
+
+DataRow is a simply a map of values keyed by their DB column name. It is a ubiqutous representation of DB data used internally by Cayenne. And it can be quite usable as is in the application in many cases. So performance sensitive selects should consider DataRows - it saves memory and CPU cycles. All selecting queries support DataRows option, e.g.:
+
+[source, Java]
+----
+SelectQuery query = new SelectQuery(Artist.class);
+query.setFetchingDataRows(true);
+
+List<DataRow> rows = context.performQuery(query);
+----
+
+[source, Java]
+----
+SQLTemplate query = new SQLTemplate(Artist.class, "SELECT * FROM ARTIST");
+query.setFetchingDataRows(true);
+
+List<DataRow> rows = context.performQuery(query);
+----
+
+Moreover DataRows may be converted to Persistent objects later as needed. So e.g. you may implement some in-memory filtering, only converting a subset of fetched objects:
+
+[source, Java]
+----
+// you need to cast ObjectContext to DataContext to get access to 'objectFromDataRow'
+DataContext dataContext = (DataContext) context;
+
+for(DataRow row : rows) {
+    if(row.get("DATE_OF_BIRTH") != null) {
+        Artist artist = dataContext.objectFromDataRow(Artist.class, row);
+        // do something with Artist...
+        ...
+    }
+}
+----
+
+==== Iterated Queries
+
+While contemporary hardware may easily allow applications to fetch hundreds of thousands or even millions of objects into memory, it doesn't mean this is always a good idea to do so. You can optimize processing of very large result sets with two techniques discussed in this and the following chapter - iterated and paginated queries.
+
+Iterated query is not actually a special query. Any selecting query can be executed in iterated mode by the DataContext (like in the previous example, a cast to DataContext is needed). DataContext returns an object called ResultIterator that is backed by an open ResultSet. Data is read from ResultIterator one row at a time until it is exhausted. Data comes as a DataRows regardless of whether the orginating query was configured to fetch DataRows or not. A ResultIterator must be explicitly closed to avoid JDBC resource leak.
+
+Iterated query provides constant memory performance for arbitrarily large ResultSets. This is true at least on the Cayenne end, as JDBC driver may still decide to bring the entire ResultSet into the JVM memory.
+
+Here is a full example:
+[source, Java]
+----
+// you need to cast ObjectContext to DataContext to get access to 'performIteratedQuery'
+DataContext dataContext = (DataContext) context;
+
+// create a regular query
+SelectQuery q = new SelectQuery(Artist.class);
+
+// ResultIterator operations all throw checked CayenneException
+// moreover 'finally' is required to close it
+try {
+
+    ResultIterator it = dataContext.performIteratedQuery(q);
+
+    try {
+        while(it.hasNextRow()) {
+            // normally we'd read a row, process its data, and throw it away
+            // this gives us constant memory performance
+            Map row = (Map) it.nextRow();
+
+            // do something with the row...
+            ...
+        }
+    }
+    finally {
+        it.close();
+    }
+}
+catch(CayenneException e) {
+   e.printStackTrace();
+}
+----
+
+Also common sense tells us that ResultIterators should be processed and closed as soon as possible to release the DB connection. E.g. storing open iterators between HTTP requests and for unpredictable length of time would quickly exhaust the connection pool.
+
+==== Paginated Queries
+
+Enabling query pagination allows to load very large result sets in a Java app with very little memory overhead (much smaller than even the DataRows option discussed above). Moreover it is completely transparent to the application - a user gets what appears to be a list of Persistent objects - there's no iterator to close or DataRows to convert to objects:
+
+[source, Java]
+----
+SelectQuery query = new SelectQuery(Artist.class);
+query.setPageSize(50);
+
+// the fact that result is paginated is transparent
+List<Artist> artists = ctxt.performQuery(query);
+----
+
+Having said that, DataRows option can be combined with pagination, providing the best of both worlds:
+
+
+[source, Java]
+----
+SelectQuery query = new SelectQuery(Artist.class);
+query.setPageSize(50);
+query.setFetchingDataRows(true);
+
+List<DataRow> rows = ctxt.performQuery(query);
+----
+
+The way pagination works internally, it first fetches a list of IDs for the root entity of the query. This is very fast and initially takes very little memory. Then when an object is requested at an arbitrary index in the list, this object and adjacent objects (a "page" of objects that is determined by the query pageSize parameter) are fetched together by ID. Subsequent requests to the objects of this "page" are served from memory.
+
+An obvious limitation of pagination is that if you eventually access all objects in the list, the memory use will end up being the same as with no pagination. However it is still a very useful approach. With some lists (e.g. multi-page search results) only a few top objects are normally accessed. At the same time pagination allows to estimate the full list size without fetching all the objects. And again - it is completely transparent and looks like a normal query.
+
+[[caching]]
+==== Caching and Fresh Data
+
+===== Object Caching
+
+===== Query Result Caching
+
+==== Turning off Synchronization of ObjectContexts
+
+By default when a single ObjectContext commits its changes, all other contexts in the same runtime receive an event that contains all the committed changes. This allows them to update their cached object state to match the latest committed data. There are however many problems with this ostensibly helpful feature. In short - it works well in environments with few contexts and in unclustered scenarios, such as single user desktop applications, or simple webapps with only a few users. More specifically:
+
+- The performance of synchronization is (probably worse than) O(N) where N is the number of peer ObjectContexts in the system. In a typical webapp N can be quite large. Besides for any given context, due to locking on synchronization, context own performance will depend not only on the queries that it runs, but also on external events that it does not control. This is unacceptable in most situations.
+
+- Commit events are untargeted - even contexts that do not hold a given updated object will receive the full event that they will have to process.
+
+- Clustering between JVMs doesn't scale - apps with large volumes of commits will quickly saturate the network with events, while most of those will be thrown away on the receiving end as mentioned above.
+
+- Some contexts may not want to be refreshed. A refresh in the middle of an operation may lead to unpredictable results.
+
+- Synchronization will interfere with optimistic locking.
+
+So we've made a good case for disabling synchronization in most webapps. To do that, set to "false" the following DI property - `_Constants.SERVER_CONTEXTS_SYNC_PROPERTY_`, using one of the standard Cayenne DI approaches. E.g. from command line:
+
+[source]
+----
+$ java -Dcayenne.server.contexts_sync_strategy=false
+----
+
+Or by changing the standard properties Map in a custom extensions module:
+
+[source, Java]
+----
+public class MyModule implements Module {
+
+    @Override
+    public void configure(Binder binder) {
+        binder.bindMap(Constants.PROPERTIES_MAP).put(Constants.SERVER_CONTEXTS_SYNC_PROPERTY, "false");
+    }
+}
+----
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

http://git-wip-us.apache.org/repos/asf/cayenne/blob/7783cd34/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3.adoc
----------------------------------------------------------------------
diff --git a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3.adoc b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3.adoc
new file mode 100644
index 0000000..5e211d1
--- /dev/null
+++ b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3.adoc
@@ -0,0 +1,28 @@
+// 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.
+
+== Cayenne Framework - Remote Object Persistence
+
+include::part3/rop.adoc[]
+
+include::part3/ropSetup.adoc[]
+
+include::part3/serverImpl.adoc[]
+
+include::part3/clientImpl.adoc[]
+
+include::part3/ropDeployment.adoc[]
+
+include::part3/limitations.adoc[]
+

http://git-wip-us.apache.org/repos/asf/cayenne/blob/7783cd34/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/clientImpl.adoc
----------------------------------------------------------------------
diff --git a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/clientImpl.adoc b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/clientImpl.adoc
new file mode 100644
index 0000000..027a22e
--- /dev/null
+++ b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/clientImpl.adoc
@@ -0,0 +1,16 @@
+// 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.
+
+=== Implementing ROP Client
+

http://git-wip-us.apache.org/repos/asf/cayenne/blob/7783cd34/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/limitations.adoc
----------------------------------------------------------------------
diff --git a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/limitations.adoc b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/limitations.adoc
new file mode 100644
index 0000000..f378cdb
--- /dev/null
+++ b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/limitations.adoc
@@ -0,0 +1,18 @@
+// 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.
+
+=== Current Limitations
+
+
+

http://git-wip-us.apache.org/repos/asf/cayenne/blob/7783cd34/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/rop.adoc
----------------------------------------------------------------------
diff --git a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/rop.adoc b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/rop.adoc
new file mode 100644
index 0000000..f69f98a
--- /dev/null
+++ b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/rop.adoc
@@ -0,0 +1,54 @@
+// 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.
+
+[[rop]]
+=== Introduction to ROP
+
+==== What is ROP
+
+"Remote Object Persistence" is a low-overhead web services-based technology that provides lightweight object persistence and query functionality to 'remote' applications. In other words it provides familiar Cayenne API to applications that do not have direct access to the database. Instead such applications would access Cayenne Web Service (CWS). A single abstract data model (expressed as Cayenne XML DataMap) is used on the server and on the client, while execution logic can be partitioned between the tiers.The following picture compares a regular Cayenne web application and a rich client application that uses remote object persistence technology:
+
+image::../images/remote-object-persistence.jpg[align="center"]
+
+Persistence stack above consists of the following parts:
+
+- ORM Tier: a server-side Cayenne Java application that directly connects to the database via JDBC.
+
+- CWS (Cayenne Web Service): A wrapper around an ORM tier that makes it accessible to remote CWS clients.
+
+- Remote Tier (aka Client Tier): A Java application that has no direct DB connection and persists its objects by connecting to remote Cayenne Web Service (CWS). Note that CWS Client doesn't have to be a desktop application. It can be another server-side application. The word "client" means a client of Cayenne Web Service.
+
+==== Main Features
+
+- Unified approach to lightweight object persistence across multiple tiers of a distributed system.
+
+- Same abstract object model on the server and on the client.
+
+- Client can "bootstrap" from the server by dynamically loading persistence metadata.
+
+- An ability to define client objects differently than the server ones, and still have seamless persistence.
+
+- Generic web service interface that doesn't change when object model changes.
+
+- An ability to work in two modes: dedicated session mode or shared ("chat") mode when multiple remote clients collaboratively work on the same data.
+
+- Lazy object and collection faulting.
+
+- Full context lifecycle
+
+- Queries, expressions, local query caching, paginated queries.
+
+- Validation
+
+- Delete Rules
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/7783cd34/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/ropDeployment.adoc
----------------------------------------------------------------------
diff --git a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/ropDeployment.adoc b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/ropDeployment.adoc
new file mode 100644
index 0000000..6aa4388
--- /dev/null
+++ b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/ropDeployment.adoc
@@ -0,0 +1,34 @@
+// 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.
+
+=== ROP Deployment
+
+==== Deploying ROP Server
+
+NOTE: Recent versions of Tomcat and Jetty containers (e.g. Tomcat 6 and 7, Jetty 8) contain code addressing a security concern related to "session fixation problem" by resetting the existing session ID of any request that requires BASIC authentcaition. If ROP service is protected with declarative security (see the ROP tutorial and the following chapters on security), this feature prevents the ROP client from attaching to its session, resulting in MissingSessionExceptions. To solve that you will need to either switch to an alternative security mechanism, or disable "session fixation problem" protections of the container. E.g. the later can be achieved in Tomcat 7 by adding the following context.xml file to the webapp's META-INF/ directory:
+
+[source, XML]
+----
+<Context>
+    <Valve className="org.apache.catalina.authenticator.BasicAuthenticator"
+            changeSessionIdOnAuthentication="false" />
+</Context>
+----
+
+(The <Valve> tag can also be placed within the <Context> in any other locations used by Tomcat to load context configurations)
+
+==== Deploying ROP Client
+
+==== Security
+

http://git-wip-us.apache.org/repos/asf/cayenne/blob/7783cd34/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/ropSetup.adoc
----------------------------------------------------------------------
diff --git a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/ropSetup.adoc b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/ropSetup.adoc
new file mode 100644
index 0000000..0307dfb
--- /dev/null
+++ b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/ropSetup.adoc
@@ -0,0 +1,20 @@
+// 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.
+
+=== Implementing ROP Client
+
+==== System Requirements
+
+==== Jar Files and Dependencies
+

http://git-wip-us.apache.org/repos/asf/cayenne/blob/7783cd34/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/serverImpl.adoc
----------------------------------------------------------------------
diff --git a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/serverImpl.adoc b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/serverImpl.adoc
new file mode 100644
index 0000000..67e09e2
--- /dev/null
+++ b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part3/serverImpl.adoc
@@ -0,0 +1,16 @@
+// 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.
+
+=== Implementing ROP Server
+

http://git-wip-us.apache.org/repos/asf/cayenne/blob/7783cd34/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/serviceCollections.adoc
----------------------------------------------------------------------
diff --git a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/serviceCollections.adoc b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/serviceCollections.adoc
new file mode 100644
index 0000000..d234723
--- /dev/null
+++ b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/serviceCollections.adoc
@@ -0,0 +1,62 @@
+// 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.
+
+== Appendix B. Service Collections
+
+Note that the collection keys below are defined as constants in `org.apache.cayenne.configuration.Constants` interface.
+
+[#serviceCollections.table.table-bordered]
+.Service Collection Keys Present in ServerRuntime and/or ClientRuntime
+[cols="3,2,3"]
+|===
+|Collection Property |Type |Description
+
+.^|`cayenne.properties`
+.^|`Map<String,String>`
+.^|Properties used by built-in Cayenne services. The keys in this map are the property names from the table in Appendix A. Separate copies of this map exist on the server and ROP client.
+
+.^|`cayenne.server.adapter_detectors`
+.^|`List<DbAdapterDetector>`
+.^|Contains objects that can discover the type of current database and install the correct DbAdapter in runtime.
+
+.^|`cayenne.server.domain_filters`
+.^|`List<DataChannelFilter>`
+.^|Stores DataDomain filters.
+
+
+.^|`cayenne.server.project_locations`
+.^|`List<String>`
+.^|Stores locations of the one of more project configuration files.
+
+
+.^|`cayenne.server.default_types`
+.^|`List<ExtendedType>`
+.^|Stores default adapter-agnostic ExtendedTypes. Default ExtendedTypes can be overridden / extended by DB-specific DbAdapters as well as by user-provided types configured in another colltecion (see `"cayenne.server.user_types"`).
+
+
+.^|`cayenne.server.user_types`
+.^|`List<ExtendedType>`
+.^|Stores a user-provided ExtendedTypes. This collection will be merged into a full list of ExtendedTypes and would override any ExtendedTypes defined in a default list, or by a DbAdapter.
+
+
+.^|`cayenne.server.type_factories`
+.^|`List<ExtendedTypeFactory>`
+.^|Stores default and user-provided ExtendedTypeFactories. ExtendedTypeFactory allows to define ExtendedTypes dynamically for the whole group of Java classes. E.g. Cayenne supplies a factory to map all Enums regardless of their type.
+
+
+.^|`cayenne.server.rop_event_bridge_properties`
+.^|`Map<String, String>`
+.^|Stores event bridge properties passed to the ROP client on bootstrap. This means that the map is configured by server DI, and passed to the client via the wire. The properties in this map are specific to EventBridgeFactory implementation (e.g JMS or XMPP connection prameters). One common property is `"cayenne.server.rop_event_bridge_factory"` that defines the type of the factory.
+
+|===
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/7783cd34/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/var.adoc
----------------------------------------------------------------------
diff --git a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/var.adoc b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/var.adoc
new file mode 100644
index 0000000..e575eda
--- /dev/null
+++ b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/var.adoc
@@ -0,0 +1 @@
+:version: {project-version}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/7783cd34/docs/asciidoc/cayenne-guide/src/docs/asciidoc/cayenne-guide.adoc
----------------------------------------------------------------------
diff --git a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/cayenne-guide.adoc b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/cayenne-guide.adoc
new file mode 100644
index 0000000..ab8c880
--- /dev/null
+++ b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/cayenne-guide.adoc
@@ -0,0 +1,47 @@
+// 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.
+= Cayenne Guide
+:revnumber: {project-major-version} ({project-version})
+// enable section numbering, limiting depth to 2
+:sectnums:
+:sectnumlevels: 2
+// use custom header
+:cayenne-header: _cayenne_guide/header.html
+:cayenne-header-position: body
+// customize final layout
+//:linkcss:
+// base path to java code include
+:cayenne-root: {basedir}/../../..
+
+[small]#Copyright © 2011-2017 Apache Software Foundation and individual authors#
+
+.License
+[small]#_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_#
+
+[small]#_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._#
+
+include::_cayenne-guide/part1.adoc[]
+include::_cayenne-guide/part2.adoc[]
+include::_cayenne-guide/part3.adoc[]
+include::_cayenne-guide/configurationProperties.adoc[]
+include::_cayenne-guide/serviceCollections.adoc[]
+include::_cayenne-guide/expressionsBNF.adoc[]
+include::_cayenne-guide/listOfTables.adoc[]
+

http://git-wip-us.apache.org/repos/asf/cayenne/blob/7783cd34/docs/asciidoc/cayenne-guide/src/docs/asciidoc/images/ext-crypto-obj-entity.png
----------------------------------------------------------------------
diff --git a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/images/ext-crypto-obj-entity.png b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/images/ext-crypto-obj-entity.png
new file mode 100644
index 0000000..2d8c32a
Binary files /dev/null and b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/images/ext-crypto-obj-entity.png differ

http://git-wip-us.apache.org/repos/asf/cayenne/blob/7783cd34/docs/asciidoc/cayenne-guide/src/docs/asciidoc/images/re-modeler-datasource-select.png
----------------------------------------------------------------------
diff --git a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/images/re-modeler-datasource-select.png b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/images/re-modeler-datasource-select.png
new file mode 100644
index 0000000..79ada1c
Binary files /dev/null and b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/images/re-modeler-datasource-select.png differ

http://git-wip-us.apache.org/repos/asf/cayenne/blob/7783cd34/docs/asciidoc/cayenne-guide/src/docs/asciidoc/images/re-modeler-reverseengineering-dialog.png
----------------------------------------------------------------------
diff --git a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/images/re-modeler-reverseengineering-dialog.png b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/images/re-modeler-reverseengineering-dialog.png
new file mode 100644
index 0000000..8b09d07
Binary files /dev/null and b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/images/re-modeler-reverseengineering-dialog.png differ

http://git-wip-us.apache.org/repos/asf/cayenne/blob/7783cd34/docs/asciidoc/cayenne-guide/src/docs/asciidoc/images/remote-object-persistence.jpg
----------------------------------------------------------------------
diff --git a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/images/remote-object-persistence.jpg b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/images/remote-object-persistence.jpg
new file mode 100644
index 0000000..43f820d
Binary files /dev/null and b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/images/remote-object-persistence.jpg differ

http://git-wip-us.apache.org/repos/asf/cayenne/blob/7783cd34/docs/asciidoc/getting-started-guide/pom.xml
----------------------------------------------------------------------
diff --git a/docs/asciidoc/getting-started-guide/pom.xml b/docs/asciidoc/getting-started-guide/pom.xml
new file mode 100644
index 0000000..041f2bd
--- /dev/null
+++ b/docs/asciidoc/getting-started-guide/pom.xml
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  ~   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.
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-->
+
+<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/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.apache.cayenne.parents</groupId>
+        <artifactId>cayenne-asciidoc-parent</artifactId>
+        <version>3.1.3-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>getting-started-guide</artifactId>
+
+    <packaging>jar</packaging>
+    <name>getting-started-guide: AsciiDoc - Getting Started with Cayenne</name>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.asciidoctor</groupId>
+                <artifactId>asciidoctor-maven-plugin</artifactId>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.apache.cayenne.docs</groupId>
+                        <artifactId>cayenne-asciidoc-extension</artifactId>
+                        <version>${project.version}</version>
+                    </dependency>
+                </dependencies>
+
+                <executions>
+                    <!-- generate "embeddable" html content with front matter and without header/footer/styles -->
+                    <execution>
+                        <id>asciidoctor-html-web</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>process-asciidoc</goal>
+                        </goals>
+                        <configuration>
+                            <backend>html5</backend>
+                            <headerFooter>false</headerFooter> <!-- do not generate header and footer -->
+                            <outputDirectory>${project.build.directory}/tmp/</outputDirectory>
+                            <extensions>
+                                <extension>
+                                    <className>org.apache.cayenne.asciidoc.CayennePostProcessor</className>
+                                </extension>
+                            </extensions>
+                            <attributes>
+                                <toc>auto</toc>
+                            </attributes>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <!-- Move images to proper path for site -->
+            <plugin>
+                <artifactId>maven-resources-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy docs for site</id>
+                        <phase>install</phase>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>
+
+                        <configuration>
+                            <outputDirectory>${project.build.directory}/site/</outputDirectory>
+                            <resources>
+                                <resource>
+                                    <directory>${project.build.directory}/tmp/</directory>
+                                    <includes>
+                                        <include>${project.artifactId}.html</include>
+                                        <include>${project.artifactId}.toc.html</include>
+                                    </includes>
+                                </resource>
+                            </resources>
+                        </configuration>
+                    </execution>
+
+                    <execution>
+                        <id>copy images for site</id>
+                        <phase>install</phase>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>
+
+                        <configuration>
+                            <outputDirectory>${project.build.directory}/site/${project.artifactId}/images/</outputDirectory>
+                            <resources>
+                                <resource>
+                                    <directory>${project.build.directory}/tmp/images/</directory>
+                                    <filtering>true</filtering>
+                                </resource>
+                            </resources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <profiles>
+        <profile>
+            <id>assembly</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.asciidoctor</groupId>
+                        <artifactId>asciidoctor-maven-plugin</artifactId>
+                        <executions>
+                            <!-- generate standalone html help -->
+                            <execution>
+                                <id>asciidoctor-html-standalone</id>
+                                <phase>generate-resources</phase>
+                                <goals>
+                                    <goal>process-asciidoc</goal>
+                                </goals>
+                                <configuration>
+                                    <backend>html5</backend>
+                                    <sourceHighlighter>coderay</sourceHighlighter>
+                                    <embedAssets>true</embedAssets>
+                                    <attributes>
+                                        <toc>left</toc>
+                                    </attributes>
+                                </configuration>
+                            </execution>
+
+                            <!-- generate PDF -->
+                            <execution>
+                                <id>generate-pdf-doc</id>
+                                <phase>generate-resources</phase>
+                                <goals>
+                                    <goal>process-asciidoc</goal>
+                                </goals>
+                                <configuration>
+                                    <backend>pdf</backend>
+                                    <sourceHighlighter>coderay</sourceHighlighter>
+                                    <attributes>
+                                        <pagenums/>
+                                        <toc/>
+                                    </attributes>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+
+</project>
\ No newline at end of file


Mime
View raw message