You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2018/01/04 16:01:27 UTC

[13/14] cayenne git commit: Switch documentation from Docbook to Asciidoctor format

http://git-wip-us.apache.org/repos/asf/cayenne/blob/df1324e4/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/customize.adoc
----------------------------------------------------------------------
diff --git a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/customize.adoc b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/customize.adoc
new file mode 100644
index 0000000..1b2001d
--- /dev/null
+++ b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/customize.adoc
@@ -0,0 +1,498 @@
+// 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.
+
+[[customize]]
+=== Customizing Cayenne Runtime
+
+==== Dependency Injection Container
+
+Cayenne runtime is built around a small powerful dependency injection (DI) container. Just like other popular DI technologies, such as Spring or Guice, Cayenne DI container manages sets of interdependent objects and allows users to configure them. These objects are regular Java objects. We are calling them "services" in this document to distinguish from all other objects that are not configured in the container and are not managed. DI container is responsible for service instantiation, injecting correct dependencies, maintaining service instances scope, and dispatching scope events to services.
+
+The services are configured in special Java classes called "modules". Each module defines binding of service interfaces to implementation instances, implementation types or providers of implementation instances. There are no XML configuration files, and all the bindings are type-safe. The container supports injection into instance variables and constructor parameters based on the @Inject annotation. This mechanism is very close to Google Guice.
+
+The discussion later in this chapter demonstrates a standalone DI container. But keep in mind that Cayenne already has a built-in Injector, and a set of default modules. A Cayenne user would normally only use the API below to write custom extension modules that will be loaded in that existing container when creating ServerRuntime. See "Starting and Stopping ServerRuntime" chapter for an example of passing an extension module to Cayenne.
+
+Cayenne DI probably has ~80% of the features expected in a DI container and has no dependency on the rest of Cayenne, so in theory can be used as an application-wide DI engine. But it's primary purpose is still to serve Cayenne. Hence there are no plans to expand it beyond Cayenne needs. It is an ideal "embedded" DI that does not interfere with Spring, Guice or any other such framework present elsewhere in the application.
+
+===== DI Bindings API
+
+To have a working DI container, we need three things: service interfaces and classes, a module that describes service bindings, a container that loads the module, and resolves the depedencies. Let's start with service interfaces and classes:
+
+[source, Java]
+----
+public interface Service1 {
+    public String getString();
+}
+----
+
+[source, Java]
+----
+public interface Service2 {
+    public int getInt();
+}
+----
+
+A service implementation using instance variable injection:
+
+[source, Java]
+----
+public class Service1Impl implements Service1 {
+    @Inject
+    private Service2 service2;
+
+    public String getString() {
+        return service2.getInt() + "_Service1Impl";
+    }
+}
+----
+
+Same thing, but using constructor injection:
+
+[source, Java]
+----
+public class Service1Impl implements Service1 {
+
+    private Service2 service2;
+
+    public Service1Impl(@Inject Service2 service2) {
+        this.service2 = service2;
+    }
+
+    public String getString() {
+        return service2.getInt() + "_Service1Impl";
+    }
+}
+----
+
+[source, Java]
+----
+public class Service2Impl implements Service2 {
+    private int i;
+
+    public int getInt() {
+        return i++;
+    }
+}
+----
+
+Now let's create a module implementing `org.apache.cayenne.tutorial.di.Module` interface that will contain DI configuration. A module binds service objects to keys that are reference. Binder provided by container implements fluent API to connect the key to implementation, and to configure various binding options (the options, such as scope, are demonstrated later in this chapter). The simplest form of a key is a Java Class object representing service interface. Here is a module that binds Service1 and Service2 to corresponding default implementations:
+
+[source, Java]
+----
+public class Module1 implements Module {
+
+    public void configure(Binder binder) {
+        binder.bind(Service1.class).to(Service1Impl.class);
+        binder.bind(Service2.class).to(Service2Impl.class);
+    }
+}
+----
+
+Once we have at least one module, we can create a DI container. `org.apache.cayenne.di.Injector` is the container class in Cayenne:
+
+[source, Java]
+----
+Injector injector = DIBootstrap.createInjector(new Module1());
+----
+
+Now that we have created the container, we can obtain services from it and call their methods:
+
+[source, Java]
+----
+Service1 s1 = injector.getInstance(Service1.class);
+for (int i = 0; i < 5; i++) {
+    System.out.println("S1 String: " + s1.getString());
+}
+----
+
+This outputs the following lines, demonstrating that s1 was Service1Impl and Service2 injected into it was Service2Impl:
+
+[source]
+----
+0_Service1Impl
+1_Service1Impl
+2_Service1Impl
+3_Service1Impl
+4_Service1Impl
+----
+
+There are more flavors of bindings:
+
+[source, Java]
+----
+// binding to instance - allowing user to create and configure instance
+// inside the module class
+binder.bind(Service2.class).toInstance(new Service2Impl());
+
+// binding to provider - delegating instance creation to a special
+// provider class
+binder.bind(Service1.class).toProvider(Service1Provider.class);
+
+// binding to provider instance
+binder.bind(Service1.class).toProviderInstance(new Service1Provider());
+
+// multiple bindings of the same type using Key
+// injection can reference the key name in annotation:
+// @Inject("i1")
+// private Service2 service2;
+binder.bind(Key.get(Service2.class, "i1")).to(Service2Impl.class);
+binder.bind(Key.get(Service2.class, "i2")).to(Service2Impl.class);
+----
+
+
+Another types of confiuguration that can be bound in the container are lists and maps. They will be discussed in the following chapters.
+
+===== Service Lifecycle
+
+An important feature of the Cayenne DI container is instance scope. The default scope (implicitly used in all examples above)
+is "singleton", meaning that a binding would result in creation of only one service instance, that will be repeatedly returned from `Injector.getInstance(..)`,
+as well as injected into classes that declare it as a dependency.
+
+Singleton scope dispatches a "BeforeScopeEnd" event to interested services. This event occurs before the scope is shutdown,
+i.e. when `Injector.shutdown()` is called. Note that the built-in Cayenne injector is shutdown behind the scenes when `ServerRuntime.shutdown()` is invoked.
+Services may register as listeners for this event by annotating a no-argument method with `@BeforeScopeEnd` annotation.
+Such method should be implemented if a service needs to clean up some resources, stop threads, etc.
+
+Another useful scope is "no scope", meaning that every time a container is asked to provide a service instance for a given key, a new instance will be created and returned:
+
+[source, Java]
+----
+binder.bind(Service2.class).to(Service2Impl.class).withoutScope();
+----
+
+Users can also create their own scopes, e.g. a web application request scope or a session scope. Most often than not custom scopes
+can be created as instances of `org.apache.cayenne.di.spi.DefaultScope` with startup and shutdown managed by the application
+(e.g. singleton scope is a DefaultScope managed by the Injector) .
+
+===== Overriding Services
+
+Cayenne DI allows to override services already definied in the current module, or more commonly - some other module
+in the the same container. Actually there's no special API to override a service, you'd just bind the service key again
+with a new implementation or provider. The last binding for a key takes precedence. This means that the order of modules is important when configuring a container.
+The built-in Cayenne injector ensures that Cayenne standard modules are loaded first, followed by optional user extension modules.
+This way the application can override the standard services in Cayenne.
+
+==== Customization Strategies
+
+The previous section discussed how Cayenne DI works in general terms. Since Cayenne users will mostly be dealing with
+an existing Injector provided by ServerRuntime, it is important to understand how to build custom extensions to a preconfigured container.
+As shown in "Starting and Stopping ServerRuntime" chapter, custom extensions are done by writing an application
+DI module (or multiple modules) that configures service overrides. This section shows all the configuration possibilities in detail,
+including changing properties of the existing services, contributing services to standard service lists and maps, and overriding service implementations.
+All the code examples later in this section are assumed to be placed in an application module "configure" method:
+
+[source, Java]
+----
+public class MyExtensionsModule implements Module {
+    public void configure(Binder binder) {
+        // customizations go here...
+    }
+}
+----
+
+[source, Java]
+----
+Module extensions = new MyExtensionsModule();
+ServerRuntime runtime = ServerRuntime.builder()
+        .addConfig("com/example/cayenne-mydomain.xml")
+        .addModule(extensions)
+        .build();
+----
+
+===== Changing Properties of Existing Services
+
+Many built-in Cayenne services change their behavior based on a value of some environment property.
+A user may change Cayenne behavior without even knowing which services are responsible for it, but setting a specific value of a known property.
+Supported property names are listed in "Appendix A".
+
+There are two ways to set service properties. The most obvious one is to pass it to the JVM with -D flag on startup. E.g.
+
+[source]
+----
+$ java -Dcayenne.server.contexts_sync_strategy=false ...
+----
+
+A second one is to contribute a property to `o.a.c.configuration.DefaultRuntimeProperties.properties` map (see the next section on how to do that).
+This map contains the default property values and can accept application-specific values, overrding the defaults.
+
+Note that if a property value is a name of a Java class, when this Java class is instantiated by Cayenne,
+the container performs injection of instance variables. So even the dynamically specified Java classes can use @Inject annotation to get a hold of other Cayenne services.
+
+If the same property is specified both in the command line and in the properties map, the command-line value takes precedence.
+The map value will be ignored. This way Cayenne runtime can be reconfigured during deployment.
+
+===== Contributing to Service Collections
+
+Cayenne can be extended by adding custom objects to named maps or lists bound in DI. We are calling these lists/maps "service collections".
+A service collection allows things like appending a custom strategy to a list of built-in strategies.
+E.g. an application that needs to install a custom DbAdapter for some database type may contribute an instance of custom
+DbAdapterDetector to a `o.a.c.configuration.server.DefaultDbAdapterFactory.detectors` list:
+
+[source, Java]
+----
+public class MyDbAdapterDetector implements DbAdapterDetector {
+    public DbAdapter createAdapter(DatabaseMetaData md) throws SQLException {
+        // check if we support this database and retun custom adapter
+        ...
+    }
+}
+----
+
+[source, Java]
+----
+// since build-in list for this key is a singleton, repeated
+// calls to 'bindList' will return the same instance
+binder.bindList(DefaultDbAdapterFactory.DETECTORS_LIST)
+       .add(MyDbAdapterDetector.class);
+----
+
+Maps are customized using a similar `"bindMap"` method.
+
+The names of built-in collections are listed in "Appendix B".
+
+===== Alternative Service Implementations
+
+As mentioned above, custom modules are loaded by ServerRuntime after the built-in modules. So it is easy to redefine a built-in service in Cayenne by rebinding desired implementations or providers. To do that, first we need to know what those services to redefine are. While we describe some of them in the following sections, the best way to get a full list is to check the source code of the Cayenne version you are using and namely look in `org.apache.cayenne.configuration.server.ServerModule` - the main built-in module in Cayenne.
+
+Now an example of overriding `QueryCache` service. The default implementation of this service is provided by `MapQueryCacheProvider`. But if we want to use `EhCacheQueryCache` (a Cayenne wrapper for the EhCache framework), we can define it like this:
+
+[source, Java]
+----
+binder.bind(QueryCache.class).to(EhCacheQueryCache.class);
+----
+
+==== Using custom data types
+
+===== Value object type
+
+`ValueObjectType` is a new and lightweight alternative to the Extended Types API described in the following section. In most cases is should be preferred as is it easier to understand and use. Currently only one case is known when `ExtendedType` should be used: when your value object can be mapped on different JDBC types.
+
+In order to use your custom data type you should implement `ValueObjectType` describing it in terms of some type already known to Cayenne (e.g. backed by system or user ExtendedType). Let's assume we want to support some data type called `Money`:
+
+[source, Java]
+----
+public class Money {
+    private BigDecimal value;
+
+    public Money(BigDecimal value) {
+        this.value = value;
+    }
+
+    public BigDecimal getValue() {
+        return value;
+    }
+
+    // .. some other business logic ..
+}
+----
+
+Here is how `ValueObjectType` that will allow to store our `Money` class as `BigDecimal` can be implemented:
+
+[source, Java]
+----
+public class MoneyValueObjectType implements ValueObjectType<Money, BigDecimal> {
+
+    @Override
+    public Class<BigDecimal> getTargetType() {
+        return BigDecimal.class;
+    }
+
+    @Override
+    public Class<Money> getValueType() {
+        return Money.class;
+    }
+
+    @Override
+    public Money toJavaObject(BigDecimal value) {
+        return new Money(value);
+    }
+
+    @Override
+    public BigDecimal fromJavaObject(Money object) {
+        return object.getValue();
+    }
+
+    @Override
+    public String toCacheKey(Money object) {
+        return object.getValue().toString();
+    }
+}
+----
+
+Last step is to register this new type in `ServerRuntime`:
+
+[source, Java]
+----
+ServerRuntime runtime = ServerRuntime.builder()
+    .addConfig("cayenne-project.xml")
+    .addModule(binder -> ServerModule.contributeValueObjectTypes(binder).add(MoneyValueObjectType.class))
+    .build();
+----
+
+More examples of implementation you can find in https://github.com/apache/cayenne/tree/master/cayenne-joda[cayenne-joda module].
+
+===== Extended Types
+
+JDBC specification defines a set of "standard" database column types (defined in java.sql.Types class) and a very specific mapping of these types to Java Object Types, such as java.lang.String, java.math.BigDecimal, etc. Sometimes there is a need to use a custom Java type not known to JDBC driver and Cayenne allows to configure it. For this Cayenne needs to know how to instantiate this type from a database "primitive" value, and conversely, how to transform an object of the custom type to a JDBC-compatible object.
+
+====== Supporting Non-Standard Types
+
+For supporting non-standard type you should define it via an interface `org.apache.cayenne.access.types.ExtendedType`. An implementation must provide `ExtendedType.getClassName()` method that returns a fully qualified Java class name for the supported custom type, and a number of methods that convert data between JDBC and custom type. The following example demonstrates how to add a custom DoubleArrayType to store `java.lang.Double[]` as a custom string in a database:
+
+[source, Java]
+----
+/**
+* Defines methods to read Java objects from JDBC ResultSets and write as parameters of
+* PreparedStatements.
+*/
+public class DoubleArrayType implements ExtendedType {
+
+    private final String SEPARATOR = ",";
+
+    /**
+    * Returns a full name of Java class that this ExtendedType supports.
+    */
+    @Override
+    public String getClassName() {
+        return Double[].class.getCanonicalName();
+    }
+
+    /**
+    * Initializes a single parameter of a PreparedStatement with object value.
+    */
+    @Override
+    public void setJdbcObject(PreparedStatement statement, Object value,
+            int pos, int type, int scale) throws Exception {
+
+        String str = StringUtils.join((Double[]) value, SEPARATOR);
+        statement.setString(pos, str);
+    }
+
+
+    /**
+    * Reads an object from JDBC ResultSet column, converting it to class returned by
+    * 'getClassName' method.
+    *
+    * @throws Exception if read error occurred, or an object can't be converted to a
+    *             target Java class.
+    */
+    @Override
+    public Object materializeObject(ResultSet rs, int index, int type) throws Exception {
+        String[] str = rs.getString(index).split(SEPARATOR);
+        Double[] res = new Double[str.length];
+
+        for (int i = 0; i < str.length; i++) {
+            res[i] = Double.valueOf(str[i]);
+        }
+
+        return res;
+    }
+
+    /**
+    * Reads an object from a stored procedure OUT parameter, converting it to class
+    * returned by 'getClassName' method.
+    *
+    * @throws Exception if read error ocurred, or an object can't be converted to a
+    *             target Java class.
+    */
+    @Override
+    public Object materializeObject(CallableStatement rs, int index, int type) throws Exception {
+        String[] str = rs.getString(index).split(SEPARATOR);
+        Double[] res = new Double[str.length];
+
+        for (int i = 0; i < str.length; i++) {
+            res[i] = Double.valueOf(str[i]);
+        }
+
+        return res;
+    }
+}
+----
+
+//For Java7
+//
+//[source, Java]
+//----
+// add DoubleArrayType to list of user types
+//ServerRuntime runtime = ServerRuntime.builder()
+//                .addConfig("cayenne-project.xml")
+//                .addModule(new Module() {
+//                    @Override
+//                    public void configure(Binder binder) {
+//                        ServerModule.contributeUserTypes(binder).add(new DoubleArrayType());
+//                    }
+//                })
+//                .build();
+//----
+
+
+[source, Java]
+----
+// add DoubleArrayType to list of user types
+ServerRuntime runtime = ServerRuntime.builder()
+                .addConfig("cayenne-project.xml")
+                .addModule(binder -> ServerModule.contributeUserTypes(binder).add(new DoubleArrayType()))
+                .build();
+----
+
+====== DbAdapters and Extended Types
+
+As shown in the example above, ExtendedTypes are stored by DbAdapter. In fact DbAdapters often install their own extended types to address incompatibilities, incompleteness and differences between JDBC drivers in handling "standard" JDBC types. For instance some drivers support reading large character columns (CLOB) as java.sql.Clob, but some other - as "character stream", etc. Adapters provided with Cayenne override `configureExtendedTypes()` method to install their own types, possibly substituting Cayenne defaults. Custom DbAdapters can use the same technique.
+
+==== Noteworthy Built-in Services
+
+===== JdbcEventLogger
+
+`org.apache.cayenne.log.JdbcEventLogger` is the service that defines logging API for Cayenne internals. It provides facilities for logging queries, commits, transactions, etc. The default implementation is `org.apache.cayenne.log.Slf4jJdbcEventLogger` that performs logging via slf4j-api library. Cayenne library includes another potentially useful logger - `org.apache.cayenne.log.FormattedSlf4jJdbcEventLogger` that produces formatted multiline SQL output that can be easier to read.
+
+===== DataSourceFactory
+
+Factory that returns `javax.sql.DataSource` object based on the configuration provided in the "nodeDescriptor".
+
+===== DataChannelFilter
+
+An interface of a filter that allows to intercept DataChannel operations. Filters allow to implement chains of custom processors around a DataChannel, that can be used for security, monitoring, business logic, providing context to lifecycle event listeners, etc.
+
+===== QueryCache
+
+Defines API of a cache that stores query results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

