Compare commits

..
Author SHA1 Message Date
Robin Bygrave 7480904792 [maven-release-plugin] prepare release ebean-spring-7.1.2 2016-08-03 17:46:18 +12:00
Robin Bygrave b12cfafc21 Change groupId to ... org.avaje.ebean, and artifactId to ... ebean-spring 2016-08-03 17:45:51 +12:00
Robin Bygrave f07727651e [maven-release-plugin] prepare for next development iteration 2016-05-18 08:33:54 +12:00
Robin Bygrave 6090eaa167 [maven-release-plugin] prepare release avaje-ebeanorm-spring-7.1.1 2016-05-18 08:33:34 +12:00
Robin Bygrave 40eada4e80 #6 - Modify POM dependencies, change to provided scope for Ebean and Spring context 2016-05-18 08:33:04 +12:00
Robin Bygrave 2d375b3596 [maven-release-plugin] prepare for next development iteration 2015-11-04 08:34:33 +13:00
Robin Bygrave d864e2c723 [maven-release-plugin] prepare release avaje-ebeanorm-spring-6.1.1 2015-11-04 08:34:08 +13:00
Robin Bygrave e50c372562 Bump pom to 6.1.1-SNAPSHOT 2015-11-04 08:33:37 +13:00
Robin Bygrave e2cb033119 #5 - Error creating bean with name 'serverConfig' defined in class path resource [init-database.xml]: Cannot create inner bean 'com.avaje.ebean.config.AutofetchConfig#2e385cce' of type [com.avaje.ebean.config.AutofetchConfig] while setting bean property 'autofetchConfig' 2015-11-04 08:33:16 +13:00
Robin Bygrave 9620c57f19 [maven-release-plugin] prepare for next development iteration 2015-07-30 05:03:49 +12:00
Robin Bygrave 07cc0fcbb6 [maven-release-plugin] prepare release avaje-ebeanorm-spring-4.5.3 2015-07-30 05:03:28 +12:00
Robin Bygrave 6d1beb5c03 Add javadoc-plugin to pom 2015-07-30 05:03:05 +12:00
Robin Bygrave 1667107422 Update spring xsd to spring-beans-4.1.xsd 2015-07-30 04:57:03 +12:00
Robin Bygrave de5cf1df2c No effective change - format 2015-07-30 04:54:25 +12:00
Robin Bygrave a83114ced2 Update tests and dependencies 2015-07-30 04:53:25 +12:00
Rob Bygrave d6983422bf Merge pull request #3 from abguorui0928/master
Create AgentLoaderSupport.java
2015-05-14 22:45:43 +12:00
guor 6d4b3ad84e Create AgentLoaderSupport.java
add support for setup enhancement in spring
2015-05-11 21:01:58 +08:00
Eddie Mc Greal a3df7919b5 Updated to correct ebeanorm dependency range 2015-01-20 09:54:21 +01:00
Rob Bygrave 6f1aa39cc9 Merge pull request #2 from nedge/master
Update Version to 4.1.9 and edited MANIFEST for OSGi
2014-10-15 19:56:11 +13:00
Eddie Mc Greal f18c24c1d1 Update Version to 4.1.9 and edited MANIFEST for OSGi 2014-10-14 08:11:32 +02:00
Rob Bygrave 068401c29c [maven-release-plugin] prepare for next development iteration 2014-04-02 22:15:51 +13:00
Rob Bygrave 6fbbd8b107 [maven-release-plugin] prepare release avaje-ebeanorm-spring-3.3.1 2014-04-02 22:15:25 +13:00
Rob Bygrave 6379bd9e5d Set pom to 3.3.1-SNAPSHOT, ready for release 2014-04-02 22:12:31 +13:00
Rob Bygrave 94d58dfa7c Merge pull request #1 from nedge/develop
Changed to correct version and removed old logging config stuff
2014-04-02 22:08:21 +13:00
Eddie Mc Greal 035fb80959 Changed to correct version and removed old logging config stuff 2014-03-06 22:17:55 +01:00
Robin Bygrave 3b97f77083 [maven-release-plugin] prepare for next development iteration 2013-04-29 21:27:36 +12:00
Robin Bygrave a7d47202e6 [maven-release-plugin] prepare release avaje-ebeanorm-spring-3.2.1 2013-04-29 21:27:19 +12:00
Robin Bygrave 199a9d3118 Opps, fixed scm location 2013-04-29 21:26:37 +12:00
Robin Bygrave 5df3ac4b04 Change package of test beans etc for enhancement 2013-04-29 21:13:37 +12:00
Robin Bygrave 782f77b688 [maven-release-plugin] prepare for next development iteration 2012-09-15 01:32:05 +12:00
Robin Bygrave 1d570a233e [maven-release-plugin] prepare release avaje-ebeanorm-spring-3.1.1 2012-09-15 01:31:49 +12:00
Robin Bygrave 4a6b58bd9b Remove commons logging from dependency 2012-09-15 01:30:21 +12:00
rbygrave d64073bef0 Change license to Apache2, clean up dependencies 2012-09-15 01:15:37 +12:00
rbygrave 6d8a9236f8 initial add of EbeanORM spring from v2.8.1 2012-09-14 01:06:56 +12:00
Rob Bygrave 1665b4f2fa Initial commit 2012-09-13 05:59:29 -07:00
2674 changed files with 1091 additions and 288718 deletions
-13
View File
@@ -1,13 +0,0 @@
# editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
spaces_around_operators = true
max_line_length = 130
-19
View File
@@ -1,19 +0,0 @@
GITHUB ISSUES ARE STRICTLY CONTROLLED FOR THIS PROJECT.
Refer to http://ebean-orm.github.io/support for the policies controlling the use of github issues.
Please post issues to the Ebean group https://groups.google.com/forum/#!forum/ebean first.
## Expected behavior
## Actual behavior
### Steps to reproduce
```java
// some java code
```
```console
// some logging output
```
+3 -17
View File
@@ -1,23 +1,9 @@
*.autofetch
*create-all.sql
*drop-all.sql
*.orig
*.sql
.classpath
.project
.settings/
target/
logs/
log/
ebean-autotune.xml
ebean-profiling*.xml
/db
/mydb.db
!src/test/ddl-review/*.sql
profiling/
# Intellij project files
*.iml
*.ipr
*.iws
.idea/
*uuid.state
*.iml
-44
View File
@@ -1,44 +0,0 @@
dist: trusty
sudo: required
language: java
jdk:
- oraclejdk8
git:
depth: 3
addons:
postgresql: "9.6"
# apt:
# packages:
# - mysql-server-5.7
# - mysql-client-core-5.7
# - mysql-client-5.7
services:
- docker
- postgresql
- mysql
before_script:
- ./.travis/setup_database
- mysql -u root -e 'CREATE DATABASE test_ebean;'
- mysql -u root -e "CREATE USER 'test_ebean'@'localhost' IDENTIFIED BY 'test';"
- mysql -u root -e "GRANT ALL ON test_ebean.* TO 'test_ebean'@'localhost';"
env:
- EBEAN_DB=h2
- EBEAN_DB=pg
# - EBEAN_DB=mysql
install: true
script:
- mvn clean test
after_failure:
- ./.travis/print_surefire_reports
cache:
directories:
- $HOME/.m2
-10
View File
@@ -1,10 +0,0 @@
#!/bin/sh
echo "\n=== SUREFIRE REPORTS ===\n"
for file in target/surefire-reports/*.txt
do
echo ${file}
cat ${file}
echo
done
-14
View File
@@ -1,14 +0,0 @@
#!/bin/sh
echo "\n=== SETUP DATABASE ===\n"
#set -e
#set -x
# Setup postgres' users and databases
sudo -u postgres psql -c "CREATE USER unit WITH PASSWORD 'unit';"
sudo -u postgres psql -c 'CREATE DATABASE unit WITH OWNER unit;'
sudo -u postgres psql unit -c 'CREATE EXTENSION hstore;'
sudo -u postgres psql unit -c 'CREATE EXTENSION pgcrypto;'
#sudo -u postgres psql test2 -c 'CREATE EXTENSION postgis;'
-298
View File
@@ -1,298 +0,0 @@
Overview of ebean.properties file
=================================
### DbMigration options
You can set individual values for different platforms when generating migrations
`dbmigration.platform.<PLATFORM>.databaseSequenceBatchSize`
For DB's using sequences this is the number of sequence values prefetched.
`dbmigration.platform.<PLATFORM>.dbuuid`
Control, how UUID generation should work - it affects DDL which column type is generated. Possible values:
- BINARY enforces binary UUID
- VARCHAR enforces varchar UUID
- BINARY_OPTIMIZED enforces binary-optimized UUID (makes sense only with Type1 ID)
- AUTO_BINARY use binary when platform does not support native UUID
- AUTO_BINARY_OPTIMIZED use binary-optimized when platform does not support native UUID
- AUTO_VARCHAR (default) use varchar when platform does not support UUID
`dbmigration.platform.<PLATFORM>.uuidStoreAsBinary`
Same as setting dbuuid to BINARY
`dbmigration.platform.<PLATFORM>.geometrySRID`
The Geometry SRID value (default 4326).
`dbmigration.platform.<PLATFORM>.idType`
The ID type (IDENTITY, SEQUENCE, GENERATOR, EXTERNAL)
`dbmigration.platform.<PLATFORM>.mapping`
Adjust the mapping. For example `BOOLEAN=integer(32);BIT=tinyint(3)`
`ebean.migration.applyPrefix`
Set this to "V" to be compatible with FlywayDB.
`ebean.migration.applySuffix`
Defaults to '.sql'
`ebean.migration.dbusername`
DB user used to run the DB migration.
`ebean.migration.dbpassword`
DB password used to run the DB migration.
`ebean.migration.generate`
Set to true if the DB migration should be generated on server start.
`ebean.migration.generatePendingDrop`
The version of a pending drop that should be generated as the next migration.
`ebean.migration.includeGeneratedFileComment`
TODO
`ebean.migration.metaTable`
For running migration the DB table that holds migration execution status. Default 'db_migration'
`ebean.migration.migrationPath`
Resource path for the migration xml and sql.
`ebean.migration.modelPath`
Subdirectory the model xml files go into. Default 'model'
`ebean.migration.modelSuffix`
Suffix. Default '.model.xml'
`ebean.migration.name`
Description text that can be appended to the version to become the ddl script file name
`ebean.migration.patchInsertOn`
migration versions that should be added to history without running.
`ebean.migration.patchResetChecksumOn`
migration versions that should have their checksum reset and not run.
Use this if you get a 'Checksum mismatch' error.
`ebean.migration.placeholders`
A comma and equals delimited placeholders that are substituted in SQL scripts when running migration (used by DB Migration runner only).
`ebean.migration.platform`
The database platform to generate migration DDL for.
`ebean.migration.run`
Flag set to true means to run any outstanding migrations on startup.
`ebean.migration.version`
The migration version name (typically FlywayDb compatible). Example: 1.1.1_2
### Ebean UUID options
`ebean.uuidVersion`
Controls, how the UUIDs are generated. Possible values
- VERSION4 (default) generate random V4 UUIDs,
- VERSION1 generate rfc4122 compliant Type 1 UUIDs (requires a state file)
- VERSION1RND generate fake Type 1 UUIDs
Note, that V1 UUIDs in conjunction with AUTO_BINARY_OPTIMIZED will give you the best index performance, but you MUST understand how this works to avoid collisions.
`ebean.uuidStateFile`
The state file that is Required to generate V1 UUIDs
### DocStoreConfig
`ebean.docstore.active`
True when the Document store integration is active/on.
`ebean.docstore.allowAllCertificates`
Set to true such that the client allows connections to invalid/self signed SSL certificates.
`ebean.docstore.bulkBatchSize`
The default batch size to use for the Bulk API calls.
`ebean.docstore.create`
When true the Document store should create any document indexes that don't already exist.
`ebean.docstore.dropCreate`
When true the Document store should drop and re-create document indexes.
`ebean.docstore.generateMapping`
Set to true means Ebean will generate mapping files on startup.
`ebean.docstore.mappingPath`
Resource path for the Document store mapping files.
`ebean.docstore.mappingSuffix`
Suffix used for mapping files.
`ebean.docstore.password`
Password credential that be used for authentication to document store.
`ebean.docstore.pathToResources`
Location of resources that mapping files are generated into.
`ebean.docstore.persist`
The default mode used by indexes. `DEFAULT|IGNORE|QUEUE|UPDATE`
`ebean.docstore.url`
The URL of the Document store server. For example: http://localhost:9200.
`ebean.docstore.username`
Credential that be used for authentication to document store.
### Ebean Autotune
`ebean.autoTune.mode`
The autoTune mode `DEFAULT_OFF|DEFAULT_ON|DEFAULT_ONIFEMPTY`
`ebean.autoTune.profiling`
TODO
`ebean.autoTune.profilingBase`
TODO
`ebean.autoTune.profilingFile`
TODO
`ebean.autoTune.profilingRate`
TODO
`ebean.autoTune.profilingUpdateFrequency`
TODO
`ebean.autoTune.queryTuning`
TODO
`ebean.autoTune.queryTuningAddVersion`
TODO
`ebean.autoTune.queryTuningFile`
TODO
`ebean.autoTune.skipGarbageCollectionOnShutdown`
TODO
`ebean.autoTune.skipProfileReportingOnShutdown`
TODO
### Ebean options
`ebean.allQuotedIdentifiers`
Quote all identifiers
`ebean.asOfSysPeriod`
Column used to support history and 'As of' queries. This column is a timestamp range or equivalent.
`ebean.asOfViewSuffix`
Suffix appended to the base table to derive the view that contains the union of the base table and the history table in order to support asOf queries.
`ebean.autoCommitMode`
Set to true if the DataSource uses autoCommit. Indicates that Ebean should use autoCommit friendly Transactions and TransactionManager.
`ebean.autoReadOnlyDataSource`
When true create a read only DataSource using readOnlyDataSourceConfig defaulting values from dataSourceConfig
`ebean.autostart`
Should the server start all
`ebean.backgroundExecutorSchedulePoolSize`
TODO
`ebean.backgroundExecutorShutdownSecs`
TODO
and some more todos:
`ebean.batch.mode`
`ebean.batch.size`
`ebean.changeLogAsync`
`ebean.changeLogIncludeInserts`
`ebean.classes`
`ebean.collectQueryOrigins`
`ebean.collectQueryStatsByNode`
`ebean.currentUserProvider`
`ebean.dataSourceJndiName`
`ebean.dataTimeZone`
`ebean.databaseBooleanFalse`
`ebean.databaseBooleanTrue`
`ebean.databasePlatform`
`ebean.databasePlatformName`
`ebean.databaseSequenceBatchSize`
ebean.datasource.h2.adminpassword
ebean.datasource.h2.adminusername
`ebean.dbEncrypt`
`ebean.dbOffline`
ebean.ddl.createOnly
ebean.ddl.generate
ebean.ddl.header
ebean.ddl.initSql
ebean.ddl.run
ebean.ddl.seedSql
ebean.defaultDeleteMissingChildren
ebean.defaultOrderById
ebean.disableClasspathSearch
ebean.disableL2Cache
ebean.docStoreOnly
ebean.docstore.active
ebean.docstore.allowAllCertificates
ebean.docstore.bulkBatchSize
ebean.docstore.create
ebean.docstore.dropCreate
ebean.docstore.generateMapping
ebean.docstore.mappingPath
ebean.docstore.mappingSuffix
ebean.docstore.password
ebean.docstore.pathToResources
ebean.docstore.persist
ebean.docstore.url
ebean.docstore.username
ebean.encryptDeployManager
ebean.encryptKeyManager
ebean.encryptor
ebean.explicitTransactionBeginMode
ebean.expressionEqualsWithNullAsNoop
ebean.expressionNativeIlike
ebean.geometrySRID
ebean.historyTableSuffix
ebean.jdbcFetchSizeFindEach
ebean.jdbcFetchSizeFindList
ebean.jodaLocalTimeMode
ebean.jsonDateTime
ebean.jsonInclude
ebean.lazyLoadBatchSize
ebean.localTimeWithNanos
ebean.namingConvention.schema
ebean.namingConvention.sequenceFormat
ebean.namingConvention.useForeignKeyPrefix
ebean.namingconvention
ebean.notifyL2CacheInForeground
ebean.packages
ebean.persistBatch
ebean.persistBatchOnCascade
ebean.persistBatchSize
ebean.persistBatching
ebean.persistenceContextScope
ebean.profiling
ebean.profiling.directory
ebean.profiling.includeProfileIds
ebean.profiling.minimumMicros
ebean.profiling.profilesPerFile
ebean.profiling.verbose
ebean.queryBatchSize
ebean.queryPlanTTLSeconds
ebean.search.packages
ebean.serverCachePlugin
ebean.skipCacheAfterWrite
ebean.slowQueryMillis
ebean.tenant.catalogProvider
ebean.tenant.currentTenantProvider
ebean.tenant.mode
ebean.tenant.partitionColumn
ebean.tenant.schemaProvider
ebean.updateAllPropertiesInBatch
ebean.updateChangesOnly
ebean.updatesDeleteMissingChildren
ebean.useJavaxValidationNotNull
ebean.useJtaTransactionManager
-15
View File
@@ -1,15 +0,0 @@
EbeanORM
Copyright 2012 Authors.
Licensed 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.
+3 -16
View File
@@ -1,17 +1,4 @@
# Need help?
Post questions or issues to the Ebean google group - https://groups.google.com/forum/#!forum/ebean
# Documentation
Goto [https://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Website")
## Maven cental links:
[Maven central - ebean](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22io.ebean%22%20AND%20a%3A%22ebean%22 "maven central ebean")
[Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cebean "maven central all related projects")
## Current versions
* [![Maven Central : ebean](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean) - ebean
* [![Maven Central : ebean-agent](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-agent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-agent) - ebean-agent
* [![Maven Central : ebean-maven-plugin](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-maven-plugin/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-maven-plugin) - ebean-maven-plugin
avaje-ebeanorm-spring
=====================
Spring integration with EbeanORM
-153
View File
@@ -1,153 +0,0 @@
This is a short description how to run tests
============================================
Run tests from maven
--------------------
Just type `mvn test` - it will run the whole test suite with the settings
from `src/test/resources/ebean.properties`.
Run tests from eclipse
----------------------
Running tests requires, that the classes are enhanced. By default, the
`BaseTestCase` tries to load the enhancer-agent in a very early stage. This
also works for most test cases, but it does not work if you try to run a
complete test-suite, as classes that are loaded before the enhancer-agent
kicks in will not get enhanced. To solve this problem, you need either the
[Eclipse-Enhancer-Plugin](https://github.com/ebean-orm-tools/ebean-eclipse-enhancer)
or add the agent to your JVM arguments (Preferences->Installed JREs) or to
your run configuration:
`-javaagent:<USER_HOME>/.m2/repository/io/ebean/ebean-agent/<VERSION>/ebean-agent-<VERSION>.jar=debug=0`
Platform Tests
==============
By default, the `h2` platform is used. To test a different platform, add
`-Ddatasource.default=xxx` to your maven command or JVM arguments.
'h2' platform
-------------
Reqires no setup
run: `mvn clean test`
Current status: PASS
Tests run: 1986, Failures: 0, Errors: 0, Skipped: 16
'pg' platform
-------------
Reqirements
- a locally installed PostgreSQL server with PostGis.
- Create a user "unit" with password "unit" and a database "unit"
- Give the user all permissions to that db
run: `mvn clean test -Ddatasource.default=pg`
Current status: PASS
Tests run: 2166, Failures: 0, Errors: 0, Skipped: 25
'mysql' platform
-------------
Reqirements
- a locally installed MySQL server.
- Create a user "unit" with password "unit" and a database "unit"
- Give the user all permissions to that db
run: `mvn clean test -Ddatasource.default=mysql`
Current status: PASS
Tests run: 2166, Failures: 0, Errors: 0, Skipped: 33
'sqlserver' platform
--------------------
Reqires an installed sqlserver - e.g. https://hub.docker.com/r/microsoft/mssql-server-linux/
- Create a user "ebean" with password "ebean" and a database "ebean_unittest"
- Adjust the connection string and/or username in ebean.properties
run: `mvn clean test -Ddatasource.default=mssql`
Current status: PASS
Tests run: 2166, Failures: 0, Errors: 0, Skipped: 39
'oracle' platform
-----------------
Reqires a locally installed Oracle server.
- Create a user "unit" with password "unit" with all permissions
- The test wirtes directly to the "xe" SID - so do not use a productive server!
- As the Oracle JDBC driver is only available on an oracle repository,
you need a special maven setup as described [here](http://docs.oracle.com/middleware/1213/core/MAVEN/config_maven_repo.htm#MAVEN9010)
run: `mvn clean test -Ddatasource.default=ora -Poracle`
Current status: FAIL
Tests run: 1986, Failures: 17, Errors: 34, Skipped: 16
'db2' platform
--------------
Reqires a locally installed DB2 Express-C server.
- Create a user "unit" with password "unit" with all permissions
- Install the db2jcc4 driver (see pom.xml)
run: `mvn clean test -Ddatasource.default=db2 -Pdb2`
Current status: FAIL
Tests run: 2166, Failures: 29, Errors: 58, Skipped: 30
'sqlite' platform
-----------------
Reqires no setup
run: `mvn clean test -Ddatasource.default=sqlite`
Current status: FAIL
Tests run: 1986, Failures: 24, Errors: 86, Skipped: 16
After some time, the db locks up, every test takes 3 seconds and fails with
"the database file is locked"
'hsqldb' platform
-----------------
Reqires no setup
run: `mvn clean test -Ddatasource.default=hsqldb`
Current status: FAIL
Tests run: 1980, Failures: 3, Errors: 657, Skipped: 16
@Rob FYI
The problem is https://sourceforge.net/p/hsqldb/bugs/1364/
In `InsertHandler.getPstmt` the `meta.getIdentityDbColumns()` contains
'id' in lowercase. Changing that to uppercase gives me this result:
`Tests run: 1986, Failures: 2, Errors: 18, Skipped: 16`
(as quick hack I added temporary a toUpperCase to BindableIdScalar.getIdentityColumn)
'sqlanywhere' platform
----------------------
TODO: not yet tested
+162 -317
View File
@@ -1,392 +1,237 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.avaje</groupId>
<artifactId>java8-parent</artifactId>
<version>1.3</version>
<artifactId>avaje-javaparent</artifactId>
<version>1.2</version>
</parent>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>11.15.2</version>
<groupId>org.avaje.ebean</groupId>
<artifactId>ebean-spring</artifactId>
<name>ebean-spring</name>
<version>7.1.2</version>
<packaging>jar</packaging>
<description>Support for Spring transactions and IOC setup of Ebean server config</description>
<name>ebean</name>
<url>http://ebean-orm.github.io/</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.framework.version>4.1.7.RELEASE</spring.framework.version>
</properties>
<url>http://www.avaje.org</url>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-11.15.2</tag>
<connection>scm:git:https://github.com/ebean-orm/avaje-ebeanorm-spring.git</connection>
<developerConnection>scm:git:https://github.com/ebean-orm/avaje-ebeanorm-spring.git</developerConnection>
<url>https://github.com/ebean-orm/avaje-ebeanorm-spring.git</url>
</scm>
<profiles>
<profile>
<!-- Note: to use this profile, you need credentials for the oracle repository in your
settings.xml as described here:
http://docs.oracle.com/middleware/1213/core/MAVEN/config_maven_repo.htm#MAVEN9010 -->
<id>oracle</id>
<dependencies>
<dependency>
<groupId>com.oracle.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>12.2.0.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>maven.oracle.com</id>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
<url>https://maven.oracle.com</url>
<layout>default</layout>
</repository>
</repositories>
</profile>
<profile>
<!-- Note: to use this profile, you need to download manually the db2jcc4 driver.
After that, install it into your local maven repository:
mvn install:install-file \
-Dfile=db2jcc4.jar \
-DgroupId=com.ibm.jdbc \
-DartifactId=db2jcc4 \
-Dversion=4.23.42 \
-Dpackaging=jar
-->
<id>db2</id>
<dependencies>
<dependency>
<groupId>com.ibm.jdbc</groupId>
<artifactId>db2jcc4</artifactId>
<version>4.23.42</version>
<scope>test</scope>
</dependency>
</dependencies>
</profile>
</profiles>
<dependencies>
<!--
Projects are expected to explicit depend on version
of slf4j that they want to use
-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
<artifactId>jcl-over-slf4j</artifactId>
<version>[1.7,)</version>
</dependency>
<!-- Provided: Bring in explicitly -->
<dependency>
<groupId>org.avaje.ebean</groupId>
<artifactId>ebean</artifactId>
<version>8.1.1</version>
<scope>provided</scope>
</dependency>
<!--
Exclude snakeyaml if you desire - it is not strictly required.
-->
<!-- Optional: Add to use AgentLoaderSupport -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.19</version>
</dependency>
<!--
Class retention Nonnull and Nullable annotations
to assist with IDE auto-completion with Ebean API
-->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jsr305</artifactId>
<version>1.1</version>
<groupId>org.avaje.ebean</groupId>
<artifactId>ebean-agent</artifactId>
<version>8.1.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>persistence-api</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-annotation</artifactId>
<version>3.11</version>
</dependency>
<dependency>
<groupId>org.avaje</groupId>
<artifactId>avaje-datasource</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.avaje</groupId>
<artifactId>avaje-classpath-scanner</artifactId>
<version>3.1.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-migration</artifactId>
<version>11.5.1</version>
</dependency>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4-runtime</artifactId>
<version>4.7.1</version>
</dependency>
<!-- Jackson core used internally by Ebean -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<!-- provided scope for JsonNode support -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>1.1</version>
<scope>provided</scope>
</dependency>
<!-- provided scope to read validation annotations Size etc -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.9.7</version>
<scope>provided</scope>
</dependency>
<!-- Provided scope for Postgres JSON/JSONB support -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4.1212</version>
<scope>provided</scope>
</dependency>
<!-- Test scope -->
<!--<dependency>-->
<!--<groupId>oracle</groupId>-->
<!--<artifactId>oracle-jdbc</artifactId>-->
<!--<version>7.0</version>-->
<!--<scope>test</scope>-->
<!--</dependency>-->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-docker-run</artifactId>
<version>1.5.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<scope>test</scope>
</dependency>
<!-- Optional: Add to use AgentLoaderSupport -->
<dependency>
<groupId>org.avaje</groupId>
<artifactId>avaje-agentloader</artifactId>
<version>2.1.2</version>
<scope>test</scope>
<scope>provided</scope>
</dependency>
<!-- Provided: Spring, bring in explicitly -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-agent</artifactId>
<version>11.11.1</version>
<scope>test</scope>
</dependency>
<!-- Provided scope so that the H2HistoryTrigger can live in Ebean core
and not require a separate module for it -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.196</version>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.framework.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.15.1</version>
<scope>test</scope>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.framework.version}</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.framework.version}</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.framework.version}</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Test dependencies -->
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.3.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>6.4.0.jre8</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<!-- Do not upgrade to 6.0.6: https://bugs.mysql.com/bug.php?id=82896 -->
<version>5.1.43</version>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.framework.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.avaje.composite</groupId>
<artifactId>avaje-composite-testing</artifactId>
<version>1.1</version>
<scope>test</scope>
<artifactId>avaje-composite-testing-ebean</artifactId>
<version>4.1</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.avaje.moduuid</groupId>
<artifactId>avaje-moduuid</artifactId>
<version>2.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>io.ebean</groupId>
<groupId>org.avaje.ebean</groupId>
<artifactId>ebean-maven-plugin</artifactId>
<version>11.11.1</version>
<version>8.1.1</version>
<executions>
<execution>
<id>test</id>
<id>main</id>
<phase>process-test-classes</phase>
<configuration>
<transformArgs>debug=1</transformArgs>
<classSource>target/test-classes</classSource>
<packages>com.avaje.**</packages>
<transformArgs>debug=9</transformArgs>
</configuration>
<goals>
<goal>testEnhance</goal>
<goal>enhance</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.5</version>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
<failIfNoTests>false</failIfNoTests>
<includes>
<include>**/Test*.java</include>
<include>**/*Test.java</include>
<include>**/*Tests.java</include>
</includes>
<systemProperties>
<property>
<!-- transfer datasource.default parameter -->
<name>datasource.default</name>
<value>${datasource.default}</value>
</property>
<property>
<!-- transfer dbClockDelta parameter -->
<name>dbClockDelta</name>
<value>${dbClockDelta}</value>
</property>
</systemProperties>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.5</version>
<configuration>
<archive>
<manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<configuration>
<doctitle>Ebean 10</doctitle>
<overview>src/main/java/io/ebean/overview.html</overview>
<source>1.8</source>
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
<excludePackageNames>io.ebeaninternal.*:com.avaje.ebean.util</excludePackageNames>
<docletArtifact>
<groupId>org.avaje</groupId>
<artifactId>pygments-doclet</artifactId>
<version>1.0.0</version>
</docletArtifact>
<additionalparam>
-Xdoclint:none
-include-basedir ${project.basedir}
-attributes "idseparator=-; project_name=${project.name}; \
project_version=${project.version}; \
project_desc=${project.description}"
</additionalparam>
<linksource>true</linksource>
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<!--This plugin's configuration is used to store Eclipse m2e settings
only. It has no influence on the Maven build itself. -->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>
org.avaje.ebean
</groupId>
<artifactId>
ebean-maven-plugin
</artifactId>
<versionRange>
[3,4)
</versionRange>
<goals>
<goal>enhance</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore />
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<configuration>
<source>1.8</source>
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
<docletArtifact>
<groupId>org.avaje</groupId>
<artifactId>pygments-doclet</artifactId>
<version>1.0.0</version>
</docletArtifact>
<additionalparam>
-Xdoclint:none
</additionalparam>
<linksource>true</linksource>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
+3
View File
@@ -0,0 +1,3 @@
Manifest-Version: 1.0
Class-Path:
@@ -0,0 +1,46 @@
package com.avaje.ebean.springsupport;
import org.avaje.agentloader.AgentLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
/**
* To Setup Enhancement in Spring
* <bean class="org.ebean.AgentLoaderSupport">
* <property name="debug" value="1" />
* <property name="packages" value="org.ebean.**" />
* </bean>
* Created by guor on 2015/5/11.
*/
public class AgentLoaderSupport implements InitializingBean {
private Logger logger = LoggerFactory.getLogger(getClass());
private int debug;
private String packages;
public int getDebug() {
return debug;
}
public void setDebug(int debug) {
this.debug = debug;
}
public String getPackages() {
return packages;
}
public void setPackages(String packages) {
this.packages = packages;
}
@Override
public void afterPropertiesSet() throws Exception {
String args = "debug=" + getDebug() + ";packages=" + getPackages();
if (!AgentLoader.loadAgentFromClasspath("avaje-ebeanorm-agent", args)) {
logger.info("avaje-ebeanorm-agent not found in classpath - not dynamically loaded");
}
}
}
@@ -0,0 +1,85 @@
/**
* Copyright (C) 2009 the original author or authors
* <p>
* This file is part of Ebean.
* <p>
* Ebean is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
* <p>
* Ebean is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* <p>
* You should have received a copy of the GNU Lesser General Public License
* along with Ebean; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.avaje.ebean.springsupport.factory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import com.avaje.ebean.EbeanServer;
import com.avaje.ebean.EbeanServerFactory;
import com.avaje.ebean.config.ServerConfig;
/**
* A Spring FactoryBean for constructing EbeanServer instances.
*
* @since 18.05.2009
* @author E Mc Greal
*/
public class EbeanServerFactoryBean implements InitializingBean, FactoryBean<EbeanServer> {
/**
* The Ebean server configuration.
*/
private ServerConfig serverConfig;
/**
* The EbeanServer instance.
*/
private EbeanServer ebeanServer;
public void afterPropertiesSet() throws Exception {
if (serverConfig == null) {
throw new Exception("No ServerConig set. You must define a ServerConfig bean");
}
// Create the new EbeanServer using the configuration
this.ebeanServer = EbeanServerFactory.create(serverConfig);
}
public EbeanServer getObject() throws Exception {
return ebeanServer;
}
public Class<? extends EbeanServer> getObjectType() {
return EbeanServer.class;
}
/**
* Returns true for EbeanServer.
*/
public boolean isSingleton() {
return true;
}
/**
* Return the server configuration.
*/
public ServerConfig getServerConfig() {
return serverConfig;
}
/**
* Set the server configuration.
*/
public void setServerConfig(ServerConfig serverConfig) {
this.serverConfig = serverConfig;
}
}
@@ -0,0 +1,232 @@
/**
* Copyright (C) 2009 the original author or authors
* <p>
* This file is part of Ebean.
* <p>
* Ebean is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
* <p>
* Ebean is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* <p>
* You should have received a copy of the GNU Lesser General Public License
* along with Ebean; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.avaje.ebean.springsupport.txn;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.PersistenceException;
import javax.sql.DataSource;
import org.springframework.jdbc.datasource.ConnectionHolder;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import com.avaje.ebean.config.ExternalTransactionManager;
import com.avaje.ebeaninternal.api.SpiTransaction;
import com.avaje.ebeaninternal.server.transaction.DefaultTransactionThreadLocal;
import com.avaje.ebeaninternal.server.transaction.TransactionManager;
/**
* A Spring aware TransactionScopeManager.
*
* <p>
* Will look for Spring transactions and use them if they exist.
* </p>
*
* @since 18.05.2009
* @author E Mc Greal
*/
public class SpringAwareJdbcTransactionManager implements ExternalTransactionManager {
private final static Logger logger = Logger.getLogger(SpringAwareJdbcTransactionManager.class.getName());
/**
* The data source.
*/
private DataSource dataSource;
/**
* The Ebean transaction manager.
*/
private TransactionManager transactionManager;
/**
* The EbeanServer name.
*/
private String serverName;
/**
* Instantiates a new spring aware transaction scope manager.
*/
public SpringAwareJdbcTransactionManager() {
}
/**
* Initialise this with the Ebean internal transaction manager.
*/
public void setTransactionManager(Object txnMgr) {
// RB: At this stage not exposing TransactionManager to
// the public API and hence the Object type and casting here
this.transactionManager = (TransactionManager) txnMgr;
this.dataSource = transactionManager.getDataSource();
this.serverName = transactionManager.getServerName();
}
/**
* Looks for a current Spring managed transaction and wraps/returns that as a Ebean transaction.
* <p>
* Returns null if there is no current spring transaction (lazy loading outside a spring txn etc).
* </p>
*/
public Object getCurrentTransaction() {
// Get the current Spring ConnectionHolder associated to the current spring managed transaction
ConnectionHolder holder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
if (holder == null || !holder.isSynchronizedWithTransaction()) {
// no current Spring transaction
SpiTransaction currentEbeanTransaction = DefaultTransactionThreadLocal.get(serverName);
if (currentEbeanTransaction != null) {
// NOT expecting this so log WARNING
String msg = "SpringTransaction - no current spring txn BUT using current Ebean one " + currentEbeanTransaction.getId();
logger.log(Level.WARNING, msg);
} else if (logger.isLoggable(Level.FINEST)) {
logger.log(Level.FINEST, "Spring Txn - no current transaction ");
}
return currentEbeanTransaction;
}
SpringTxnListener springTxnLister = getSpringTxnListener();
if (springTxnLister != null) {
// we have already seen this transaction
return springTxnLister.getTransaction();
} else {
// This is a new spring transaction that we have not seen before.
// "wrap" it in a SpringJdbcTransaction for use with Ebean
SpringJdbcTransaction newTrans = new SpringJdbcTransaction(holder, transactionManager);
// Create and register a Spring TransactionSynchronization for this transaction
springTxnLister = createSpringTxnListener(newTrans);
TransactionSynchronizationManager.registerSynchronization(springTxnLister);
// also put in Ebean ThreadLocal
DefaultTransactionThreadLocal.set(serverName, newTrans);
return newTrans;
}
}
/**
* Search for our specific transaction listener.
* <p>
* If it exists then we have already seen and "wrapped" this transaction.
* </p>
*/
private SpringTxnListener getSpringTxnListener() {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
List<TransactionSynchronization> synchronizations = TransactionSynchronizationManager.getSynchronizations();
if (synchronizations != null) {
// search for our specific listener
for (int i = 0; i < synchronizations.size(); i++) {
if (synchronizations.get(i) instanceof SpringTxnListener) {
return (SpringTxnListener) synchronizations.get(i);
}
}
}
}
return null;
}
/**
* Create a listener to register with Spring to enable Ebean to be
* notified when transactions commit and rollback.
* <p>
* This is used by Ebean to notify it's appropriate listeners and maintain it's server
* cache etc.
* </p>
*/
private SpringTxnListener createSpringTxnListener(SpringJdbcTransaction t) {
return new SpringTxnListener(transactionManager, t);
}
/**
* A Spring TransactionSynchronization that we register with Spring to get
* notified when a Spring managed transaction has been committed or rolled
* back.
* <p>
* When Ebean is notified (of the commit/rollback) it can then manage its
* cache, notify BeanPersistListeners etc.
* </p>
*/
private static class SpringTxnListener extends TransactionSynchronizationAdapter {
private final TransactionManager transactionManager;
private final SpringJdbcTransaction transaction;
private final String serverName;
private SpringTxnListener(TransactionManager transactionManager, SpringJdbcTransaction t) {
this.transactionManager = transactionManager;
this.transaction = t;
this.serverName = transactionManager.getServerName();
}
/**
* Return the associated Ebean wrapped transaction.
*/
public SpringJdbcTransaction getTransaction() {
return transaction;
}
@Override
public void beforeCommit(boolean readOnly) {
// Future note: for JPA2 locking we will
// have beforeCommit events to fire
}
@Override
public void afterCompletion(int status) {
switch (status) {
case STATUS_COMMITTED:
if (logger.isLoggable(Level.FINE)) {
logger.fine("Spring Txn [" + transaction.getId() + "] committed");
}
transactionManager.notifyOfCommit(transaction);
break;
case STATUS_ROLLED_BACK:
if (logger.isLoggable(Level.FINE)) {
logger.fine("Spring Txn [" + transaction.getId() + "] rollback");
}
transactionManager.notifyOfRollback(transaction, null);
break;
default:
// this should never happen
String msg = "Invalid status " + status;
throw new PersistenceException(msg);
}
// Remove this transaction object as it is completed
DefaultTransactionThreadLocal.replace(serverName, null);
}
}
}
@@ -0,0 +1,45 @@
/**
* Copyright (C) 2009 the original author or authors
* <p>
* This file is part of Ebean.
* <p>
* Ebean is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
* <p>
* Ebean is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* <p>
* You should have received a copy of the GNU Lesser General Public License
* along with Ebean; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.avaje.ebean.springsupport.txn;
import org.springframework.jdbc.datasource.ConnectionHolder;
import com.avaje.ebeaninternal.server.transaction.ExternalJdbcTransaction;
import com.avaje.ebeaninternal.server.transaction.TransactionManager;
public class SpringJdbcTransaction extends ExternalJdbcTransaction {
private final ConnectionHolder holder;
public SpringJdbcTransaction(ConnectionHolder holder, TransactionManager manager) {
super("s" + holder.hashCode(), true, holder.getConnection(), manager);
this.holder = holder;
}
@Override
public boolean isActive() {
return holder.isSynchronizedWithTransaction();
}
public ConnectionHolder getConnectionHolder() {
return holder;
}
}
@@ -1,21 +0,0 @@
package io.ebean;
import javax.persistence.PessimisticLockException;
/**
* Thrown when failing to acquire a pessimistic lock.
* <p>
* Typically when "select for update nowait" or "select for update" is being used and
* the lock can not be obtained (as it is held by another transaction).
* </p>
*/
public class AcquireLockException extends PessimisticLockException {
private static final long serialVersionUID = -8585962352965876691L;
/**
* Create with a message and cause.
*/
public AcquireLockException(String message, Throwable cause) {
super(message, cause);
}
}
-24
View File
@@ -1,24 +0,0 @@
package io.ebean;
/**
* Administrative control of AutoTune during runtime.
*/
public interface AutoTune {
/**
* Fire a garbage collection (hint to the JVM). Assuming garbage collection
* fires this will gather remaining usage profiling information.
*/
void collectProfiling();
/**
* Output the profiling.
* <p>
* When profiling updates are applied to tuning at runtime this reports all tuning and profiling combined.
* When profiling is not applied at runtime then this reports the diff report with new and diff entries relative
* to the existing tuning.
* </p>
*/
void reportProfiling();
}
@@ -1,40 +0,0 @@
package io.ebean;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* Background thread pool service for executing of tasks asynchronously.
* <p>
* This service is used internally by Ebean for executing background tasks such
* as the {@link Query#findFutureList()} and also for executing background tasks
* periodically.
* </p>
* <p>
* This service has been made available so you can use it for your application
* code if you want. It can be useful for some server caching implementations
* (background population and trimming of the cache etc).
* </p>
*
* @author rbygrave
*/
public interface BackgroundExecutor {
/**
* Execute a task in the background.
*/
void execute(Runnable r);
/**
* Execute a task periodically with a fixed delay between each execution.
* <p>
* For example, execute a runnable every minute.
* </p>
* <p>
* The delay is the time between executions no matter how long the task took.
* That is, this method has the same behaviour characteristics as
* {@link ScheduledExecutorService#scheduleWithFixedDelay(Runnable, long, long, TimeUnit)}
* </p>
*/
void executePeriodically(Runnable r, long delay, TimeUnit unit);
}
-169
View File
@@ -1,169 +0,0 @@
package io.ebean;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Optional;
/**
* Provides finder functionality for use with "Dependency Injection style" use of Ebean.
* <p>
* Note that typically users would extend BeanRepository rather than BeanFinder.
* </p>
* <pre>{@code
*
* public class CustomerFinder extends BeanFinder<Long,Customer> {
*
* @Inject
* public CustomerFinder(EbeanServer server) {
* super(Customer.class, server);
* }
*
* // ... add customer specific finders
* }
*
* }</pre>
*
* @param <I> The ID type
* @param <T> The Bean type
*/
public abstract class BeanFinder<I,T> {
protected final EbeanServer server;
protected final Class<T> type;
/**
* Create with the given bean type and EbeanServer instance.
*
* @param type The bean type
* @param server The EbeanServer instance typically created via Spring factory or equivalent.
*/
protected BeanFinder(Class<T> type, EbeanServer server) {
this.type = type;
this.server = server;
}
/**
* Return the EbeanServer to use.
*/
public EbeanServer db() {
return server;
}
/**
* Return the current transaction.
*/
public Transaction currentTransaction() {
return db().currentTransaction();
}
/**
* Flush the JDBC batch on the current transaction.
*/
public void flush() {
db().flush();
}
/**
* Return typically a different EbeanServer to the default.
* <p>
* This is equivalent to {@link Ebean#getServer(String)}
*
* @param server The name of the EbeanServer. If this is null then the default EbeanServer is
* returned.
*/
public EbeanServer db(String server) {
return Ebean.getServer(server);
}
/**
* Creates an entity reference for this ID.
* <p>
* Equivalent to {@link EbeanServer#getReference(Class, Object)}
*/
@Nonnull
public T ref(I id) {
return db().getReference(type, id);
}
/**
* Retrieves an entity by ID.
* <p>
* Equivalent to {@link EbeanServer#find(Class, Object)}
*/
@Nullable
public T findById(I id) {
return db().find(type, id);
}
/**
* Find an entity by ID returning an Optional.
*/
@Nullable
public Optional<T> findByIdOrEmpty(I id) {
return db().find(type).setId(id).findOneOrEmpty();
}
/**
* Delete a bean by Id.
* <p>
* Equivalent to {@link EbeanServer#delete(Class, Object)}
*/
public void deleteById(I id) {
db().delete(type, id);
}
/**
* Retrieves all entities of the given type.
*/
@Nonnull
public List<T> findAll() {
return query().findList();
}
/**
* Creates an update query.
*
* <pre>{@code
*
* int rows =
* updateQuery()
* .set("status", Customer.Status.ACTIVE)
* .set("updtime", new Timestamp(System.currentTimeMillis()))
* .where()
* .gt("id", 1000)
* .update();
*
* }</pre>
*
* <p>
* Equivalent to {@link EbeanServer#update(Class)}
*/
protected UpdateQuery<T> updateQuery() {
return db().update(type);
}
/**
* Creates a query.
* <p>
* Equivalent to {@link EbeanServer#find(Class)}
*/
protected Query<T> query() {
return db().find(type);
}
/**
* Creates a native sql query.
*/
protected Query<T> nativeSql(String nativeSql) {
return db().findNative(type, nativeSql);
}
/**
* Creates a query using the ORM query language.
*/
protected Query<T> query(String ormQuery) {
return db().createQuery(type, ormQuery);
}
}
-178
View File
@@ -1,178 +0,0 @@
package io.ebean;
import io.ebean.bean.EntityBean;
/**
* Provides finder functionality for use with "Dependency Injection style" use of Ebean.
* <p>
* <pre>{@code
*
* @Repository
* public class CustomerRepository extends BeanRepository<Long,Customer> {
*
* @Inject
* public CustomerRepository(EbeanServer server) {
* super(Customer.class, server);
* }
*
* // ... add customer specific finders and persist logic
*
* public List<Customer> findByName(String nameStart) {
* return query().where()
* .istartsWith("name", nameStart)
* .findList();
* }
*
* }
* }</pre>
*
* @param <I> The ID type
* @param <T> The Bean type
*/
public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
/**
* Create with the given bean type and EbeanServer instance.
* <p>
* Typically users would extend BeanRepository rather than BeanFinder.
* </p>
* <pre>{@code
*
* @Inject
* public CustomerRepository(EbeanServer server) {
* super(Customer.class, server);
* }
*
* }</pre>
*
* @param type The bean type
* @param server The EbeanServer instance typically created via Spring factory or equivalent
*/
protected BeanRepository(Class<T> type, EbeanServer server) {
super(type, server);
}
/**
* Marks the entity bean as dirty.
* <p>
* This is used so that when a bean that is otherwise unmodified is updated the version
* property is updated.
* <p>
* An unmodified bean that is saved or updated is normally skipped and this marks the bean as
* dirty so that it is not skipped.
* <p>
* <pre>{@code
*
* Customer customer = customerRepository.byId(id);
*
* // mark the bean as dirty so that a save() or update() will
* // increment the version property
*
* customerRepository.markAsDirty(customer);
* customerRepository.save(customer);
*
* }</pre>
*
* @see EbeanServer#markAsDirty(Object)
*/
public void markAsDirty(T bean) {
db().markAsDirty(bean);
}
/**
* Mark the property as unset or 'not loaded'.
* <p>
* This would be used to specify a property that we did not wish to include in a stateless update.
* </p>
* <pre>{@code
*
* // populate an entity bean from JSON or whatever
* Customer customer = ...;
*
* // mark the email property as 'unset' so that it is not
* // included in a 'stateless update'
* customerRepository.markPropertyUnset(customer, "email");
*
* customerRepository.update(customer);
*
* }</pre>
*
* @param propertyName the name of the property on the bean to be marked as 'unset'
*/
public void markPropertyUnset(T bean, String propertyName) {
((EntityBean) bean)._ebean_getIntercept().setPropertyLoaded(propertyName, false);
}
/**
* Insert or update this entity depending on its state.
* <p>
* Ebean will detect if this is a new bean or a previously fetched bean and perform either an
* insert or an update based on that.
*
* @see EbeanServer#save(Object)
*/
public void save(T bean) {
db().save(bean);
}
/**
* Update this entity.
*
* @see EbeanServer#update(Object)
*/
public void update(T bean) {
db().update(bean);
}
/**
* Insert this entity.
*
* @see EbeanServer#insert(Object)
*/
public void insert(T bean) {
db().insert(bean);
}
/**
* Delete this bean.
* <p>
* This will return true if the bean was deleted successfully or JDBC batch is being used.
* </p>
* <p>
* If there is no current transaction one will be created and committed for
* you automatically.
* </p>
* <p>
* If the Bean does not have a version property (or loaded version property) and
* the bean does not exist then this returns false indicating that nothing was
* deleted. Note that, if JDBC batch mode is used then this always returns true.
* </p>
*
* @see EbeanServer#delete(Object)
*/
public boolean delete(T bean) {
return db().delete(bean);
}
/**
* Delete a bean permanently without soft delete.
* <p>
* This is used when the bean contains a <code>@SoftDelete</code> property and we
* want to perform a hard/permanent delete.
* </p>
*
* @see EbeanServer#deletePermanent(Object)
*/
public boolean deletePermanent(T bean) {
return db().deletePermanent(bean);
}
/**
* Refreshes this entity from the database.
*
* @see EbeanServer#refresh(Object)
*/
public void refresh(T bean) {
db().refresh(bean);
}
}
-114
View File
@@ -1,114 +0,0 @@
package io.ebean;
import java.util.Map;
import java.util.Set;
/**
* Provides access to the internal state of an entity bean.
*/
public interface BeanState {
/**
* Return true if this is a lazy loading reference bean.
* <p>
* If so the this bean only holds the Id property and will invoke lazy loading
* if any other property is get or set.
* </p>
*/
boolean isReference();
/**
* Return true if the bean is new (and not yet saved).
*/
boolean isNew();
/**
* Return true if the bean is new or dirty (and probably needs to be saved).
*/
boolean isNewOrDirty();
/**
* Return true if the bean has been changed but not yet saved.
*/
boolean isDirty();
/**
* This can be called with true to disable lazy loading on the bean.
*/
void setDisableLazyLoad(boolean disableLazyLoading);
/**
* Return true if the bean has lazy loading disabled.
*/
boolean isDisableLazyLoad();
/**
* Set the loaded state of the property given it's name.
* <p>
* Typically this would be used to set the loaded state of a property
* to false to ensure that the specific property is excluded from a
* stateless update.
* </p>
* <pre>{@code
*
* // populate a bean via say JSON
* User user = ...;
*
* // set loaded state on the email property to false so that
* // the email property is not included in a stateless update
* Ebean.getBeanState(user).setPropertyLoaded("email", false);
*
* user.update();
*
* }</pre>
* <p>
* This will throw an IllegalArgumentException if the property is unknown.
*/
void setPropertyLoaded(String propertyName, boolean loaded);
/**
* For partially populated beans returns the properties that are loaded on the
* bean.
* <p>
* Accessing another property will cause lazy loading to occur.
* </p>
*/
Set<String> getLoadedProps();
/**
* Return the set of changed properties.
*/
Set<String> getChangedProps();
/**
* Return a map of the updated properties and their new and old values.
*/
Map<String, ValuePair> getDirtyValues();
/**
* Return true if the bean is readOnly.
* <p>
* If a setter is called on a readOnly bean it will throw an exception.
* </p>
*/
boolean isReadOnly();
/**
* Set the readOnly status for the bean.
*/
void setReadOnly(boolean readOnly);
/**
* Advanced - Used to programmatically build a partially or fully loaded
* entity bean. First create an entity bean via
* {@link EbeanServer#createEntityBean(Class)}, then populate its properties
* and then call this method specifying which properties where loaded or null
* for a fully loaded entity bean.
*/
void setLoaded();
/**
* Reset the bean putting it into NEW state such that a save() results in an insert.
*/
void resetForInsert();
}
-93
View File
@@ -1,93 +0,0 @@
package io.ebean;
/**
* Enum to control the different cache modes for queryCache and beanCache.
* <h3>Bean cache</h3>
* <p>
* The bean cache is automatically used by default on <code>@Cache</code> beans for
* the following queries:
* </p>
* <ul>
* <li>findOne() by id</li>
* <li>findOne() by natural key(s)</li>
* <li>findList() by ids</li>
* </ul>
* <p>
* Bean caching needs to be explicitly turned on for queries that are findList() by natural keys.
* </p>
* <h3>Query cache</h3>
* <p>
* For query cache use note that you must be careful, what you do with the returned collection.
* By default the returned collections are read only and you will get an exception if you try
* to change them.
* If you add ".setReadOnly(false)" to your query, you'll get a collection that is a clone from the
* one in the cache. That means, changing does not affect the cache.
* </p>
*
* @author Roland Praml, FOCONIS AG
*/
public enum CacheMode {
/**
* Do not use cache.
*/
OFF(false, false),
/**
* Use the cache and store a result when needed.
*/
ON(true, true),
/**
* Only used for bean caching.
* <p>
* The bean cache is automatically used by default on <code>@Cache</code> beans for
* the following queries:
* </p>
* <ul>
* <li>findOne() by id</li>
* <li>findOne() by natural key(s)</li>
* <li>findList() by ids</li>
* </ul>
* <p>
* Bean caching needs to be explicitly turned on for queries that are findList() by natural keys.
* </p>
*/
AUTO(true, true),
/**
* Do not read from cache, but put beans into the cache and invalidate parts of the cache as necessary.
* <p>
* Use this on a query if you want to get the fresh value from database and put it into the cache.
*/
PUT(false, true),
/**
* GET only from the cache.
* <p>
* This mode does not put entries into the cache or invalidate parts of the cache.
*/
GET(true, false);
private boolean get;
private boolean put;
CacheMode(boolean get, boolean put) {
this.get = get;
this.put = put;
}
/**
* Return true if value is read from cache.
*/
public boolean isGet() {
return get;
}
/**
* Return true if a newly loaded value (from database) is put into the cache.
*/
public boolean isPut() {
return put;
}
}
-187
View File
@@ -1,187 +0,0 @@
package io.ebean;
import java.sql.CallableStatement;
import java.sql.SQLException;
/**
* For making calls to stored procedures. Refer to the Ebean execute() method.
* <p>
* Note that UpdateSql is designed for general DML sql and CallableSql is
* designed for use with stored procedures. Also note that when using this in
* batch mode the out parameters are not read.
* </p>
* <p>
* Example 1:
* </p>
* <pre>{@code
*
* String sql = "{call sp_order_mod(?,?)}";
*
* CallableSql cs = Ebean.createCallableSql(sql);
* cs.setParameter(1, "turbo");
* cs.registerOut(2, Types.INTEGER);
*
* Ebean.execute(cs);
*
* // read the out parameter
* Integer returnValue = (Integer) cs.getObject(2);
*
* }</pre>
* <p>
* Example 2:<br>
* Includes batch mode, table modification information and label. Note that the
* label is really only to help people reading the transaction logs to identify
* the procedure called etc.
* </p>
*
* <pre>{@code
*
* String sql = "{call sp_insert_order(?,?)}";
*
* CallableSql cs = Ebean.createCallableSql(sql);
*
* // Inform Ebean this stored procedure inserts into the
* // oe_order table and inserts + updates the oe_order_detail table.
* // this is used to invalidate objects in the cache
* cs.addModification("oe_order", true, false, false);
* cs.addModification("oe_order_detail", true, true, false);
*
* Transaction t = Ebean.startTransaction();
*
* // execute using JDBC batching 10 statements at a time
* t.setBatchMode(true);
* t.setBatchSize(10);
* try {
* cs.setParameter(1, "Was");
* cs.setParameter(2, "Banana");
* Ebean.execute(cs);
*
* cs.setParameter(1, "Here");
* cs.setParameter(2, "Kumera");
* Ebean.execute(cs);
*
* cs.setParameter(1, "More");
* cs.setParameter(2, "Apple");
* Ebean.execute(cs);
*
* // Ebean.externalModification("oe_order",true,false,false);
* // Ebean.externalModification("oe_order_detail",true,true,false);
* Ebean.commitTransaction();
*
* } finally {
* Ebean.endTransaction();
* }
* }</pre>
*
* @see SqlUpdate
* @see Ebean#execute(CallableSql)
*/
public interface CallableSql {
/**
* Return the label that is put into the transaction log.
*/
String getLabel();
/**
* Set the label that is put in the transaction log.
*/
CallableSql setLabel(String label);
/**
* Return the statement execution timeout.
*/
int getTimeout();
/**
* Return the callable sql.
*/
String getSql();
/**
* Set the statement execution timeout. Zero implies unlimited time.
* <p>
* This is set to the underlying CallableStatement.
* </p>
*/
CallableSql setTimeout(int secs);
/**
* Set the callable sql.
*/
CallableSql setSql(String sql);
/**
* Bind a parameter that is bound as a IN parameter.
* <p>
* position starts at value 1 (not 0) to be consistent with CallableStatement.
* </p>
* <p>
* This is designed so that you do not need to set params in index order. You
* can set/register param 2 before param 1 etc.
* </p>
*
* @param position the index position of the parameter.
* @param value the value of the parameter.
*/
CallableSql bind(int position, Object value);
/**
* Bind a positioned parameter (same as bind method).
*
* @param position the index position of the parameter.
* @param value the value of the parameter.
*/
CallableSql setParameter(int position, Object value);
/**
* Register an OUT parameter.
* <p>
* Note that position starts at value 1 (not 0) to be consistent with
* CallableStatement.
* </p>
* <p>
* This is designed so that you do not need to register params in index order.
* You can set/register param 2 before param 1 etc.
* </p>
*
* @param position the index position of the parameter (starts with 1).
* @param type the jdbc type of the OUT parameter that will be read.
*/
CallableSql registerOut(int position, int type);
/**
* Return an OUT parameter value.
* <p>
* position starts at value 1 (not 0) to be consistent with CallableStatement.
* </p>
* <p>
* This can only be called after the CallableSql has been executed. When run
* in batch mode you effectively can't use this method.
* </p>
*/
Object getObject(int position);
/**
* You can extend this object and override this method for more advanced
* stored procedure calls. This would be the case when ResultSets are returned
* etc.
*/
boolean executeOverride(CallableStatement cstmt) throws SQLException;
/**
* Add table modification information to the TransactionEvent.
* <p>
* This would be similar to using the
* <code>Ebean.externalModification()</code> method. It may be easier and make
* more sense to set it here with the CallableSql.
* </p>
* <p>
* For UpdateSql the table modification information is derived by parsing the
* sql to determine the table name and whether it was an insert, update or
* delete.
* </p>
*/
CallableSql addModification(String tableName, boolean inserts, boolean updates, boolean deletes);
}
@@ -1,27 +0,0 @@
package io.ebean;
/**
* Enumeration to use with {@link Query#setCountDistinct(CountDistinctOrder)}.
* @author Roland Praml, FOCONIS AG
*
*/
public enum CountDistinctOrder {
NO_ORDERING,
/** order by attribute ascending */
ATTR_ASC,
/** order by attribute descending */
ATTR_DESC,
/** order by count ascending and attribute ascending */
COUNT_ASC_ATTR_ASC,
/** order by count ascending and attribute descending */
COUNT_ASC_ATTR_DESC,
/** order by count descending and attribute ascending */
COUNT_DESC_ATTR_ASC,
/** order by count descending and attribute descending */
COUNT_DESC_ATTR_DESC,
}
-33
View File
@@ -1,33 +0,0 @@
package io.ebean;
import java.io.Serializable;
/**
* Holds a distinct value with it's count.
* (Used with {@link Query#findSingleAttributeList()} and {@link Query#setCountDistinct(CountDistinctOrder)}.)
* @author Roland Praml, FOCONIS AG
*/
public class CountedValue<A> implements Serializable {
private static final long serialVersionUID = -2267971668356749695L;
private final A value;
private final long count;
public CountedValue(A value, long count) {
this.value = value;
this.count = count;
}
public long getCount() {
return count;
}
public A getValue() {
return value;
}
@Override
public String toString() {
return count + ": " + value;
}
}
@@ -1,17 +0,0 @@
package io.ebean;
import javax.persistence.PersistenceException;
/**
* Thrown when a foreign key constraint is enforced.
*/
public class DataIntegrityException extends PersistenceException {
private static final long serialVersionUID = -6740171949170180970L;
/**
* Create with a message and cause.
*/
public DataIntegrityException(String message, Throwable cause) {
super(message, cause);
}
}
@@ -1,94 +0,0 @@
package io.ebean;
/**
* Bean holding the details to update the document store.
*/
public final class DocStoreQueueEntry {
/**
* Action to either update or delete a document from the index.
*/
public enum Action {
/**
* Action is to update a document in the doc store.
*/
INDEX(1),
/**
* Action is to delete a document from the doc store..
*/
DELETE(2),
/**
* An update is required based on a change to a nested/embedded object at a given path.
*/
NESTED(3);
int value;
Action(int value) {
this.value = value;
}
/**
* Return the value associated with this action type.
*/
public int getValue() {
return value;
}
}
private final Action type;
private final String queueId;
private final String path;
private final Object beanId;
/**
* Construct for an INDEX or DELETE action.
*/
public DocStoreQueueEntry(Action type, String queueId, Object beanId) {
this(type, queueId, null, beanId);
}
/**
* Construct for an NESTED/embedded path invalidation action.
*/
public DocStoreQueueEntry(Action type, String queueId, String path, Object beanId) {
this.type = type;
this.queueId = queueId;
this.path = path;
this.beanId = beanId;
}
/**
* Return the event type.
*/
public Action getType() {
return type;
}
/**
* Return the associate queueId.
*/
public String getQueueId() {
return queueId;
}
/**
* Return the path if this is a nested update.
*/
public String getPath() {
return path;
}
/**
* Return the bean id (which matches the document id).
*/
public Object getBeanId() {
return beanId;
}
}
-310
View File
@@ -1,310 +0,0 @@
package io.ebean;
import io.ebeanservice.docstore.api.DocQueryRequest;
import io.ebeanservice.docstore.api.RawDoc;
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* Document storage operations.
*/
public interface DocumentStore {
/**
* Update the associated document store using the result of the query.
* <p>
* This will execute the query against the database creating a document for each
* bean graph and sending this to the document store.
* </p>
* <p>
* Note that the select and fetch paths of the query is set for you to match the
* document structure needed based on <code>@DocStore</code> and <code>@DocStoreEmbedded</code>
* so what this query requires is the predicates only.
* </p>
* <p>
* This query will be executed using findEach so it is safe to use a query
* that will fetch a lot of beans. The default bulkBatchSize is used.
* </p>
*
* @param query The query that selects object to send to the document store.
*/
<T> void indexByQuery(Query<T> query);
/**
* Update the associated document store index using the result of the query additionally specifying a
* bulkBatchSize to use for sending the messages to ElasticSearch.
*
* @param query The query that selects object to send to the document store.
* @param bulkBatchSize The batch size to use when bulk sending to the document store.
*/
<T> void indexByQuery(Query<T> query, int bulkBatchSize);
/**
* Update the document store for all beans of this type.
* <p>
* This is the same as indexByQuery where the query has no predicates and so fetches all rows.
* </p>
*/
void indexAll(Class<?> beanType);
/**
* Return the bean by fetching it's content from the document store.
* If the document is not found null is returned.
* <p>
* Typically this is called indirectly by findOne() on the query.
* </p>
* <pre>{@code
*
* Customer customer =
* server.find(Customer.class)
* .setUseDocStore(true)
* .setId(42)
* .findOne();
*
* }</pre>
*/
@Nullable
<T> T find(DocQueryRequest<T> request);
/**
* Execute the find list query. This request is prepared to execute secondary queries.
* <p>
* Typically this is called indirectly by findList() on the query that has setUseDocStore(true).
* </p>
* <pre>{@code
*
* List<Customer> newCustomers =
* server.find(Customer.class)
* .setUseDocStore(true)
* .where().eq("status, Customer.Status.NEW)
* .findList();
*
* }</pre>
*/
<T> List<T> findList(DocQueryRequest<T> request);
/**
* Execute the query against the document store returning the paged list.
* <p>
* The query should have <code>firstRow</code> or <code>maxRows</code> set prior to calling this method.
* </p>
* <p>
* Typically this is called indirectly by findPagedList() on the query that has setUseDocStore(true).
* </p>
* <pre>{@code
*
* PagedList<Customer> newCustomers =
* server.find(Customer.class)
* .setUseDocStore(true)
* .where().eq("status, Customer.Status.NEW)
* .setMaxRows(50)
* .findPagedList();
*
* }</pre>
*/
<T> PagedList<T> findPagedList(DocQueryRequest<T> request);
/**
* Execute the query against the document store with the expectation of a large set of results
* that are processed in a scrolling resultSet fashion.
* <p>
* For example, with the ElasticSearch doc store this uses SCROLL.
* </p>
* <p>
* Typically this is called indirectly by findEach() on the query that has setUseDocStore(true).
* </p>
* <pre>{@code
*
* server.find(Order.class)
* .setUseDocStore(true)
* .where()... // perhaps add predicates
* .findEach((Order order) -> {
* // process the bean ...
* });
*
* }</pre>
*/
<T> void findEach(DocQueryRequest<T> query, Consumer<T> consumer);
/**
* Execute the query against the document store with the expectation of a large set of results
* that are processed in a scrolling resultSet fashion.
* <p>
* Unlike findEach() this provides the opportunity to stop iterating through the large query.
* </p>
* <p>
* For example, with the ElasticSearch doc store this uses SCROLL.
* </p>
* <p>
* Typically this is called indirectly by findEachWhile() on the query that has setUseDocStore(true).
* </p>
* <pre>{@code
*
* server.find(Order.class)
* .setUseDocStore(true)
* .where()... // perhaps add predicates
* .findEachWhile(new Predicate<Order>() {
* @Override
* public void accept(Order bean) {
* // process the bean
*
* // return true to continue, false to stop
* // boolean shouldContinue = ...
* return shouldContinue;
* }
* });
*
* }</pre>
*/
<T> void findEachWhile(DocQueryRequest<T> query, Predicate<T> consumer);
/**
* Find each processing raw documents.
*
* @param indexNameType The full index name and type
* @param rawQuery The query to execute
* @param consumer Consumer to process each document
*/
void findEach(String indexNameType, String rawQuery, Consumer<RawDoc> consumer);
/**
* Find each processing raw documents stopping when the predicate returns false.
*
* @param indexNameType The full index name and type
* @param rawQuery The query to execute
* @param consumer Consumer to process each document until false is returned
*/
void findEachWhile(String indexNameType, String rawQuery, Predicate<RawDoc> consumer);
/**
* Process the queue entries sending updates to the document store or queuing them for later processing.
*/
long process(List<DocStoreQueueEntry> queueEntries) throws IOException;
/**
* Drop the index from the document store (similar to DDL drop table).
* <pre>{@code
*
* DocumentStore documentStore = server.docStore();
*
* documentStore.dropIndex("product_copy");
*
* }</pre>
*/
void dropIndex(String indexName);
/**
* Create an index given a mapping file as a resource in the classPath (similar to DDL create table).
* <pre>{@code
*
* DocumentStore documentStore = server.docStore();
*
* // uses product_copy.mapping.json resource
* // ... to define mappings for the index
*
* documentStore.createIndex("product_copy", null);
*
* }</pre>
*
* @param indexName the name of the new index
* @param alias the alias of the index
*/
void createIndex(String indexName, String alias);
/**
* Modify the settings on an index.
* <p>
* For example, this can be used be used to set elasticSearch refresh_interval
* on an index before a bulk update.
* </p>
* <pre>{@code
*
* // refresh_interval -1 ... disable refresh while bulk loading
*
* Map<String,Object> settings = new LinkedHashMap<>();
* settings.put("refresh_interval", "-1");
*
* documentStore.indexSettings("product", settings);
*
* }</pre>
* <pre>{@code
*
* // refresh_interval 1s ... restore after bulk loading
*
* Map<String,Object> settings = new LinkedHashMap<>();
* settings.put("refresh_interval", "1s");
*
* documentStore.indexSettings("product", settings);
*
* }</pre>
*
* @param indexName the name of the index to update settings on
* @param settings the settings to set on the index
*/
void indexSettings(String indexName, Map<String, Object> settings);
/**
* Copy the index to a new index.
* <p>
* This copy process does not use the database but instead will copy from the source index to a destination index.
* </p>
* <pre>{@code
*
* long copyCount = documentStore.copyIndex(Product.class, "product_copy");
*
* }</pre>
*
* @param beanType The bean type of the source index
* @param newIndex The name of the index to copy to
* @return the number of documents copied to the new index
*/
long copyIndex(Class<?> beanType, String newIndex);
/**
* Copy entries from an index to a new index but limiting to documents that have been
* modified since the sinceEpochMillis time.
* <p>
* To support this the document needs to have a <code>@WhenModified</code> property.
* </p>
* <pre>{@code
*
* long copyCount = documentStore.copyIndex(Product.class, "product_copy", sinceMillis);
*
* }</pre>
*
* @param beanType The bean type of the source index
* @param newIndex The name of the index to copy to
* @return the number of documents copied to the new index
*/
long copyIndex(Class<?> beanType, String newIndex, long sinceEpochMillis);
/**
* Copy from a source index to a new index taking only the documents
* matching the given query.
* <pre>{@code
*
* // predicates to select the source documents to copy
* Query<Product> query = server.find(Product.class)
* .where()
* .ge("whenModified", new Timestamp(since))
* .ge("name", "A")
* .lt("name", "D")
* .query();
*
* // copy from the source index to "product_copy" index
* long copyCount = documentStore.copyIndex(query, "product_copy", 1000);
*
* }</pre>
*
* @param query The query to select the source documents to copy
* @param newIndex The target index to copy the documents to
* @param bulkBatchSize The ElasticSearch bulk batch size, if 0 uses the default.
* @return The number of documents copied to the new index.
*/
long copyIndex(Query<?> query, String newIndex, int bulkBatchSize);
}
-133
View File
@@ -1,133 +0,0 @@
package io.ebean;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* Query for performing native SQL queries that return DTO Bean's.
* <p>
* These beans are just normal classes. They must have public constructors
* and setters.
* <p>
* Constructors with arguments are used if the number of constructor arguments
* matches the number of columns in the resultSet.
* </p>
* <p>
* If the number of columns in the resultSet is greater than the largest constructor
* then the largest constructor is used for the first columns and remaining columns
* are mapped by setter methods.
* </p>
*
* <pre>{@code
*
* // CustomerDto is just a 'bean like' class
* // with public constructor(s) and public setter methods
*
* String sql = "select id, name from customer where name like :name and status_code = :status";
*
* List<CustomerDto> beans =
* Ebean.findDto(CustomrDto.class, sql)
* .setParameter("name", "Acme%")
* .setParameter("status", "ACTIVE")
* .findList();
*
* }</pre>
*/
public interface DtoQuery<T> {
/**
* Execute the query returning a list.
*/
@Nonnull
List<T> findList();
/**
* Execute the query iterating a row at a time.
* <p>
* This streaming type query is useful for large query execution as only 1 row needs to be held in memory.
* </p>
*/
void findEach(Consumer<T> consumer);
/**
* Execute the query iterating a row at a time with the ability to stop consuming part way through.
* <p>
* Returning false after processing a row stops the iteration through the query results.
* </p>
* <p>
* This streaming type query is useful for large query execution as only 1 row needs to be held in memory.
* </p>
*/
void findEachWhile(Predicate<T> consumer);
/**
* Execute the query returning a single bean.
*/
@Nullable
T findOne();
/**
* Execute the query returning an optional bean.
*/
@Nonnull
Optional<T> findOneOrEmpty();
/**
* The same as bind for named parameters.
*/
DtoQuery<T> setParameter(String name, Object value);
/**
* The same as bind for positioned parameters.
*/
DtoQuery<T> setParameter(int position, Object value);
/**
* Set the index of the first row of the results to return.
*/
DtoQuery<T> setFirstRow(int firstRow);
/**
* Set the maximum number of query results to return.
*/
DtoQuery<T> setMaxRows(int maxRows);
/**
* When resultSet columns are not able to be mapped to a bean property then instead of
* throwing effectively skip reading that column.
*/
DtoQuery<T> setRelaxedMode();
/**
* Set a label on the query to make it easier to identify queries related to query execution statistics.
*
* @param label A label that is unique to the DTO bean type.
*/
DtoQuery<T> setLabel(String label);
/**
* Set a timeout on this query.
* <p>
* This will typically result in a call to setQueryTimeout() on a
* preparedStatement. If the timeout occurs an exception will be thrown - this
* will be a SQLException wrapped up in a PersistenceException.
* </p>
*
* @param secs the query timeout limit in seconds. Zero means there is no limit.
*/
DtoQuery<T> setTimeout(int secs);
/**
* A hint which for JDBC translates to the Statement.fetchSize().
* <p>
* Gives the JDBC driver a hint as to the number of rows that should be
* fetched from the database when more rows are needed for ResultSet.
* </p>
*/
DtoQuery<T> setBufferFetchSizeHint(int bufferFetchSizeHint);
}
@@ -1,15 +0,0 @@
package io.ebean;
/**
* Thrown when a duplicate is attempted on a unique constraint.
*/
public class DuplicateKeyException extends DataIntegrityException {
private static final long serialVersionUID = -4771932723285724817L;
/**
* Create with a message and cause.
*/
public DuplicateKeyException(String message, Throwable cause) {
super(message, cause);
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,145 +0,0 @@
package io.ebean;
import io.ebean.config.ContainerConfig;
import io.ebean.config.ServerConfig;
import io.ebean.service.SpiContainer;
import io.ebean.service.SpiContainerFactory;
import javax.persistence.PersistenceException;
import java.util.Iterator;
import java.util.Properties;
import java.util.ServiceLoader;
/**
* Creates EbeanServer instances.
* <p>
* This uses either a ServerConfig or properties in the ebean.properties file to
* configure and create a EbeanServer instance.
* </p>
* <p>
* The EbeanServer instance can either be registered with the Ebean singleton or
* not. The Ebean singleton effectively holds a map of EbeanServers by a name.
* If the EbeanServer is registered with the Ebean singleton you can retrieve it
* later via {@link Ebean#getServer(String)}.
* </p>
* <p>
* One EbeanServer can be nominated as the 'default/primary' EbeanServer. Many
* methods on the Ebean singleton such as {@link Ebean#find(Class)} are just a
* convenient way of using the 'default/primary' EbeanServer.
* </p>
*/
public class EbeanServerFactory {
private static SpiContainer container;
static {
EbeanVersion.getVersion(); // initalizes the version class and logs the version.
}
/**
* Initialise the container with clustering configuration.
* <p>
* Call this prior to creating any EbeanServer instances or alternatively set the
* ContainerConfig on the ServerConfig when creating the first EbeanServer instance.
*/
public static synchronized void initialiseContainer(ContainerConfig containerConfig) {
getContainer(containerConfig);
}
/**
* Create using ebean.properties to configure the server.
*/
public static synchronized EbeanServer create(String name) {
// construct based on loading properties files
// and if invoked by Ebean then it handles registration
SpiContainer serverFactory = getContainer(null);
return serverFactory.createServer(name);
}
/**
* Create using the ServerConfig object to configure the server.
*/
public static synchronized EbeanServer create(ServerConfig config) {
if (config.getName() == null) {
throw new PersistenceException("The name is null (it is required)");
}
EbeanServer server = createInternal(config);
if (config.isRegister()) {
PrimaryServer.setSkip(true);
Ebean.register(server, config.isDefaultServer());
}
return server;
}
/**
* Create using the ServerConfig additionally specifying a classLoader to use as the context class loader.
*/
public static synchronized EbeanServer createWithContextClassLoader(ServerConfig config, ClassLoader classLoader) {
ClassLoader currentContextLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);
try {
return EbeanServerFactory.create(config);
} finally {
// set the currentContextLoader back
Thread.currentThread().setContextClassLoader(currentContextLoader);
}
}
/**
* Shutdown gracefully all EbeanServers cleaning up any resources as required.
* <p>
* This is typically invoked via JVM shutdown hook and not explicitly called.
* </p>
*/
public static synchronized void shutdown() {
container.shutdown();
}
private static EbeanServer createInternal(ServerConfig config) {
return getContainer(config.getContainerConfig()).createServer(config);
}
/**
* Get the EbeanContainer initialising it if necessary.
*
* @param containerConfig the configuration controlling clustering communication
*/
private static SpiContainer getContainer(ContainerConfig containerConfig) {
// thread safe in that all calling methods are synchronized
if (container != null) {
return container;
}
if (containerConfig == null) {
// effectively load configuration from ebean.properties
Properties properties = PrimaryServer.getProperties();
containerConfig = new ContainerConfig();
containerConfig.loadFromProperties(properties);
}
container = createContainer(containerConfig);
return container;
}
/**
* Create the container instance using the configuration.
*/
protected static SpiContainer createContainer(ContainerConfig containerConfig) {
Iterator<SpiContainerFactory> factories = ServiceLoader.load(SpiContainerFactory.class).iterator();
if (factories.hasNext()) {
return factories.next().create(containerConfig);
}
throw new IllegalStateException("Service loader didn't find a SpiContainerFactory?");
}
}
-43
View File
@@ -1,43 +0,0 @@
package io.ebean;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Class to determine the ebean version. (
* @author Roland Praml, FOCONIS AG
*
*/
public class EbeanVersion {
private EbeanVersion() {
}
private static final Logger logger = LoggerFactory.getLogger(EbeanVersion.class);
private static String version = "unknown";
static {
try {
Properties prop = new Properties();
InputStream in = Ebean.class.getResourceAsStream("/META-INF/maven/io.ebean/ebean/pom.properties");
if (in != null) {
prop.load(in);
in.close();
version = prop.getProperty("version");
}
logger.info("ebean version: {}", version);
} catch (IOException e) {
logger.warn("Could not determine ebean version: {}", e.getMessage());
}
}
/**
* Returns the ebean version (read from /META-INF/maven/io.ebean/ebean/pom.properties)
*/
public static String getVersion() {
return version;
}
}
@@ -1,93 +0,0 @@
package io.ebean;
/**
* Query by Example expression.
* <p>
* Pass in an example entity and for each non-null scalar properties an
* expression is added.
* </p>
* <p>
* By Default this case sensitive, will ignore numeric zero values and will use
* a Like for string values (you must put in your own wildcards).
* </p>
* <p>
* To get control over the options you can create an ExampleExpression and set
* those options such as case insensitive etc.
* </p>
*
* <pre>{@code
* // create an example bean and set the properties
* // with the query parameters you want
* Customer example = new Customer();
* example.setName("Rob%");
* example.setNotes("%something%");
*
* List&lt;Customer&gt; list =
* Ebean.find(Customer.class)
* .where()
* // pass the bean into the where() clause
* .exampleLike(example)
* // you can add other expressions to the same query
* .gt("id", 2)
* .findList();
*
* }</pre>
*
* Similarly you can create an ExampleExpression
*
* <pre>{@code
*
* Customer example = new Customer();
* example.setName("Rob%");
* example.setNotes("%something%");
*
* // create a ExampleExpression with more control
* ExampleExpression qbe = new ExampleExpression(example, true, LikeType.EQUAL_TO)
* .includeZeros();
*
* List<Customer> list =
* Ebean.find(Customer.class)
* .where()
* .add(qbe)
* .findList();
*
* }</pre>
*/
public interface ExampleExpression extends Expression {
/**
* By calling this method zero value properties are going to be included in
* the expression.
* <p>
* By default numeric zero values are excluded as they can result from
* primitive int and long types.
* </p>
*/
ExampleExpression includeZeros();
/**
* Set case insensitive to true.
*/
ExampleExpression caseInsensitive();
/**
* Use startsWith expression for string properties.
*/
ExampleExpression useStartsWith();
/**
* Use contains expression for string properties.
*/
ExampleExpression useContains();
/**
* Use endsWith expression for string properties.
*/
ExampleExpression useEndsWith();
/**
* Use equal to expression for string properties.
*/
ExampleExpression useEqualTo();
}
-333
View File
@@ -1,333 +0,0 @@
package io.ebean;
import java.util.Collection;
import java.util.Map;
/**
* Expression factory for creating standard expressions for WHERE and HAVING
* clauses.
* <p>
* Generally you will only need to use this object for creating OR, JUNCTION or
* CONJUNCTION expressions. To create simple expressions you will most likely
* just use the methods on the ExpressionList object that is returned via
* {@link Query#where()}.
* </p>
* <p>
* This provides a convenient way to create expressions for the 'Default'
* server. It is actually a short cut for using the ExpressionFactory of the
* 'default' EbeanServer.
* <p>
* See also {@link Ebean#getExpressionFactory()}
* </p>
* <p>
* Creates standard common expressions for using in a Query Where or Having
* clause.
* </p>
* <pre>{@code
*
* // Example: Using an Expr.or() method
* Query<Order> query = Ebean.createQuery(Order.class);
* query.where(
* Expr.or(Expr.eq("status", Order.NEW),
* Expr.gt("orderDate", lastWeek));
*
* List<Order> list = query.findList();
* ...
* }</pre>
*
* @see Query#where()
*/
public class Expr {
private Expr() {
}
/**
* Equal To - property equal to the given value.
*/
public static Expression eq(String propertyName, Object value) {
return Ebean.getExpressionFactory().eq(propertyName, value);
}
/**
* Not Equal To - property not equal to the given value.
*/
public static Expression ne(String propertyName, Object value) {
return Ebean.getExpressionFactory().ne(propertyName, value);
}
/**
* Case Insensitive Equal To - property equal to the given value (typically
* using a lower() function to make it case insensitive).
*/
public static Expression ieq(String propertyName, String value) {
return Ebean.getExpressionFactory().ieq(propertyName, value);
}
/**
* Between - property between the two given values.
*/
public static Expression between(String propertyName, Object value1, Object value2) {
return Ebean.getExpressionFactory().between(propertyName, value1, value2);
}
/**
* Between - value between two given properties.
*/
public static Expression between(String lowProperty, String highProperty, Object value) {
return Ebean.getExpressionFactory().betweenProperties(lowProperty, highProperty, value);
}
/**
* Greater Than - property greater than the given value.
*/
public static Expression gt(String propertyName, Object value) {
return Ebean.getExpressionFactory().gt(propertyName, value);
}
/**
* Greater Than or Equal to - property greater than or equal to the given
* value.
*/
public static Expression ge(String propertyName, Object value) {
return Ebean.getExpressionFactory().ge(propertyName, value);
}
/**
* Less Than - property less than the given value.
*/
public static Expression lt(String propertyName, Object value) {
return Ebean.getExpressionFactory().lt(propertyName, value);
}
/**
* Less Than or Equal to - property less than or equal to the given value.
*/
public static Expression le(String propertyName, Object value) {
return Ebean.getExpressionFactory().le(propertyName, value);
}
/**
* Is Null - property is null.
*/
public static Expression isNull(String propertyName) {
return Ebean.getExpressionFactory().isNull(propertyName);
}
/**
* Is Not Null - property is not null.
*/
public static Expression isNotNull(String propertyName) {
return Ebean.getExpressionFactory().isNotNull(propertyName);
}
/**
* Case insensitive {@link #exampleLike(Object)}
*/
public static ExampleExpression iexampleLike(Object example) {
return Ebean.getExpressionFactory().iexampleLike(example);
}
/**
* Create the query by Example expression which is case sensitive and using
* LikeType.RAW (you need to add you own wildcards % and _).
*/
public static ExampleExpression exampleLike(Object example) {
return Ebean.getExpressionFactory().exampleLike(example);
}
/**
* Create the query by Example expression specifying more options.
*/
public static ExampleExpression exampleLike(Object example, boolean caseInsensitive, LikeType likeType) {
return Ebean.getExpressionFactory().exampleLike(example, caseInsensitive, likeType);
}
/**
* Like - property like value where the value contains the SQL wild card
* characters % (percentage) and _ (underscore).
*/
public static Expression like(String propertyName, String value) {
return Ebean.getExpressionFactory().like(propertyName, value);
}
/**
* Case insensitive Like - property like value where the value contains the
* SQL wild card characters % (percentage) and _ (underscore). Typically uses
* a lower() function to make the expression case insensitive.
*/
public static Expression ilike(String propertyName, String value) {
return Ebean.getExpressionFactory().ilike(propertyName, value);
}
/**
* Starts With - property like value%.
*/
public static Expression startsWith(String propertyName, String value) {
return Ebean.getExpressionFactory().startsWith(propertyName, value);
}
/**
* Case insensitive Starts With - property like value%. Typically uses a
* lower() function to make the expression case insensitive.
*/
public static Expression istartsWith(String propertyName, String value) {
return Ebean.getExpressionFactory().istartsWith(propertyName, value);
}
/**
* Ends With - property like %value.
*/
public static Expression endsWith(String propertyName, String value) {
return Ebean.getExpressionFactory().endsWith(propertyName, value);
}
/**
* Case insensitive Ends With - property like %value. Typically uses a lower()
* function to make the expression case insensitive.
*/
public static Expression iendsWith(String propertyName, String value) {
return Ebean.getExpressionFactory().iendsWith(propertyName, value);
}
/**
* Contains - property like %value%.
*/
public static Expression contains(String propertyName, String value) {
return Ebean.getExpressionFactory().contains(propertyName, value);
}
/**
* Case insensitive Contains - property like %value%. Typically uses a lower()
* function to make the expression case insensitive.
*/
public static Expression icontains(String propertyName, String value) {
return Ebean.getExpressionFactory().icontains(propertyName, value);
}
/**
* For collection properties that are empty (have not existing elements).
*/
public static Expression isEmpty(String propertyName) {
return Ebean.getExpressionFactory().isEmpty(propertyName);
}
/**
* For collection properties that are not empty (have existing elements).
*/
public static Expression isNotEmpty(String propertyName) {
return Ebean.getExpressionFactory().isNotEmpty(propertyName);
}
/**
* In - property has a value in the array of values.
*/
public static Expression in(String propertyName, Object[] values) {
return Ebean.getExpressionFactory().in(propertyName, values);
}
/**
* In - using a subQuery.
*/
public static Expression in(String propertyName, Query<?> subQuery) {
return Ebean.getExpressionFactory().in(propertyName, subQuery);
}
/**
* In - property has a value in the collection of values.
*/
public static Expression in(String propertyName, Collection<?> values) {
return Ebean.getExpressionFactory().in(propertyName, values);
}
/**
* Id Equal to - ID property is equal to the value.
*/
public static Expression idEq(Object value) {
return Ebean.getExpressionFactory().idEq(value);
}
/**
* All Equal - Map containing property names and their values.
* <p>
* Expression where all the property names in the map are equal to the
* corresponding value.
* </p>
*
* @param propertyMap a map keyed by property names.
*/
public static Expression allEq(Map<String, Object> propertyMap) {
return Ebean.getExpressionFactory().allEq(propertyMap);
}
/**
* Add raw expression with a single parameter.
* <p>
* The raw expression should contain a single ? at the location of the
* parameter.
* </p>
*/
public static Expression raw(String raw, Object value) {
return Ebean.getExpressionFactory().raw(raw, value);
}
/**
* Add raw expression with an array of parameters.
* <p>
* The raw expression should contain the same number of ? as there are
* parameters.
* </p>
*/
public static Expression raw(String raw, Object[] values) {
return Ebean.getExpressionFactory().raw(raw, values);
}
/**
* Add raw expression with no parameters.
*/
public static Expression raw(String raw) {
return Ebean.getExpressionFactory().raw(raw);
}
/**
* And - join two expressions with a logical and.
*/
public static Expression and(Expression expOne, Expression expTwo) {
return Ebean.getExpressionFactory().and(expOne, expTwo);
}
/**
* Or - join two expressions with a logical or.
*/
public static Expression or(Expression expOne, Expression expTwo) {
return Ebean.getExpressionFactory().or(expOne, expTwo);
}
/**
* Negate the expression (prefix it with NOT).
*/
public static Expression not(Expression exp) {
return Ebean.getExpressionFactory().not(exp);
}
/**
* Return a list of expressions that will be joined by AND's.
*/
public static <T> Junction<T> conjunction(Query<T> query) {
return Ebean.getExpressionFactory().conjunction(query);
}
/**
* Return a list of expressions that will be joined by OR's.
*/
public static <T> Junction<T> disjunction(Query<T> query) {
return Ebean.getExpressionFactory().disjunction(query);
}
}
-8
View File
@@ -1,8 +0,0 @@
package io.ebean;
/**
* An expression that is part of a WHERE or HAVING clause.
*/
public interface Expression {
}
@@ -1,445 +0,0 @@
package io.ebean;
import io.ebean.search.Match;
import io.ebean.search.MultiMatch;
import io.ebean.search.TextCommonTerms;
import io.ebean.search.TextQueryString;
import io.ebean.search.TextSimple;
import java.util.Collection;
import java.util.Map;
/**
* Expression factory for creating standard expressions.
* <p>
* Creates standard common expressions for using in a Query Where or Having
* clause.
* </p>
* <p>
* You will often not use this class directly but instead just add expressions
* via the methods on ExpressionList such as
* {@link ExpressionList#gt(String, Object)}.
* </p>
* <p>
* The ExpressionList is returned from {@link Query#where()}.
* </p>
* <pre>{@code
* // Example: fetch orders where status equals new or orderDate > lastWeek.
*
* Expression newOrLastWeek =
* Expr.or(Expr.eq("status", Order.Status.NEW),
* Expr.gt("orderDate", lastWeek));
*
* Query<Order> query = Ebean.createQuery(Order.class);
* query.where().add(newOrLastWeek);
* List<Order> list = query.findList();
* ...
* }</pre>
*
* @see Query#where()
*/
public interface ExpressionFactory {
/**
* Path exists - for the given path in a JSON document.
*/
Expression jsonExists(String propertyName, String path);
/**
* Path does not exist - for the given path in a JSON document.
*/
Expression jsonNotExists(String propertyName, String path);
/**
* Equal to - for the given path in a JSON document.
*/
Expression jsonEqualTo(String propertyName, String path, Object val);
/**
* Not Equal to - for the given path in a JSON document.
*/
Expression jsonNotEqualTo(String propertyName, String path, Object val);
/**
* Greater than - for the given path in a JSON document.
*/
Expression jsonGreaterThan(String propertyName, String path, Object val);
/**
* Greater than or equal to - for the given path in a JSON document.
*/
Expression jsonGreaterOrEqual(String propertyName, String path, Object val);
/**
* Less than - for the given path in a JSON document.
*/
Expression jsonLessThan(String propertyName, String path, Object val);
/**
* Less than or equal to - for the given path in a JSON document.
*/
Expression jsonLessOrEqualTo(String propertyName, String path, Object val);
/**
* Between - for the given path in a JSON document.
*/
Expression jsonBetween(String propertyName, String path, Object lowerValue, Object upperValue);
/**
* Array contains all the given values.
* <p>
* Array support is effectively limited to Postgres at this time.
* </p>
*/
Expression arrayContains(String propertyName, Object... values);
/**
* Array does not contain the given values.
* <p>
* Array support is effectively limited to Postgres at this time.
* </p>
*/
Expression arrayNotContains(String propertyName, Object... values);
/**
* Array is empty - for the given array property.
* <p>
* Array support is effectively limited to Postgres at this time.
* </p>
*/
Expression arrayIsEmpty(String propertyName);
/**
* Array is not empty - for the given array property.
* <p>
* Array support is effectively limited to Postgres at this time.
* </p>
*/
Expression arrayIsNotEmpty(String propertyName);
/**
* Equal To - property equal to the given value.
*/
Expression eq(String propertyName, Object value);
/**
* Not Equal To - property not equal to the given value.
*/
Expression ne(String propertyName, Object value);
/**
* Case Insensitive Equal To - property equal to the given value (typically
* using a lower() function to make it case insensitive).
*/
Expression ieq(String propertyName, String value);
/**
* Case Insensitive Equal To that allows for named parameter use.
*/
Expression ieqObject(String propertyName, Object value);
/**
* Between - property between the two given values.
*/
Expression between(String propertyName, Object value1, Object value2);
/**
* Between - value between two given properties.
*/
Expression betweenProperties(String lowProperty, String highProperty, Object value);
/**
* Greater Than - property greater than the given value.
*/
Expression gt(String propertyName, Object value);
/**
* Greater Than or Equal to - property greater than or equal to the given
* value.
*/
Expression ge(String propertyName, Object value);
/**
* Less Than - property less than the given value.
*/
Expression lt(String propertyName, Object value);
/**
* Less Than or Equal to - property less than or equal to the given value.
*/
Expression le(String propertyName, Object value);
/**
* Is Null - property is null.
*/
Expression isNull(String propertyName);
/**
* Is Not Null - property is not null.
*/
Expression isNotNull(String propertyName);
/**
* Case insensitive {@link #exampleLike(Object)}
*/
ExampleExpression iexampleLike(Object example);
/**
* Create the query by Example expression which is case sensitive and using
* LikeType.RAW (you need to add you own wildcards % and _).
*/
ExampleExpression exampleLike(Object example);
/**
* Create the query by Example expression specifying more options.
*/
ExampleExpression exampleLike(Object example, boolean caseInsensitive, LikeType likeType);
/**
* Like with support for named parameters.
*/
Expression like(String propertyName, Object value, boolean caseInsensitive, LikeType likeType);
/**
* Like - property like value where the value contains the SQL wild card
* characters % (percentage) and _ (underscore).
*/
Expression like(String propertyName, String value);
/**
* Case insensitive Like - property like value where the value contains the
* SQL wild card characters % (percentage) and _ (underscore). Typically uses
* a lower() function to make the expression case insensitive.
*/
Expression ilike(String propertyName, String value);
/**
* Starts With - property like value%.
*/
Expression startsWith(String propertyName, String value);
/**
* Case insensitive Starts With - property like value%. Typically uses a
* lower() function to make the expression case insensitive.
*/
Expression istartsWith(String propertyName, String value);
/**
* Ends With - property like %value.
*/
Expression endsWith(String propertyName, String value);
/**
* Case insensitive Ends With - property like %value. Typically uses a lower()
* function to make the expression case insensitive.
*/
Expression iendsWith(String propertyName, String value);
/**
* Contains - property like %value%.
*/
Expression contains(String propertyName, String value);
/**
* Case insensitive Contains - property like %value%. Typically uses a lower()
* function to make the expression case insensitive.
*/
Expression icontains(String propertyName, String value);
/**
* In expression using pairs of value objects.
*/
Expression inPairs(Pairs pairs);
/**
* In - property has a value in the array of values.
*/
Expression in(String propertyName, Object[] values);
/**
* In - using a subQuery.
*/
Expression in(String propertyName, Query<?> subQuery);
/**
* In - property has a value in the collection of values.
*/
Expression in(String propertyName, Collection<?> values);
/**
* Not In - property has a value in the array of values.
*/
Expression notIn(String propertyName, Object[] values);
/**
* Not In - property has a value in the collection of values.
*/
Expression notIn(String propertyName, Collection<?> values);
/**
* Not In - using a subQuery.
*/
Expression notIn(String propertyName, Query<?> subQuery);
/**
* Exists expression
*/
Expression exists(Query<?> subQuery);
/**
* Not exists expression
*/
Expression notExists(Query<?> subQuery);
/**
* Is empty expression for collection properties.
*/
Expression isEmpty(String propertyName);
/**
* Is not empty expression for collection properties.
*/
Expression isNotEmpty(String propertyName);
/**
* Id Equal to - ID property is equal to the value.
*/
Expression idEq(Object value);
/**
* Id IN a list of Id values.
*/
Expression idIn(Object... idValues);
/**
* Id IN a collection of Id values.
*/
Expression idIn(Collection<?> idCollection);
/**
* All Equal - Map containing property names and their values.
* <p>
* Expression where all the property names in the map are equal to the
* corresponding value.
* </p>
*
* @param propertyMap a map keyed by property names.
*/
Expression allEq(Map<String, Object> propertyMap);
/**
* Add expression for ANY of the given bit flags to be set.
*
* @param propertyName The property that holds the flags value
* @param flags The flags we are looking for
*/
Expression bitwiseAny(String propertyName, long flags);
/**
* Add expression for ALL of the given bit flags to be set.
*
* @param propertyName The property that holds the flags value
* @param flags The flags we are looking for
*/
Expression bitwiseAll(String propertyName, long flags);
/**
* Add bitwise AND expression of the given bit flags to compare with the match/mask.
*
* @param propertyName The property that holds the flags value
* @param flags The flags we are looking for
*/
Expression bitwiseAnd(String propertyName, long flags, long match);
/**
* Add raw expression with a single parameter.
* <p>
* The raw expression should contain a single ? at the location of the
* parameter.
* </p>
*/
Expression raw(String raw, Object value);
/**
* Add raw expression with an array of parameters.
* <p>
* The raw expression should contain the same number of ? as there are
* parameters.
* </p>
*/
Expression raw(String raw, Object[] values);
/**
* Add raw expression with no parameters.
*/
Expression raw(String raw);
/**
* Create a Text Match expression (currently doc store/Elastic only).
*/
Expression textMatch(String propertyName, String search, Match options);
/**
* Create a Text Multi match expression (currently doc store/Elastic only).
*/
Expression textMultiMatch(String query, MultiMatch options);
/**
* Create a text simple query expression (currently doc store/Elastic only).
*/
Expression textSimple(String search, TextSimple options);
/**
* Create a text query string expression (currently doc store/Elastic only).
*/
Expression textQueryString(String search, TextQueryString options);
/**
* Create a text common terms expression (currently doc store/Elastic only).
*/
Expression textCommonTerms(String search, TextCommonTerms options);
/**
* And - join two expressions with a logical and.
*/
Expression and(Expression expOne, Expression expTwo);
/**
* Or - join two expressions with a logical or.
*/
Expression or(Expression expOne, Expression expTwo);
/**
* Negate the expression (prefix it with NOT).
*/
Expression not(Expression exp);
/**
* Return a list of expressions that will be joined by AND's.
*/
<T> Junction<T> conjunction(Query<T> query);
/**
* Return a list of expressions that will be joined by OR's.
*/
<T> Junction<T> disjunction(Query<T> query);
/**
* Return a list of expressions that will be joined by AND's.
*/
<T> Junction<T> conjunction(Query<T> query, ExpressionList<T> parent);
/**
* Return a list of expressions that will be joined by OR's.
*/
<T> Junction<T> disjunction(Query<T> query, ExpressionList<T> parent);
/**
* Return a Text query junction for MUST, SHOULD or MUST NOT.
* <p>
* This is doc store Elastic only.
* </p>
*/
<T> Junction<T> junction(Junction.Type type, Query<T> query, ExpressionList<T> parent);
}
File diff suppressed because it is too large Load Diff
-268
View File
@@ -1,268 +0,0 @@
package io.ebean;
import java.io.Serializable;
/**
* Defines the configuration options for a "query fetch" or a
* "lazy loading fetch". This gives you the ability to use multiple smaller
* queries to populate an object graph as opposed to a single large query.
* <p>
* The primary goal is to provide efficient ways of loading complex object
* graphs avoiding SQL Cartesian product and issues around populating object
* graphs that have multiple *ToMany relationships.
* </p>
* <p>
* It also provides the ability to control the lazy loading queries (batch size,
* selected properties and fetches) to avoid N+1 queries etc.
* <p>
* There can also be cases loading across a single OneToMany where 2 SQL queries
* using Ebean FetchConfig.query() can be more efficient than one SQL query.
* When the "One" side is wide (lots of columns) and the cardinality difference
* is high (a lot of "Many" beans per "One" bean) then this can be more
* efficient loaded as 2 SQL queries.
* </p>
* <p>
* <pre>{@code
* // Normal fetch join results in a single SQL query
* List<Order> list = Ebean.find(Order.class).fetch("details").findList();
*
* // Find Orders join details using a single SQL query
* }</pre>
* <p>
* Example: Using a "query join" instead of a "fetch join" we instead use 2 SQL queries
* </p>
* <p>
* <pre>{@code
*
* // This will use 2 SQL queries to build this object graph
* List<Order> list =
* Ebean.find(Order.class)
* .fetch("details", new FetchConfig().query())
* .findList();
*
* // query 1) find order
* // query 2) find orderDetails where order.id in (?,?...) // first 100 order id's
*
* }</pre>
* <p>
* Example: Using 2 "query joins"
* </p>
* <p>
* <pre>{@code
*
* // This will use 3 SQL queries to build this object graph
* List<Order> list =
* Ebean.find(Order.class)
* .fetch("details", new FetchConfig().query())
* .fetch("customer", new FetchConfig().queryFirst(5))
* .findList();
*
* // query 1) find order
* // query 2) find orderDetails where order.id in (?,?...) // first 100 order id's
* // query 3) find customer where id in (?,?,?,?,?) // first 5 customers
*
* }</pre>
* <p>
* Example: Using "query joins" and partial objects
* </p>
* <p>
*
* <pre>{@code
* // This will use 3 SQL queries to build this object graph
* List<Order> list =
* Ebean.find(Order.class)
* .select("status, shipDate")
* .fetch("details", "quantity, price", new FetchConfig().query())
* .fetch("details.product", "sku, name")
* .fetch("customer", "name", new FetchConfig().queryFirst(5))
* .fetch("customer.contacts")
* .fetch("customer.shippingAddress")
* .findList();
*
* // query 1) find order (status, shipDate)
* // query 2) find orderDetail (quantity, price) fetch product (sku, name) where
* // order.id in (?,? ...)
* // query 3) find customer (name) fetch contacts (*) fetch shippingAddress (*)
* // where id in (?,?,?,?,?)
*
* // Note: the fetch of "details.product" is automatically included into the
* // fetch of "details"
* //
* // Note: the fetch of "customer.contacts" and "customer.shippingAddress"
* // are automatically included in the fetch of "customer"
* }</pre>
* <p>
* You can use query() and lazy together on a single join. The query is executed
* immediately and the lazy defines the batch size to use for further lazy
* loading (if lazy loading is invoked).
* </p>
* <p>
* <pre>{@code
*
* List<Order> list =
* Ebean.find(Order.class)
* .fetch("customer", new FetchConfig().query(10).lazy(5))
* .findList();
*
* // query 1) find order
* // query 2) find customer where id in (?,?,?,?,?,?,?,?,?,?) // first 10 customers
* // .. then if lazy loading of customers is invoked
* // .. use a batch size of 5 to load the customers
*
* }</pre>
* <p>
* <p>
* Example of controlling the lazy loading query:
* </p>
* <p>
* This gives us the ability to optimise the lazy loading query for a given use
* case.
* </p>
* <p>
* <pre>{@code
*
* List<Order> list = Ebean.find(Order.class)
* .fetch("customer","name", new FetchConfig().lazy(5))
* .fetch("customer.contacts","contactName, phone, email")
* .fetch("customer.shippingAddress")
* .where().eq("status",Order.Status.NEW)
* .findList();
*
* // query 1) find order where status = Order.Status.NEW
* //
* // .. if lazy loading of customers is invoked
* // .. use a batch size of 5 to load the customers
*
* }</pre>
*
* @author mario
* @author rbygrave
*/
public class FetchConfig implements Serializable {
private static final long serialVersionUID = 1L;
private int lazyBatchSize = -1;
private int queryBatchSize = -1;
private boolean queryAll;
/**
* Construct the fetch configuration object.
*/
public FetchConfig() {
}
/**
* Specify that this path should be lazy loaded using the default batch load
* size.
*/
public FetchConfig lazy() {
this.lazyBatchSize = 0;
this.queryAll = false;
return this;
}
/**
* Specify that this path should be lazy loaded with a specified batch size.
*
* @param lazyBatchSize the batch size for lazy loading
*/
public FetchConfig lazy(int lazyBatchSize) {
this.lazyBatchSize = lazyBatchSize;
this.queryAll = false;
return this;
}
/**
* Eagerly fetch the beans in this path as a separate query (rather than as
* part of the main query).
* <p>
* This will use the default batch size for separate query which is 100.
* </p>
*/
public FetchConfig query() {
this.queryBatchSize = 0;
this.queryAll = true;
return this;
}
/**
* Eagerly fetch the beans in this path as a separate query (rather than as
* part of the main query).
* <p>
* The queryBatchSize is the number of parent id's that this separate query
* will load per batch.
* </p>
* <p>
* This will load all beans on this path eagerly unless a {@link #lazy(int)}
* is also used.
* </p>
*
* @param queryBatchSize the batch size used to load beans on this path
*/
public FetchConfig query(int queryBatchSize) {
this.queryBatchSize = queryBatchSize;
// queryAll true as long as a lazy batch size has not already been set
this.queryAll = (lazyBatchSize == -1);
return this;
}
/**
* Eagerly fetch the first batch of beans on this path.
* This is similar to {@link #query(int)} but only fetches the first batch.
* <p>
* If there are more parent beans than the batch size then they will not be
* loaded eagerly but instead use lazy loading.
* </p>
*
* @param queryBatchSize the number of parent beans this path is populated for
*/
public FetchConfig queryFirst(int queryBatchSize) {
this.queryBatchSize = queryBatchSize;
this.queryAll = false;
return this;
}
/**
* Return the batch size for lazy loading.
*/
public int getLazyBatchSize() {
return lazyBatchSize;
}
/**
* Return the batch size for separate query load.
*/
public int getQueryBatchSize() {
return queryBatchSize;
}
/**
* Return true if the query fetch should fetch 'all' rather than just the
* 'first' batch.
*/
public boolean isQueryAll() {
return queryAll;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FetchConfig that = (FetchConfig) o;
if (lazyBatchSize != that.lazyBatchSize) return false;
if (queryBatchSize != that.queryBatchSize) return false;
return queryAll == that.queryAll;
}
@Override
public int hashCode() {
int result = lazyBatchSize;
result = 92821 * result + queryBatchSize;
result = 92821 * result + (queryAll ? 1 : 0);
return result;
}
}
-26
View File
@@ -1,26 +0,0 @@
package io.ebean;
import java.util.Set;
/**
* Provides paths and properties for an object graph that can be used to control what parts of the object graph
* is fetching (select and fetch clauses) and also can be used to control JSON marshalling (what parts of the object
* graph are included in the JSON).
*/
public interface FetchPath {
/**
* Return true if the path is included in this FetchPath.
*/
boolean hasPath(String path);
/**
* Return the properties at the given path.
*/
Set<String> getProperties(String path);
/**
* Apply the fetch path to the query.
*/
<T> void apply(Query<T> query);
}
-196
View File
@@ -1,196 +0,0 @@
package io.ebean;
import java.util.List;
import java.util.Set;
/**
* Provides support for filtering and sorting lists of entities without going
* back to the database.
* <p>
* That is, it uses local in-memory sorting and filtering of a list of entity
* beans. It is not used in a Database query or invoke a Database query.
* </p>
* <p>
* You can optionally specify a sortByClause and if so, the sort will always
* execute prior to the filter expressions. You can specify any number of filter
* expressions and they are effectively joined by logical "AND".
* </p>
* <p>
* The result of the filter method will leave the original list unmodified and
* return a new List instance.
* </p>
* <p>
* <pre>{@code
*
* // get a list of entities (query execution statistics in this case)
*
* List<MetaQueryStatistic> list =
* Ebean.find(MetaQueryStatistic.class).findList();
*
* long nowMinus24Hrs = System.currentTimeMillis() - 24 * (1000 * 60 * 60);
*
* // sort and filter the list returning a filtered list...
*
* List<MetaQueryStatistic> filteredList =
* Ebean.filter(MetaQueryStatistic.class)
* .sort("avgTimeMicros desc")
* .gt("executionCount", 0)
* .gt("lastQueryTime", nowMinus24Hrs)
* .eq("autoTuned", true)
* .maxRows(10)
* .filter(list);
*
* }</pre>
* <p>
* The propertyNames can traverse the object graph (e.g. customer.name) by using
* dot notation. If any point during the object graph traversal to get a
* property value is null then null is returned.
* </p>
* <p>
* <pre>{@code
*
* // examples of property names that
* // ... will traverse the object graph
* // ... where customer is a property of our bean
*
* customer.name
* customer.shippingAddress.city
*
* }</pre>
* <p>
* <pre>{@code
*
* // get a list of entities (query execution statistics)
*
* List<Order> orders =
* Ebean.find(Order.class).findList();
*
* // Apply a filter...
*
* List<Order> filteredOrders =
* Ebean.filter(Order.class)
* .startsWith("customer.name", "Rob")
* .eq("customer.shippingAddress.city", "Auckland")
* .filter(orders);
*
* }</pre>
*
* @param <T> the entity bean type
*/
public interface Filter<T> {
/**
* Specify a sortByClause.
* <p>
* The sort (if specified) will always execute first followed by the filter
* expressions.
* </p>
* <p>
* Refer to {@link Ebean#sort(List, String)} for more detail.
* </p>
*/
Filter<T> sort(String sortByClause);
/**
* Specify the maximum number of rows/elements to return.
*/
Filter<T> maxRows(int maxRows);
/**
* Equal To - property equal to the given value.
*/
Filter<T> eq(String prop, Object value);
/**
* Not Equal To - property not equal to the given value.
*/
Filter<T> ne(String propertyName, Object value);
/**
* Case Insensitive Equal To.
*/
Filter<T> ieq(String propertyName, String value);
/**
* Between - property between the two given values.
*/
Filter<T> between(String propertyName, Object value1, Object value2);
/**
* Greater Than - property greater than the given value.
*/
Filter<T> gt(String propertyName, Object value);
/**
* Greater Than or Equal to - property greater than or equal to the given
* value.
*/
Filter<T> ge(String propertyName, Object value);
/**
* Less Than - property less than the given value.
*/
Filter<T> lt(String propertyName, Object value);
/**
* Less Than or Equal to - property less than or equal to the given value.
*/
Filter<T> le(String propertyName, Object value);
/**
* Is Null - property is null.
*/
Filter<T> isNull(String propertyName);
/**
* Is Not Null - property is not null.
*/
Filter<T> isNotNull(String propertyName);
/**
* Starts With.
*/
Filter<T> startsWith(String propertyName, String value);
/**
* Case insensitive Starts With.
*/
Filter<T> istartsWith(String propertyName, String value);
/**
* Ends With.
*/
Filter<T> endsWith(String propertyName, String value);
/**
* Case insensitive Ends With.
*/
Filter<T> iendsWith(String propertyName, String value);
/**
* Contains - property contains the string "value".
*/
Filter<T> contains(String propertyName, String value);
/**
* Case insensitive Contains.
*/
Filter<T> icontains(String propertyName, String value);
/**
* In - property has a value contained in the set of values.
*/
Filter<T> in(String propertyName, Set<?> values);
/**
* Apply the filter to the list returning a new list of the matching elements
* in the sorted order.
* <p>
* The sourceList will remain unmodified.
* </p>
*
* @return Returns a new list with the sorting and filters applied.
*/
List<T> filter(List<T> sourceList);
}
-213
View File
@@ -1,213 +0,0 @@
package io.ebean;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
/**
* Intended to be used as a base class for 'Finder' implementations that can then
* be injected or used as public static fields on the associated entity bean.
* <p>
* These 'finders' are a place to organise all the finder methods for that bean type
* and specific finder methods are expected to be added (find by unique properties etc).
* </p>
* <h3>Testing</h3>
* <p>
* For testing the mocki-ebean project has the ability to replace the finder implementation
* <p>
* </p>
* <pre>{@code
*
* public class CustomerFinder extends Finder<Long,Customer> {
*
* public CustomerFinder() {
* super(Customer.class);
* }
*
* // Add your customer finder methods ...
*
* public Customer byName(String name) {
* return query().eq("name", name).findOne();
* }
*
* public List<Customer> findNew() {
* return query().where()
* .eq("status", Customer.Status.NEW)
* .orderBy("name")
* .findList()
* }
* }
*
* @Entity
* public class Customer extends BaseModel {
*
* public static final CustomerFinder find = new CustomerFinder();
* ...
*
* }</pre>
*/
public class Finder<I, T> {
/**
* The entity bean type.
*/
private final Class<T> type;
/**
* The name of the EbeanServer, null for the default server.
*/
private final String serverName;
/**
* Create with the type of the entity bean.
* <pre>{@code
*
* public class CustomerFinder extends Finder<Customer> {
*
* public CustomerFinder() {
* super(Customer.class);
* }
*
* // ... add extra customer specific finder methods
* }
*
* @Entity
* public class Customer extends BaseModel {
*
* public static final CustomerFinder find = new CustomerFinder();
* ...
*
* }</pre>
*/
public Finder(Class<T> type) {
this.type = type;
this.serverName = null;
}
/**
* Create with the type of the entity bean and specific server name.
*/
public Finder(Class<T> type, String serverName) {
this.type = type;
this.serverName = serverName;
}
/**
* Return the current transaction.
*/
public Transaction currentTransaction() {
return db().currentTransaction();
}
/**
* Flush the JDBC batch on the current transaction.
*/
public void flush() {
db().flush();
}
/**
* Return the underlying 'default' EbeanServer.
* <p>
* This provides full access to the API such as explicit transaction demarcation etc.
*/
public EbeanServer db() {
return Ebean.getServer(serverName);
}
/**
* Return typically a different EbeanServer to the default.
* <p>
* This is equivalent to {@link Ebean#getServer(String)}
*
* @param server The name of the EbeanServer. If this is null then the default EbeanServer is
* returned.
*/
public EbeanServer db(String server) {
return Ebean.getServer(server);
}
/**
* Creates an entity reference for this ID.
* <p>
* Equivalent to {@link EbeanServer#getReference(Class, Object)}
*/
@Nonnull
public T ref(I id) {
return db().getReference(type, id);
}
/**
* Retrieves an entity by ID.
* <p>
* Equivalent to {@link EbeanServer#find(Class, Object)}
*/
@Nullable
public T byId(I id) {
return db().find(type, id);
}
/**
* Delete a bean by Id.
* <p>
* Equivalent to {@link EbeanServer#delete(Class, Object)}
*/
public void deleteById(I id) {
db().delete(type, id);
}
/**
* Retrieves all entities of the given type.
*/
@Nonnull
public List<T> all() {
return query().findList();
}
/**
* Creates an update query.
*
* <pre>{@code
*
* int rows =
* finder.update()
* .set("status", Customer.Status.ACTIVE)
* .set("updtime", new Timestamp(System.currentTimeMillis()))
* .where()
* .gt("id", 1000)
* .update();
*
* }</pre>
*
* <p>
* Equivalent to {@link EbeanServer#update(Class)}
*/
public UpdateQuery<T> update() {
return db().update(type);
}
/**
* Creates a query.
* <p>
* Equivalent to {@link EbeanServer#find(Class)}
*/
public Query<T> query() {
return db().find(type);
}
/**
* Creates a native sql query.
*/
public Query<T> nativeSql(String nativeSql) {
return db().findNative(type, nativeSql);
}
/**
* Creates a query using the ORM query language.
*/
public Query<T> query(String ormQuery) {
return db().createQuery(type, ormQuery);
}
}
-20
View File
@@ -1,20 +0,0 @@
package io.ebean;
import java.util.List;
import java.util.concurrent.Future;
/**
* FutureIds represents the result of a background query execution for the Id's.
* <p>
* It extends the java.util.concurrent.Future with the ability to get the Id's
* while the query is still executing in the background.
* </p>
*/
public interface FutureIds<T> extends Future<List<Object>> {
/**
* Returns the original query used to fetch the Id's.
*/
Query<T> getQuery();
}
-72
View File
@@ -1,72 +0,0 @@
package io.ebean;
import javax.persistence.PersistenceException;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* FutureList represents the result of a background query execution that will
* return a list of entities.
* <p>
* It extends the java.util.concurrent.Future with the ability to cancel the
* query, check if it is finished and get the resulting list waiting for the
* query to finish (ie. the standard features of java.util.concurrent.Future).
* </p>
* <p>
* A simple example:
* </p>
* <pre>{@code
*
* // create a query to find all orders
* Query<Order> query = Ebean.find(Order.class);
*
* // execute the query in a background thread
* // immediately returning the futureList
* FutureList<Order> futureList = query.findFutureList();
*
* // do something else ...
*
* if (!futureList.isDone()){
* // we can cancel the query execution. This will cancel
* // the underlying query if that is supported by the JDBC
* // driver and database
* futureList.cancel(true);
* }
*
* if (!futureList.isCancelled()){
* // wait for the query to finish and return the list
* List<Order> list = futureList.get();
* ...
* }
*
* }</pre>
*/
public interface FutureList<T> extends Future<List<T>> {
/**
* Return the query that is being executed by a background thread.
*/
Query<T> getQuery();
/**
* Same as {@link #get()} but wraps InterruptedException and ExecutionException in the
* unchecked PersistenceException.
*
* @return The query list result
* @throws PersistenceException when a InterruptedException or ExecutionException occurs.
*/
List<T> getUnchecked();
/**
* Same as {@link #get(long, java.util.concurrent.TimeUnit)} but wraps InterruptedException
* and ExecutionException in the unchecked PersistenceException.
*
* @return The query list result
* @throws TimeoutException if the wait timed out
* @throws PersistenceException if a InterruptedException or ExecutionException occurs.
*/
List<T> getUnchecked(long timeout, TimeUnit unit) throws TimeoutException;
}
@@ -1,16 +0,0 @@
package io.ebean;
import java.util.concurrent.Future;
/**
* Represents the result of a background query execution for the total row count
* for a query.
* <p>
* It extends the java.util.concurrent.Future.
* </p>
*
* @param <T> the BeanType
* @author rbygrave
*/
public interface FutureRowCount<T> extends Future<Integer> {
}
-149
View File
@@ -1,149 +0,0 @@
package io.ebean;
/**
* Represents a Conjunction or a Disjunction.
* <p>
* Basically with a Conjunction you join together many expressions with AND, and
* with a Disjunction you join together many expressions with OR.
* </p>
* <p>
* Note: where() always takes you to the top level WHERE expression list.
* </p>
* <pre>{@code
* Query q =
* Ebean.find(Person.class)
* .where()
* .or()
* .like("name", "Rob%")
* .eq("status", Status.NEW)
*
* // where() returns us to the top level expression list
* .where().gt("id", 10);
*
* // read as...
* // where ( ((name like Rob%) or (status = NEW)) AND (id &gt; 10) )
*
* }</pre>
* <p>
* Note: endJunction() takes you to the parent expression list
* </p>
* <pre>{@code
*
* Query q =
* Ebean.find(Person.class)
* .where()
* .or()
* .like("name", "Rob%")
* .eq("status", Status.NEW)
* .endJunction()
*
* // endJunction().. takes us to the 'parent' expression list
* // which in this case is the top level (same as where())
*
* .gt("id", 10);
*
* // read as...
* // where ( ((name like Rob%) or (status = NEW)) AND (id > 10) )
* }</pre>
* <p>
* Example of a nested disjunction.
* </p>
* <pre>{@code
* Query<Customer> q =
* Ebean.find(Customer.class)
* .where()
* .or()
* .and()
* .startsWith("name", "r")
* .eq("anniversary", onAfter)
* .endAnd()
* .and()
* .eq("status", Customer.Status.ACTIVE)
* .gt("id", 0)
* .endAnd()
* .order().asc("name");
*
* q.findList();
* String s = q.getGeneratedSql();
*
* // this produces an expression like:
* ( name like ? and c.anniversary = ? ) or (c.status = ? and c.id > ? )
*
* }</pre>
*/
public interface Junction<T> extends Expression, ExpressionList<T> {
/**
* The type of Junction used in full text expressions.
*/
enum Type {
/**
* AND group.
*/
AND(" and ", "", false),
/**
* OR group.
*/
OR(" or ", "", false),
/**
* NOT group.
*/
NOT(" and ", "not ", false),
/**
* FILTER group (for internal use only).
*/
FILTER("filter", "", true),
/**
* Text search AND group.
*/
MUST("must", "", true),
/**
* Text search NOT group.
*/
MUST_NOT("must_not", "", true),
/**
* Text search OR group.
*/
SHOULD("should", "", true);
private String prefix;
private String literal;
private boolean text;
Type(String literal, String prefix, boolean text) {
this.literal = literal;
this.prefix = prefix;
this.text = text;
}
/**
* Return the literal value for this type.
*/
public String literal() {
return literal;
}
/**
* Return the prefix value for this type.
*/
public String prefix() {
return prefix;
}
/**
* Return true if this is a text type.
*/
public boolean isText() {
return text;
}
}
}
-35
View File
@@ -1,35 +0,0 @@
package io.ebean;
/**
* Used to specify the type of like matching used.
*/
public enum LikeType {
/**
* You need to put in your own wildcards - no escaping is performed.
*/
RAW,
/**
* The % wildcard is added to the end of the search word and search word is escaped.
*/
STARTS_WITH,
/**
* The % wildcard is added to the beginning of the search word and search word is escaped.
*/
ENDS_WITH,
/**
* The % wildcard is added to the beginning and end of the search word and search word is escaped.
*/
CONTAINS,
/**
* Uses equal to rather than a LIKE with wildcards.
* <p>
* This is mainly here to be available for use with ExampleExpression.
* </p>
*/
EQUAL_TO
}
-29
View File
@@ -1,29 +0,0 @@
package io.ebean;
import java.util.Set;
/**
* Options used to control a merge. Use MergeOptionsBuilder to create an instance.
* <p>
* Instances of MergeOptions are thread safe and safe to share across threads.
*/
public interface MergeOptions {
/**
* Returns true if Id values are supplied by the client.
* <p>
* This would be the case when for example a mobile creates data in it's own local database
* and then sync's. In this case often the id values are UUID.
*/
boolean isClientGeneratedIds();
/**
* Return true if delete permanent should be used and false for 'normal' delete that allows soft deletes.
*/
boolean isDeletePermanent();
/**
* Return the paths included in the merge.
*/
Set<String> paths();
}
@@ -1,80 +0,0 @@
package io.ebean;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* Builds a MergeOptions which is immutable and thread safe.
*/
public class MergeOptionsBuilder {
private Set<String> paths = new LinkedHashSet<>();
private boolean clientGeneratedIds;
private boolean deletePermanent = true;
/**
* Add a path that will included in the merge.
*
* @param path The path relative to the root type.
* @return The builder to chain another addPath() or build().
*/
public MergeOptionsBuilder addPath(String path) {
paths.add(path);
return this;
}
/**
* Set to true if Id values are supplied by the client.
* <p>
* This would be the case when for example a mobile creates data in it's own local database
* and then sync's. In this case often the id values are UUID.
*/
public MergeOptionsBuilder setClientGeneratedIds() {
this.clientGeneratedIds = true;
return this;
}
/**
* Set that deletions should use delete permanent (rather than default which allows soft deletes).
*/
public MergeOptionsBuilder setDeletePermanent() {
this.deletePermanent = true;
return this;
}
/**
* Build and return the MergeOptions instance.
*/
public MOptions build() {
return new MOptions(paths, clientGeneratedIds, deletePermanent);
}
private static class MOptions implements MergeOptions {
private final boolean clientGeneratedIds;
private final boolean deletePermanent;
private final Set<String> paths;
private MOptions(Set<String> paths, boolean clientGeneratedIds, boolean deletePermanent) {
this.paths = paths;
this.clientGeneratedIds = clientGeneratedIds;
this.deletePermanent = deletePermanent;
}
public Set<String> paths() {
return paths;
}
@Override
public boolean isClientGeneratedIds() {
return clientGeneratedIds;
}
@Override
public boolean isDeletePermanent() {
return deletePermanent;
}
}
}
-286
View File
@@ -1,286 +0,0 @@
package io.ebean;
import io.ebean.bean.EntityBean;
import javax.persistence.MappedSuperclass;
/**
* A MappedSuperclass base class that provides convenience methods for inserting, updating and
* deleting beans.
* <p>
* By having your entity beans extend this it provides a 'Active Record' style programming model for
* Ebean users.
* <p>
* Note that there is a ebean-mocker project that enables you to use Mockito or similar
* tools to still mock out the underlying 'default EbeanServer' for testing purposes.
* <p>
* You may choose not use this Model mapped superclass if you don't like the 'Active Record' style
* or if you believe it 'pollutes' your entity beans.
* <p>
* You can use Dependency Injection like Guice or Spring to construct and wire a EbeanServer instance
* and have that same instance used with this Model and Finder. The way that works is that when the
* DI container creates the EbeanServer instance it can be registered with the Ebean singleton. In this
* way the EbeanServer instance can be injected as per normal Guice / Spring dependency injection and
* that same instance also used to support the Model and Finder active record style.
* <p>
* If you choose to use the Model mapped superclass you will probably also chose to additionally add
* a {@link Finder} as a public static field to complete the active record pattern and provide a
* relatively nice clean way to write queries.
* <p>
* <h3>Typical common @MappedSuperclass</h3>
* <pre>{@code
*
* // Typically there is a common base model that has some
* // common properties like the ones below
*
* @MappedSuperclass
* public class BaseModel extends Model {
*
* @Id Long id;
*
* @Version Long version;
*
* @WhenCreated Timestamp whenCreated;
*
* @WhenUpdated Timestamp whenUpdated;
*
* ...
*
* }</pre>
* <p>
* <h3>Extend the Model</h3>
* <pre>{@code
*
* // Extend the mappedSuperclass
*
* @Entity @Table(name="o_account")
* public class Customer extends BaseModel {
*
* String name;
* ...
* }
*
* }</pre>
* <p>
* <h3>Modal: save()</h3>
* <pre>{@code
*
* // Active record style ... save(), delete() etc
* Customer customer = new Customer();
* customer.setName("AC234");
*
* // save() method inherited from Model
* customer.save();
*
* }</pre>
*/
@MappedSuperclass
public abstract class Model {
/**
* Return the underlying 'default' EbeanServer.
* <p>
* This provides full access to the API such as explicit transaction demarcation etc.
* <p>
* Example:
* <pre>{@code
*
* Transaction transaction = Customer.db().beginTransaction();
* try {
*
* // turn off cascade persist for this transaction
* transaction.setPersistCascade(false);
*
* // extra control over jdbc batching for this transaction
* transaction.setBatchGetGeneratedKeys(false);
* transaction.setBatchMode(true);
* transaction.setBatchSize(20);
*
* Customer customer = new Customer();
* customer.setName(&quot;Roberto&quot;);
* customer.save();
*
* Customer otherCustomer = new Customer();
* otherCustomer.setName("Franko");
* otherCustomer.save();
*
* transaction.commit();
*
* } finally {
* transaction.end();
* }
*
* }</pre>
*/
public static EbeanServer db() {
return Ebean.getDefaultServer();
}
/**
* Return a named EbeanServer that is typically different to the default server.
* <p>
* If you are using multiple databases then each database has a name and maps to a single
* EbeanServer. You can use this method to get an EbeanServer for another database.
*
* @param server The name of the EbeanServer. If this is null then the default EbeanServer is returned.
*/
public static EbeanServer db(String server) {
return Ebean.getServer(server);
}
/**
* Marks the entity bean as dirty.
* <p>
* This is used so that when a bean that is otherwise unmodified is updated the version
* property is updated.
* <p>
* An unmodified bean that is saved or updated is normally skipped and this marks the bean as
* dirty so that it is not skipped.
* <p>
* <pre>{@code
*
* Customer customer = Customer.find.byId(id);
*
* // mark the bean as dirty so that a save() or update() will
* // increment the version property
* customer.markAsDirty();
* customer.save();
*
* }</pre>
*
* @see EbeanServer#markAsDirty(Object)
*/
public void markAsDirty() {
db().markAsDirty(this);
}
/**
* Mark the property as unset or 'not loaded'.
* <p>
* This would be used to specify a property that we did not wish to include in a stateless update.
* </p>
* <pre>{@code
*
* // populate an entity bean from JSON or whatever
* User user = ...;
*
* // mark the email property as 'unset' so that it is not
* // included in a 'stateless update'
* user.markPropertyUnset("email");
*
* user.update();
*
* }</pre>
*
* @param propertyName the name of the property on the bean to be marked as 'unset'
*/
public void markPropertyUnset(String propertyName) {
((EntityBean) this)._ebean_getIntercept().setPropertyLoaded(propertyName, false);
}
/**
* Insert or update this entity depending on its state.
* <p>
* Ebean will detect if this is a new bean or a previously fetched bean and perform either an
* insert or an update based on that.
*
* @see EbeanServer#save(Object)
*/
public void save() {
db().save(this);
}
/**
* Flush any batched changes to the database.
* <p>
* When using JDBC batch flushing occurs automatically at commit() time or when the batch size
* is reached. This provides the ability to manually flush the batch.
* </p>
*/
public void flush() {
db().flush();
}
/**
* Update this entity.
*
* @see EbeanServer#update(Object)
*/
public void update() {
db().update(this);
}
/**
* Insert this entity.
*
* @see EbeanServer#insert(Object)
*/
public void insert() {
db().insert(this);
}
/**
* Delete this bean.
* <p>
* This will return true if the bean was deleted successfully or JDBC batch is being used.
* </p>
* <p>
* If there is no current transaction one will be created and committed for
* you automatically.
* </p>
* <p>
* If the Bean does not have a version property (or loaded version property) and
* the bean does not exist then this returns false indicating that nothing was
* deleted. Note that, if JDBC batch mode is used then this always returns true.
* </p>
*
* @see EbeanServer#delete(Object)
*/
public boolean delete() {
return db().delete(this);
}
/**
* Delete a bean permanently without soft delete.
* <p>
* This is used when the bean contains a <code>@SoftDelete</code> property and we
* want to perform a hard/permanent delete.
* </p>
*
* @see EbeanServer#deletePermanent(Object)
*/
public boolean deletePermanent() {
return db().deletePermanent(this);
}
/**
* Perform an update using this entity against the specified server.
*/
public void update(String server) {
db(server).update(this);
}
/**
* Perform an insert using this entity against the specified server.
*/
public void insert(String server) {
db(server).insert(this);
}
/**
* Perform a delete using this entity against the specified server.
*/
public boolean delete(String server) {
return db(server).delete(this);
}
/**
* Refreshes this entity from the database.
*
* @see EbeanServer#refresh(Object)
*/
public void refresh() {
db().refresh(this);
}
}
-416
View File
@@ -1,416 +0,0 @@
package io.ebean;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Represents an Order By for a Query.
* <p>
* Is a ordered list of OrderBy.Property objects each specifying a property and
* whether it is ascending or descending order.
* </p>
* <p>
* Typically you will not construct an OrderBy yourself but use one that exists
* on the Query object.
* </p>
*/
public final class OrderBy<T> implements Serializable {
private static final long serialVersionUID = 9157089257745730539L;
private transient Query<T> query;
private final List<Property> list;
/**
* Create an empty OrderBy with no associated query.
*/
public OrderBy() {
this.list = new ArrayList<>(3);
}
private OrderBy(List<Property> list) {
this.list = list;
}
/**
* Create an orderBy parsing the order by clause.
* <p>
* The order by clause follows SQL order by clause with comma's between each
* property and optionally "asc" or "desc" to represent ascending or
* descending order respectively.
* </p>
*/
public OrderBy(String orderByClause) {
this(null, orderByClause);
}
/**
* Construct with a given query and order by clause.
*/
public OrderBy(Query<T> query, String orderByClause) {
this.query = query;
this.list = new ArrayList<>(3);
parse(orderByClause);
}
/**
* Reverse the ascending/descending order on all the properties.
*/
public void reverse() {
for (Property aList : list) {
aList.reverse();
}
}
/**
* Add a property with ascending order to this OrderBy.
*/
public Query<T> asc(String propertyName) {
list.add(new Property(propertyName, true));
return query;
}
/**
* Add a property with descending order to this OrderBy.
*/
public Query<T> desc(String propertyName) {
list.add(new Property(propertyName, false));
return query;
}
/**
* Return true if the property is known to be contained in the order by clause.
*/
public boolean containsProperty(String propertyName) {
for (Property aList : list) {
if (propertyName.equals(aList.getProperty())) {
return true;
}
}
return false;
}
/**
* Return a copy of this OrderBy with the path trimmed.
*/
public OrderBy<T> copyWithTrim(String path) {
List<Property> newList = new ArrayList<>(list.size());
for (Property aList : list) {
newList.add(aList.copyWithTrim(path));
}
return new OrderBy<>(newList);
}
/**
* Return the properties for this OrderBy.
*/
public List<Property> getProperties() {
// not returning an Immutable list at this point
return list;
}
/**
* Return true if this OrderBy does not have any properties.
*/
public boolean isEmpty() {
return list.isEmpty();
}
/**
* Return the associated query if there is one.
*/
public Query<T> getQuery() {
return query;
}
/**
* Associate this OrderBy with a query.
*/
public void setQuery(Query<T> query) {
this.query = query;
}
/**
* Return a copy of the OrderBy.
*/
public OrderBy<T> copy() {
OrderBy<T> copy = new OrderBy<>();
for (Property aList : list) {
copy.add(aList.copy());
}
return copy;
}
/**
* Add to the order by by parsing a raw expression.
*/
public void add(String rawExpression) {
parse(rawExpression);
}
/**
* Add a property to the order by.
*/
public void add(Property p) {
list.add(p);
}
@Override
public String toString() {
return list.toString();
}
/**
* Returns the OrderBy in string format.
*/
public String toStringFormat() {
if (list.isEmpty()) {
return null;
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < list.size(); i++) {
Property property = list.get(i);
if (i > 0) {
sb.append(", ");
}
sb.append(property.toStringFormat());
}
return sb.toString();
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof OrderBy<?>)) {
return false;
}
OrderBy<?> e = (OrderBy<?>) obj;
return e.list.equals(list);
}
/**
* Return a hash value for this OrderBy. This can be to determine logical
* equality for OrderBy clauses.
*/
@Override
public int hashCode() {
return list.hashCode();
}
/**
* Clear the orderBy removing any current order by properties.
* <p>
* This is intended to be used when some code creates a query with a
* 'default' order by clause and some other code may clear the 'default'
* order by clause and replace.
* </p>
*/
public OrderBy<T> clear() {
list.clear();
return this;
}
/**
* A property and its ascending descending order.
*/
public static final class Property implements Serializable {
private static final long serialVersionUID = 1546009780322478077L;
private String property;
private boolean ascending;
private String nulls;
private String highLow;
public Property(String property, boolean ascending) {
this.property = property;
this.ascending = ascending;
}
public Property(String property, boolean ascending, String nulls, String highLow) {
this.property = property;
this.ascending = ascending;
this.nulls = nulls;
this.highLow = highLow;
}
/**
* Return a copy of this Property with the path trimmed.
*/
public Property copyWithTrim(String path) {
return new Property(property.substring(path.length() + 1), ascending, nulls, highLow);
}
@Override
public int hashCode() {
int hc = property.hashCode();
hc = hc * 92821 + (ascending ? 0 : 1);
hc = hc * 92821 + (nulls == null ? 0 : nulls.hashCode());
hc = hc * 92821 + (highLow == null ? 0 : highLow.hashCode());
return hc;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof Property)) {
return false;
}
Property e = (Property) obj;
if (ascending != e.ascending) return false;
if (!property.equals(e.property)) return false;
if (nulls != null ? !nulls.equals(e.nulls) : e.nulls != null) return false;
return highLow != null ? highLow.equals(e.highLow) : e.highLow == null;
}
@Override
public String toString() {
return toStringFormat();
}
public String toStringFormat() {
if (nulls == null) {
if (ascending) {
return property;
} else {
return property + " desc";
}
} else {
StringBuilder sb = new StringBuilder();
sb.append(property);
if (!ascending) {
sb.append(" ").append("desc");
}
sb.append(" ").append(nulls).append(" ").append(highLow);
return sb.toString();
}
}
/**
* Reverse the ascending/descending order for this property.
*/
public void reverse() {
this.ascending = !ascending;
}
/**
* Trim off the pathPrefix.
*/
public void trim(String pathPrefix) {
property = property.substring(pathPrefix.length() + 1);
}
/**
* Return a copy of this property.
*/
public Property copy() {
return new Property(property, ascending, nulls, highLow);
}
/**
* Return the property name.
*/
public String getProperty() {
return property;
}
/**
* Set the property name.
*/
public void setProperty(String property) {
this.property = property;
}
/**
* Return true if the order is ascending.
*/
public boolean isAscending() {
return ascending;
}
/**
* Set to true if the order is ascending.
*/
public void setAscending(boolean ascending) {
this.ascending = ascending;
}
}
private void parse(String orderByClause) {
if (orderByClause == null) {
return;
}
String[] chunks = orderByClause.split(",");
for (String chunk : chunks) {
String[] pairs = chunk.split(" ");
Property p = parseProperty(pairs);
if (p != null) {
list.add(p);
}
}
}
private Property parseProperty(String[] pairs) {
if (pairs.length == 0) {
return null;
}
ArrayList<String> wordList = new ArrayList<>(pairs.length);
for (String pair : pairs) {
if (!isEmptyString(pair)) {
wordList.add(pair);
}
}
if (wordList.isEmpty()) {
return null;
}
if (wordList.size() == 1) {
return new Property(wordList.get(0), true);
}
if (wordList.size() == 2) {
boolean asc = isAscending(wordList.get(1));
return new Property(wordList.get(0), asc);
}
if (wordList.size() == 4) {
// nulls high or nulls low as 3rd and 4th
boolean asc = isAscending(wordList.get(1));
return new Property(wordList.get(0), asc, wordList.get(2), wordList.get(3));
}
String m = "Expecting a 1, 2 or 4 words in [" + Arrays.toString(pairs) + "] but got " + wordList;
throw new RuntimeException(m);
}
private boolean isAscending(String s) {
s = s.toLowerCase();
if (s.startsWith("asc")) {
return true;
}
if (s.startsWith("desc")) {
return false;
}
String m = "Expecting [" + s + "] to be asc or desc?";
throw new RuntimeException(m);
}
private boolean isEmptyString(String s) {
return s == null || s.isEmpty();
}
}
-198
View File
@@ -1,198 +0,0 @@
package io.ebean;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.concurrent.Future;
/**
* Represents a page of results.
* <p>
* The benefit of using PagedList over just using the normal Query with
* {@link Query#setFirstRow(int)} and {@link Query#setMaxRows(int)} is that it additionally wraps
* functionality that can call {@link Query#findFutureCount()} to determine total row count,
* total page count etc.
* </p>
* <p>
* Internally this works using {@link Query#setFirstRow(int)} and {@link Query#setMaxRows(int)} on
* the query. This translates into SQL that uses limit offset, rownum or row_number function to
* limit the result set.
* </p>
* <p>
* <h4>Example: typical use including total row count</h4>
* <pre>{@code
*
* // We want to find the first 50 new orders
* // ... so we don't really need setFirstRow(0)
*
* PagedList<Order> pagedList
* = ebeanServer.find(Order.class)
* .where().eq("status", Order.Status.NEW)
* .order().asc("id")
* .setFirstRow(0)
* .setMaxRows(50)
* .findPagedList();
*
* // Optional: initiate the loading of the total
* // row count in a background thread
* pagedList.loadRowCount();
*
* // fetch and return the list in the foreground thread
* List<Order> orders = pagedList.getList();
*
* // get the total row count (from the future)
* int totalRowCount = pagedList.getTotalRowCount();
*
* }</pre>
* <p>
* <h4>Example: No total row count required</h4>
* <pre>{@code
*
* // If you are not getting the 'first page' often
* // you do not bother getting the total row count again
* // so instead just get the page list of data
*
* // fetch and return the list in the foreground thread
* List<Order> orders = pagedList.getList();
*
* }</pre>
*
* @param <T> the entity bean type
* @see Query#findPagedList()
*/
public interface PagedList<T> {
/**
* Initiate the loading of the total row count in the background.
* <pre>{@code
*
* // initiate the loading of the total row count
* // in a background thread
* pagedList.loadRowCount();
*
* // fetch and return the list in the foreground thread
* List<Order> orders = pagedList.getList();
*
* // get the total row count (from the future)
* int totalRowCount = pagedList.getTotalRowCount();
*
* }</pre>
* <p>
* Also note that using loadRowCount() and getTotalRowCount() rather than getFutureRowCount()
* means that exceptions ExecutionException, InterruptedException, TimeoutException are instead
* wrapped in the unchecked PersistenceException (which might be preferrable).
* </p>
*/
void loadCount();
/**
* Return the Future row count. You might get this if you wish to cancel the total row count query
* or specify a timeout for the row count query.
* <p>
* The loadRowCount() & getTotalRowCount() methods internally make use of this getFutureRowCount() method.
* Generally I expect people to prefer loadRowCount() & getTotalRowCount() over getFutureRowCount().
* </p>
* <pre>{@code
*
* // initiate the row count query in the background thread
* Future<Integer> rowCount = pagedList.getFutureRowCount();
*
* // fetch and return the list in the foreground thread
* List<Order> orders = pagedList.getList();
*
* // now get the total count with a timeout
* Integer totalRowCount = rowCount.get(30, TimeUnit.SECONDS);
*
* // or ge the total count without a timeout
* Integer totalRowCountViaFuture = rowCount.get();
*
* // which is actually the same as ...
* int totalRowCount = pagedList.getTotalRowCount();
*
* }</pre>
*/
@Nonnull
Future<Integer> getFutureCount();
/**
* Return the list of entities for this page.
*/
@Nonnull
List<T> getList();
/**
* Return the total row count for all pages.
* <p>
* If loadRowCount() has already been called then the row count query is already executing in a background thread
* and this gets the associated Future and gets the value waiting for the future to finish.
* </p>
* <p>
* If loadRowCount() has not been called then this executes the find row count query and returns the result and this
* will just occur in the current thread and not use a background thread.
* </p>
* <pre>{@code
*
* // Optional: initiate the loading of the total
* // row count in a background thread
* pagedList.loadRowCount();
*
* // fetch and return the list in the foreground thread
* List<Order> orders = pagedList.getList();
*
* // get the total row count (which was being executed
* // in a background thread if loadRowCount() was used)
* int totalRowCount = pagedList.getTotalRowCount();
*
* }</pre>
*/
int getTotalCount();
/**
* Return the total number of pages based on the page size and total row count.
* <p>
* This method requires that the total row count has been fetched and will invoke
* the total row count query if it has not already been invoked.
* </p>
*/
int getTotalPageCount();
/**
* Return the page size used for this query. This is the same value as maxRows used by the query.
*/
int getPageSize();
/**
* Return the index position of this page (Zero based).
* <p>
* This is a calculated value based on firstRow/maxRows.
* </p>
*/
int getPageIndex();
/**
* Return true if there is a next page.
* <p>
* This method requires that the total row count has been fetched and will invoke
* the total row count query if it has not already been invoked.
* </p>
*/
boolean hasNext();
/**
* Return true if there is a previous page.
*/
boolean hasPrev();
/**
* Helper method to return a "X to Y of Z" string for this page where X is the first row, Y the
* last row and Z the total row count.
* <p>
* This method requires that the total row count has been fetched and will invoke
* the total row count query if it has not already been invoked.
* </p>
*
* @param to String to put between the first and last row
* @param of String to put between the last row and the total row count
* @return String of the format XtoYofZ.
*/
String getDisplayXtoYofZ(String to, String of);
}
-222
View File
@@ -1,222 +0,0 @@
package io.ebean;
import java.util.ArrayList;
import java.util.List;
/**
* Holds a list of value object pairs.
* <p>
* This feature is to enable use of L2 cache with complex natural keys with findList() queries in cases where the
* IN clause is not a single property but instead a pair of properties.
* </p>
* <p>
* These queries can have predicates that can be translated into a list of complex natural keys such that the L2
* cache can be hit with these keys to obtain some or all of the beans from L2 cache rather than the DB.
* </p>
* <pre>{@code
*
* // where a bean is annotated with a complex
* // natural key made of several properties
* @Cache(naturalKey = {"store","code","sku"})
*
*
* Pairs pairs = new Pairs("sku", "code");
* pairs.add("sj2", 1000);
* pairs.add("sj2", 1001);
* pairs.add("pf3", 1000);
*
* List<OCachedNatKeyBean3> list = Ebean.find(OCachedNatKeyBean3.class)
* .where()
* .eq("store", "def")
* .inPairs(pairs) // IN clause with 'pairs' of values
* .orderBy("sku desc")
*
* // query expressions cover the natural key properties
* // so we can choose to hit the L2 bean cache if we want
* .setUseCache(true)
* .findList();
*
* }</pre>
* <h3>Important implementation Note</h3>
* <p>
* When binding many pairs of values we want to be able to utilise a DB index (as this type of query usually means the
* pairs are a unique key/index or part of a unique key/index and highly selective). Currently we know we can do this
* on any DB that supports expression/formula based indexes.
* using a DB string concatenation formula
* </p>
* <p>
* This means, the implementation converts the list of pairs into a list of strings via concatenation and we use a
* DB concatenation formula to match. We see SQL like:
* </p>
* <pre>{@code sql
*
* ...
* where t0.store = ? and (t0.sku||'-'||t0.code) in (?, ? )
*
* // bind values like: "sj2-1000", "pf3-1000"
*
* }</pre>
* <p>
* We often create a DB expression index to match the DB concat formula like:
* </p>
* <pre>{@code sql
*
* create index ix_name on table_name ((sku || '-' || code));
*
* }</pre>
*/
public class Pairs {
private final String property0;
private final String property1;
private final List<Entry> entries = new ArrayList<>();
/**
* Character between the values when combined via DB varchar concatenation.
*/
private String concatSeparator = "-";
/**
* Optional suffix added to DB varchar concatenation formula.
*/
private String concatSuffix;
/**
* Create with 2 property names.
*
* @param property0 The property of the first value
* @param property1 The property of the second value
*/
public Pairs(String property0, String property1) {
this.property0 = property0;
this.property1 = property1;
}
/**
* Add a pair of value objects.
* <p>
* Both values are expected to be immutable with equals and hashCode implementations.
* </p>
*
* @param a Value of the first property
* @param b Value of the second property
*/
public Pairs add(Object a, Object b) {
entries.add(new Entry(a, b));
return this;
}
/**
* Return the first property name.
*/
public String getProperty0() {
return property0;
}
/**
* Return the second property name.
*/
public String getProperty1() {
return property1;
}
/**
* Return all the value pairs.
*/
public List<Entry> getEntries() {
return entries;
}
/**
* Return the separator character used with DB varchar concatenation to combine the 2 values.
*/
public String getConcatSeparator() {
return concatSeparator;
}
/**
* Set the separator character used with DB varchar concatenation to combine the 2 values.
*/
public Pairs setConcatSeparator(String concatSeparator) {
this.concatSeparator = concatSeparator;
return this;
}
/**
* Return a suffix used with DB varchar concatenation to combine the 2 values.
*/
public String getConcatSuffix() {
return concatSuffix;
}
/**
* Add a suffix used with DB varchar concatenation to combine the 2 values.
*/
public Pairs setConcatSuffix(String concatSuffix) {
this.concatSuffix = concatSuffix;
return this;
}
@Override
public String toString() {
return "p0:" + property0 + " p1:" + property1 + " entries:" + entries;
}
/**
* A pair of 2 value objects.
* <p>
* Used to support inPairs() expression.
*/
public static class Entry {
private final Object a;
private final Object b;
/**
* Create with values for property0 and property1 respectively.
*
* @param a Value of the first property
* @param b Value of the second property
*/
public Entry(Object a, Object b) {
this.a = a;
this.b = b;
}
@Override
public String toString() {
return "{" + a + "," + b + "}";
}
/**
* Return the value for the first property.
*/
public Object getA() {
return a;
}
/**
* Return the value for the second property.
*/
public Object getB() {
return b;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Entry that = (Entry) o;
return a.equals(that.a) && b.equals(that.b);
}
@Override
public int hashCode() {
int result = a.hashCode();
result = 92821 * result + b.hashCode();
return result;
}
}
}
@@ -1,35 +0,0 @@
package io.ebean;
/**
* Defines the scope for PersistenceContext.
* <p/>
* Ebean has traditionally used Transaction scope for the PersistenceContext. This is used to change the scope to
* use (by default) and explicitly set the scope to use for an individual query.
*
* @see io.ebean.config.ServerConfig#setPersistenceContextScope(PersistenceContextScope)
* @see Query#setPersistenceContextScope(PersistenceContextScope)
*/
public enum PersistenceContextScope {
/**
* PersistenceContext is scoped to the transaction.
* <p/>
* If a transaction spans 2 or more queries that fetch the same bean in terms of same type
* and same Id value then they share the same bean instance.
* <p/>
* You may want to change to use QUERY scope when you want a query executing in a transaction to effectively
* ignore beans that have already been loaded (by other queries in the same transaction) and instead get a
* 'fresh copy' of the bean.
*/
TRANSACTION,
/**
* PersistenceContext is scoped to the query.
* <p/>
* This means that for this query running in an existing transaction then it will effectively ignore any beans
* that have already been queried/loaded by prior queries in the same transaction.
* <p/>
* You may use QUERY scope on a query that is executed in a transaction and you want to get a 'fresh copy' of the bean.
*/
QUERY
}
@@ -1,20 +0,0 @@
package io.ebean;
import javax.persistence.PersistenceException;
/**
* Captures and wraps IOException's occurring during ElasticSearch processing etc.
*/
public class PersistenceIOException extends PersistenceException {
private static final long serialVersionUID = -7630050437148176148L;
public PersistenceIOException(String msg, Exception cause) {
super(msg, cause);
}
public PersistenceIOException(Exception cause) {
super(cause);
}
}
-89
View File
@@ -1,89 +0,0 @@
package io.ebean;
import io.ebean.config.properties.PropertiesLoader;
import java.util.Properties;
/**
* Provides singleton state for the default server.
* <p/>
* Intended for internal use as part of bootup, construction, registration of the default server.
*/
class PrimaryServer {
private static Properties globalProperties;
private static String defaultServerName;
private static boolean skip;
/**
* Set whether to skip automatically creating the primary server.
*/
static synchronized void setSkip(boolean skip) {
PrimaryServer.skip = skip;
}
/**
* Return true to skip automatically creating the primary server.
*/
static synchronized boolean isSkip() {
return skip;
}
/**
* Return the default server name.
*/
static synchronized String getDefaultServerName() {
getProperties();
return defaultServerName;
}
/**
* Return the default configuration Properties.
*/
static synchronized Properties getProperties() {
if (globalProperties == null) {
globalProperties = PropertiesLoader.load();
}
if (defaultServerName == null) {
defaultServerName = determineDefaultServerName();
}
return globalProperties;
}
/**
* Determine and return the default server name checking system environment variables and then global properties.
*/
private static String determineDefaultServerName() {
String defaultServerName = System.getenv("EBEAN_DB");
defaultServerName = System.getProperty("db", defaultServerName);
defaultServerName = System.getProperty("ebean_db", defaultServerName);
if (isEmpty(defaultServerName)) {
defaultServerName = System.getProperty("datasource.default");
if (isEmpty(defaultServerName)) {
defaultServerName = System.getProperty("ebean.default.datasource");
if (isEmpty(defaultServerName)) {
defaultServerName = globalProperties.getProperty("datasource.default");
if (isEmpty(defaultServerName)) {
defaultServerName = globalProperties.getProperty("ebean.default.datasource");
}
}
}
}
if (defaultServerName == null) {
defaultServerName = "db";
}
System.setProperty("ebean_db", defaultServerName);
return defaultServerName;
}
/**
* Return true if the string is null or empty.
*/
private static boolean isEmpty(String value) {
return value == null || value.trim().isEmpty();
}
}
@@ -1,47 +0,0 @@
package io.ebean;
/**
* A location for profiling transactions and queries.
* <p>
* Typically represents a class method in the form of class file and line of code that started
* the transaction or invoked the query.
* </p>
*/
public interface ProfileLocation {
/**
* Create and return a new ProfileLocation.
*/
static ProfileLocation create() {
return XServiceProvider.profileLocationFactory().create();
}
/**
* Create and return a new ProfileLocation with a given lineNumber and label.
*/
static ProfileLocation create(int lineNumber, String label) {
return XServiceProvider.profileLocationFactory().create(lineNumber, label);
}
/**
* Create and return a new ProfileLocation with a given location.
*/
static ProfileLocation createAt(String location) {
return XServiceProvider.profileLocationFactory().createAt(location);
}
/**
* Obtain the location description.
*/
String obtain();
/**
* Return a short version of the location description.
*/
String shortDescription();
/**
* Add execution time.
*/
void add(long executionTime);
}
File diff suppressed because it is too large Load Diff
-84
View File
@@ -1,84 +0,0 @@
package io.ebean;
import java.util.Iterator;
/**
* Used to provide iteration over query results.
* <p>
* This can be used when you want to process a very large number of results and
* means that you don't have to hold all the results in memory at once (unlike
* findList(), findSet() etc where all the beans are held in the List or Set
* etc).
* </p>
* <p>
* Note that findIterate (and findEach and findEachWhile) uses a "per graph"
* persistence context scope and adjusts jdbc fetch buffer size for large
* queries. As such it is better to use findList for small queries.
* </p>
* <p>
* Remember that with {@link QueryIterator} you must call {@link QueryIterator#close()}
* when you have finished iterating the results. Use "try with resources" or ensure it
* is closed in a finally block.
* </p>
* <h3>Try finally style</h3>
* <pre>{@code
*
* Query<Customer> query = server.find(Customer.class)
* .where().gt("id", 0)
* .orderBy("id")
* .setMaxRows(2);
*
* QueryIterator<Customer> it = query.findIterate();
* try {
* while (it.hasNext()) {
* Customer customer = it.next();
* // do something with customer ...
* }
* } finally {
* // close the underlying resources
* it.close();
* }
*
* }</pre>
* <p>
* <h3>Try with resources style</h3>
* <pre>{@code
*
* // try with resources
* try (QueryIterator<Customer> it = query.findIterate()) {
* while (it.hasNext()) {
* Customer customer = it.next();
* // do something with customer ...
* }
* }
*
* }</pre>
*
* @param <T> the type of entity bean in the iteration
*/
public interface QueryIterator<T> extends Iterator<T>, java.io.Closeable {
/**
* Returns <tt>true</tt> if the iteration has more elements.
*/
@Override
boolean hasNext();
/**
* Returns the next element in the iteration.
*/
@Override
T next();
/**
* Remove is not allowed.
*/
@Override
void remove();
/**
* Close the underlying resources held by this iterator.
*/
@Override
void close();
}
-22
View File
@@ -1,22 +0,0 @@
package io.ebean;
/**
* The type of the query being executed.
*/
public enum QueryType {
/**
* A find query.
*/
FIND,
/**
* An update query.
*/
UPDATE,
/**
* A delete query.
*/
DELETE
}
-163
View File
@@ -1,163 +0,0 @@
package io.ebean;
/**
* Used to build object graphs based on a raw SQL statement (rather than
* generated by Ebean).
* <p>
* If you don't want to build object graphs you can use {@link SqlQuery} instead
* which returns {@link SqlRow} objects rather than entity beans.
* </p>
* <p>
* <b>Unparsed RawSql:</b>
* </p>
* <p>
* When RawSql is created via {@link RawSqlBuilder#unparsed(String)} then Ebean can not
* modify the SQL at all. It can't add any extra expressions into the SQL.
* </p>
* <p>
* <b>Parsed RawSql:</b>
* </p>
* <p>
* When RawSql is created via {@link RawSqlBuilder#parse(String)} then Ebean will parse the
* SQL and find places in the SQL where it can add extra where expressions, add
* extra having expressions or replace the order by clause. If you want to
* explicitly tell Ebean where these insertion points are you can place special
* strings into your SQL ({@code ${where}} or {@code ${andWhere}} and {@code ${having}} or
* {@code ${andHaving})}.
* </p>
* <p>
* If the SQL already includes a WHERE clause put in {@code ${andWhere}} in the location
* you want Ebean to add any extra where expressions. If the SQL doesn't have a
* WHERE clause put {@code ${where}} in instead. Similarly you can put in {@code ${having}} or
* {@code ${andHaving}} where you want Ebean put add extra having expressions.
* </p>
* <p>
* <b>Aggregates:</b>
* </p>
* <p>
* Often RawSql will be used with Aggregate functions (sum, avg, max etc). The
* follow example shows an example based on Total Order Amount -
* sum(d.order_qty*d.unit_price).
* </p>
* <p>
* We can use a OrderAggregate bean that has a &#064;Sql to indicate it is based
* on RawSql and not based on a real DB Table or DB View. It has some properties
* to hold the values for the aggregate functions (sum etc) and a &#064;OneToOne
* to Order.
* </p>
* <p>
* <h3>Example OrderAggregate</h3>
* <pre>{@code
* ...
* // @Sql indicates to that this bean
* // is based on RawSql rather than a table
*
* @Entity
* @Sql
* public class OrderAggregate {
*
* @OneToOne
* Order order;
*
* Double totalAmount;
*
* Double totalItems;
*
* // getters and setters
* ...
*
* }</pre>
* <p>
* <h3>Example 1:</h3>
* <p>
* <pre>{@code
*
* String sql = " select order_id, o.status, c.id, c.name, sum(d.order_qty*d.unit_price) as totalAmount"
* + " from o_order o"
* + " join o_customer c on c.id = o.kcustomer_id "
* + " join o_order_detail d on d.order_id = o.id " + " group by order_id, o.status ";
*
* RawSql rawSql = RawSqlBuilder.parse(sql)
* // map the sql result columns to bean properties
* .columnMapping("order_id", "order.id")
* .columnMapping("o.status", "order.status")
* .columnMapping("c.id", "order.customer.id")
* .columnMapping("c.name", "order.customer.name")
* // we don't need to map this one due to the sql column alias
* // .columnMapping("sum(d.order_qty*d.unit_price)", "totalAmount")
* .create();
*
* List<OrderAggregate> list = Ebean.find(OrderAggregate.class)
* .setRawSql(rawSql)
* .where().gt("order.id", 0)
* .having().gt("totalAmount", 20)
* .findList();
*
*
* }</pre>
* <p>
* <h3>Example 2:</h3>
* <p>
* The following example uses a FetchConfig().query() so that after the initial
* RawSql query is executed Ebean executes a secondary query to fetch the
* associated order status, orderDate along with the customer name.
* </p>
* <p>
* <pre>{@code
*
* String sql = " select order_id, 'ignoreMe', sum(d.order_qty*d.unit_price) as totalAmount "
* + " from o_order_detail d"
* + " group by order_id ";
*
* RawSql rawSql = RawSqlBuilder.parse(sql)
* .columnMapping("order_id", "order.id")
* .columnMappingIgnore("'ignoreMe'")
* .create();
*
* List<OrderAggregate> orders = Ebean.find(OrderAggregate.class)
* .setRawSql(rawSql)
* .fetch("order", "status,orderDate", new FetchConfig().query())
* .fetch("order.customer", "name")
* .where().gt("order.id", 0)
* .having().gt("totalAmount", 20)
* .order().desc("totalAmount")
* .setMaxRows(10)
* .findList();
*
* }</pre>
* <p>
* <h3>Example 3: tableAliasMapping</h3>
* <p>
* Instead of mapping each column you can map each table alias to a path using tableAliasMapping().
* </p>
* <pre>{@code
*
* String rs = "select o.id, o.status, c.id, c.name, "+
* " d.id, d.order_qty, p.id, p.name " +
* "from o_order o join o_customer c on c.id = o.kcustomer_id " +
* "join o_order_detail d on d.order_id = o.id " +
* "join o_product p on p.id = d.product_id " +
* "where o.id <= :maxOrderId and p.id = :productId "+
* "order by o.id, d.id asc";
*
* RawSql rawSql = RawSqlBuilder.parse(rs)
* .tableAliasMapping("c", "customer")
* .tableAliasMapping("d", "details")
* .tableAliasMapping("p", "details.product")
* .create();
*
* List<Order> ordersFromRaw = Ebean.find(Order.class)
* .setRawSql(rawSql)
* .setParameter("maxOrderId", 2)
* .setParameter("productId", 1)
* .findList();
*
* }</pre>
* <p>
* <p>
* Note that lazy loading also works with object graphs built with RawSql.
* </p>
*/
public interface RawSql {
}
-95
View File
@@ -1,95 +0,0 @@
package io.ebean;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* Builds RawSql instances from a SQL string and column mappings.
* <p>
* Note that RawSql can also be defined in ebean-orm.xml files and be used as a
* named query.
* </p>
*
* @see RawSql
*/
public interface RawSqlBuilder {
/**
* Create and return a RawSql object based on the resultSet and list of properties the columns in
* the resultSet map to.
* <p>
* The properties listed in the propertyNames must be in the same order as the columns in the
* resultSet.
*/
static RawSql resultSet(ResultSet resultSet, String... propertyNames) {
return XServiceProvider.rawSql().resultSet(resultSet, propertyNames);
}
/**
* Create and return a SqlRow based on the resultSet with dbTrueValue and binaryOptimizedUUID options.
*/
static SqlRow sqlRow(ResultSet resultSet, final String dbTrueValue, boolean binaryOptimizedUUID) throws SQLException {
return XServiceProvider.rawSql().sqlRow(resultSet, dbTrueValue, binaryOptimizedUUID);
}
/**
* Return an unparsed RawSqlBuilder. Unlike a parsed one this query can not be
* modified - so no additional WHERE or HAVING expressions can be added to
* this query.
*/
static RawSqlBuilder unparsed(String sql) {
return XServiceProvider.rawSql().unparsed(sql);
}
/**
* Return a RawSqlBuilder parsing the sql.
* <p>
* The sql statement will be parsed so that Ebean can determine where it can
* insert additional WHERE or HAVING expressions.
* </p>
* <p>
* Additionally the selected columns are parsed to determine the column
* ordering. This also means additional checks can be made with the column
* mapping - specifically we can check that all columns are mapped and that
* correct column names are entered into the mapping.
* </p>
*/
static RawSqlBuilder parse(String sql) {
return XServiceProvider.rawSql().parsed(sql);
}
/**
* Set the mapping of a DB Column to a bean property.
* <p>
* For Unparsed SQL the columnMapping MUST be defined in the same order that
* the columns appear in the SQL statement.
* </p>
*
* @param dbColumn the DB column that we are mapping to a bean property
* @param propertyName the bean property that we are mapping the DB column to.
*/
RawSqlBuilder columnMapping(String dbColumn, String propertyName);
/**
* Ignore this DB column. It is not mapped to any bean property.
*/
RawSqlBuilder columnMappingIgnore(String dbColumn);
/**
* Modify any column mappings with the given table alias to have the path prefix.
* <p>
* For example modify all mappings with table alias "c" to have the path prefix "customer".
* </p>
* <p>
* For the "Root type" you don't need to specify a tableAliasMapping.
* </p>
*/
RawSqlBuilder tableAliasMapping(String tableAlias, String path);
/**
* Create the immutable RawSql object. Do this after all the column mapping
* has been defined.
*/
RawSql create();
}
-132
View File
@@ -1,132 +0,0 @@
package io.ebean;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.Serializable;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* Query object for performing native SQL queries that return SqlRow's.
* <p>
* Firstly note that you can use your own sql queries with <em>entity beans</em>
* by using the SqlSelect annotation. This should be your first approach when
* wanting to use your own SQL queries.
* </p>
* <p>
* If ORM Mapping is too tight and constraining for your problem then SqlQuery
* could be a good approach.
* </p>
* <p>
* The returned SqlRow objects are similar to a LinkedHashMap with some type
* conversion support added.
* </p>
* <p>
* <pre>{@code
*
* // its typically a good idea to use a named query
* // and put the sql in the orm.xml instead of in your code
*
* String sql = "select id, name from customer where name like :name and status_code = :status";
*
* SqlQuery sqlQuery = Ebean.createSqlQuery(sql);
* sqlQuery.setParameter("name", "Acme%");
* sqlQuery.setParameter("status", "ACTIVE");
*
* // execute the query returning a List of MapBean objects
* List<SqlRow> list = sqlQuery.findList();
*
* }</pre>
*/
public interface SqlQuery extends Serializable {
/**
* Execute the query returning a list.
*/
@Nonnull
List<SqlRow> findList();
/**
* Execute the SqlQuery iterating a row at a time.
* <p>
* This streaming type query is useful for large query execution as only 1 row needs to be held in memory.
* </p>
*/
void findEach(Consumer<SqlRow> consumer);
/**
* Execute the SqlQuery iterating a row at a time with the ability to stop consuming part way through.
* <p>
* Returning false after processing a row stops the iteration through the query results.
* </p>
* <p>
* This streaming type query is useful for large query execution as only 1 row needs to be held in memory.
* </p>
*/
void findEachWhile(Predicate<SqlRow> consumer);
/**
* Execute the query returning a single row or null.
* <p>
* If this query finds 2 or more rows then it will throw a
* PersistenceException.
* </p>
*/
@Nullable
SqlRow findOne();
/**
* Execute the query returning an optional row.
*/
@Nonnull
Optional<SqlRow> findOneOrEmpty();
/**
* The same as bind for named parameters.
*/
SqlQuery setParameter(String name, Object value);
/**
* The same as bind for positioned parameters.
*/
SqlQuery setParameter(int position, Object value);
/**
* Set the index of the first row of the results to return.
*/
SqlQuery setFirstRow(int firstRow);
/**
* Set the maximum number of query results to return.
*/
SqlQuery setMaxRows(int maxRows);
/**
* Set a timeout on this query.
* <p>
* This will typically result in a call to setQueryTimeout() on a
* preparedStatement. If the timeout occurs an exception will be thrown - this
* will be a SQLException wrapped up in a PersistenceException.
* </p>
*
* @param secs the query timeout limit in seconds. Zero means there is no limit.
*/
SqlQuery setTimeout(int secs);
/**
* Set a label that can be put on performance metrics that are collected.
*/
SqlQuery setLabel(String label);
/**
* A hint which for JDBC translates to the Statement.fetchSize().
* <p>
* Gives the JDBC driver a hint as to the number of rows that should be
* fetched from the database when more rows are needed for ResultSet.
* </p>
*/
SqlQuery setBufferFetchSizeHint(int bufferFetchSizeHint);
}
-181
View File
@@ -1,181 +0,0 @@
package io.ebean;
import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.Date;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
/**
* Used to return raw SQL query results.
* <p>
* Refer to {@link SqlQuery} for examples.
* </p>
* <p>
* There are convenience methods such as getInteger(), getBigDecimal() etc. The
* reason for these methods is that the values put into this map often come
* straight from the JDBC resultSet. Depending on the JDBC driver it may put a
* different type into a given property. For example an Integer, BigDecimal,
* Double could all be put into a property depending on the JDBC driver used.
* These convenience methods automatically convert the value as required
* returning the type you expect.
* </p>
*/
public interface SqlRow extends Serializable, Map<String, Object> {
/**
* Return the property names (String).
* <p>
* Internally this uses LinkedHashMap and so the order of the property names
* should be predictable and ordered by the use of LinkedHashMap.
* </p>
*/
Iterator<String> keys();
/**
* Remove a property from the map. Returns the value of the removed property.
*/
@Override
Object remove(Object name);
/**
* Return a property value by its name.
*/
@Override
Object get(Object name);
/**
* Set a value to a property.
*/
@Override
Object put(String name, Object value);
/**
* Exactly the same as the put method.
* <p>
* I added this method because it seems more bean like to have get and set
* methods.
* </p>
*/
Object set(String name, Object value);
/**
* Return a property as a Boolean.
*/
Boolean getBoolean(String name);
/**
* Return a property as a UUID.
*/
UUID getUUID(String name);
/**
* Return a property as an Integer.
*/
Integer getInteger(String name);
/**
* Return a property value as a BigDecimal.
*/
BigDecimal getBigDecimal(String name);
/**
* Return a property value as a Long.
*/
Long getLong(String name);
/**
* Return the property value as a Double.
*/
Double getDouble(String name);
/**
* Return the property value as a Float.
*/
Float getFloat(String name);
/**
* Return a property as a String.
*/
String getString(String name);
/**
* Return the property as a java.util.Date.
*/
java.util.Date getUtilDate(String name);
/**
* Return the property as a sql date.
*/
Date getDate(String name);
/**
* Return the property as a sql timestamp.
*/
Timestamp getTimestamp(String name);
/**
* String description of the underlying map.
*/
@Override
String toString();
/**
* Clear the map.
*/
@Override
void clear();
/**
* Returns true if the map contains the property.
*/
@Override
boolean containsKey(Object key);
/**
* Returns true if the map contains the value.
*/
@Override
boolean containsValue(Object value);
/**
* Returns the entrySet of the map.
*/
@Override
Set<Map.Entry<String, Object>> entrySet();
/**
* Returns true if the map is empty.
*/
@Override
boolean isEmpty();
/**
* Returns the key set of the map.
*/
@Override
Set<String> keySet();
/**
* Put all the values from t into this map.
*/
@Override
void putAll(Map<? extends String, ?> t);
/**
* Return the size of the map.
*/
@Override
int size();
/**
* Return the values from this map.
*/
@Override
Collection<Object> values();
}
-207
View File
@@ -1,207 +0,0 @@
package io.ebean;
/**
* A SqlUpdate for executing insert update or delete statements.
* <p>
* Provides a simple way to execute raw SQL insert update or delete statements
* without having to resort to JDBC.
* </p>
* <p>
* Supports the use of positioned or named parameters and can automatically
* notify Ebean of the table modified so that Ebean can maintain its cache.
* </p>
* <p>
* Note that {@link #setAutoTableMod(boolean)} and
* Ebean#externalModification(String, boolean, boolean, boolean)} can be to
* notify Ebean of external changes and enable Ebean to maintain it's "L2"
* server cache.
* </p>
* <p>
* <pre>{@code
*
* // example that uses 'named' parameters
* String s = "UPDATE f_topic set post_count = :count where id = :id";
* SqlUpdate update = Ebean.createSqlUpdate(s);
* update.setParameter("id", 1);
* update.setParameter("count", 50);
*
* int modifiedCount = Ebean.execute(update);
*
* String msg = "There were " + modifiedCount + " rows updated";
*
* }</pre>
* <p>
* <h3>Example: Using setNextParameter()</h3>
* <pre>{@code
*
* String sql = "insert into audit_log (id, description, modified_description) values (?,?,?)";
* SqlUpdate insert = Ebean.createSqlUpdate(sql);
*
* try (Transaction txn = Ebean.beginTransaction()) {
* txn.setBatchMode(true);
*
* insert.setNextParameter(10000);
* insert.setNextParameter("hello");
* insert.setNextParameter("rob");
* insert.execute();
*
* insert.setNextParameter(10001);
* insert.setNextParameter("goodbye");
* insert.setNextParameter("rob");
* insert.execute();
*
* insert.setNextParameter(10002);
* insert.setNextParameter("chow");
* insert.setNextParameter("bob");
* insert.execute();
*
* txn.commit();
* }
*
* }</pre>
*
* @see Update
* @see SqlQuery
* @see CallableSql
*/
public interface SqlUpdate {
/**
* Execute the update returning the number of rows modified.
* <p>
* After you have executed the SqlUpdate you can bind new variables using
* {@link #setParameter(String, Object)} etc and then execute the SqlUpdate
* again.
* </p>
* <p>
* For JDBC batch processing refer to
* {@link Transaction#setBatchMode(boolean)} and
* {@link Transaction#setBatchSize(int)}.
* </p>
*
* @see Ebean#execute(SqlUpdate)
*/
int execute();
/**
* Return the generated key value.
*/
Object getGeneratedKey();
/**
* Execute and return the generated key. This is effectively a short cut for:
* <p>
* <pre>{@code
*
* sqlUpdate.execute();
* Object key = sqlUpdate.getGeneratedKey();
*
* }</pre>
*
* @return The generated key value
*/
Object executeGetKey();
/**
* Return true if eBean should automatically deduce the table modification
* information and process it.
* <p>
* If this is true then cache invalidation and text index management are aware
* of the modification.
* </p>
*/
boolean isAutoTableMod();
/**
* Set this to false if you don't want eBean to automatically deduce the table
* modification information and process it.
* <p>
* Set this to false if you don't want any cache invalidation or text index
* management to occur. You may do this when say you update only one column
* and you know that it is not important for cached objects or text indexes.
* </p>
*/
SqlUpdate setAutoTableMod(boolean isAutoTableMod);
/**
* Return the label that can be seen in the transaction logs.
*/
String getLabel();
/**
* Set a descriptive text that can be put into the transaction log.
* <p>
* Useful when identifying the statement in the transaction log.
* </p>
*/
SqlUpdate setLabel(String label);
/**
* Set to true when we want to use getGeneratedKeys with this statement.
*/
SqlUpdate setGetGeneratedKeys(boolean getGeneratedKeys);
/**
* Return the sql statement.
*/
String getSql();
/**
* Return the generated sql that has named parameters converted to positioned parameters.
*/
String getGeneratedSql();
/**
* Return the timeout used to execute this statement.
*/
int getTimeout();
/**
* Set the timeout in seconds. Zero implies no limit.
* <p>
* This will set the query timeout on the underlying PreparedStatement. If the
* timeout expires a SQLException will be throw and wrapped in a
* PersistenceException.
* </p>
*/
SqlUpdate setTimeout(int secs);
/**
* Set the next positioned parameter.
*
* @param value The value to bind
*/
SqlUpdate setNextParameter(Object value);
/**
* Set a parameter via its index position.
*/
SqlUpdate setParameter(int position, Object value);
/**
* Set a null parameter via its index position.
*/
SqlUpdate setNull(int position, int jdbcType);
/**
* Set a null valued parameter using its index position.
*/
SqlUpdate setNullParameter(int position, int jdbcType);
/**
* Set a named parameter value.
*/
SqlUpdate setParameter(String name, Object param);
/**
* Set a named parameter that has a null value. Exactly the same as
* {@link #setNullParameter(String, int)}.
*/
SqlUpdate setNull(String name, int jdbcType);
/**
* Set a named parameter that has a null value.
*/
SqlUpdate setNullParameter(String name, int jdbcType);
}
-514
View File
@@ -1,514 +0,0 @@
package io.ebean;
import io.ebean.annotation.DocStoreMode;
import io.ebean.annotation.PersistBatch;
import io.ebean.config.DocStoreConfig;
import io.ebean.config.ServerConfig;
import javax.persistence.PersistenceException;
import java.sql.Connection;
/**
* The Transaction object. Typically representing a JDBC or JTA transaction.
*/
public interface Transaction extends AutoCloseable {
/**
* Return the current transaction (of the default server) or null if there is
* no current transaction in scope.
* <p>
* This is the same as <code>Ebean.currentTransaction()</code>
* </p>
* <p>
* This returns the current transaction for the 'default server'. If you are using
* multiple EbeanServer's then use {@link EbeanServer#currentTransaction()}.
* </p>
* @see Ebean#currentTransaction()
* @see EbeanServer#currentTransaction()
*/
static Transaction current() {
return Ebean.currentTransaction();
}
/**
* Read Committed transaction isolation. Same as
* java.sql.Connection.TRANSACTION_READ_COMMITTED.
*/
int READ_COMMITTED = java.sql.Connection.TRANSACTION_READ_COMMITTED;
/**
* Read Uncommitted transaction isolation. Same as
* java.sql.Connection.TRANSACTION_READ_UNCOMMITTED.
*/
int READ_UNCOMMITTED = java.sql.Connection.TRANSACTION_READ_UNCOMMITTED;
/**
* Repeatable read transaction isolation. Same as
* java.sql.Connection.TRANSACTION_REPEATABLE_READ.
*/
int REPEATABLE_READ = java.sql.Connection.TRANSACTION_REPEATABLE_READ;
/**
* Serializable transaction isolation. Same as
* java.sql.Connection.TRANSACTION_SERIALIZABLE.
*/
int SERIALIZABLE = java.sql.Connection.TRANSACTION_SERIALIZABLE;
/**
* Register a TransactionCallback with this transaction.
*/
void register(TransactionCallback callback);
/**
* Set a label on the transaction.
* <p>
* This label is used to group transaction execution times for performance metrics reporting.
* </p>
*/
void setLabel(String label);
/**
* Return true if this transaction is read only.
*/
boolean isReadOnly();
/**
* Set whether this transaction should be readOnly.
*/
void setReadOnly(boolean readOnly);
/**
* Commits the transaction at this point with the expectation that another
* commit (or rollback or end) will occur later to complete the transaction.
* <p>
* This is similar to commit() but leaves the transaction "Active".
* </p>
* <h3>Functions/h3>
* <ul>
* <li>Flush the JDBC batch buffer</li>
* <li>Call commit on the underlying JDBC connection</li>
* <li>Trigger any registered TransactionCallbacks</li>
* <li>Perform post-commit processing updating L2 cache, ElasticSearch etc</li>
* </ul>
*/
void commitAndContinue();
/**
* Commit the transaction.
* <p>
* This performs commit and completes the transaction closing underlying resources and
* marking the transaction as "In active".
* </p>
* <h3>Functions/h3>
* <ul>
* <li>Flush the JDBC batch buffer</li>
* <li>Call commit on the underlying JDBC connection</li>
* <li>Trigger any registered TransactionCallbacks</li>
* <li>Perform post-commit processing updating L2 cache, ElasticSearch etc</li>
* <li>Close any underlying resources, closing the underlying JDBC connection</li>
* <li>Mark the transaction as "Inactive"</li>
* </ul>
*/
void commit();
/**
* Rollback the transaction.
* <p>
* This performs rollback, closes underlying resources and marks the transaction as "In active".
* </p>
* <h3>Functions/h3>
* <ul>
* <li>Call rollback on the underlying JDBC connection</li>
* <li>Trigger any registered TransactionCallbacks</li>
* <li>Close any underlying resources, closing the underlying JDBC connection</li>
* <li>Mark the transaction as "Inactive"</li>
* </ul>
*/
void rollback() throws PersistenceException;
/**
* Rollback the transaction specifying a throwable that caused the rollback to
* occur.
* <p>
* If you are using transaction logging this will log the throwable in the
* transaction logs.
* </p>
*/
void rollback(Throwable e) throws PersistenceException;
/**
* Mark the transaction for rollback only.
*/
void setRollbackOnly();
/**
* Return true if the transaction is marked as rollback only.
*/
boolean isRollbackOnly();
/**
* If the transaction is active then perform rollback. Otherwise do nothing.
*/
void end();
/**
* Synonym for end() to support AutoClosable.
*/
@Override
void close();
/**
* Return true if the transaction is active.
*/
boolean isActive();
/**
* Set the behavior for document store updates on this transaction.
* <p>
* For example, set the mode to DocStoreEvent.IGNORE for this transaction and
* then any changes via this transaction are not sent to the doc store. This
* would be used when doing large bulk inserts into the database and we want
* to control how that is sent to the document store.
* </p>
*/
void setDocStoreMode(DocStoreMode mode);
/**
* Set the batch size to use for sending messages to the document store.
* <p>
* You might set this if you know the changes in this transaction result in especially large or
* especially small payloads and want to adjust the batch size to match.
* </p>
* <p>
* Setting this overrides the default of {@link DocStoreConfig#getBulkBatchSize()}
* </p>
*/
void setDocStoreBatchSize(int batchSize);
/**
* Explicitly turn off or on the cascading nature of save() and delete(). This
* gives the developer exact control over what beans are saved and deleted
* rather than Ebean cascading detecting 'dirty/modified' beans etc.
* <p>
* This is useful if you can getting back entity beans from a layer of code
* (potentially remote) and you prefer to have exact control.
* </p>
* <p>
* This may also be useful if you are using jdbc batching with jdbc drivers
* that do not support getGeneratedKeys.
* </p>
*/
void setPersistCascade(boolean persistCascade);
/**
* Set to true when you want all loaded properties to be included in the update
* (rather than just the changed properties).
* <p>
* You might set this when using JDBC batch in order to get multiple updates
* with slightly different sets of changed properties into the same statement
* and hence better JDBC batch performance.
* </p>
*/
void setUpdateAllLoadedProperties(boolean updateAllLoadedProperties);
/**
* Set if the L2 cache should be skipped for "find by id" and "find by natural key" queries.
* <p>
* By default {@link ServerConfig#isSkipCacheAfterWrite()} is true and that means that for
* "find by id" and "find by natural key" queries which normally hit L2 bean cache automatically
* - will not do so after a persist/write on the transaction.
* </p>
* <p>
* This method provides explicit control over whether "find by id" and "find by natural key"
* will skip the L2 bean cache or not (regardless of whether the transaction is considered "read only").
* </p>
* <p>
* Refer to {@link ServerConfig#setSkipCacheAfterWrite(boolean)} for configuring the default behavior
* for using the L2 bean cache in transactions spanning multiple query/persist requests.
* </p>
* <p>
* <pre>{@code
*
* // assume Customer has L2 bean caching enabled ...
*
* Transaction transaction = Ebean.beginTransaction();
* try {
*
* // this uses L2 bean cache as the transaction
* // ... is considered "query only" at this point
* Customer.find.byId(42);
*
* // transaction no longer "query only" once
* // ... a bean has been saved etc
* Ebean.save(someBean);
*
* // will NOT use L2 bean cache as the transaction
* // ... is no longer considered "query only"
* Customer.find.byId(55);
*
*
*
* // explicit control - please use L2 bean cache
*
* transaction.setSkipCache(false);
* Customer.find.byId(77); // hit the l2 bean cache
*
*
* // explicit control - please don't use L2 bean cache
*
* transaction.setSkipCache(true);
* Customer.find.byId(99); // skips l2 bean cache
*
*
* } finally {
* transaction.end();
* }
*
* }</pre>
*
* @see ServerConfig#isSkipCacheAfterWrite()
*/
void setSkipCache(boolean skipCache);
/**
* Return true if the L2 cache should be skipped. More accurately if true then find by id
* and find by natural key queries should NOT automatically use the L2 bean cache.
*/
boolean isSkipCache();
/**
* Turn on or off statement batching. Statement batching can be transparent
* for drivers and databases that support getGeneratedKeys. Otherwise you may
* wish to specifically control when batching is used via this method.
* <p>
* Refer to <code>java.sql.PreparedStatement.addBatch();</code>
* <p>
* Note that you may also wish to use the setPersistCascade method to stop
* save and delete cascade behaviour. You may do this to have full control
* over the order of execution rather than the normal cascading fashion.
* </p>
* <p>
* Note that the <em>execution order</em> in batch mode may be different from
* non batch mode execution order. Also note that <em>insert behaviour</em>
* may be different depending on the JDBC driver and its support for
* getGeneratedKeys. That is, for JDBC drivers that do not support
* getGeneratedKeys you may not get back the generated IDs (used for inserting
* associated detail beans etc).
* </p>
* <p>
* Calls to save(), delete(), insert() and execute() all support batch
* processing. This includes normal beans, MapBean, CallableSql and UpdateSql.
* </p>
* <p>
* The flushing of the batched statements is automatic but you can call
* batchFlush when you like. Note that flushing occurs when a query is
* executed or when you mix UpdateSql and CallableSql with save and delete of
* beans.
* </p>
* <p>
* Example: batch processing executing every 3 rows
* </p>
* <p>
* <pre>{@code
*
* String data = "This is a simple test of the batch processing"
* + " mode and the transaction execute batch method";
*
* String[] da = data.split(" ");
*
* String sql = "{call sp_t3(?,?)}";
*
* CallableSql cs = new CallableSql(sql);
* cs.registerOut(2, Types.INTEGER);
*
* // (optional) inform eBean this stored procedure
* // inserts into a table called sp_test
* cs.addModification("sp_test", true, false, false);
*
* Transaction txn = ebeanServer.beginTransaction();
* txn.setBatchMode(true);
* txn.setBatchSize(3);
* try {
* for (int i = 0; i < da.length;) {
* cs.setParameter(1, da[i]);
* ebeanServer.execute(cs);
* }
*
* // NB: commit implicitly flushes
* txn.commit();
*
* } finally {
* txn.end();
* }
*
* }</pre>
*/
void setBatchMode(boolean useBatch);
/**
* The JDBC batch mode to use for this transaction.
* <p>
* If this is NONE then JDBC batch can still be used for each request - save(), insert(), update() or delete()
* and this would be useful if the request cascades to detail beans.
* </p>
*
* @param persistBatchMode the batch mode to use for this transaction
* @see io.ebean.config.ServerConfig#setPersistBatch(PersistBatch)
*/
void setBatch(PersistBatch persistBatchMode);
/**
* Return the batch mode at the transaction level.
*/
PersistBatch getBatch();
/**
* Set the JDBC batch mode to use for a save() or delete() request.
* <p>
* This only takes effect when batch mode on the transaction has not already meant that
* JDBC batch mode is being used.
* </p>
* <p>
* This is useful when the single save() or delete() cascades. For example, inserting a 'master' cascades
* and inserts a collection of 'detail' beans. The detail beans can be inserted using JDBC batch.
* </p>
*
* @param batchOnCascadeMode the batch mode to use per save(), insert(), update() or delete()
* @see io.ebean.config.ServerConfig#setPersistBatchOnCascade(PersistBatch)
*/
void setBatchOnCascade(PersistBatch batchOnCascadeMode);
/**
* Return the batch mode at the request level (for each save(), insert(), update() or delete()).
*/
PersistBatch getBatchOnCascade();
/**
* Specify the number of statements before a batch is flushed automatically.
*/
void setBatchSize(int batchSize);
/**
* Return the current batch size.
*/
int getBatchSize();
/**
* Specify if you want batched inserts to use getGeneratedKeys.
* <p>
* By default batched inserts will try to use getGeneratedKeys if it is
* supported by the underlying jdbc driver and database.
* </p>
* <p>
* You may want to turn getGeneratedKeys off when you are inserting a large
* number of objects and you don't care about getting back the ids.
* </p>
*/
void setBatchGetGeneratedKeys(boolean getGeneratedKeys);
/**
* By default when mixing UpdateSql (or CallableSql) with Beans the batch is
* automatically flushed when you change (between persisting beans and
* executing UpdateSql or CallableSql).
* <p>
* If you want to execute both WITHOUT having the batch automatically flush
* you need to call this with batchFlushOnMixed = false.
* </p>
* <p>
* Note that UpdateSql and CallableSql are ALWAYS executed first (before the
* beans are executed). This is because the UpdateSql and CallableSql have
* already been bound to their PreparedStatements. The beans on the other hand
* have a 2 step process (delayed binding).
* </p>
*/
void setBatchFlushOnMixed(boolean batchFlushOnMixed);
/**
* By default executing a query will automatically flush any batched
* statements (persisted beans, executed UpdateSql etc).
* <p>
* Calling this method with batchFlushOnQuery = false means that you can
* execute a query and the batch will not be automatically flushed.
* </p>
*/
void setBatchFlushOnQuery(boolean batchFlushOnQuery);
/**
* Return true if the batch (of persisted beans or executed UpdateSql etc)
* should be flushed prior to executing a query.
* <p>
* The default is for this to be true.
* </p>
*/
boolean isBatchFlushOnQuery();
/**
* The batch will be flushing automatically but you can use this to explicitly
* flush the batch if you like.
* <p>
* Flushing occurs automatically when:
* </p>
* <ul>
* <li>the batch size is reached</li>
* <li>A query is executed on the same transaction</li>
* <li>UpdateSql or CallableSql are mixed with bean save and delete</li>
* <li>Transaction commit occurs</li>
* <li>A getter method is called on a batched bean</li>
* </ul>
*/
void flush() throws PersistenceException;
/**
* This is a synonym for flush() and will be deprecated.
* <p>
* flush() is preferred as it matches the JPA flush() method.
* </p>
*/
void flushBatch() throws PersistenceException;
/**
* Return the underlying Connection object.
* <p>
* Useful where a Developer wishes to use the JDBC API directly. Note that the
* commit() rollback() and end() methods on the Transaction should still be
* used. Calling these methods on the Connection would be a big no no unless
* you know what you are doing.
* </p>
* <p>
* Examples of when a developer may wish to use the connection directly are:
* Savepoints, advanced CLOB BLOB use and advanced stored procedure calls.
* </p>
*/
Connection getConnection();
/**
* Add table modification information to the TransactionEvent.
* <p>
* Use this in conjunction with getConnection() and raw JDBC.
* </p>
* <p>
* This effectively informs Ebean of the data that has been changed by the
* transaction and this information is normally automatically handled by Ebean
* when you save entity beans or use UpdateSql etc.
* </p>
* <p>
* If you use raw JDBC then you can use this method to inform Ebean for the
* tables that have been modified. Ebean uses this information to keep its
* caches in synch and maintain text indexes.
* </p>
*/
void addModification(String tableName, boolean inserts, boolean updates, boolean deletes);
/**
* Add an arbitrary user object to the transaction. The objects added have no
* impact on any internals of ebean and are solely meant as a convenient
* method push user information (although somewhat replaced by TransactionCallback).
*/
void putUserObject(String name, Object value);
/**
* Get an object added with {@link #putUserObject(String, Object)}.
*/
Object getUserObject(String name);
}
@@ -1,34 +0,0 @@
package io.ebean;
/**
* Provides a callback that can be registered with a Transaction.
* <p/>
* The callback methods are called just prior to and after the transaction performs a commit or rollback.
* <p/>
* A typical use of TransactionCallback would be to clean up non-transactional resources like files. For example,
* when processing files on postCommit/postRollback clean up the associated files. As another example when
* on postCommit of a delete remove associated resources from the file system or remote service.
*/
public interface TransactionCallback {
/**
* Perform processing just prior to the transaction commit.
*/
void preCommit();
/**
* Perform processing just after the transaction commit.
*/
void postCommit();
/**
* Perform processing just prior to the transaction rollback.
*/
void preRollback();
/**
* Perform processing just after the transaction rollback.
*/
void postRollback();
}
@@ -1,42 +0,0 @@
package io.ebean;
/**
* Adapter that can be extended for easier implementation of TransactionCallback.
* <p/>
* Provides 'no operation' implementation for each of the TransactionCallback methods. It is expected that this
* class is extended and override the methods you need to.
*/
public abstract class TransactionCallbackAdapter implements TransactionCallback {
/**
* Perform processing just prior to the transaction commit.
*/
@Override
public void preCommit() {
// do nothing - override as necessary
}
/**
* Perform processing just after the transaction commit.
*/
@Override
public void postCommit() {
// do nothing - override as necessary
}
/**
* Perform processing just prior to the transaction rollback.
*/
@Override
public void preRollback() {
// do nothing - override as necessary
}
/**
* Perform processing just after the transaction rollback.
*/
@Override
public void postRollback() {
// do nothing - override as necessary
}
}
-435
View File
@@ -1,435 +0,0 @@
package io.ebean;
import io.ebean.annotation.PersistBatch;
import io.ebean.annotation.TxIsolation;
import io.ebean.annotation.TxType;
import java.util.ArrayList;
import java.util.concurrent.Callable;
/**
* Holds the definition of how a transactional method should run.
* <p>
* This information matches the features of the Transactional annotation. You
* can use it directly with Runnable or Callable via
* {@link Ebean#execute(TxScope, Runnable)} or
* {@link Ebean#executeCall(TxScope, Callable)}.
* </p>
* <p>
* This object is used internally with the enhancement of a method with
* Transactional annotation.
* </p>
*
* @see Ebean#execute(TxScope, Runnable)
* @see Ebean#executeCall(TxScope, Callable)
*/
public final class TxScope {
private int profileId;
private TxType type;
private String serverName;
private TxIsolation isolation;
private PersistBatch batch;
private PersistBatch batchOnCascade;
private int batchSize;
private boolean skipGeneratedKeys;
private boolean readOnly;
/**
* Set this to false if the JDBC batch should not be automatically be flushed when a query is executed.
*/
private boolean flushOnQuery = true;
private boolean skipCache;
private String label;
private ArrayList<Class<? extends Throwable>> rollbackFor;
private ArrayList<Class<? extends Throwable>> noRollbackFor;
private ProfileLocation profileLocation;
/**
* Helper method to create a TxScope with REQUIRES.
*/
public static TxScope required() {
return new TxScope(TxType.REQUIRED);
}
/**
* Helper method to create a TxScope with REQUIRES_NEW.
*/
public static TxScope requiresNew() {
return new TxScope(TxType.REQUIRES_NEW);
}
/**
* Helper method to create a TxScope with MANDATORY.
*/
public static TxScope mandatory() {
return new TxScope(TxType.MANDATORY);
}
/**
* Helper method to create a TxScope with SUPPORTS.
*/
public static TxScope supports() {
return new TxScope(TxType.SUPPORTS);
}
/**
* Helper method to create a TxScope with NOT_SUPPORTED.
*/
public static TxScope notSupported() {
return new TxScope(TxType.NOT_SUPPORTED);
}
/**
* Helper method to create a TxScope with NEVER.
*/
public static TxScope never() {
return new TxScope(TxType.NEVER);
}
/**
* Create a REQUIRED transaction scope.
*/
public TxScope() {
this.type = TxType.REQUIRED;
}
/**
* Create with a given transaction scope type.
*/
public TxScope(TxType type) {
this.type = type;
}
/**
* Describes this TxScope instance.
*/
@Override
public String toString() {
return "TxScope[" + type + "] readOnly[" + readOnly + "] isolation[" + isolation
+ "] serverName[" + serverName + "] rollbackFor[" + rollbackFor + "] noRollbackFor[" + noRollbackFor + "]";
}
/**
* Return true if PersistBatch has been set.
*/
public boolean isBatchSet() {
return batch != null && batch != PersistBatch.INHERIT;
}
/**
* Return true if batch on cascade has been set.
*/
public boolean isBatchOnCascadeSet() {
return batchOnCascade != null && batchOnCascade != PersistBatch.INHERIT;
}
/**
* Return true if batch size has been set.
*/
public boolean isBatchSizeSet() {
return batchSize > 0;
}
/**
* Check for batchSize being set without batch mode and use this to imply PersistBatch.ALL.
*/
public void checkBatchMode() {
if (batchSize > 0 && notSet(batch) && notSet(batchOnCascade)) {
// Use setting the batchSize as implying PersistBatch.ALL for @Transactional
batch = PersistBatch.ALL;
}
}
/**
* Return true if the mode is considered not set.
*/
private boolean notSet(PersistBatch batchMode) {
return batchMode == null || batchMode == PersistBatch.INHERIT;
}
/**
* Return the transaction type.
*/
public TxType getType() {
return type;
}
/**
* Set the transaction type.
*/
public TxScope setType(TxType type) {
this.type = type;
return this;
}
/**
* Return the transaction profile id.
*/
public int getProfileId() {
return profileId;
}
/**
* Set the transaction profile id.
*/
public TxScope setProfileId(int profileId) {
this.profileId = profileId;
return this;
}
/**
* Return the profile location.
*/
public ProfileLocation getProfileLocation() {
return profileLocation;
}
/**
* Set the profile location.
*/
public TxScope setProfileLocation(ProfileLocation profileLocation) {
this.profileLocation = profileLocation;
return this;
}
/**
* Return true if the L2 cache should be skipped for this transaction.
*/
public boolean isSkipCache() {
return skipCache;
}
/**
* Set to true if the transaction should skip L2 cache access.
*/
public TxScope setSkipCache(boolean skipCache) {
this.skipCache = skipCache;
return this;
}
/**
* Return the label for the transaction.
*/
public String getLabel() {
return label;
}
/**
* Set a label for the transaction.
*/
public TxScope setLabel(String label) {
this.label = label;
return this;
}
/**
* Return the batch mode.
*/
public PersistBatch getBatch() {
return batch;
}
/**
* Set the batch mode to use.
*/
public TxScope setBatch(PersistBatch batch) {
this.batch = batch;
return this;
}
/**
* Return the batch on cascade mode.
*/
public PersistBatch getBatchOnCascade() {
return batchOnCascade;
}
/**
* Set the batch on cascade mode.
*/
public TxScope setBatchOnCascade(PersistBatch batchOnCascade) {
this.batchOnCascade = batchOnCascade;
return this;
}
/**
* Return the batch size. 0 means use the default value.
*/
public int getBatchSize() {
return batchSize;
}
/**
* Set the batch size to use.
*/
public TxScope setBatchSize(int batchSize) {
this.batchSize = batchSize;
return this;
}
/**
* Set if the transaction should skip reading generated keys for inserts.
*/
public TxScope setSkipGeneratedKeys() {
this.skipGeneratedKeys = true;
return this;
}
/**
* Return true if getGeneratedKeys should be skipped for this transaction.
*/
public boolean isSkipGeneratedKeys() {
return skipGeneratedKeys;
}
/**
* Return if the transaction should be treated as read only.
*/
public boolean isReadonly() {
return readOnly;
}
/**
* Set if the transaction should be treated as read only.
*/
public TxScope setReadOnly(boolean readOnly) {
this.readOnly = readOnly;
return this;
}
/**
* Return false if the JDBC batch buffer should not be flushed automatically when a query is executed.
*/
public boolean isFlushOnQuery() {
return flushOnQuery;
}
/**
* Set flushOnQuery to be false to stop automatically flushing the JDBC batch buffer when a query is executed.
*/
public TxScope setFlushOnQuery(boolean flushOnQuery) {
this.flushOnQuery = flushOnQuery;
return this;
}
/**
* Return the isolation level.
*/
public int getIsolationLevel() {
return isolation != null ? isolation.getLevel() : -1;
}
/**
* Return the Isolation level this transaction should run with.
*/
public TxIsolation getIsolation() {
return isolation;
}
/**
* Set the transaction isolation level this transaction should run with.
*/
public TxScope setIsolation(TxIsolation isolation) {
this.isolation = isolation;
return this;
}
/**
* Return the serverName for this transaction. If this is null then the
* default server (default DataSource) will be used.
*/
public String getServerName() {
return serverName;
}
/**
* Set the serverName (DataSource name) for which this transaction will be. If
* the serverName is not specified (left null) then the default server will be
* used.
*/
public TxScope setServerName(String serverName) {
this.serverName = serverName;
return this;
}
/**
* Return the throwable's that should cause a rollback.
*/
public ArrayList<Class<? extends Throwable>> getRollbackFor() {
return rollbackFor;
}
/**
* Set a Throwable that should explicitly cause a rollback.
*/
public TxScope setRollbackFor(Class<? extends Throwable> rollbackThrowable) {
if (rollbackFor == null) {
rollbackFor = new ArrayList<>(2);
}
rollbackFor.add(rollbackThrowable);
return this;
}
/**
* Set multiple throwable's that will cause a rollback.
*/
@SuppressWarnings("unchecked")
public TxScope setRollbackFor(Class<?>[] rollbackThrowables) {
if (rollbackFor == null) {
rollbackFor = new ArrayList<>(rollbackThrowables.length);
}
for (Class<?> rollbackThrowable : rollbackThrowables) {
rollbackFor.add((Class<? extends Throwable>) rollbackThrowable);
}
return this;
}
/**
* Return the throwable's that should NOT cause a rollback.
*/
public ArrayList<Class<? extends Throwable>> getNoRollbackFor() {
return noRollbackFor;
}
/**
* Add a Throwable to a list that will NOT cause a rollback. You are able to
* call this method multiple times with different throwable's and they will
* added to a list.
*/
public TxScope setNoRollbackFor(Class<? extends Throwable> noRollback) {
if (noRollbackFor == null) {
noRollbackFor = new ArrayList<>(2);
}
this.noRollbackFor.add(noRollback);
return this;
}
/**
* Set multiple throwable's that will NOT cause a rollback.
*/
@SuppressWarnings("unchecked")
public TxScope setNoRollbackFor(Class<?>[] noRollbacks) {
if (noRollbackFor == null) {
noRollbackFor = new ArrayList<>(noRollbacks.length);
}
for (Class<?> noRollback : noRollbacks) {
noRollbackFor.add((Class<? extends Throwable>) noRollback);
}
return this;
}
}
-165
View File
@@ -1,165 +0,0 @@
package io.ebean;
/**
* An Insert Update or Delete statement.
* <p>
* Generally a named update will be defined on the entity bean. This will take
* the form of either an actual sql insert update delete statement or a similar
* statement with bean name and property names in place of database table and
* column names. The statement will likely include named parameters.
* </p>
* <p>
* The following is an example of named updates on an entity bean.
* </p>
* <pre>{@code
* ...
* @NamedUpdates(value = {
* @NamedUpdate(
* name = "setTitle",
* notifyCache = false,
* update = "update topic set title = :title, postCount = :count where id = :id"),
* @NamedUpdate(
* name = "setPostCount",
* notifyCache = false,
* update = "update f_topic set post_count = :postCount where id = :id"),
* @NamedUpdate(
* name = "incrementPostCount",
* notifyCache = false,
* update = "update Topic set postCount = postCount + 1 where id = :id")
* //update = "update f_topic set post_count = post_count + 1 where id = :id")
* })
* @Entity
* @Table(name = "f_topic")
* public class Topic {
* ...
* }</pre>
*
* <p>
* The following show code that would use a named update on the Topic entity
* bean.
* </p>
* <p>
* <pre>{@code
*
* Update<Topic> update = Ebean.createUpdate(Topic.class, "incrementPostCount");
* update.setParameter("id", 1);
* int rows = update.execute();
*
* }</pre>
*
* @param <T> the type of entity beans inserted updated or deleted
*/
public interface Update<T> {
/**
* Return the name if it is a named update.
*/
String getName();
/**
* Set this to false if you do not want the cache to invalidate related
* objects.
* <p>
* If you don't set this Ebean will automatically invalidate the appropriate
* parts of the "L2" server cache.
* </p>
*/
Update<T> setNotifyCache(boolean notifyCache);
/**
* Set a timeout for statement execution.
* <p>
* This will typically result in a call to setQueryTimeout() on a
* preparedStatement. If the timeout occurs an exception will be thrown - this
* will be a SQLException wrapped up in a PersistenceException.
* </p>
*
* @param secs the timeout in seconds. Zero implies unlimited.
*/
Update<T> setTimeout(int secs);
/**
* Execute the statement returning the number of rows modified.
*/
int execute();
/**
* Set an ordered bind parameter.
* <p>
* position starts at value 1 (not 0) to be consistent with PreparedStatement.
* </p>
* <p>
* Set a value for each ? you have in the sql.
* </p>
*
* @param position the index position of the parameter starting with 1.
* @param value the parameter value to bind.
*/
Update<T> set(int position, Object value);
/**
* Set and ordered bind parameter (same as bind).
*
* @param position the index position of the parameter starting with 1.
* @param value the parameter value to bind.
*/
Update<T> setParameter(int position, Object value);
/**
* Set an ordered parameter that is null. The JDBC type of the null must be
* specified.
* <p>
* position starts at value 1 (not 0) to be consistent with PreparedStatement.
* </p>
*/
Update<T> setNull(int position, int jdbcType);
/**
* Set an ordered parameter that is null (same as bind).
*/
Update<T> setNullParameter(int position, int jdbcType);
/**
* Set a named parameter. Named parameters have a colon to prefix the name.
* <p>
* A more succinct version of setParameter() to be consistent with Query.
* </p>
*
* @param name the parameter name.
* @param value the parameter value.
*/
Update<T> set(String name, Object value);
/**
* Bind a named parameter (same as bind).
*/
Update<T> setParameter(String name, Object param);
/**
* Set a named parameter that is null. The JDBC type of the null must be
* specified.
* <p>
* A more succinct version of setNullParameter().
* </p>
*
* @param name the parameter name.
* @param jdbcType the type of the property being bound.
*/
Update<T> setNull(String name, int jdbcType);
/**
* Bind a named parameter that is null (same as bind).
*/
Update<T> setNullParameter(String name, int jdbcType);
/**
* Set a label meaning performance metrics will be collected for the execution of this update.
*/
Update<T> setLabel(String label);
/**
* Return the sql that is actually executed.
*/
String getGeneratedSql();
}
-162
View File
@@ -1,162 +0,0 @@
package io.ebean;
/**
* An update query typically intended to perform a bulk update of many rows that match the query.
* <p>
* Also note that you can also just use a raw SQL update via {@link SqlUpdate} which is pretty light and simple.
* This UpdateQuery is more for the cases where we want to build the where expression of the update using the
* {@link ExpressionList} "Criteria API" that is used with a normal ORM query.
* </p>
* <p>
* <h4>Example: Simple update</h4>
* <p>
* <pre>{@code
*
* int rows = ebeanServer
* .update(Customer.class)
* .set("status", Customer.Status.ACTIVE)
* .set("updtime", new Timestamp(System.currentTimeMillis()))
* .where()
* .gt("id", 1000)
* .update();
*
* }</pre>
* <pre>{@code sql
*
* update o_customer set status=?, updtime=? where id > ?
*
* }</pre>
* <p>
* Note that if the where() clause contains a join then the SQL update changes to use a
* <code> WHERE ID IN () </code> form.
* </p>
* <p>
* <h4>Example: Update with a JOIN</h4>
* <p>
* In this example the expression <code>.eq("billingAddress.country", nz)</code> requires a join
* to the address table.
* </p>
* <p>
* <pre>{@code
*
* int rows = ebeanServer
* .update(Customer.class)
* .set("status", Customer.Status.ACTIVE)
* .set("updtime", new Timestamp(System.currentTimeMillis()))
* .where()
* .eq("status", Customer.Status.NEW)
* .eq("billingAddress.country", nz)
* .gt("id", 1000)
* .update();
* }</pre>
* <p>
* <pre>{@code sql
*
* update o_customer set status=?, updtime=?
* where id in (
* select t0.id c0
* from o_customer t0
* left join o_address t1 on t1.id = t0.billing_address_id
* where t0.status = ?
* and t1.country_code = ?
* and t0.id > ? )
*
* }</pre>
*
* @param <T> The type of entity bean being updated
* @see SqlUpdate
*/
public interface UpdateQuery<T> {
/**
* Set the value of a property.
* <p>
* <pre>{@code
*
* int rows = ebeanServer
* .update(Customer.class)
* .set("status", Customer.Status.ACTIVE)
* .set("updtime", new Timestamp(System.currentTimeMillis()))
* .where()
* .gt("id", 1000)
* .update();
*
* }</pre>
*
* @param property The bean property to be set
* @param value The value to set the property to
*/
UpdateQuery<T> set(String property, Object value);
/**
* Set the property to be null.
* <p>
* <pre>{@code
*
* int rows = ebeanServer
* .update(Customer.class)
* .setNull("notes")
* .where()
* .gt("id", 1000)
* .update();
*
* }</pre>
*
* @param property The property to be set to null.
*/
UpdateQuery<T> setNull(String property);
/**
* Set using a property expression that does not need any bind values.
* <p>
* The property expression typically contains database functions.
* </p>
* <p>
* <pre>{@code
*
* int rows = ebeanServer
* .update(Customer.class)
* .setRaw("status = coalesce(status, 'A')")
* .where()
* .gt("id", 1000)
* .update();
*
* }</pre>
*
* @param propertyExpression A property expression
*/
UpdateQuery<T> setRaw(String propertyExpression);
/**
* Set using a property expression that can contain <code>?</code> bind value placeholders.
* <p>
* For each <code>?</code> in the property expression there should be a matching bind value supplied.
* </p>
* <pre>{@code
*
* int rows = ebeanServer
* .update(Customer.class)
* .setRaw("status = coalesce(status, ?)", Customer.Status.ACTIVE)
* .where()
* .gt("id", 1000)
* .update();
*
* }</pre>
*
* @param propertyExpression A raw property expression
* @param values The values to bind with the property expression
*/
UpdateQuery<T> setRaw(String propertyExpression, Object... values);
/**
* Set the profile location of this update query. This is used to relate query execution metrics
* back to a location like a specific line of code.
*/
UpdateQuery<T> setProfileLocation(ProfileLocation profileLocation);
/**
* Return the query expression list to add predicates to.
*/
ExpressionList<T> where();
}
-58
View File
@@ -1,58 +0,0 @@
package io.ebean;
/**
* Holds two values as the result of a difference comparison.
*/
public class ValuePair {
protected Object newValue;
protected Object oldValue;
/**
* Default constructor for JSON tools.
*/
public ValuePair() {
}
/**
* Construct with the pair of new and old values.
*/
public ValuePair(Object newValue, Object oldValue) {
this.newValue = newValue;
this.oldValue = oldValue;
}
/**
* Return the new value.
*/
public Object getNewValue() {
return newValue;
}
/**
* Return the old value.
*/
public Object getOldValue() {
return oldValue;
}
/**
* Set the new value.
*/
public void setNewValue(Object newValue) {
this.newValue = newValue;
}
/**
* Set the old value.
*/
public void setOldValue(Object oldValue) {
this.oldValue = oldValue;
}
@Override
public String toString() {
return newValue + "," + oldValue;
}
}
-101
View File
@@ -1,101 +0,0 @@
package io.ebean;
import java.sql.Timestamp;
import java.util.Map;
/**
* Wraps a version of a @History bean.
*/
public class Version<T> {
/**
* The version of the bean.
*/
protected T bean;
/**
* The effective start date time of this version.
*/
protected Timestamp start;
/**
* The effective end date time of this version.
*/
protected Timestamp end;
/**
* The map of changed properties.
*/
protected Map<String, ValuePair> diff;
/**
* Construct with bean and an effective date time range.
*/
public Version(T bean, Timestamp start, Timestamp end) {
this.bean = bean;
this.start = start;
this.end = end;
}
/**
* Default constructor - useful for JSON tools such as Jackson.
*/
public Version() {
}
/**
* Return the bean instance for this version.
*/
public T getBean() {
return bean;
}
/**
* Set the bean instance for this version.
*/
public void setBean(T bean) {
this.bean = bean;
}
/**
* Return the effective start date time of this version.
*/
public Timestamp getStart() {
return start;
}
/**
* Set the effective start date time of this version.
*/
public void setStart(Timestamp start) {
this.start = start;
}
/**
* Return the effective end date time of this version.
*/
public Timestamp getEnd() {
return end;
}
/**
* Set the effective end date time of this version.
*/
public void setEnd(Timestamp end) {
this.end = end;
}
/**
* Set the map of differences from this bean to the prior version.
*/
public void setDiff(Map<String, ValuePair> diff) {
this.diff = diff;
}
/**
* Return the map of differences from this bean to the prior version.
*/
public Map<String, ValuePair> getDiff() {
return diff;
}
}
@@ -1,50 +0,0 @@
package io.ebean;
import io.ebean.service.SpiProfileLocationFactory;
import io.ebean.service.SpiRawSqlService;
import java.util.Iterator;
import java.util.ServiceLoader;
/**
* Lookup internal services.
*/
class XServiceProvider {
private static SpiRawSqlService rawSqlService = initRawSql();
private static SpiProfileLocationFactory profileLocationFactory = initProfileLocation();
private static SpiRawSqlService initRawSql() {
Iterator<SpiRawSqlService> loader = ServiceLoader.load(SpiRawSqlService.class).iterator();
if (loader.hasNext()) {
return loader.next();
}
throw new IllegalStateException("No service implementation found for SpiRawSqlService?");
}
private static SpiProfileLocationFactory initProfileLocation() {
Iterator<SpiProfileLocationFactory> loader = ServiceLoader.load(SpiProfileLocationFactory.class).iterator();
if (loader.hasNext()) {
return loader.next();
}
throw new IllegalStateException("No service implementation found for SpiProfileLocationFactory?");
}
/**
* Return the RawSqlService implementation.
*/
static SpiRawSqlService rawSql() {
return rawSqlService;
}
/**
* Return the RawSqlService implementation.
*/
static SpiProfileLocationFactory profileLocationFactory() {
return profileLocationFactory;
}
}
@@ -1,249 +0,0 @@
package io.ebean.bean;
import io.ebean.ExpressionList;
import java.io.Serializable;
import java.util.Collection;
import java.util.Set;
/**
* Lazy loading capable Maps, Lists and Sets.
* <p>
* This also includes the ability to listen for additions and removals to or
* from the Map Set or List. The purpose of gathering the additions and removals
* is to support persisting ManyToMany objects. The additions and removals
* become inserts and deletes from the intersection table.
* </p>
* <p>
* Technically this is <em>NOT</em> an extension of
* <em>java.util.Collection</em>. The reason being that java.util.Map is not a
* Collection. I realise this makes this name confusing so I apologise for that.
* </p>
*/
public interface BeanCollection<E> extends Serializable {
enum ModifyListenMode {
/**
* The common mode
*/
NONE,
/**
* Mode used for PrivateOwned
*/
REMOVALS,
/**
* Mode used for ManyToMany relationships
*/
ALL
}
/**
* Set the disableLazyLoad state.
*/
void setDisableLazyLoad(boolean disableLazyLoad);
/**
* Load bean from another collection.
*/
void loadFrom(BeanCollection<?> other);
/**
* Add a bean to the list/set with modifyListen notification.
*/
void addBean(E bean);
/**
* Remove a bean to the list/set with modifyListen notification.
*/
void removeBean(E bean);
/**
* Reset the collection back to an empty state ready for reloading.
* <p>
* This is done as part of bean refresh.
*/
void reset(EntityBean ownerBean, String propertyName);
/**
* Return true if the collection is uninitialised or is empty without any held modifications.
* <p>
* Returning true means can safely skip cascade save for this bean collection.
* </p>
*/
boolean isSkipSave();
/**
* Return true if the collection holds modifications.
*/
boolean holdsModifications();
/**
* Return the bean that owns this collection.
*/
EntityBean getOwnerBean();
/**
* Return the bean property name this collection represents.
*/
String getPropertyName();
/**
* Check after the lazy load that the underlying collection is not null
* (handle case where join to many not outer).
* <p>
* That is, if the collection was not loaded due to filterMany predicates etc
* then make sure the collection is set to empty.
* </p>
*/
boolean checkEmptyLazyLoad();
/**
* Return the filter (if any) that was used in building this collection.
* <p>
* This is so that the filter can be applied on refresh.
* </p>
*/
ExpressionList<?> getFilterMany();
/**
* Set the filter that was used in building this collection.
*/
void setFilterMany(ExpressionList<?> filterMany);
/**
* Return true if the collection has been registered with the batch loading context.
*/
boolean isRegisteredWithLoadContext();
/**
* Set the loader that will be used to lazy/query load this collection.
* <p>
* This is effectively the batch loading context this collection is registered with.
* </p>
*/
void setLoader(BeanCollectionLoader beanLoader);
/**
* Set to true if you want the BeanCollection to be treated as read only. This
* means no elements can be added or removed etc.
*/
void setReadOnly(boolean readOnly);
/**
* Return true if the collection should be treated as readOnly and no elements
* can be added or removed etc.
*/
boolean isReadOnly();
/**
* Add the bean to the collection.
* <p>
* This is disallowed for BeanMap.
* </p>
*/
void internalAdd(Object bean);
/**
* Add the bean with a check to see if it is already contained.
*/
void internalAddWithCheck(Object bean);
/**
* Return the number of elements in the List Set or Map.
*/
int size();
/**
* Return true if the List Set or Map is empty.
*/
boolean isEmpty();
/**
* Returns the underlying collection of beans from the Set, Map or List.
*/
Collection<E> getActualDetails();
/**
* Returns the underlying entries so for Maps this is a collection of
* Map.Entry.
* <p>
* For maps this returns the entrySet as we need the keys of the map.
* </p>
*/
Collection<?> getActualEntries();
/**
* return true if there are real rows held. Return false is this is using
* Deferred fetch to lazy load the rows and the rows have not yet been
* fetched.
*/
boolean isPopulated();
/**
* Return true if this is a reference (lazy loading) bean collection. This is
* the same as !isPopulated();
*/
boolean isReference();
/**
* Set modify listening on or off. This is used to keep track of objects that
* have been added to or removed from the list set or map.
* <p>
* This is required only for ManyToMany collections. The additions and
* deletions are used to insert or delete entries from the intersection table.
* Otherwise modifyListening is false.
* </p>
*/
void setModifyListening(ModifyListenMode modifyListenMode);
/**
* Return the current modify listening mode. Can be null for on newly created beans.
*/
ModifyListenMode getModifyListening();
/**
* Add an object to the additions list.
* <p>
* This will potentially end up as an insert into a intersection table for a
* ManyToMany.
* </p>
*/
void modifyAddition(E bean);
/**
* Add an object to the deletions list.
* <p>
* This will potentially end up as an delete from an intersection table for a
* ManyToMany.
* </p>
*/
void modifyRemoval(Object bean);
/**
* Return the list of objects added to the list set or map. These will used to
* insert rows into the intersection table of a ManyToMany.
*/
Set<E> getModifyAdditions();
/**
* Return the list of objects removed from the list set or map. These will
* used to delete rows from the intersection table of a ManyToMany.
*/
Set<E> getModifyRemovals();
/**
* Reset the set of additions and deletions. This is called after the
* additions and removals have been processed.
*/
void modifyReset();
/**
* Has been modified by an addition or removal.
*/
boolean wasTouched();
/**
* Return a shallow copy of this collection that is modifiable.
*/
BeanCollection<E> getShallowCopy();
}
@@ -1,16 +0,0 @@
package io.ebean.bean;
/**
* Interface to define the addition of a bean to the underlying collection.
* <p>
* For maps this takes into account the map key. For List and Set this simply
* adds the bean to the underlying list or set.
* </p>
*/
public interface BeanCollectionAdd {
/**
* Add a loaded bean to the collection.
*/
void addEntityBean(EntityBean bean);
}
@@ -1,21 +0,0 @@
package io.ebean.bean;
/**
* Loads a entity bean collection.
* <p>
* Typically invokes lazy loading for a single or batch of collections.
* </p>
*/
public interface BeanCollectionLoader {
/**
* Return the name of the associated EbeanServer.
*/
String getName();
/**
* Invoke the lazy loading for this bean collection.
*/
void loadMany(BeanCollection<?> collection, boolean onlyIds);
}
@@ -1,22 +0,0 @@
package io.ebean.bean;
/**
* Visitor for collecting new/old values for a bean update.
*/
public interface BeanDiffVisitor {
/**
* Collect a new/old value pair.
*/
void visit(int position, Object newVal, Object oldVal);
/**
* Start processing an associated bean.
*/
void visitPush(int position);
/**
* Stop processing an associated bean.
*/
void visitPop();
}
@@ -1,21 +0,0 @@
package io.ebean.bean;
/**
* Loads a entity bean.
* <p>
* Typically invokes lazy loading for a single or batch of entity beans.
* </p>
*/
public interface BeanLoader {
/**
* Return the name of the associated EbeanServer.
*/
String getName();
/**
* Invoke the lazy loading for this bean.
*/
void loadBean(EntityBeanIntercept ebi);
}
-135
View File
@@ -1,135 +0,0 @@
package io.ebean.bean;
import java.io.Serializable;
import java.util.Arrays;
/**
* Represent the call stack (stack trace elements).
* <p>
* Used with a query to identify a CallStackQuery for AutoTune automatic query
* tuning.
* </p>
* <p>
* This is used so that a single query called from different methods can be
* tuned for each different call stack.
* </p>
* <p>
* Note the call stack is trimmed to remove the common ebean internal elements.
* </p>
*/
public final class CallStack implements Serializable {
private static final long serialVersionUID = -8590644046907438579L;
private final String zeroHash;
private final String pathHash;
private final StackTraceElement[] callStack;
private final int hc;
public CallStack(StackTraceElement[] callStack, int zeroHash, int pathHash) {
this.callStack = callStack;
this.zeroHash = enc(zeroHash);
this.pathHash = enc(pathHash);
this.hc = computeHashCode();
}
private int computeHashCode() {
int hc = 0;
for (StackTraceElement aCallStack : callStack) {
hc = 92821 * hc + aCallStack.hashCode();
}
return hc;
}
@Override
public int hashCode() {
return hc;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof CallStack)) {
return false;
}
CallStack e = (CallStack) obj;
return Arrays.equals(callStack, e.callStack);
}
/**
* Return the first element of the call stack.
*/
public StackTraceElement getFirstStackTraceElement() {
return callStack[0];
}
/**
* Return the call stack.
*/
public StackTraceElement[] getCallStack() {
return callStack;
}
/**
* Return the hash for the first stack element.
*/
public String getZeroHash() {
return zeroHash;
}
/**
* Return the hash for the stack elements (excluding first stack element).
*/
public String getPathHash() {
return pathHash;
}
@Override
public String toString() {
return zeroHash + ":" + pathHash + ":" + callStack[0];
}
/**
* Return the call stack lines appended with the given newLine string.
*/
public String description(String newLine) {
StringBuilder sb = new StringBuilder(400);
for (StackTraceElement aCallStack : callStack) {
sb.append(aCallStack.toString()).append(newLine);
}
return sb.toString();
}
public String getOriginKey(int queryHash) {
return enc(queryHash) + "." + zeroHash + "." + pathHash;
}
private static final int radix = 1 << 6;
private static final int mask = radix - 1;
/**
* Convert the integer to unsigned base 64.
*/
public static String enc(int i) {
char[] buf = new char[32];
int charPos = 32;
do {
buf[--charPos] = intToBase64[i & mask];
i >>>= 6;
} while (i != 0);
return new String(buf, charPos, (32 - charPos));
}
private static final char intToBase64[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
};
}
@@ -1,8 +0,0 @@
package io.ebean.bean;
/**
* Marker interface for classes enhanced to support Transactional methods.
*/
public interface EnhancedTransactional {
}
@@ -1,99 +0,0 @@
package io.ebean.bean;
import java.io.Serializable;
/**
* Bean that is aware of EntityBeanIntercept.
* <p>
* This interface and implementation of these methods is added to Entity Beans
* via instrumentation. These methods have a funny _ebean_ prefix to avoid any
* clash with normal methods these beans would have. These methods are not for
* general application consumption.
* </p>
*/
public interface EntityBean extends Serializable {
/**
* Return all the property names in defined order.
*/
String[] _ebean_getPropertyNames();
/**
* Return the property name at the given position.
*/
String _ebean_getPropertyName(int pos);
/**
* Return the enhancement marker value.
* <p>
* This is the class name of the enhanced class and used to check that all
* entity classes are enhanced (specifically not just a super class).
* </p>
*/
String _ebean_getMarker();
/**
* Create and return a new entity bean instance.
*/
Object _ebean_newInstance();
/**
* Generated method that sets the loaded state on all the embedded beans on
* this entity bean by using EntityBeanIntercept.setEmbeddedLoaded(Object o);
*/
void _ebean_setEmbeddedLoaded();
/**
* Return true if any embedded beans are new or dirty.
*/
boolean _ebean_isEmbeddedNewOrDirty();
/**
* Return the intercept for this object.
*/
EntityBeanIntercept _ebean_getIntercept();
/**
* Similar to _ebean_getIntercept() except it checks to see if the intercept
* field is null and will create it if required.
* <p>
* This is really only required when transientInternalFields=true as an
* enhancement option. In this case the intercept field is transient and will
* be null after a bean has been deserialised.
* </p>
* <p>
* This transientInternalFields=true option was to support some serialization
* frameworks that can't take into account our ebean fields.
* </p>
*/
EntityBeanIntercept _ebean_intercept();
/**
* Set the value of a field of an entity bean of this type.
* <p>
* Note that using this method bypasses any interception that otherwise occurs
* on entity beans. That means lazy loading and oldValues creation.
* </p>
*/
void _ebean_setField(int fieldIndex, Object value);
/**
* Set the field value with interception.
*/
void _ebean_setFieldIntercept(int fieldIndex, Object value);
/**
* Return the value of a field from an entity bean of this type.
* <p>
* Note that using this method bypasses any interception that otherwise occurs
* on entity beans. That means lazy loading.
* </p>
*/
Object _ebean_getField(int fieldIndex);
/**
* Return the field value with interception.
*/
Object _ebean_getFieldIntercept(int fieldIndex);
}
File diff suppressed because it is too large Load Diff
@@ -1,127 +0,0 @@
package io.ebean.bean;
import java.lang.ref.WeakReference;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* Collects profile information for a bean (or reference/proxy bean) at a given node.
* <p>
* The node identifies the location of the bean in the object graph.
* </p>
* <p>
* It has to use a weak reference so as to ensure that it does not stop the
* associated bean from being garbage collected.
* </p>
*/
public final class NodeUsageCollector {
/**
* The point in the object graph for a specific query and call stack point.
*/
private final ObjectGraphNode node;
/**
* Weak to allow garbage collection.
*/
private final WeakReference<NodeUsageListener> managerRef;
/**
* The properties used at this profile point.
*/
private final Set<String> used = new LinkedHashSet<>();
/**
* set to true if the bean is modified (setter called)
*/
private boolean modified;
/**
* The property that cause a reference to lazy load.
*/
private String loadProperty;
public NodeUsageCollector(ObjectGraphNode node, WeakReference<NodeUsageListener> managerRef) {
this.node = node;
// weak to allow garbage collection.
this.managerRef = managerRef;
}
/**
* The bean has been modified by a setter method.
*/
public void setModified() {
modified = true;
}
/**
* Add the name of a property that has been used.
*/
public void addUsed(String property) {
used.add(property);
}
/**
* The property that invoked a lazy load.
*/
public void setLoadProperty(String loadProperty) {
this.loadProperty = loadProperty;
}
/**
* Publish the usage info to the manager.
*/
private void publishUsageInfo() {
NodeUsageListener manager = managerRef.get();
if (manager != null) {
manager.collectNodeUsage(this);
}
}
/**
* publish the collected usage information when garbage collection occurs.
*/
@Override
protected void finalize() throws Throwable {
publishUsageInfo();
super.finalize();
}
/**
* Return the associated node which identifies the location in the object
* graph of the bean/reference.
*/
public ObjectGraphNode getNode() {
return node;
}
/**
* Return true if no properties where used.
*/
public boolean isEmpty() {
return used.isEmpty();
}
/**
* Return the set of used properties.
*/
public Set<String> getUsed() {
return used;
}
/**
* Return true if the bean was modified by a setter.
*/
public boolean isModified() {
return modified;
}
public String getLoadProperty() {
return loadProperty;
}
@Override
public String toString() {
return node + " read:" + used + " modified:" + modified;
}
}
@@ -1,16 +0,0 @@
package io.ebean.bean;
/**
* Collects the profile information.
*/
public interface NodeUsageListener {
/**
* Collect node usage "profiling" information.
* <p>
* This is the properties that are used for a given bean in the object graph.
* This information is used by autoTune to tune queries.
* </p>
*/
void collectNodeUsage(NodeUsageCollector collector);
}
@@ -1,92 +0,0 @@
package io.ebean.bean;
import java.io.Serializable;
/**
* Identifies a unique node of an object graph.
* <p>
* It represents a location relative to the root of an object graph and specific
* to a query and call stack hash.
* </p>
*/
public final class ObjectGraphNode implements Serializable {
private static final long serialVersionUID = 2087081778650228996L;
/**
* Identifies the origin.
*/
private final ObjectGraphOrigin originQueryPoint;
/**
* The path relative to the root.
*/
private final String path;
/**
* Create at a sub level.
*/
public ObjectGraphNode(ObjectGraphNode parent, String path) {
this.originQueryPoint = parent.getOriginQueryPoint();
this.path = parent.getChildPath(path);
}
/**
* Create an the root level.
*/
public ObjectGraphNode(ObjectGraphOrigin originQueryPoint, String path) {
this.originQueryPoint = originQueryPoint;
this.path = path;
}
/**
* Return the origin query point.
*/
public ObjectGraphOrigin getOriginQueryPoint() {
return originQueryPoint;
}
private String getChildPath(String childPath) {
if (path == null) {
return childPath;
} else if (childPath == null) {
return path;
} else {
return path + "." + childPath;
}
}
/**
* Return the path relative to the root.
*/
public String getPath() {
return path;
}
@Override
public String toString() {
return "origin:" + originQueryPoint + " path[" + path + "]";
}
@Override
public int hashCode() {
int hc = 92821 * originQueryPoint.hashCode();
hc = 92821 * hc + (path == null ? 0 : path.hashCode());
return hc;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof ObjectGraphNode)) {
return false;
}
ObjectGraphNode e = (ObjectGraphNode) obj;
//noinspection StringEquality
return ((e.path == path) || (e.path != null && e.path.equals(path)))
&& e.originQueryPoint.equals(originQueryPoint);
}
}
@@ -1,87 +0,0 @@
package io.ebean.bean;
import java.io.Serializable;
/**
* Represents a "origin" of an ORM object graph. This combines the call stack
* and query plan hash.
* <p>
* The call stack is included so that the query can have different tuned fetches
* for each unique call stack. For example, a query to fetch a customer could be
* called by three different methods and each can be treated as a separate
* origin point (and autoTune can tune each one separately).
* </p>
*/
public final class ObjectGraphOrigin implements Serializable {
private static final long serialVersionUID = 410937765287968708L;
private final CallStack callStack;
private final String beanType;
private final int queryHash;
private final String key;
public ObjectGraphOrigin(int queryHash, CallStack callStack, String beanType) {
this.callStack = callStack;
this.beanType = beanType;
this.queryHash = queryHash;
this.key = callStack.getOriginKey(queryHash);
}
/**
* The key includes the queryPlan hash and the callStack hash. This becomes
* the unique identifier for a query point.
*/
public String getKey() {
return key;
}
/**
* The type of bean the query is fetching.
*/
public String getBeanType() {
return beanType;
}
/**
* The call stack involved.
*/
public CallStack getCallStack() {
return callStack;
}
public String getFirstStackElement() {
return callStack.getFirstStackTraceElement().toString();
}
@Override
public String toString() {
return "key[" + key + "] type[" + beanType + "] " + callStack.getFirstStackTraceElement() + " ";
}
@Override
public int hashCode() {
int hc = 92821 * callStack.hashCode();
hc = 92821 * hc + beanType.hashCode();
hc = 92821 * hc + queryHash;
return hc;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof ObjectGraphOrigin)) {
return false;
}
ObjectGraphOrigin e = (ObjectGraphOrigin) obj;
return e.queryHash == queryHash
&& e.beanType.equals(beanType)
&& e.callStack.equals(callStack);
}
}
@@ -1,110 +0,0 @@
package io.ebean.bean;
/**
* Holds entity beans by there type and id.
* <p>
* This is used to ensure only one instance for a given entity type and id is
* used to build object graphs from queries and lazy loading.
* </p>
*/
public interface PersistenceContext {
/**
* Put the entity bean into the PersistenceContext.
*/
void put(Class<?> rootType, Object id, Object bean);
/**
* Put the entity bean into the PersistenceContext if one is not already
* present (for this id).
* <p>
* Returns an existing entity bean (if one is already there) and otherwise
* returns null.
* </p>
*/
Object putIfAbsent(Class<?> rootType, Object id, Object bean);
/**
* Return an object given its type and unique id.
*/
Object get(Class<?> rootType, Object uid);
/**
* Get the bean from the persistence context also checked to see if it had
* been previously deleted (if so then you also can't hit the L2 cache to
* fetch the bean for this particular persistence context).
*/
WithOption getWithOption(Class<?> rootType, Object uid);
/**
* Clear all the references.
*/
void clear();
/**
* Clear all the references for a given type of entity bean.
*/
void clear(Class<?> rootType);
/**
* Clear the reference to a specific entity bean.
*/
void clear(Class<?> rootType, Object uid);
/**
* Clear the reference as a result of an entity being deleted.
*/
void deleted(Class<?> rootType, Object id);
/**
* Return the number of beans of the given type in the persistence context.
*/
int size(Class<?> rootType);
/**
* Wrapper on a bean to also indicate if a bean has been deleted.
* <p>
* If a bean has been deleted then for the same persistence context is should
* not be able to be fetched from persistence context or L2 cache.
* </p>
*/
class WithOption {
/**
* The bean was previously deleted from this persistence context (can't hit
* L2 cache).
*/
public static final WithOption DELETED = new WithOption();
private final boolean deleted;
private final Object bean;
private WithOption() {
this.deleted = true;
this.bean = null;
}
/**
* The bean exists in the persistence context (and not been previously deleted).
*/
public WithOption(Object bean) {
this.deleted = false;
this.bean = bean;
}
/**
* Return true if the bean was deleted. This means you can't hit the L2
* cache.
*/
public boolean isDeleted() {
return deleted;
}
/**
* Return the bean (from the persistence context).
*/
public Object getBean() {
return bean;
}
}
}
@@ -1,15 +0,0 @@
package io.ebean.bean;
/**
* A callback that can be registered to fire on getter method calls.
* It's primary purpose is to automatically flush JDBC batch buffer.
*/
public interface PreGetterCallback {
/**
* Trigger the callback based on a getter on a property.
*
* @param propertyIndex The index of the property
*/
void preGetterTrigger(int propertyIndex);
}
-11
View File
@@ -1,11 +0,0 @@
<HTML>
<HEAD>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
<TITLE>Enhanced beans API and Support objects</TITLE>
</HEAD>
<Body BGCOLOR="#ffffff">
Enhanced beans API and Support objects
</Body>
</HTML>
-82
View File
@@ -1,82 +0,0 @@
package io.ebean.cache;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
/**
* Represents part of the "L2" server side cache.
* <p>
* This is used to cache beans or query results (bean collections).
* </p>
* <p>
* There are 2 ServerCache's for each bean type. One is used as the 'bean cache'
* which holds beans of a given type. The other is the 'query cache' holding
* query results for a given type.
* </p>
*/
public interface ServerCache {
default Map<Object, Object> getAll(Set<Object> keys) {
Map<Object, Object> map = new LinkedHashMap<>();
for (Object key : keys) {
Object value = get(key);
if (value != null) {
map.put(key, value);
}
}
return map;
}
/**
* Return the value given the key.
*/
Object get(Object id);
/**
* Put all the values in the cache.
*/
default void putAll(Map<Object, Object> keyValues) {
keyValues.forEach(this::put);
}
/**
* Put the value in the cache with a given id.
*/
void put(Object id, Object value);
/**
* Remove the entries from the cache given the id values.
*/
default void removeAll(Set<Object> keys) {
keys.forEach(this::remove);
}
/**
* Remove a entry from the cache given its id.
*/
void remove(Object id);
/**
* Clear all entries from the cache.
*/
void clear();
/**
* Return the number of entries in the cache.
*/
int size();
/**
* Return the hit ratio the cache is currently getting.
*/
int getHitRatio();
/**
* Return statistics for the cache.
*
* @param reset if true the statistics are reset.
*/
ServerCacheStatistics getStatistics(boolean reset);
}
-15
View File
@@ -1,15 +0,0 @@
package io.ebean.cache;
import io.ebean.config.CurrentTenantProvider;
/**
* Defines method for constructing caches for beans and queries.
*/
public interface ServerCacheFactory {
/**
* Create the cache for the given type with options.
*/
ServerCache createCache(ServerCacheType type, String cacheKey, CurrentTenantProvider tenantProvider, ServerCacheOptions cacheOptions);
}
-62
View File
@@ -1,62 +0,0 @@
package io.ebean.cache;
/**
* The cache service for server side caching of beans and query results.
*/
public interface ServerCacheManager {
/**
* Return true if the L2 caching is local.
* <p>
* Local L2 caching means that the cache updates should occur in foreground
* rather than background processing.
* </p>
*/
boolean isLocalL2Caching();
/**
* Return the cache for mapping natural keys to id values.
*/
ServerCache getNaturalKeyCache(Class<?> beanType);
/**
* Return the cache for beans of a particular type.
*/
ServerCache getBeanCache(Class<?> beanType);
/**
* Return the cache for associated many properties of a bean type.
*/
ServerCache getCollectionIdsCache(Class<?> beanType, String propertyName);
/**
* Return the cache for query results of a particular type of bean.
*/
ServerCache getQueryCache(Class<?> beanType);
/**
* This clears both the bean and query cache for a given type.
*/
void clear(Class<?> beanType);
/**
* Clear all the caches.
*/
void clearAll();
/**
* Clear all the local caches.
*
* This is used when the L2 Cache is based on clustered near-caches (Like Ebean-K8s-L2Cache).
* It is not used when the L2 cache is a distributed cache such as HazelCast or Ignite etc.
*/
void clearAllLocal();
/**
* Clear the local caches for this bean type.
*
* This is used when the L2 Cache is based on clustered near-caches (Like Ebean-K8s-L2Cache).
* It is not used when the L2 cache is a distributed cache such as HazelCast or Ignite etc.
*/
void clearLocal(Class<?> beanType);
}
-131
View File
@@ -1,131 +0,0 @@
package io.ebean.cache;
import io.ebean.annotation.CacheBeanTuning;
import io.ebean.annotation.CacheQueryTuning;
/**
* Options for controlling a cache.
*/
public class ServerCacheOptions {
private int maxSize;
private int maxIdleSecs;
private int maxSecsToLive;
private int trimFrequency;
/**
* Construct with no set options.
*/
public ServerCacheOptions() {
}
/**
* Create from the cacheTuning deployment annotation.
*/
public ServerCacheOptions(CacheBeanTuning tuning) {
this.maxSize = tuning.maxSize();
this.maxIdleSecs = tuning.maxIdleSecs();
this.maxSecsToLive = tuning.maxSecsToLive();
this.trimFrequency = tuning.trimFrequency();
}
/**
* Create from the cacheTuning deployment annotation.
*/
public ServerCacheOptions(CacheQueryTuning cacheTuning) {
this.maxSize = cacheTuning.maxSize();
this.maxIdleSecs = cacheTuning.maxIdleSecs();
this.maxSecsToLive = cacheTuning.maxSecsToLive();
this.trimFrequency = cacheTuning.trimFrequency();
}
/**
* Apply any settings from the default settings that have not already been
* specifically set.
*/
public ServerCacheOptions applyDefaults(ServerCacheOptions defaults) {
if (maxSize == 0) {
maxSize = defaults.getMaxSize();
}
if (maxIdleSecs == 0) {
maxIdleSecs = defaults.getMaxIdleSecs();
}
if (maxSecsToLive == 0) {
maxSecsToLive = defaults.getMaxSecsToLive();
}
if (trimFrequency == 0) {
trimFrequency = defaults.getTrimFrequency();
}
return this;
}
/**
* Return a copy of this object.
*/
public ServerCacheOptions copy() {
ServerCacheOptions copy = new ServerCacheOptions();
copy.maxSize = maxSize;
copy.maxIdleSecs = maxIdleSecs;
copy.maxSecsToLive = maxSecsToLive;
copy.trimFrequency = trimFrequency;
return copy;
}
/**
* Return the maximum cache size.
*/
public int getMaxSize() {
return maxSize;
}
/**
* Set the maximum cache size.
*/
public void setMaxSize(int maxSize) {
this.maxSize = maxSize;
}
/**
* Return the maximum idle time.
*/
public int getMaxIdleSecs() {
return maxIdleSecs;
}
/**
* Set the maximum idle time.
*/
public void setMaxIdleSecs(int maxIdleSecs) {
this.maxIdleSecs = maxIdleSecs;
}
/**
* Return the maximum time to live.
*/
public int getMaxSecsToLive() {
return maxSecsToLive;
}
/**
* Set the maximum time to live.
*/
public void setMaxSecsToLive(int maxSecsToLive) {
this.maxSecsToLive = maxSecsToLive;
}
/**
* Return the trim frequency in seconds.
*/
public int getTrimFrequency() {
return trimFrequency;
}
/**
* Set the trim frequency in seconds.
*/
public void setTrimFrequency(int trimFrequency) {
this.trimFrequency = trimFrequency;
}
}
-15
View File
@@ -1,15 +0,0 @@
package io.ebean.cache;
import io.ebean.BackgroundExecutor;
import io.ebean.config.ServerConfig;
/**
* The plugin interface that creates a ServerCacheFactory.
*/
public interface ServerCachePlugin {
/**
* Create the ServerCacheFactory given the server config and background executor service.
*/
ServerCacheFactory create(ServerConfig config, BackgroundExecutor executor);
}
-278
View File
@@ -1,278 +0,0 @@
package io.ebean.cache;
/**
* The statistics collected per cache.
* <p>
* These can be monitored to review the effectiveness of a particular cache.
* </p>
* <p>
* Depending on the cache implementation not all the statistics may be collected.
* </p>
*/
public class ServerCacheStatistics {
protected String cacheName;
protected int maxSize;
protected int size;
protected long hitCount;
protected long missCount;
protected long insertCount;
protected long updateCount;
protected long removeCount;
protected long clearCount;
protected long evictionRunCount;
protected long evictionRunMicros;
protected long evictByIdle;
protected long evictByTTL;
protected long evictByLRU;
@Override
public String toString() {
//noinspection StringBufferReplaceableByString
StringBuilder sb = new StringBuilder(80);
sb.append(cacheName);
sb.append(" maxSize:").append(maxSize);
sb.append(" size:").append(size);
sb.append(" hitRatio:").append(getHitRatio());
sb.append(" hit:").append(hitCount);
sb.append(" miss:").append(missCount);
sb.append(" insert:").append(insertCount);
sb.append(" update:").append(updateCount);
sb.append(" remove:").append(removeCount);
sb.append(" clear:").append(clearCount);
sb.append(" evictByIdle:").append(evictByIdle);
sb.append(" evictByTTL:").append(evictByTTL);
sb.append(" evictByLRU:").append(evictByLRU);
sb.append(" evictionRunCount:").append(evictionRunCount);
sb.append(" evictionRunMicros:").append(evictionRunMicros);
return sb.toString();
}
/**
* Returns an int from 0 to 100 (percentage) for the hit ratio.
* <p>
* A hit ratio of 100 means every get request against the cache hits an entry.
* </p>
*/
public int getHitRatio() {
long totalCount = hitCount + missCount;
if (totalCount == 0) {
return 0;
} else {
return (int) (hitCount * 100 / totalCount);
}
}
/**
* Return the name of the cache.
*/
public String getCacheName() {
return cacheName;
}
/**
* Set the name of the cache.
*/
public void setCacheName(String cacheName) {
this.cacheName = cacheName;
}
/**
* Return the hit count. The number of successful gets.
*/
public long getHitCount() {
return hitCount;
}
/**
* Set the hit count.
*/
public void setHitCount(long hitCount) {
this.hitCount = hitCount;
}
/**
* Return the miss count. The number of gets that returned null.
*/
public long getMissCount() {
return missCount;
}
/**
* Set the miss count.
*/
public void setMissCount(long missCount) {
this.missCount = missCount;
}
/**
* Return the size of the cache.
*/
public int getSize() {
return size;
}
/**
* Set the size of the cache.
*/
public void setSize(int size) {
this.size = size;
}
/**
* Return the maximum size of the cache.
* <p>
* Can be used in conjunction with the size to determine if the cache use is
* being potentially limited by its maximum size.
* </p>
*/
public int getMaxSize() {
return maxSize;
}
/**
* Set the maximum size of the cache.
*/
public void setMaxSize(int maxSize) {
this.maxSize = maxSize;
}
/**
* Set the put insert count.
*/
public void setInsertCount(long insertCount) {
this.insertCount = insertCount;
}
/**
* Return the put insert count.
*/
public long getInsertCount() {
return insertCount;
}
/**
* Set the put update count.
*/
public void setUpdateCount(long updateCount) {
this.updateCount = updateCount;
}
/**
* Return the put update count.
*/
public long getUpdateCount() {
return updateCount;
}
/**
* Set the remove count.
*/
public void setRemoveCount(long removeCount) {
this.removeCount = removeCount;
}
/**
* Return the remove count.
*/
public long getRemoveCount() {
return removeCount;
}
/**
* Set the clear count.
*/
public void setClearCount(long clearCount) {
this.clearCount = clearCount;
}
/**
* Return the clear count.
*/
public long getClearCount() {
return clearCount;
}
/**
* Set the eviction run count.
*/
public void setEvictionRunCount(long evictCount) {
this.evictionRunCount = evictCount;
}
/**
* Return the eviction run count.
*/
public long getEvictionRunCount() {
return evictionRunCount;
}
/**
* Set the eviction run time in micros.
*/
public void setEvictionRunMicros(long evictionRunMicros) {
this.evictionRunMicros = evictionRunMicros;
}
/**
* Return the eviction run time in micros.
*/
public long getEvictionRunMicros() {
return evictionRunMicros;
}
/**
* Set the count of entries evicted due to idle time.
*/
public void setEvictByIdle(long evictByIdle) {
this.evictByIdle = evictByIdle;
}
/**
* Return the count of entries evicted due to idle time.
*/
public long getEvictByIdle() {
return evictByIdle;
}
/**
* Set the count of entries evicted due to time to live.
*/
public void setEvictByTTL(long evictByTTL) {
this.evictByTTL = evictByTTL;
}
/**
* Return the count of entries evicted due to time to live.
*/
public long getEvictByTTL() {
return evictByTTL;
}
/**
* Set the count of entries evicted due to time least recently used.
*/
public void setEvictByLRU(long evictByLRU) {
this.evictByLRU = evictByLRU;
}
/**
* Return the count of entries evicted due to time least recently used.
*/
public long getEvictByLRU() {
return evictByLRU;
}
}
-37
View File
@@ -1,37 +0,0 @@
package io.ebean.cache;
/**
* The type of L2 caches.
*/
public enum ServerCacheType {
/**
* Bean cache.
*/
BEAN("_B"),
/**
* Natural key cache.
*/
NATURAL_KEY("_N"),
/**
* Collection Ids for Many properties.
*/
COLLECTION_IDS("_C"),
/**
* Query cache.
*/
QUERY("_Q");
private String code;
ServerCacheType(String code) {
this.code = code;
}
public String code(){
return code;
}
}
-77
View File
@@ -1,77 +0,0 @@
package io.ebean.cache;
import io.ebean.config.CurrentTenantProvider;
import java.io.Serializable;
import java.util.Objects;
/**
* Tenant aware handling for caching.
*/
public class TenantAwareKey {
private final CurrentTenantProvider tenantProvider;
/**
* Construct with a tenant provider than can be null.
*/
public TenantAwareKey(CurrentTenantProvider tenantProvider) {
this.tenantProvider = tenantProvider;
}
/**
* Return a tenant aware key.
*/
public Object key(Object key) {
if (tenantProvider != null) {
return new CacheKey(key, tenantProvider.currentId());
} else {
return key;
}
}
/**
* We use a combined key, if this serverCache is per tenant.
*/
public static final class CacheKey implements Serializable {
private static final long serialVersionUID = 1L;
final Object key;
final Object tenantId;
/**
* Create with optional tenantId.
*/
public CacheKey(Object key, Object tenantId) {
this.key = key;
this.tenantId = tenantId;
}
@Override
public int hashCode() {
int result = key.hashCode();
result = 92821 * result + Objects.hashCode(tenantId);
return result;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof CacheKey) {
CacheKey that = (CacheKey) obj;
return Objects.equals(that.key, this.key)
&& Objects.equals(that.tenantId, this.tenantId);
}
return false;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(key.toString());
if (tenantId != null) {
sb.append(":").append(tenantId);
}
return sb.toString();
}
}
}

Some files were not shown because too many files have changed in this diff Show More