that will allow to store our Money
class as BigDecimal
can be implemented:
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
:
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 cayenne-server.
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.
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:
/**
* 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
// 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();
For Java8
// add DoubleArrayType to list of user types
ServerRuntime runtime = ServerRuntime.builder()
.addConfig("cayenne-project.xml")
.addModule(binder ->
ServerModule.contributeUserTypes(binder)
.add(new DoubleArrayType()))
.build();
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.
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.
Factory that returns javax.sql.DataSource
object based on the configuration provided in the "nodeDescriptor".
"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:
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.
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
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 authentication. 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:
<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)
An ORM system consists of three parts: database, OR mapping and persistent Java classes. These parts always need to be kept in sync with each other for the application to work. "DB-first" flow is a common and practical approach to synchronization that assumes the database to be the master source of the metadata, with other two parts synchronized from the DB as the schema evolves. Cayenne provides a number of tools to automate and control it. Here is how "DB-first" flow is typically implemented:
A SQL migrations framework is used to bring a local DB to a certain version. This is outside of the scope of Cayenne and is done with a third-party tool, such as Liquibase or Flyway.
OR mapping model (Cayenne XML files) are synchronized with the state of the database using "cdbimport"
tool provdied by Cayenne.
Object layer of the OR mapping model is customized to the developer liking, usually via CayenneModeler. Subsequent runs of "cdbimport"
will not override any customizations that you make.
Java classes are generated using "cgen"
tool provided by Cayenne.
"cgen" and "cdbimport" tools can be invoked from Maven or Ant as discussed in the "Including Cayenne in a Project" chapter or run from CayenneModeler. This chapter will mostly focus on "cdbimport".
Here is simple maven configuration to start with:
Here is a simple Maven configuration of "cdbimport" (for details see cayenne-maven-plugin documentation)
<plugin>
<groupId>org.apache.cayenne.plugins</groupId>
<artifactId>cayenne-maven-plugin</artifactId>
<version>4.0.2</version>
<configuration>
<map>${project.basedir}/src/main/resources/datamap.map.xml</map>
<dataSource>
<url><!-- jdbc url --></url>
<driver><!-- jdbc driver class --></driver>
<username>username</username>
<password>password</password>
</dataSource>
<dbimport>
<defaultPackage>com.example.package</defaultPackage>
<includeTable>.*</includeTable>
</dbimport>
</configuration>
<dependencies>
<!-- jdbc driver dependency -->
</dependencies>
</plugin>
In the next chapters we will discuss various filtering and other reverse-engineering options.
The first thing you usually want to control during reverse engineering is what exactly should be loaded from database and what not. One of the most common cases is excluding system tables, as you usually don’t want to map them.
Briefly, you are able to include/exclude tables, columns and procedures and do it at several levels: default, catalog, schema. Although everything defined at the top level (default rules) will be applied for the nested elements, all rules from the most specific areas will override general rules (i.e. rules from schemas override rules from catalogs and even more override default rules).
The following use-cases will provide you a better understanding of how filtering works and how you could use it.
The simplest example of reverse engineering is processing tables from one schema of catalog and there are several options to do this. Basic syntax is described below:
<dbimport>
<!-- Ant/Maven in case you only want to specify the schema to import -->
<schema>SCHEMA_NAME</schema>
<!-- Maven way in case you have nested elements in the schema -->
<schema>
<name>SCHEMA_NAME</name>
...
</schema>
<!-- Ant way in case you have nested elements in the schema -->
<schema name="SCHEMA_NAME">
...
</schema>
</dbimport>
The same options are available for catalogs:
<dbimport>
<!-- Ant/Maven in case you only want to specify the catalog to import -->
<catalog>CATALOG_NAME</catalog>
<!-- Maven way in case you have nested elements in the catalog -->
<catalog>
<name>CATALOG_NAME</name>
...
</catalog>
<!-- Ant way in case you have nested elements in the catalog -->
<catalog name="CATALOG_NAME">
...
</catalog>
</dbimport>
Cayenne supports combination of different schemas and catalogs, and it filters data according to your requirements. You could achieve this by the following example of reverse engineering configuration:
<dbimport>
<catalog>
<name>shop_01</name>
<schema>schema-name-01</schema>
<schema>schema-name-02</schema>
<schema>schema-name-03</schema>
</catalog>
<catalog>
<name>shop_02</name>
<schema>schema-name-01</schema>
</catalog>
<catalog>
<name>shop_03</name>
<schema>schema-name-01</schema>
<schema>schema-name-02</schema>
<schema>schema-name-03</schema>
</catalog>
</dbimport>
In the example above, Cayenne reverse engineering process contains three catalogs named as shop_01, shop_02 and shop_03, each of wich has their own schemas. Cayenne will load all data only from the declared catalogs and schemas.
If you want to load everything from database, you could simply declare catalog specification alone.
<dbimport>
<catalog>shop_01</catalog>
<catalog>shop_02</catalog>
<catalog>shop_03</catalog>
</dbimport>
If you want to do reverse engineering for specific schemas, just remove unwanted schemas from the catalog section. For example, if you want to process schema-name-01 and schema-name-03 schemas only, then you should change reverse engineering section like this.
<dbimport>
<catalog>
<name>shop_01</name>
<schema>schema-name-01</schema>
<schema>schema-name-03</schema>
</catalog>
<catalog>
<name>shop_02</name>
<schema>schema-name-01</schema>
</catalog>
<catalog>
<name>shop_03</name>
<schema>schema-name-01</schema>
<schema>schema-name-03</schema>
</catalog>
</dbimport>
Cayenne reverse engineering let you fine tune table, columns and stored procedures names that you need to import to your model file. In every filter you can use regexp syntax. Here is some examples of configuration for common tasks.
1) Include tables with ‘CRM_’ prefix if you are working in that domain of application:
<includeTable>CRM_.*</includeTable>
2) Include tables with ‘_LOOKUP’ suffix
<includeTable>
<pattern>.*_LOOKUP</pattern>
</includeTable>
3) Exclude tables with ‘CRM_’ prefix if you are not working only in that domain of application:
<excludeTable>CRM_.*</excludeTable>
4) Include only specific columns that follows specific naming convention:
<includeColumn>includeColumn01</includeColumn>
<includeColumn>includeColumn03</includeColumn>
5) Exclude system or obsolete columns:
<excludeColumn>excludeColumn01</excludeColumn>
<excludeColumn>excludeColumn03</excludeColumn>
6) Include/Exclude columns for particular table or group of tables:
<includeTable>
<pattern>table pattern</pattern>
<includeColumn>includeColumn01</includeColumn>
<excludeColumn>excludeColumn01</excludeColumn>
</includeTable>
7) Include stored procedures:
<includeProcedure>includeProcedure01</includeProcedure>
<includeProcedure>
<pattern>includeProcedure03</pattern>
</includeProcedure>
8) Exclude stored procedures by pattern:
<excludeProcedure>excludeProcedure01</excludeProcedure>
<excludeProcedure>
<pattern>excludeProcedure03</pattern>
</excludeProcedure>
All filtering tags <includeTable>
, <excludeTable>
, <includeColumn>
, <excludeColumn>
, <includeProcedure>
and <excludeProcedure>
have 2 ways to pass filtering RegExp.
1) text inside tag
<includeTable>CRM_.*</includeTable>
2) pattern inner tag
<includeTable>
<pattern>.*_LOOKUP</pattern>
</includeTable>
All filtering tags can be placed inside schema and catalog tags, but also inside <dbimport>
tag. It means that filtering rules will be applied for all schemas and catalogs.
Initially, let’s make a small sample. Consider the following reverse engineering configuration.
<dbimport>
<catalog>shop-01</catalog>
</dbimport>
In this case reverse engineering will not filter anything from the shop-01 catalog. If you really want to filter database columns, tables, stored procedures and relationships, you could do it in the following way.
<dbimport>
<catalog>shop-01</catalog>
<catalog>
<name>shop-02</name>
<includeTable>includeTable-01</includeTable>
</catalog>
</dbimport>
Then Cayenne will do reverse engineering for both shop-01 and shop-02 catalogs. First catalog will not be processed for filtering, but the second catalog will be processed with “includeTable-01” filter.
Let’s assume you have a lot of table prefixes with the same names. Cayenne allows you to mention a pattern as regular expression. Using regular expressions is easier way to handle a big amount of database entities than writing filter config for each use-case. They make your configuration more readable, understandable and straightforward. There is not complex. Let’s see how to use patterns in reverse engineering configuration with complete example.
<dbimport>
<catalog>shop-01</catalog>
<catalog>
<name>shop-02</name>
</catalog>
<catalog>
<name>shop-03</name>
<includeTable>includeTable-01</includeTable>
<includeTable>
<pattern>includeTable-02</pattern>
</includeTable>
<includeTable>
<pattern>includeTable-03</pattern>
<includeColumn>includeColumn-01</includeColumn>
<excludeColumn>excludeColumn-01</excludeColumn>
</includeTable>
<excludeTable>excludeTable-01</excludeTable>
<excludeTable>
<pattern>excludeTable-02</pattern>
</excludeTable>
<includeColumn>includeColumn-01</includeColumn>
<includeColumn>
<pattern>includeColumn-02</pattern>
</includeColumn>
<excludeColumn>excludeColumn-01</excludeColumn>
<excludeColumn>
<pattern>excludeColumn-02</pattern>
</excludeColumn>
<includeProcedure>includeProcedure-01</includeProcedure>
<includeProcedure>
<pattern>includeProcedure-02</pattern>
</includeProcedure>
<excludeProcedure>excludeProcedure-01</excludeProcedure>
<excludeProcedure>
<pattern>excludeProcedure-02</pattern>
</excludeProcedure>
</catalog>
</dbimport>
The example above should provide you more idea about how to use filtering and patterns in Cayenne reverse engineering. You could notice that this example demonstrates you the "name" and "pattern" configurations. Yes, you could use these as separates xml element and xml attributes.
The cdbimport will execute reverse engineering task for all entities from “shop-01” and “shop-02”, including tables, views, stored procedures and table columns. As “shop-03” has variety filter tags, entities from this catalog will be filtered by cdbimport.
Here is config sample for Ant
task:
<!-- inside <cdbimport> tag -->
<catalog>shop-01</catalog>
<catalog name="shop-02"/>
<catalog name="shop-03">
<includeTable>includeTable-01</includeTable>
<includeTable pattern="includeTable-02"/>
<includeTable pattern="includeTable-03">
<includeColumn>includeColumn-01</includeColumn>
<excludeColumn>excludeColumn-01</excludeColumn>
</includeTable>
<excludeTable>excludeTable-01</excludeTable>
<excludeTable pattern="excludeTable-02"/>
<includeColumn>includeColumn-01</includeColumn>
<includeColumn pattern="includeColumn-02"/>
<excludeColumn>excludeColumn-01</excludeColumn>
<excludeColumn pattern="excludeColumn-02"/>
<includeProcedure>includeProcedure-01</includeProcedure>
<includeProcedure pattern="includeProcedure-02"/>
<excludeProcedure>excludeProcedure-01</excludeProcedure>
<excludeProcedure pattern="excludeProcedure-02"/>
</catalog>
In Ant task configuration all filter tags located inside root tag <cdbimport> as there is no <dbimport> tag. |
In databases relations are defined via foreign keys and there are a lot of different politics according to the level of relationships and ways how those relationships could be modeled in database. Anyway, cdbimport is able to recognize basic patterns of relationships, such as OneToMany, OneToOne and ManyToMany.
You are able to skip relationships loading by the <skipRelationshipsLoading>
element.
<dbimport>
<skipRelationshipsLoading>true</skipRelationshipsLoading>
</dbimport>
Another useful Cayenne reverse engineering property is <skipPrimaryKeyLoading>
. If you decide to support all relationships at the application layer and avoid their management in database, you’ll find useful to turn off primary keys synchronization at all.
<dbimport>
<skipPrimaryKeyLoading>true</skipPrimaryKeyLoading>
</dbimport>
By default, cdbimport imports tables and views. Some databases may support other table-like objects, e.g. SYSTEM TABLE, GLOBAL TEMPORARY, LOCAL TEMPORARY, ALIAS, SYNONYM
, etc. To control which types should be included <tableType></tableType>
element is used. Some examples:
Import tables only (skip views and others and other types):
<dbimport>
<tableType>TABLE</tableType>
</dbimport>
Tables and views (the default option):
<dbimport>
<tableType>TABLE</tableType>
<tableType>VIEWS</tableType>
</dbimport>
Alternative aproach to using cdbimport is doing reverse engineering from CayenneModeler. Currently modeler GUI doesn’t support all features of ant/maven tasks but it suffice for general DB import. Especially it’s a good place to quickly start working on your data model.
You can find reverse engineering tool in main modeler menu Tools > Reengineer Database Schema
First you should select DataSource. If you don’t have any DataSource yet you can create one from this menu.
Datasource selection dialog.
Once DataSource is selected you can proceed to reverse engineering options.
Reverse Engineering dialog.
Here is a list of options to tune what will be processed by reverse engineering:
Select Catalog: catalog to process
| You can only select one catalog. If you need to import multiple catalogs you need to run process several times. |
Table Name Pattern: RegExp to filter tables. Default pattern .* includes all tables.
Procedure Name Pattern: RegExp to filter procedures. Default pattern .* includes all stored procedures.
Naming Strategy: Currently there is only one naming strategy available. See ant/maven tools documentation for details about naming strategy.
Tables with Meaningful PK Pattern: Comma separated list of RegExp’s for tables that you want to have meaningful primary keys. By default no meaningful PKs are created.
Use Java primitive types: Use primitive types (e.g. int) or Object types (e.g. java.lang.Integer).
Use old java.util.Date type: Use java.util.Date for all columns with DATE/TIME/TIMESTAMP types. By default java.time. types will be used.
Cache invalidation module is an extension that allows to define cache invalidation policy programmatically.
Module supports autoloading mechanism, so no other actions required to enable it. Just mark your entities with @CacheGroups annotation and you are ready to use it:
@CacheGroups("some-group")
public class MyEntity extends _MyEntity {
// ...
}
After any modification of MyEntity
objects cache group "some-group"
will be dropped from cache automatically.
You can read more about cache and cache groups in corresponding chapter of this documentation.
In case you need some complex logic of cache invalidation you can disable default behaviour and provide your own.
To do so you need to implement org.apache.cayenne.cache.invalidation.InvalidationHandler
interface and setup Cache Invalidation module to use it. Let’s use implementation class called CustomInvalidationHandler
that will simply match all entities' types with "custom-group"
cache group regardless of any annotations:
public class CustomInvalidationHandler implements InvalidationHandler {
@Override
public InvalidationFunction canHandle(Class<? extends Persistent> type) {
return p -> Collections.singleton(new CacheGroupDescriptor("custom-group"));
}
}
Now we’ll set up it’s usage by ServerRuntime
:
ServerRuntime.builder()
.addModule(CacheInvalidationModule.extend()
// optionally you can disable @CacheGroups annotation processing
.noCacheGroupsHandler()
.addHandler(CustomInvalidationHandler.class)
.module())
| You can combine as many invalidation handlers as you need. |
The goal of this module is to capture commit changes and present them to interested parties in an easy-to-process format.
In order to use commitlog
module you need to perform three steps:
Mark all entities which changes you are interested in with @org.apache.cayenne.commitlog.CommitLog
annotation
@CommitLog(ignoredProperties = {"somePrivatePropertyToSkip"})
public class MyEntity extends _MyEntity {
// ...
}
Implement CommitLogListener
interface.
public class MyCommitLogListener implements CommitLogListener {
@Override
public void onPostCommit(ObjectContext originatingContext, ChangeMap changes) {
// ChangeMap will contain all information about changes happened in performed commit
// this particular example will print IDs of all inserted objects
changes.getUniqueChanges().stream()
.filter(change -> change.getType() == ObjectChangeType.INSERT)
.map(ObjectChange::getPostCommitId)
.forEach(id -> System.out.println("Inserted new entity with id: " + id));
}
}
Register your listener implementation.
ServerRuntime.builder()
.addModule(CommitLogModule.extend()
.addListener(MyCommitLogListener.class)
.module())
| You can use several listeners, but they all will get same changes. |
Crypto module allows encrypt and decrypt values stored in DB transparently to your Java app.
To use crypto module you must prepare your database to allow byte[]
storage and properly name columns that will contain encrypted values.
Currently supported SQL types that can be used to store encrypted data are:
Binary types: BINARY, BLOB, VARBINARY, LONGVARBINARY
. These types are preferred.
Character types, that will store base64
encoded value: CHAR, NCHAR, CLOB, NCLOB, LONGVARCHAR, LONGNVARCHAR, VARCHAR, NVARCHAR
.
Not all data types may be supported by your database.
Default naming strategy that doesn’t require additional setup suggests using "CRYPTO_" prefix. You can change this default strategy by injecting you own implementation of org.apache.cayenne.crypto.map.ColumnMapper
interface.
ServerRuntime.builder()
.addModule(CryptoModule.extend()
.columnMapper(MyColumnMapper.class)
.module())
Here is an example of how ObjEntity
with two encrypted and two unencrypted properties can look like:
To perform encryption you must provide KEYSTORE_URL
and KEY_PASSWORD
. Currently crypto module supports only Java "jceks" KeyStore.
ServerRuntime.builder()
.addModule(CryptoModule.extend()
.keyStore(this.getClass().getResource("keystore.jcek"), "my-password".toCharArray(), "my-key-alias")
.module())
Additionally to ColumnMapper
mentioned above you can customize other parts of crypto module
. You can enable gzip
compression and HMAC
usage (later will ensure integrity of data).
ServerRuntime.builder()
.addModule(CryptoModule.extend()
.compress()
.useHMAC()
.module())
Another useful extension point is support for custom Java value types. To add support for your data type you need to implement org.apache.cayenne.crypto.transformer.value.BytesConverter
interface that will convert required type to and from byte[]
.
ServerRuntime.builder()
.addModule(CryptoModule.extend()
.objectToBytesConverter(MyClass.class, new MyClassBytesConverter())
.module())
In addition to Java primitive types (and their object counterparts), crypto module supports encryption only of java.util.Date, java.math.BigInteger and java.math.BigDecimal types. |
Java 8 module allows to use java.time.LocalTime, java.time.LocalDate
and java.time.LocalDateTime
types for entity attributes
This module allows to integrate any JCache (JSR 107) compatible caching provider with Cayenne.
To use JCache provider in your app you need to include this module and caching provider libs (e.g. Ehcache). You can provide own implementation of org.apache.cayenne.jcache.JCacheConfigurationFactory
to customize cache configuration if required.
For advanced configuration and management please use provider specific options and tools.
| You can read about using cache in Cayenne in this chapter. |
You may else be interested in Cache invalidation extension.
Joda time module allows to use org.joda.time.LocalTime
, org.joda.time.LocalDate
, org.joda.time.LocalDateTime
and org.joda.time.DateTime
types for entity attributes.
Note that the property names below are defined as constants in org.apache.cayenne.configuration.Constants
interface.
cayenne.jdbc.driver[.domain_name.node_name]
defines a JDBC driver class to use when creating a DataSource. If domain name and optionally - node name are specified, the setting overrides DataSource info just for this domain/node. Otherwise the override is applied to all domains/nodes in the system.
Default value: none, project DataNode configuration is used
cayenne.jdbc.url[.domain_name.node_name]
defines a DB URL to use when creating a DataSource. If domain name and optionally - node name are specified, the setting overrides DataSource info just for this domain/node. Otherwise the override is applied to all domains/nodes in the system.
Default value: none, project DataNode configuration is used
cayenne.jdbc.username[.domain_name.node_name]
defines a DB user name to use when creating a DataSource. If domain name and optionally - node name are specified, the setting overrides DataSource info just for this domain/node. Otherwise the override is applied to all domains/nodes in the system.
Possible values: any
Default value: none, project DataNode configuration is used
cayenne.jdbc.password[.domain_name.node_name]
defines a DB password to use when creating a DataSource. If domain name and optionally - node name are specified, the setting overrides DataSource info just for this domain/node. Otherwise the override is applied to all domains/nodes in the system
Default value: none, project DataNode configuration is used
cayenne.jdbc.min_connections[.domain_name.node_name]
defines the DB connection pool minimal size. If domain name and optionally - node name are specified, the setting overrides DataSource info just for this domain/node. Otherwise the override is applied to all domains/nodes in the system
Default value: none, project DataNode configuration is used
cayenne.jdbc.max_connections[.domain_name.node_name]
defines the DB connection pool maximum size. If domain name and optionally - node name are specified, the setting overrides DataSource info just for this domain/node. Otherwise the override is applied to all domains/nodes in the system
Default value: none, project DataNode configuration is used
cayenne.jdbc.max_wait
defines a maximum time in milliseconds that a connection request could wait in the connection queue. After this period expires, an exception will be thrown in the calling method. A value of zero will make the thread wait until a connection is available with no time out.
Default value: 20 seconds
cayenne.jdbc.validation_query
defines a SQL string that returns some result. It will be used to validate connections in the pool.
Default value: none
cayenne.querycache.size
An integer defining the maximum number of entries in the query cache. Note that not all QueryCache providers may respect this property. MapQueryCache uses it, but the rest would use alternative configuration methods.
Possible values: any positive int value
Default value: 2000
cayenne.DataRowStore.snapshot.size
defines snapshot cache max size
Possible values: any positive int
Default value: 10000
cayenne.server.contexts_sync_strategy
defines whether peer ObjectContexts should receive snapshot events after commits from other contexts. If true (default), the contexts would automatically synchronize their state with peers.
Possible values: true, false
Default value: true
cayenne.server.object_retain_strategy
defines fetched objects retain strategy for ObjectContexts. When weak or soft strategy is used, objects retained by ObjectContext that have no local changes can potentially get garbage collected when JVM feels like doing it.
Possible values: weak, soft, hard
Default value: weak
cayenne.server.max_id_qualifier_size
defines a maximum number of ID qualifiers in the WHERE clause of queries that are generated for paginated queries and for DISJOINT_BY_ID prefetch processing. This is needed to avoid hitting WHERE clause size limitations and memory usage efficiency.
Possible values: any positive int
Default value: 10000
cayenne.server.external_tx
defines whether runtime should use external transactions.
Possible values: true, false
Default value: false
cayenne.server.query_execution_time_logging_threshold
defines the minimum number of milliseconds a query must run before it is logged. A value less than or equal to zero disables logging.
Default value: 0
cayenne.server.domain.name
defines an optional name of the runtime DataDomain. If not specified, the name is inferred from the configuration name.
Default value: none
cayenne.rop.service_url
defines the URL of the ROP server
Default value: none
cayenne.rop.service_username
defines the user name for an ROP client to login to an ROP server.
Default value: none
cayenne.rop.service_password
defines the password for an ROP client to login to an ROP server.
Default value: none
cayenne.rop.shared_session_name
defines the name of the shared session that an ROP client wants to join on an ROP server. If omitted, a dedicated session is created.
Default value: none
cayenne.rop.service.timeout
a value in milliseconds for the ROP client-server connection read operation timeout
Possible values: any positive long value
Default value: none
cayenne.rop.channel_events
defines whether client-side DataChannel should dispatch events to child ObjectContexts. If set to true, ObjectContexts will receive commit events and merge changes committed by peer contexts that passed through the common client DataChannel.
Possible values: true, false
Default value: false
cayenne.rop.context_change_events
defines whether object property changes in the client context result in firing events. Client UI components can listen to these events and update the UI. Disabled by default.
Possible values: true, false
Default value: false
cayenne.rop.context_lifecycle_events
defines whether object commit and rollback operations in the client context result in firing events. Client UI components can listen to these events and update the UI. Disabled by default.
Possible values: true,false
Default value: false
cayenne.server.rop_event_bridge_factory
defines the name of the org.apache.cayenne.event.EventBridgeFactory
that is passed from the ROP server to the client. I.e. server DI would provide a name of the factory, passing this name to the client via the wire. The client would instantiate it to receive events from the server. Note that this property is stored in cayenne.server.rop_event_bridge_properties
map, not in the main cayenne.properties
.
Default value: false
Note that the collection keys below are defined as constants in org.apache.cayenne.configuration.Constants
interface.
| Collection Property | Type | Description |
|---|---|---|
|
|
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. |
|
|
Contains objects that can discover the type of current database and install the correct DbAdapter in runtime. |
|
|
Stores DataDomain filters. |
|
|
Stores DataDomain listeners. |
|
|
Stores locations of the one of more project configuration files. |
|
|
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 |
|
|
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. |
|
|
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. |
|
|
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 |
TOKENS
<DEFAULT> SKIP : {
" "
| "\t"
| "\n"
| "\r"
}
<DEFAULT> TOKEN : {
<NULL: "null" | "NULL">
| <TRUE: "true" | "TRUE">
| <FALSE: "false" | "FALSE">
}
<DEFAULT> TOKEN : {
<PROPERTY_PATH: <IDENTIFIER> ("." <IDENTIFIER>)*>
}
<DEFAULT> TOKEN : {
<IDENTIFIER: <LETTER> (<LETTER> | <DIGIT>)* (["+"])?>
| <#LETTER: ["_","a"-"z","A"-"Z"]>
| <#DIGIT: ["0"-"9"]>
}
/**
* Quoted Strings, whose object value is stored in the token manager's
* "literalValue" field. Both single and double qoutes are allowed
*/<DEFAULT> MORE : {
"\'" : WithinSingleQuoteLiteral
| "\"" : WithinDoubleQuoteLiteral
}
<WithinSingleQuoteLiteral> MORE : {
<ESC: "\\" (["n","r","t","b","f","\\","\'","`","\""] | (["0"-"3"])? ["0"-"7"] (["0"-"7"])?)> : {
| <~["\'","\\"]> : {
}
<WithinSingleQuoteLiteral> TOKEN : {
<SINGLE_QUOTED_STRING: "\'"> : DEFAULT
}
<WithinDoubleQuoteLiteral> MORE : {
<STRING_ESC: <ESC>> : {
| <~["\"","\\"]> : {
}
<WithinDoubleQuoteLiteral> TOKEN : {
<DOUBLE_QUOTED_STRING: "\""> : DEFAULT
}
/**
* Integer or real Numeric literal, whose object value is stored in the token manager's
* "literalValue" field.
*/<DEFAULT> TOKEN : {
<INT_LITERAL: ("0" (["0"-"7"])* | ["1"-"9"] (["0"-"9"])* | "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+)
(["l","L","h","H"])?> : {
| <FLOAT_LITERAL: <DEC_FLT> (<EXPONENT>)? (<FLT_SUFF>)? | <DEC_DIGITS> <EXPONENT> (<FLT_SUFF>)?
| <DEC_DIGITS> <FLT_SUFF>> : {
| <#DEC_FLT: (["0"-"9"])+ "." (["0"-"9"])* | "." (["0"-"9"])+>
| <#DEC_DIGITS: (["0"-"9"])+>
| <#EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+>
| <#FLT_SUFF: ["d","D","f","F","b","B"]>
}
NON-TERMINALS
expression := orCondition <EOF>
orCondition := andCondition ( "or" andCondition )*
andCondition := notCondition ( "and" notCondition )*
notCondition := ( "not" | "!" ) simpleCondition
| simpleCondition
simpleCondition := <TRUE>
| <FALSE>
| scalarConditionExpression
( simpleNotCondition
| ( "=" | "==" ) scalarExpression
| ( "!=" | "<>" ) scalarExpression
| "<=" scalarExpression
| "<" scalarExpression | ">" scalarExpression
| ">=" scalarExpression
| "like" scalarExpression
| "likeIgnoreCase" scalarExpression
| "in" ( namedParameter | "(" scalarCommaList ")" )
| "between" scalarExpression "and" scalarExpression
)?
simpleNotCondition := ( "not" | "!" )
( "like" scalarExpression
| "likeIgnoreCase" scalarExpression
| "in" ( namedParameter | "(" scalarCommaList ")" )
| "between" scalarExpression "and" scalarExpression
)
scalarCommaList := ( scalarConstExpression ( "," scalarConstExpression )* )
scalarConditionExpression := scalarNumericExpression
| <SINGLE_QUOTED_STRING>
| <DOUBLE_QUOTED_STRING>
| <NULL>
scalarExpression := scalarConditionExpression
| <TRUE>
| <FALSE>
scalarConstExpression := <SINGLE_QUOTED_STRING>
| <DOUBLE_QUOTED_STRING>
| namedParameter
| <INT_LITERAL>
| <FLOAT_LITERAL>
| <TRUE>
| <FALSE>
scalarNumericExpression := multiplySubtractExp
( "+" multiplySubtractExp | "-" multiplySubtractExp )*
multiplySubtractExp := numericTerm ( "*" numericTerm | "/" numericTerm )*
numericTerm := ( "+" )? numericPrimary
| "-" numericPrimary
numericPrimary := "(" orCondition ")"
| pathExpression
| namedParameter
| <INT_LITERAL>
| <FLOAT_LITERAL>
namedParameter := "$" <PROPERTY_PATH>
pathExpression := ( <PROPERTY_PATH>
| "obj:" <PROPERTY_PATH>
| "db:" <PROPERTY_PATH>
| "enum:" <PROPERTY_PATH> )


NEW AGE ESPORTS
CREATE TOURNAMENT
CREATE
Setup
Brackets
Streams
Publish
SHARE
Invite Players
Embed Codes
ALL MAPS
ASCENT
1st half
2nd half
PLAYERS STATS, TOTAL
PLAYERS STATS, ATTACK