http://git-wip-us.apache.org/repos/asf/cayenne/blob/df1324e4/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/expressions.adoc
----------------------------------------------------------------------
diff --git a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/expressions.adoc b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/expressions.adoc
new file mode 100644
index 0000000..8e443d8
--- /dev/null
+++ b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/expressions.adoc
@@ -0,0 +1,324 @@
+// 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.
+[[expressions]]
+=== Expressions
+
+==== Expressions Overview
+
+Cayenne provides a simple yet powerful object-based expression language. The most common use of expressions are to build
+qualifiers and orderings of queries that are later converted to SQL by Cayenne and to evaluate in-memory against specific
+objects (to access certain values in the object graph or to perform in-memory object filtering and sorting).
+Cayenne provides API to build expressions in the code and a parser to create expressions from strings.
+
+==== Path Expressions
+
+Before discussing how to build expressions, it is important to understand one group of expressions widely used
+in Cayenne - path expressions. There are two types of path expressions - object and database, used for navigating graphs
+of connected objects or joined DB tables respectively. Object paths are much more commonly used, as after all
+Cayenne is supposed to provide a degree of isolation of the object model from the database. However database paths
+are helpful in certain situations. General structure of path expressions is the following:
+
+[source, java]
+----
+ [db:]segment[+][.segment[+]...]
+----
+
+- `db:` is an optional prefix indicating that the following path is a DB path. Otherwise it is an object path.
+
+- `segment` is a name of a property (relationship or attribute in Cayenne terms) in the path. Path must have at least one segment; segments are separated by dot (".").
+
+- `+` An "OUTER JOIN" path component. Currently "+" only has effect when translated to SQL as OUTER JOIN. When evaluating expressions in memory, it is ignored.
+
+An object path expression represents a chain of property names rooted in a certain (unspecified during expression creation) object and "navigating" to its related value.
+E.g. a path expression "artist.name" might be a property path starting from a Painting object, pointing to the related Artist object, and then to its name attribute. A few more examples:
+
+- `name` - can be used to navigate (read) the "name" property of a Person (or any other type of object that has a "name" property).
+
+- `artist.exhibits.closingDate` - can be used to navigate to a closing date of any of the exhibits of a Painting's Artist object.
+
+- `artist.exhibits+.closingDate` - same as the previous example, but when translated into SQL, an OUTER JOIN will be used for "exhibits".
+
+Similarly a database path expression is a dot-separated path through DB table joins and columns.
+In Cayenne joins are mapped as DbRelationships with some symbolic names (the closest concept to DbRelationship name in the DB world
+is a named foreign key constraint. But DbRelationship names are usually chosen arbitrarily,
+without regard to constraints naming or even constraints presence).
+A database path therefore might look like this - `db:dbrelationshipX.dbrelationshipY.COLUMN_Z"`. More specific examples:
+
+- `db:NAME` - can be used to navigate to the value of "NAME" column of some unspecified table.
+
+- `db:artist.artistExhibits.exhibit.CLOSING_DATE` - can be used to match a closing date of any of the exhibits of a related artist record.
+
+Cayenne supports "aliases" in path Expressions. E.g. the same expression can be written using explicit path or an alias:
+
+- `artist.exhibits.closingDate` - full path
+
+- `e.closingDate` - alias "e" is used for `artist.exhibits`.
+
+SelectQuery using the second form of the path expression must be made aware of the alias via `SelectQuery.aliasPathSplits(..)`,
+otherwise an Exception will be thrown.
+The main use of aliases is to allow users to control how SQL joins are generated if the same path is encountered more than once in any given Expression.
+Each alias for any given path would result in a separate join. Without aliases, a single join will be used for a group of matching paths.
+
+==== Creating Expressions from Strings
+
+While in most cases users are likely to rely on API from the following section for expression creation, we'll start by showing String expressions,
+as this will help to understand the semantics. A Cayenne expression can be represented as a String,
+which can be converted to an expression object using `ExpressionFactory.exp` static method. Here is an example:
+
+
+[source, java]
+----
+String expString = "name like 'A%' and price < 1000";
+Expression exp = ExpressionFactory.exp(expString);
+----
+
+This particular expression may be used to match Paintings whose names that start with "A" and whose price is less than $1000.
+While this example is pretty self-explanatory, there are a few points worth mentioning. "name" and "price" here are object paths discussed earlier.
+As always, paths themselves are not attached to a specific root entity and can be applied to any entity that has similarly named attributes or relationships.
+So when we are saying that this expression "may be used to match Paintings", we are implying that there may be other entities, for which this expression is valid.
+Now the expression details...
+
+Character constants that are not paths or numeric values should be enclosed in single or double quotes. Two of the expressions below are equivalent:
+
+[source, java]
+----
+name = 'ABC'
+
+// double quotes are escaped inside Java Strings of course
+name = \"ABC\"
+----
+
+Case sensitivity. Expression operators are case sensitive and are usually lowercase. Complex words follow the Java camel-case style:
+
+[source, java]
+----
+// valid
+name likeIgnoreCase 'A%'
+
+// invalid - will throw a parse exception
+name LIKEIGNORECASE 'A%'
+----
+
+Grouping with parenthesis:
+
+
+[source, java]
+----
+value = (price + 250.00) * 3
+----
+
+Path prefixes. Object expressions are unquoted strings, optionally prefixed by `obj:` (usually they are not prefixed at all actually).
+Database expressions are always prefixed with `db:`. A special kind of prefix, not discussed yet is `enum:` that prefixes an enumeration constant:
+
+[source, java]
+----
+// object path
+name = 'Salvador Dali'
+
+// same object path - a rarely used form
+obj:name = 'Salvador Dali'
+
+// multi-segment object path
+artist.name = 'Salvador Dali'
+
+// db path
+db:NAME = 'Salvador Dali'
+
+// enumeration constant
+name = enum:org.foo.EnumClass.VALUE1
+----
+
+Binary conditions are expressions that contain a path on the left, a value on the right, and some operation between them, such as equals, like, etc.
+They can be used as qualifiers in SelectQueries:
+
+[source, java]
+----
+name like 'A%'
+----
+
+
+Parameters. Expressions can contain named parameters (names that start with "$") that can be substituted with values either by name or by position.
+Parameterized expressions allow to create reusable expression templates. Also if an Expression contains a complex object that doesn't have a simple
+String representation (e.g. a Date, a DataObject, an ObjectId), parameterizing such expression is the only way to represent it as String.
+Here are the examples of both positional and named parameter bindings:
+
+[source, java]
+----
+Expression template = ExpressionFactory.exp("name = $name");
+...
+// name binding
+Map p1 = Collections.singletonMap("name", "Salvador Dali");
+Expression qualifier1 = template.params(p1);
+...
+// positional binding
+Expression qualifier2 = template.paramsArray("Monet");
+----
+
+Positional binding is usually shorter. You can pass positional bindings to the `exp(..)` factory method (its second argument is a params vararg):
+
+[source, java]
+----
+Expression qualifier = ExpressionFactory.exp("name = $name", "Monet");
+----
+
+In parameterized expressions with LIKE clause, SQL wildcards must be part of the values in the Map and not the expression string itself:
+
+[source, java]
+----
+Expression qualifier = ExpressionFactory.exp("name like $name", "Salvador%");
+----
+
+When matching on a relationship, the value parameter must be either a Persistent object, an `org.apache.cayenne.ObjectId`, or a numeric ID value (for single column IDs). E.g.:
+
+[source, java]
+----
+Artist dali = ... // asume we fetched this one already
+Expression qualifier = ExpressionFactory.exp("artist = $artist", dali);
+----
+
+When using positional binding, Cayenne would expect values for all parameters to be present. Binding by name offers extra flexibility:
+subexpressions with uninitialized parameters are automatically pruned from the expression.
+So e.g. if certain parts of the expression criteria are not provided to the application, you can still build a valid expression:
+
+
+[source, java]
+----
+Expression template = ExpressionFactory.exp("name like $name and dateOfBirth > $date");
+...
+Map p1 = Collections.singletonMap("name", "Salvador%");
+Expression qualifier1 = template.params(p1);
+
+// "qualifier1" is now "name like 'Salvador%'".
+// 'dateOfBirth > $date' condition was pruned, as no value was specified for
+// the $date parameter
+----
+
+Null handling. Handling of Java nulls as operands is no different from normal values. Instead of using special conditional operators,
+like SQL does (`IS NULL`, `IS NOT NULL`), "=" and "!=" expressions are used directly with null values. It is up to Cayenne to translate expressions with nulls to the valid SQL.
+
+
+NOTE: A formal definition of the expression grammar is provided in xref:appendixC[Appendix C]
+
+==== Creating Expressions via API
+
+Creating expressions from Strings is a powerful and dynamic approach, however a safer alternative is to use Java API.
+It provides compile-time checking of expressions validity. The API in question is provided by `ExpressionFactory` class (that we've seen already),
+Property class and Expression class itself. `ExpressionFactory` contains a number of self-explanatory static methods that can be used to build expressions. E.g.:
+
+[source, java]
+----
+// String expression: name like 'A%' and price < 1000
+Expression e1 = ExpressionFactory.likeExp("name", "A%");
+Expression e2 = ExpressionFactory.lessExp("price", 1000);
+Expression finalExp = e1.andExp(e2);
+----
+
+NOTE: The last line in the example above shows how to create a new expression by "chaining" two other expressions.
+A common error when chaining expressions is to assume that "andExp" and "orExp" append another expression to the current expression.
+In fact a new expression is created. I.e. Expression API treats existing expressions as immutable.
+
+As discussed earlier, Cayenne supports aliases in path Expressions, allowing to control how SQL joins are generated
+if the same path is encountered more than once in the same Expression. Two ExpressionFactory methods allow to implicitly generate aliases to "split" match paths into individual joins if needed:
+
+[source, java]
+----
+Expression matchAllExp(String path, Collection values)
+Expression matchAllExp(String path, Object... values)
+----
+
+"Path" argument to both of these methods can use a split character (a pipe symbol '|') instead of dot to indicate that relationship
+following a path should be split into a separate set of joins, one per collection value. There can only be one split at most in any given path.
+Split must always precede a relationship. E.g. `"|exhibits.paintings"`, `"exhibits|paintings"`, etc.
+Internally Cayenne would generate distinct aliases for each of the split expressions, forcing separate joins.
+
+While ExpressionFactory is pretty powerful, there's an even easier way to create expression using static Property objects generated by Cayenne for each persistent class.
+Some examples:
+
+[source, java]
+----
+// Artist.NAME is generated by Cayenne and has a type of Property<String>
+Expression e1 = Artist.NAME.eq("Pablo");
+
+// Chaining multiple properties into a path..
+// Painting.ARTIST is generated by Cayenne and has a type of Property<Artist>
+Expression e2 = Painting.ARTIST.dot(Artist.NAME).eq("Pablo");
+----
+
+Property objects provide the API mostly analogius to ExpressionFactory, though it is significantly shorter and is aware of the value types.
+It provides compile-time checks of both property names and types of arguments in conditions. We will use Property-based API in further examples.
+
+[[evaluete]]
+==== Evaluating Expressions in Memory
+
+When used in a query, an expression is converted to SQL WHERE clause (or ORDER BY clause) by Cayenne during query execution.
+Thus the actual evaluation against the data is done by the database engine. However the same expressions can also be used
+for accessing object properties, calculating values, in-memory filtering.
+
+
+Checking whether an object satisfies an expression:
+
+[source, java]
+----
+Expression e = Artist.NAME.in("John", "Bob");
+Artist artist = ...
+if(e.match(artist)) {
+   ...
+}
+----
+
+Reading property value:
+
+
+[source, java]
+----
+String name = Artist.NAME.path().evaluate(artist);
+----
+
+Filtering a list of objects:
+
+[source, java]
+----
+Expression e = Artist.NAME.in("John", "Bob");
+List<Artist> unfiltered = ...
+List<Artist> filtered = e.filterObjects(unfiltered);
+----
+
+
+NOTE: Current limitation of in-memory expressions is that no collections are permitted in the property path.
+
+==== Translating Expressions to EJBQL
+
+xref:ejbql[EJBQL] is a textual query language that can be used with Cayenne. In some situations,
+it is convenient to be able to convert Expression instances into EJBQL. Expressions support this conversion. An example is shown below.
+
+[source, java]
+----
+String serial = ...
+Expression e = Pkg.SERIAL.eq(serial);
+List<Object> params = new ArrayList<Object>();
+EJBQLQuery query = new EJBQLQuery("SELECT p FROM Pkg p WHERE " + e.toEJBQL(params,"p");
+
+for(int i=0;i<params.size();i++) {
+  query.setParameter(i+1, params.get(i));
+}
+----
+
+This would be equivalent to the following purely EJBQL querying logic;
+
+[source, java]
+----
+EJBQLQuery query = new EJBQLQuery("SELECT p FROM Pkg p WHERE p.serial = ?1");
+query.setParameter(1,serial);
+----
+

http://git-wip-us.apache.org/repos/asf/cayenne/blob/df1324e4/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/including.adoc
----------------------------------------------------------------------
diff --git a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/including.adoc b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/including.adoc
new file mode 100644
index 0000000..4227b85
--- /dev/null
+++ b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/including.adoc
@@ -0,0 +1,663 @@
+// 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.
+
+include::../var.adoc[]
+
+[[include]]
+=== Including Cayenne in a Project
+
+==== Jar Files
+
+This is an overview of Cayenne jars that is agnostic of the build tool used. The following are the important libraries:
+
+- `cayenne-di-{version}.jar` - Cayenne dependency injection (DI) container library. All applications will require this file.
+
+- `cayenne-server-{version}.jar` - contains main Cayenne runtime (adapters, DB access classes, etc.). Most applications will require this file.
+
+- `cayenne-client-{version}.jar` - a client-side runtime for xref:rop[ROP applications].
+
+- Other cayenne-* jars - various Cayenne tools extensions.
+
+==== Dependencies
+
+With modern build tools like Maven and Gradle, you should not worry about tracking dependencies. If you have one of those, you can skip this section and go straight to the Maven section below. However if your environment requires manual dependency resolution (like Ant), the distribution provides all of Cayenne jars plus a minimal set of third-party dependencies to get you started in a default configuration. Check lib and `lib/third-party` folders for those.
+
+Dependencies for non-standard configurations will need to be figured out by the users on their own. Check `pom.xml` files of the corresponding Cayenne modules in one of the searchable Maven archives out there to get an idea of those dependencies (e.g. http://search.maven.org).
+
+==== Maven Projects
+
+If you are using Maven, you won't have to deal with figuring out the dependencies. You can simply include cayenne-server artifact in your POM:
+
+[source,xml,subs="verbatim,attributes"]
+----
+<dependency>
+   <groupId>org.apache.cayenne</groupId>
+   <artifactId>cayenne-server</artifactId>
+   <version>{version}</version>
+</dependency>
+----
+
+Additionally Cayenne provides a Maven plugin with a set of goals to perform various project tasks, such as synching generated Java classes with the mapping, described in the following subsection. The full plugin name is `org.apache.cayenne.plugins:cayenne-maven-plugin`.
+
+[[cgen]]
+===== cgen
+
+`cgen` is a `cayenne-maven-plugin` goal that generates and maintains source (.java) files of persistent objects based on a DataMap. By default, it is bound to the generate-sources phase. If "makePairs" is set to "true" (which is the recommended default), this task will generate a pair of classes (superclass/subclass) for each ObjEntity in the DataMap. Superclasses should not be changed manually, since they are always overwritten. Subclasses are never overwritten and may be later customized by the user. If "makePairs" is set to "false", a single class will be generated for each ObjEntity.
+
+By creating custom templates, you can use cgen to generate other output (such as web pages, reports, specialized code templates) based on DataMap information.
+
+[#tablecgen.table.table-bordered]
+.cgen required parameters
+[cols="1,1,4"]
+|===
+|Name |Type|Description
+
+.^|map
+.^|File
+a|DataMap XML file which serves as a source of metadata for class generation. E.g.
+[source]
+----
+${project.basedir}/src/main/resources/my.map.xml
+----
+|===
+
+
+[#cgenOptional.table.table-bordered]
+.cgen optional parameters
+[cols="2,1,5"]
+|===
+|Name |Type|Description
+
+.^|additionalMaps
+.^|File
+.^|A directory that contains additional DataMap XML files that may be needed to resolve cross-DataMap relationships for the the main DataMap, for which class generation occurs.
+
+.^|client
+.^|boolean
+.^|Whether we are generating classes for the client tier in a Remote Object Persistence application. "False" by default.
+
+.^|destDir
+.^|File
+.^|Root destination directory for Java classes (ignoring their package names). The default is "src/main/java".
+
+.^|embeddableTemplate
+.^|String
+.^|Location of a custom Velocity template file for Embeddable class generation. If omitted, default template is used.
+
+.^|embeddableSuperTemplate
+.^|String
+.^|Location of a custom Velocity template file for Embeddable superclass generation. Ignored unless "makepairs" set to "true". If omitted, default template is used.
+
+.^|encoding
+.^|String
+.^|Generated files encoding if different from the default on current platform. Target encoding must be supported by the JVM running the build. Standard encodings supported by Java on all platforms are US-ASCII, ISO-8859-1, UTF-8, UTF-16BE, UTF-16LE, UTF-16. See javadocs for java.nio.charset.Charset for more information.
+
+.^|excludeEntities
+.^|String
+.^|A comma-separated list of ObjEntity patterns (expressed as a perl5 regex) to exclude from template generation. By default none of the DataMap entities are excluded.
+
+.^|includeEntities
+.^|String
+.^|A comma-separated list of ObjEntity patterns (expressed as a perl5 regex) to include from template generation. By default all DataMap entities are included.
+
+.^|makePairs
+.^|boolean
+.^|If "true" (a recommended default), will generate subclass/superclass pairs, with all generated code placed in superclass.
+
+.^|mode
+.^|String
+.^|Specifies class generator iteration target. There are three possible values: "entity" (default), "datamap", "all". "entity" performs one generator iteration for each included ObjEntity, applying either standard to custom entity templates. "datamap" performs a single iteration, applying DataMap templates. "All" is a combination of entity and datamap.
+
+.^|overwrite
+.^|boolean
+.^|Only has effect when "makePairs" is set to "false". If "overwrite" is "true", will overwrite older versions of generated classes.
+
+.^|superPkg
+.^|String
+.^|Java package name of all generated superclasses. If omitted, each superclass will be placed in the subpackage of its subclass called "auto". Doesn't have any effect if either "makepairs" or "usePkgPath" are false (both are true by default).
+
+.^|superTemplate
+.^|String
+.^|Location of a custom Velocity template file for ObjEntity superclass generation. Only has effect if "makepairs" set to "true". If omitted, default template is used.
+
+.^|template
+.^|String
+.^|Location of a custom Velocity template file for ObjEntity class generation. If omitted, default template is used.
+
+.^|usePkgPath
+.^|boolean
+.^|If set to "true" (default), a directory tree will be generated in "destDir" corresponding to the class package structure, if set to "false", classes will be generated in "destDir" ignoring their package.
+
+.^|createPropertyNames
+.^|boolean
+.^|If set to "true", will generate String Property names. Default is "false"
+|===
+
+Example - a typical class generation scenario, where pairs of classes are generated with default Maven source destination and superclass package:
+
+[source,xml,subs="verbatim,attributes"]
+----
+<plugin>
+    <groupId>org.apache.cayenne.plugins</groupId>
+    <artifactId>cayenne-maven-plugin</artifactId>
+    <version>{project-version}</version>
+
+    <configuration>
+        <map>${project.basedir}/src/main/resources/my.map.xml</map>
+    </configuration>
+
+    <executions>
+        <execution>
+            <goals>
+                <goal>cgen</goal>
+            </goals>
+        </execution>
+    </executions>
+</plugin>
+----
+
+===== cdbgen
+
+`cdbgen` is a `cayenne-maven-plugin` goal that drops and/or generates tables in a database on Cayenne DataMap. By default, it is bound to the pre-integration-test phase.
+
+[#cdbgenTable.table.table-bordered]
+.cdbgen required parameters
+[cols="1,1,4"]
+|===
+|Name |Type|Description
+
+.^|map
+.^|File
+a|DataMap XML file which serves as a source of metadata for class generation. E.g.
+[source]
+----
+${project.basedir}/src/main/resources/my.map.xml
+----
+
+.^|dataSource
+.^|XML
+.^|An object that contains Data Source parameters
+|===
+
+
+[#dataSourceParameteres.table.table-bordered]
+.<dataSource> parameters
+[cols="2,1,2,5"]
+|===
+|Name |Type |Required |Description
+
+.^|driver
+.^|String
+.^|Yes
+.^|A class of JDBC driver to use for the target database.
+
+.^|url
+.^|String
+.^|Yes
+.^|JDBC URL of a target database.
+
+.^|username
+.^|String
+.^|No
+.^|Database user name.
+
+.^|password
+.^|String
+.^|No
+.^|Database user password.
+|===
+
+[#cdbgenOptionl.table.table-bordered]
+.cdbgen optional parameters
+[cols="1,1,4"]
+|===
+|Name |Type|Description
+
+.^|adapter
+.^|String
+.^|Java class name implementing org.apache.cayenne.dba.DbAdapter. While this attribute is optional (a generic JdbcAdapter is used if not set), it is highly recommended to specify correct target adapter.
+
+
+.^|createFK
+.^|boolean
+.^|Indicates whether cdbgen should create foreign key constraints. Default is "true".
+
+.^|createPK
+.^|boolean
+.^|Indicates whether cdbgen should create Cayenne-specific auto PK objects. Default is "true".
+
+.^|createTables
+.^|boolean
+.^|Indicates whether cdbgen should create new tables. Default is "true".
+
+.^|dropPK
+.^|boolean
+.^|Indicates whether cdbgen should drop Cayenne primary key support objects. Default is "false".
+
+.^|dropTables
+.^|boolean
+.^|Indicates whether cdbgen should drop the tables before attempting to create new ones. Default is "false".
+|===
+
+Example - creating a DB schema on a local HSQLDB database:
+
+[source,xml,subs="verbatim,attributes"]
+----
+<plugin>
+    <groupId>org.apache.cayenne.plugins</groupId>
+    <artifactId>cayenne-maven-plugin</artifactId>
+    <version>{version}</version>
+    <executions>
+        <execution>
+            <configuration>
+                <map>${project.basedir}/src/main/resources/my.map.xml</map>
+                <adapter>org.apache.cayenne.dba.hsqldb.HSQLDBAdapter</adapter>
+                <dataSource>
+                    <url>jdbc:hsqldb:hsql://localhost/testdb</url>
+                    <driver>org.hsqldb.jdbcDriver</driver>
+                    <username>sa</username>
+                </dataSource>
+            </configuration>
+            <goals>
+                <goal>cdbgen</goal>
+            </goals>
+        </execution>
+    </executions>
+</plugin>
+----
+
+[[mavenCdbimort]]
+===== cdbimport
+
+`cdbimport` is a `cayenne-maven-plugin` goal that generates a DataMap based on an existing database schema. By default, it is bound to the generate-sources phase. This allows you to generate your DataMap prior to building your project, possibly followed by "cgen" execution to generate the classes. CDBImport plugin described in details in chapter xref:dbFirstFlow["DB-First Flow"]
+[#cdbimportTable.table.table-bordered]
+.cdbimport parameters
+[cols="2,1,2,5"]
+|===
+|Name |Type |Required |Description
+
+.^|map
+.^|File
+.^|Yes
+.^|DataMap XML file which is the destination of the schema import. Can be an existing file. If this file does not exist, it is created when cdbimport is executed. E.g. `${project.basedir}/src/main/resources/my.map.xml`. If "overwrite" is true (the default), an existing DataMap will be used as a template for the new imported DataMap, i.e. all its entities will be cleared and recreated, but its common settings, such as default Java package, will be preserved (unless changed explicitly in the plugin configuration).
+
+.^|adapter
+.^|String
+.^|No
+.^|A Java class name implementing org.apache.cayenne.dba.DbAdapter. This attribute is optional. If not specified, AutoAdapter is used, which will attempt to guess the DB type.
+
+.^|dataSource
+.^|XML
+.^|Yes
+.^|An object that contains Data Source parameters.
+
+.^|dbimport
+.^|XML
+.^|No
+.^|An object that contains detailed reverse engineering rules about what DB objects should be processed. For full information about this parameter see xref:dbFirstFlow["DB-First Flow"] chapter.
+|===
+
+[#cdbimportDataSource.table.table-bordered]
+.<dataSource> parameters
+[cols="2,1,2,5"]
+|===
+|Name |Type |Required |Description
+
+.^|driver
+.^|String
+.^|Yes
+.^|A class of JDBC driver to use for the target database.
+
+.^|url
+.^|String
+.^|Yes
+.^|JDBC URL of a target database.
+
+.^|username
+.^|String
+.^|No
+.^|Database user name.
+
+.^|password
+.^|String
+.^|No
+.^|Database user password.
+|===
+
+[#dbimportParameters.table.table-bordered]
+.<dbimport> parameters
+[cols="3,1,4"]
+|===
+|Name |Type|Description
+
+.^|defaultPackage
+.^|String
+.^|A Java package that will be set as the imported DataMap default and a package of all the persistent Java classes. This is a required attribute if the "map" itself does not already contain a default package, as otherwise all the persistent classes will be mapped with no package, and will not compile.
+
+.^|forceDataMapCatalog
+.^|boolean
+.^|Automatically tagging each DbEntity with the actual DB catalog/schema (default behavior) may sometimes be undesirable. If this is the case then setting `forceDataMapCatalog` to `true` will set DbEntity catalog to one in the DataMap. Default value is `false`.
+
+.^|forceDataMapSchema
+.^|boolean
+.^|Automatically tagging each DbEntity with the actual DB catalog/schema (default behavior) may sometimes be undesirable. If this is the case then setting `forceDataMapSchema` to `true` will set DbEntity schema to one in the DataMap. Default value is `false`.
+
+.^|meaningfulPkTables
+.^|String
+.^|A comma-separated list of Perl5 patterns that defines which imported tables should have their primary key columns mapped as ObjAttributes. "*" would indicate all tables.
+
+.^|namingStrategy
+.^|String
+.^|The naming strategy used for mapping database names to object entity names. Default is `o.a.c.dbsync.naming.DefaultObjectNameGenerator`.
+
+.^|skipPrimaryKeyLoading
+.^|boolean
+.^|Whether to load primary keys. Default "false".
+
+.^|skipRelationshipsLoading
+.^|boolean
+.^|Whether to load relationships. Default "false".
+
+.^|stripFromTableNames
+.^|String
+a|Regex that matches the part of the table name that needs to be stripped off when generating ObjEntity name. Here are some examples:
+[source,XML]
+----
+<!-- Strip prefix -->
+<stripFromTableNames>^myt_</stripFromTableNames>
+
+<!-- Strip suffix -->
+<stripFromTableNames>_s$</stripFromTableNames>
+
+<!-- Strip multiple occurrences in the middle -->
+<stripFromTableNames>_abc</stripFromTableNames>
+----
+
+.^|usePrimitives
+.^|boolean
+.^|Whether numeric and boolean data types should be mapped as Java primitives or Java classes. Default is "true", i.e. primitives will be used.
+
+.^|useJava7Types
+.^|boolean
+.^|Whether _DATE_, _TIME_ and _TIMESTAMP_ data types should be mapped as `java.util.Date` or `java.time.* classes`. Default is "false", i.e. `java.time.*` will be used.
+
+.^|filters configuration
+.^|XML
+a|Detailed reverse engineering rules about what DB objects should be processed. For full information about this parameter see  xref:dbFirstFlow["DB-First Flow"] chapter. Here is some simple example:
+[source,XML]
+----
+<dbimport>
+	<catalog name="test_catalog">
+		<schema name="test_schema">
+			<includeTable>.*</includeTable>
+			<excludeTable>test_table</excludeTable>
+		</schema>
+	</catalog>
+
+	<includeProcedure pattern=".*"/>
+</dbimport>
+----
+
+
+|===
+
+Example - loading a DB schema from a local HSQLDB database (essentially a reverse operation compared to the cdbgen example above) :
+
+[source, XML,,subs="verbatim,attributes"]
+----
+<plugin>
+    <groupId>org.apache.cayenne.plugins</groupId>
+    <artifactId>cayenne-maven-plugin</artifactId>
+    <version>{version}</version>
+
+    <executions>
+        <execution>
+            <configuration>
+                <map>${project.basedir}/src/main/resources/my.map.xml</map>
+                <dataSource>
+                    <url>jdbc:mysql://127.0.0.1/mydb</url>
+                    <driver>com.mysql.jdbc.Driver</driver>
+                    <username>sa</username>
+                </dataSource>
+                <dbimport>
+                    <defaultPackage>com.example.cayenne</defaultPackage>
+                </dbimport>
+            </configuration>
+            <goals>
+                <goal>cdbimport</goal>
+            </goals>
+        </execution>
+    </executions>
+</plugin>
+----
+
+==== Gradle Projects
+
+To include Cayenne into your Gradle project you have two options:
+
+- Simply add Cayenne as a dependency:
+
+[source, Groovy,subs="verbatim,attributes"]
+----
+compile 'org.apache.cayenne:cayenne-server:{version}'
+----
+
+- Or you can use Cayenne Gradle plugin
+
+===== Gradle Plugin
+
+Cayenne Gradle plugin provides several tasks, such as synching generated Java classes with the mapping or synching mapping with the database. Plugin also provides `cayenne` extension that have some useful utility methods. Here is example of how to include Cayenne plugin into your project:
+
+[source, Groovy, subs="verbatim,attributes"]
+----
+buildscript {
+    // add Maven Central repository
+    repositories {
+        mavenCentral()
+    }
+    // add Cayenne Gradle Plugin
+    dependencies {
+        classpath group: 'org.apache.cayenne.plugins', name: 'cayenne-gradle-plugin', version: '{version}'
+    }
+}
+
+// apply plugin
+apply plugin: 'org.apache.cayenne'
+
+// set default DataMap
+cayenne.defaultDataMap 'datamap.map.xml'
+
+// add Cayenne dependencies to your project
+dependencies {
+    // this is a shortcut for 'org.apache.cayenne:cayenne-server:VERSION_OF_PLUGIN'
+    compile cayenne.dependency('server')
+}
+----
+
+====== Warning
+
+Cayenne Gradle plugin is experimental and it's API can change later.
+
+===== cgen
+
+Cgen task generates Java classes based on your DataMap, it has same configuration parameters as in Maven Plugin version, described in xref:tablecgen[Table, “cgen required parameters”.]. If you provided default DataMap via `cayenne.defaultDataMap`, you can skip `cgen` configuration as default settings will suffice in common case.
+
+Here is how you can change settings of the default `cgen` task:
+
+[source, Groovy]
+----
+cgen {
+    client = false
+    mode = 'all'
+    overwrite = true
+    createPropertiesNames = true
+}
+----
+
+And here is example of how to define additional cgen task (e.g. for client classes if you are using ROP):
+
+
+[source, Groovy]
+----
+task clientCgen(type: cayenne.cgen) {
+    client = true
+}
+----
+
+===== cdbimport
+
+This task is for creating and synchronizing your Cayenne model from database schema. Full list of parameters are same as in Maven Plugin version, described in xref:cdbimportTable[Table, “cdbimport parameters”], with exception that Gradle version will use Groovy instead of XML.
+
+Here is example of configuration for cdbimport task:
+
+[source, Groovy]
+----
+cdbimport {
+    // map can be skipped if it is defined in cayenne.defaultDataMap
+    map 'datamap.map.xml'
+
+    dataSource {
+        driver 'com.mysql.cj.jdbc.Driver'
+        url 'jdbc:mysql://127.0.0.1:3306/test?useSSL=false'
+        username 'root'
+        password ''
+    }
+
+    dbImport
+        // additional settings
+        usePrimitives false
+        defaultPackage 'org.apache.cayenne.test'
+
+        // DB filter configuration
+        catalog 'catalog-1'
+        schema 'schema-1'
+
+        catalog {
+            name 'catalog-2'
+
+            includeTable 'table0', {
+                excludeColumns '_column_'
+            }
+
+            includeTables 'table1', 'table2', 'table3'
+
+            includeTable 'table4', {
+                includeColumns 'id', 'type', 'data'
+            }
+
+            excludeTable '^GENERATED_.*'
+        }
+
+        catalog {
+            name 'catalog-3'
+            schema {
+                name 'schema-2'
+                includeTable 'test_table'
+                includeTable 'test_table2', {
+                    excludeColumn '__excluded'
+                }
+            }
+        }
+
+        includeProcedure 'procedure_test_1'
+
+        includeColumns 'id', 'version'
+
+        tableTypes 'TABLE', 'VIEW'
+    }
+}
+----
+
+===== cdbgen
+
+Cdbgen task drops and/or generates tables in a database on Cayenne DataMap. Full list of parameters are same as in Maven Plugin version, described in xref:cdbgenTable[Table , “cdbgen required parameters”]
+
+Here is example of how to configure default `cdbgen` task:
+
+[source, Groovy]
+----
+cdbgen {
+
+    adapter 'org.apache.cayenne.dba.derby.DerbyAdapter'
+
+    dataSource {
+        driver 'org.apache.derby.jdbc.EmbeddedDriver'
+        url 'jdbc:derby:build/testdb;create=true'
+        username 'sa'
+        password ''
+    }
+
+    dropTables true
+    dropPk true
+
+    createTables true
+    createPk true
+    createFk true
+}
+----
+
+===== Link tasks to Gradle build lifecycle
+
+With gradle you can easily connect Cayenne tasks to default build lifecycle. Here is short example of how to connect defaut `cgen` and `cdbimport` tasks with `compileJava` task:
+
+[source, Groovy]
+----
+cgen.dependsOn cdbimport
+compileJava.dependsOn cgen
+----
+
+NOTE: Running `cdbimport` automatically with build not always a good choice, e.g. in case of complex model that you need to alter in the Cayenne Modeler after import.
+
+==== Ant Projects
+
+Ant tasks are the same as Maven plugin goals described above, namely "cgen", "cdbgen", "cdbimport". Configuration parameters are also similar (except Maven can guess many defaults that Ant can't). To include Ant tasks in the project, use the following Antlib:
+
+[source, XML]
+----
+<typedef resource="org/apache/cayenne/tools/antlib.xml">
+   <classpath>
+   		<fileset dir="lib" >
+			<include name="cayenne-ant-*.jar" />
+			<include name="cayenne-cgen-*.jar" />
+			<include name="cayenne-dbsync-*.jar" />
+			<include name="cayenne-di-*.jar" />
+			<include name="cayenne-project-*.jar" />
+			<include name="cayenne-server-*.jar" />
+			<include name="commons-collections-*.jar" />
+			<include name="commons-lang-*.jar" />
+			<include name="slf4j-api-*.jar" />
+			<include name="velocity-*.jar" />
+			<include name="vpp-2.2.1.jar" />
+		</fileset>
+   </classpath>
+</typedef>
+----
+
+===== cgen
+
+===== cdbgen
+
+===== cdbimport
+
+This is an Ant counterpart of "cdbimport" goal of cayenne-maven-plugin described above. It has exactly the same properties. Here is a usage example:
+
+[source, XML]
+----
+ <cdbimport map="${context.dir}/WEB-INF/my.map.xml"
+    driver="com.mysql.jdbc.Driver"
+    url="jdbc:mysql://127.0.0.1/mydb"
+    username="sa"
+    defaultPackage="com.example.cayenne"/>
+----
+

http://git-wip-us.apache.org/repos/asf/cayenne/blob/df1324e4/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/lifecycle.adoc
----------------------------------------------------------------------
diff --git a/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/lifecycle.adoc b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/lifecycle.adoc
new file mode 100644
index 0000000..9305723
--- /dev/null
+++ b/docs/asciidoc/cayenne-guide/src/docs/asciidoc/_cayenne-guide/part2/lifecycle.adoc
@@ -0,0 +1,273 @@
+// 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.
+
+=== Lifecycle Events
+
+An application might be interested in getting notified when a Persistent object moves through its lifecycle (i.e. fetched from DB, created, modified, committed). E.g. when a new object is created, the application may want to initialize its default properties (this can't be done in constructor, as constructor is also called when an object is fetched from DB). Before save, the application may perform validation and/or set some properties (e.g. "updatedTimestamp"). After save it may want to create an audit record for each saved object, etc., etc.
+
+All this can be achieved by declaring callback methods either in Persistent objects or in non-persistent listener classes defined by the application (further simply called "listeners"). There are eight types of lifecycle events supported by Cayenne, listed later in this chapter. When any such event occurs (e.g. an object is committed), Cayenne would invoke all appropriate callbacks. Persistent objects would receive their own events, while listeners would receive events from any objects.
+
+Cayenne allows to build rather powerful and complex "workflows" or "processors" tied to objects lifecycle, especially with listeners, as they have full access to the application evnironment outside Cayenne. This power comes from such features as filtering which entity events are sent to a given listener and the ability to create a common operation context for multiple callback invocations. All of these are discussed later in this chapter.
+
+==== Types of Lifecycle Events
+
+Cayenne defines the following 8 types of lifecycle events for which callbacks can be regsitered:
+
+[#lifecycleEvent.table.table-bordered]
+.Lifecycle Event Types
+[cols="1,4"]
+|===
+|Event |Occurs...
+
+.^|PostAdd
+.^|right after a new object is created inside `ObjectContext.newObject()`. When this event is fired the object is already registered with its ObjectContext and has its ObjectId and ObjectContext properties set.
+
+.^|PrePersist
+.^|right before a new object is committed, inside `ObjectContext.commitChanges()` and `ObjectContext.commitChangesToParent()` (and after `"validateForInsert()"`).
+
+.^|PreUpdate
+.^|right before a modified object is committed, inside `ObjectContext.commitChanges()` and `ObjectContext.commitChangesToParent()` (and after `"validateForUpdate()"`).
+
+.^|PreRemove
+.^|right before an object is deleted, inside `ObjectContext.deleteObjects()`. The event is also generated for each object indirectly deleted as a result of CASCADE delete rule.
+
+.^|PostPersist
+.^|right after a commit of a new object is done, inside `ObjectContext.commitChanges()`.
+
+.^|PostUpdate
+.^|right after a commit of a modified object is done, inside `ObjectContext.commitChanges()`.
+
+.^|PostRemove
+.^|right after a commit of a deleted object is done, inside `ObjectContext.commitChanges()`.
+
+.^|PostLoad
+a|
+- After an object is fetched inside ObjectContext.performQuery().
+- After an object is reverted inside ObjectContext.rollbackChanges().
+- Anytime a faulted object is resolved (i.e. if a relationship is fetched).
+|===
+
+==== Callbacks on Persistent Objects
+
+Callback methods on Persistent classes are mapped in CayenneModeler for each ObjEntity. Empty callback methods are automatically created as a part of class generation (either with Maven, Ant or the Modeler) and are later filled with appropriate logic by the programmer. E.g. assuming we mapped a 'post-add' callback called 'onNewOrder' in ObjEntity 'Order', the following code will be generated:
+
+[source, Java]
+----
+public abstract class _Order extends CayenneDataObject {
+    protected abstract void onNewOrder();
+}
+
+public class Order extends _Order {
+
+    @Override
+    protected void onNewOrder() {
+        //TODO: implement onNewOrder
+    }
+}
+----
+
+As `onNewOrder()` is already declared in the mapping, it does not need to be registered explicitly. Implementing the method in subclass to do something meaningful is all that is required at this point.
+
+As a rule callback methods do not have any knowledge of the outside application, and can only access the state of the object itself and possibly the state of other persistent objects via object's own ObjectContext.
+
+NOTE: Validation and callbacks: There is a clear overlap in functionality between object callbacks and `DataObject.validateForX()` methods. In the future validation may be completely superceeded by callbacks. It is a good idea to use "validateForX" strictly for validation (or not use it at all). Updating the state before commit should be done via callbacks.
+
+==== Callbacks on Non-Persistent Listeners
+
+A listener is simply some application class that has one or more annotated callback methods. A callback method signature should be `void someMethod(SomePersistentType object)`. It can be public, private, protected or use default access:
+
+[source, Java]
+----
+ public class OrderListener {
+
+   @PostAdd(Order.class)
+   public void setDefaultsForNewOrder(Order o) {
+      o.setCreatedOn(new Date());
+   }
+}
+----
+
+Notice that the example above contains an annotation on the callback method that defines the type of the event this method should be called for. Before we go into annotation details, we'll show how to create and register a listener with Cayenne. It is always a user responsibility to register desired application listeners, usually right after ServerRuntime is started. Here is an example:
+
+First let's define 2 simple listeners.
+
+[source, Java]
+----
+public class Listener1 {
+
+    @PostAdd(MyEntity.class)
+    void postAdd(Persistent object) {
+        // do something
+    }
+}
+
+public class Listener2 {
+
+    @PostRemove({ MyEntity1.class, MyEntity2.class })
+    void postRemove(Persistent object) {
+        // do something
+    }
+
+    @PostUpdate({ MyEntity1.class, MyEntity2.class })
+    void postUpdate(Persistent object) {
+        // do something
+    }
+}
+----
+
+Ignore the annotations for a minute. The important point here is that the listeners are arbitrary classes unmapped and unknown to Cayenne, that contain some callback methods. Now let's register them with runtime:
+
+[source, Java]
+----
+ServerRuntime runtime = ...
+
+runtime.getDataDomain().addListener(new Listener1());
+runtime.getDataDomain().addListener(new Listener2());
+----
+
+
+Listeners in this example are very simple. However they don't have to be. Unlike Persistent objects, normally listeners initialization is managed by the application code, not Cayenne, so listeners may have knowledge of various application services, operation transactional context, etc. Besides a single listener can apply to multiple entities. As a consequence their callbacks can do more than just access a single ObjectContext.
+
+Now let's discuss the annotations. There are eight annotations exactly matching the names of eight lifecycle events. A callback method in a listener should be annotated with at least one, but possibly with more than one of them. Annotation itself defines what event the callback should react to. Annotation parameters are essentially an entity filter, defining a subset of ObjEntities whose events we are interested in:
+
+[source, Java]
+----
+// this callback will be invoked on PostRemove event of any object
+// belonging to MyEntity1, MyEntity2 or their subclasses
+@PostRemove({ MyEntity1.class, MyEntity2.class })
+void postRemove(Persistent object) {
+    ...
+}
+----
+
+[source, Java]
+----
+// similar example with multipe annotations on a single method
+// each matching just one entity
+@PostPersist(MyEntity1.class)
+@PostRemove(MyEntity1.class)
+@PostUpdate(MyEntity1.class)
+void postCommit(MyEntity1 object) {
+    ...
+}
+----
+
+As shown above, "value" (the implicit annotation parameter) can contain one or more entity classes. Only these entities' events will result in callback invocation. There's also another way to match entities - via custom annotations. This allows to match any number of entities without even knowing what they are. Here is an example. We'll first define a custom annotation:
+
+[source, Java]
+----
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Tag {
+
+}
+----
+
+Now we can define a listener that will react to events from ObjEntities annotated with this annotation:
+
+[source, Java]
+----
+public class Listener3 {
+
+    @PostAdd(entityAnnotations = Tag.class)
+    void postAdd(Persistent object) {
+        // do something
+    }
+}
+----
+
+As you see we don't have any entities yet, still we can define a listener that does something useful. Now let's annotate some entities:
+
+[source, Java]
+----
+@Tag
+public class MyEntity1 extends _MyEntity1 {
+
+}
+
+@Tag
+public class MyEntity2 extends _MyEntity2 {
+
+}
+----
+
+
+==== Combining Listeners with DataChannelFilters
+
+A final touch in the listeners design is preserving the state of the listener within a single select or commit, so that events generated by multiple objects can be collected and processed all together. To do that you will need to implement a `DataChannelFilter`, and add some callback methods to it. They will store their state in a ThreadLocal variable of the filter. Here is an example filter that does something pretty meaningless - counts how many total objects were committed. However it demonstrates the important pattern of aggregating multiple events and presenting a combined result:
+
+[source, Java]
+----
+public class CommittedObjectCounter implements DataChannelFilter {
+
+    private ThreadLocal<int[]> counter;
+
+    @Override
+    public void init(DataChannel channel) {
+        counter = new ThreadLocal<int[]>();
+    }
+
+    @Override
+    public QueryResponse onQuery(ObjectContext originatingContext, Query query, DataChannelFilterChain filterChain) {
+        return filterChain.onQuery(originatingContext, query);
+    }
+
+    @Override
+    public GraphDiff onSync(ObjectContext originatingContext, GraphDiff changes, int syncType,
+            DataChannelFilterChain filterChain) {
+
+        // init the counter for the current commit
+        counter.set(new int[1]);
+
+        try {
+            return filterChain.onSync(originatingContext, changes, syncType);
+        } finally {
+
+            // process aggregated result and release the counter
+            System.out.println("Committed " + counter.get()[0] + " object(s)");
+            counter.set(null);
+        }
+    }
+
+    @PostPersist(entityAnnotations = Tag.class)
+    @PostUpdate(entityAnnotations = Tag.class)
+    @PostRemove(entityAnnotations = Tag.class)
+    void afterCommit(Persistent object) {
+        counter.get()[0]++;
+    }
+}
+----
+
+Now since this is both a filter and a listener, it needs to be registered as such:
+
+[source, Java]
+----
+CommittedObjectCounter counter = new CommittedObjectCounter();
+
+ServerRuntime runtime = ...
+DataDomain domain = runtime.getDataDomain();
+
+// register filter
+// this will also add it as a listener (since 3.2)
+domain.addFilter(counter);
+----
+
+
+
+
+
+
+
+
+