Compare commits

...
Author SHA1 Message Date
Rob Bygrave aa004f11af [maven-release-plugin] prepare release ebean-11.15.2 2018-03-29 01:49:28 +13:00
Rob Bygrave acd5578d8a #115 - Mapping - Add support for @ElementCollection enhancement
Add element collection L2 cache support
2018-03-29 01:15:58 +13:00
Rob Bygrave 07946cd505 #115 - Mapping - Add support for @ElementCollection enhancement
Add element collection notification - combine into preUpdate/postUpdate of the bean
2018-03-28 17:31:53 +13:00
Rob Bygrave 57870aaa05 #115 - Mapping - Add support for @ElementCollection enhancement
Add embedded bean support
2018-03-28 13:22:46 +13:00
Rob Bygrave cca837bcfa #1354 - ENH: Add SqlUpdate setNextParameter() ... as alternative for positioned parameters 2018-03-28 00:45:12 +13:00
Rob Bygrave 534eb2f0e2 #1354 - ENH: Add SqlUpdate setNextParameter() ... as alternative for positioned parameters 2018-03-27 23:24:30 +13:00
Rob Bygrave dfa7b765f9 #1354 - ENH: Add SqlUpdate setNextParameter() ... as alternative for positioned parameters 2018-03-27 22:58:19 +13:00
Rob Bygrave 4ef581f87c No effective change - Update agent in pom to 11.11.1 2018-03-27 17:16:35 +13:00
Rob Bygrave eb96c726fd No effective change - Modify some tests to use transaction try with resources 2018-03-27 10:47:24 +13:00
Rob Bygrave abbcd35ee6 #1353 - Use of ebeanServer.commitTransaction() in nested transaction doesn't match transction.commit() and closes parent scope 2018-03-27 09:14:45 +13:00
Rob Bygrave db5a2b194d No effective change - add extra test coverage on DefaultTransactionThreadLocal 2018-03-26 23:31:31 +13:00
Rob Bygrave 74e0a16531 #1351 - ENH: Add named DtoQuery
Merge branch 'feature/namedDtoQuery' of https://github.com/hexagonframework/ebean into hexagonframework-feature/namedDtoQuery
2018-03-26 20:45:39 +13:00
Rob Bygrave 8601f51a6c #1351 - ENH: Add named DtoQuery
Merge branch 'feature/namedDtoQuery' of https://github.com/hexagonframework/ebean into hexagonframework-feature/namedDtoQuery
2018-03-26 20:45:22 +13:00
Rob Bygrave 6534feb5da #1350 - ENH: Add mappingsLocation config to search xml mapping files.
Minor adjustments - read "mappingLocations" only etc.
2018-03-26 16:55:25 +13:00
Yuan XueguiandRob Bygrave 6cf5e3386d ENH: Add mappingsLocation config to search xml mapping files. (#1350)
ENH: Add mappingsLocation config and search xml mapping files feature.
2018-03-26 16:37:25 +13:00
Rob Bygrave 7651256083 #1352 - Bump default datasource - with better defaults for Idle connection cleanup (5 mins) 2018-03-26 15:47:20 +13:00
Rob Bygrave 057d7480b0 #115 - Mapping - Add support for @ElementCollection enhancement
Add simple Map support with Json
2018-03-21 00:15:40 +13:00
Rob Bygrave 85c4385498 #115 - Mapping - Add support for @ElementCollection enhancement
Initial support - add simple Set support and Json support for simple List and Set.
2018-03-20 17:24:35 +13:00
Rob Bygrave 74a9019535 #115 - Mapping - Add support for @ElementCollection enhancement
Initial support - simple List.
2018-03-20 14:22:29 +13:00
Rob Bygrave c44931ea25 #115 - Supporting changes for Element collection support 2018-03-20 09:04:58 +13:00
Rob Bygrave 012322503f #115 - Supporting changes for Element collection support 2018-03-20 09:03:16 +13:00
yuanxuegui 5575273c96 ENH: Add named DtoQuery, such that we can define native SQL queries in ebean mapping xml for DtoQuery. 2018-03-19 18:04:49 +08:00
Rob Bygrave f3251691e2 Test only change - Add test for SavePoint and compare to transaction.setRollbackOnly() 2018-03-19 09:18:00 +13:00
yuanxuegui 9d336cb20b ENH: Add mappingsLocation config to search xml mapping files.
ENH: Add mappingsLocation config to search xml mapping files.

ENH: Add mappingsLocation config to search xml mapping files.

ENH: Add mappingsLocation config to search xml mapping files.

ENH: Add mappingsLocation config to search xml mapping files.

ENH: Add mappingsLocation config to search xml mapping files.

remove unused import.

ENH: Add mappingsLocation config and search xml mapping files feature.
2018-03-17 17:27:51 +08:00
Rob Bygrave 9895e48485 #1349 - Example passing test for - RawSql fetch object with inheritance / 2 2018-03-15 22:47:37 +13:00
Rob Bygrave 4799c56e25 #225 - Mapping - Add / review support for @IdClass 2018-03-15 18:19:17 +13:00
Rob Bygrave 602a35d0b6 #1348 - ENH: Add support for bitwiseAnd / bitwiseAny / bitwiseAll .. expressions for use with integer/long "Flags" properties 2018-03-14 16:23:16 +13:00
Rob Bygrave 4bc1f2ede4 [maven-release-plugin] prepare for next development iteration 2018-03-14 00:03:11 +13:00
Rob Bygrave 674617eb9e [maven-release-plugin] prepare release ebean-11.15.1 2018-03-14 00:02:58 +13:00
Rob Bygrave afead2da41 #1221 - ENH: Add a merge(bean) and merge(bean, paths) 2018-03-13 23:55:47 +13:00
Rob Bygrave 607cf3156c #1347 - Improve cleanup of inactive transactions from threadLocal when no end() used 2018-03-13 00:15:42 +13:00
Rob Bygrave af2b8976fa #1346 - Since ebean version 11.12.1 executing docStore query with findPagedList fails with error (due to order by id) 2018-03-12 18:28:17 +13:00
Rob Bygrave 85bfe3d03e #1345 - Refactor io.ebean.meta.MetaInfoManager API (query execution metrics). Breaking change for people collecting query execution metrics. 2018-03-10 02:51:51 +13:00
Rob Bygrave eda6350d89 #1344 - ENH: Add initial Cockroach DB support ... need to review JSON
Adds in the DB ARRAY support (exactly the same as Postgres)
2018-03-09 17:40:34 +13:00
Rob Bygrave 8ac1b745df #1344 - ENH: Add initial Cockroach DB support ... need to review JSON and DB ARRAY support 2018-03-09 16:54:38 +13:00
Rob Bygrave 6c8cf0c5b7 #1343 - Update for ... #1283 ENH: Support simplified test configuration (with docker setup typically via application-test.yml)
DefaultContainer with config.loadFromProperties(PropertiesLoader.load()); effectively runs eval twice on properties which is unnecessary.

Additionally add ServerConfig.setRunMigration() because I think it makes more sense / easier to find.

Remote PropertiesLoader.setProperty() as it is no longer required for the ebean-test-config plugin.
2018-03-09 10:34:25 +13:00
Rob Bygrave d0b24dc340 #1343 - Update the #1283 ENH: Support simplified test configuration (with docker setup typically via application-test.yml) 2018-03-09 00:44:04 +13:00
Rob Bygrave 2042bdf29a #1342 - Refactor and rename DbTypeConfig to Platform config to support multi-platform db migration 2018-03-08 23:23:50 +13:00
Rob Bygrave 4f327c2751 No effective change - default h2 platform for testing 2018-03-08 20:47:48 +13:00
Rob Bygrave fbc2ba3912 No effective change - Test update DDL review files 2018-03-08 20:47:28 +13:00
Rob Bygrave 93d659050b No effective change - Test on rename of DDL review files 2018-03-08 20:44:15 +13:00
Rob Bygrave 2520837f5e No effective change - Test on rename of DDL review files for oracle 2018-03-08 20:42:36 +13:00
Rob Bygrave 2f349ff054 #1318 No effective change - DDL review for ... ENH: native UUID-support for SqlServer
Shows the use of uniqueidentifier DB column type for UUID with sql server.
2018-03-08 19:37:30 +13:00
Rob Bygrave 0aec597cf2 #1318 No effective change - DDL review for ... ENH: native UUID-support for SqlServer 2018-03-08 19:35:48 +13:00
Rob Bygrave 5faec61cd2 #1318 - ENH: native UUID-support for SqlServer
Merge branch 'native-uuid-sqlserver' of https://github.com/FOCONIS/ebean into FOCONIS-native-uuid-sqlserver

# Conflicts:
#	src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasePlatform.java
2018-03-08 19:34:36 +13:00
Rob Bygrave 7252e2d7d9 #1318 - ENH: native UUID-support for SqlServer
Merge branch 'native-uuid-sqlserver' of https://github.com/FOCONIS/ebean into FOCONIS-native-uuid-sqlserver

# Conflicts:
#	src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasePlatform.java
2018-03-08 19:34:09 +13:00
Rob Bygrave 0cc87009d0 #1340 - (test only change) Split SQL Server Platform into SqlServer16 and SqlServer17 (where 2017 which uses UTF8 types nvarchar etc and prefers Sequences).
Update DbMigrationGenerateTest ... for SqlServer17 platform
2018-03-08 18:37:36 +13:00
Rob Bygrave ef58954af5 Test only changes - related to #1336 - Change DDL generation such that it does create index before alter table add foreign key 2018-03-08 18:31:12 +13:00
Rob Bygrave 824f5e468e #1340 - (test only change) Split SQL Server Platform into SqlServer16 and SqlServer17 (where 2017 which uses UTF8 types nvarchar etc and prefers Sequences).
Reset Offline platform in DbMigrationSqlServerTest
2018-03-08 18:18:13 +13:00
Rob Bygrave d84cdab714 #1340 - Split SQL Server Platform into SqlServer16 and SqlServer17 (where 2017 which uses UTF8 types nvarchar etc and prefers Sequences).
Only need to run H2 based test TestAutoCommitDataSource with H2
2018-03-08 17:45:19 +13:00
Rob Bygrave 5a3550e603 #1340 - Split SQL Server Platform into SqlServer16 and SqlServer17 (where 2017 which uses UTF8 types nvarchar etc and prefers Sequences).
Unrelated - update dbmigration ddl for create index / add fk change in order (db2)
2018-03-08 17:43:25 +13:00
Rob Bygrave f840cfc2ae #1340 - Split SQL Server Platform into SqlServer16 and SqlServer17 (where 2017 which uses UTF8 types nvarchar etc and prefers Sequences).
test changes
2018-03-08 17:40:11 +13:00
Rob Bygrave 8e0d2f8749 #1340 - Split SQL Server Platform into SqlServer16 and SqlServer17 (where 2017 which uses UTF8 types nvarchar etc and prefers Sequences).
test - dbmigration ddl
2018-03-08 17:39:10 +13:00
Rob Bygrave eef514f922 #1340 - Split SQL Server Platform into SqlServer16 and SqlServer17 (where 2017 which uses UTF8 types nvarchar etc and prefers Sequences).
Changes to pom
2018-03-08 17:37:29 +13:00
Rob Bygrave 4fc7898f85 #1340 - Split SQL Server Platform into SqlServer16 and SqlServer17 (where 2017 which uses UTF8 types nvarchar etc and prefers Sequences).
Changes to main
2018-03-08 17:36:53 +13:00
Rob Bygrave 6258a5d263 Logging only change - Drop the logging from WARN to DEBUG for beans without an Id property (which is not usual but valid for Ebean) 2018-03-08 14:36:18 +13:00
Rob Bygrave dbf5f3b57b [maven-release-plugin] prepare for next development iteration 2018-03-08 14:16:45 +13:00
Rob Bygrave 4b594fb533 [maven-release-plugin] prepare release ebean-11.14.3 2018-03-08 14:16:30 +13:00
Rob Bygrave c0efd49c73 #1341 - Cascade persist with JDBC batch and BeanPersistAdapter with preUpdate() that invokes lazy loading on persisted bean ... results in OptimisticLockException 2018-03-08 14:12:32 +13:00
Rob Bygrave 54ba1480eb [maven-release-plugin] prepare for next development iteration 2018-03-07 20:22:38 +13:00
Rob Bygrave 4d8bc0a2ce [maven-release-plugin] prepare release ebean-11.14.2 2018-03-07 20:22:25 +13:00
Rob Bygrave e182190f96 #1339 - Regression: Fix for not throwing OptimisticLockException when loaded bean has @Version property set 2018-03-07 20:19:48 +13:00
Rob Bygrave 8711ebc6f7 Merge branch 'fix-limit-constraint-names' of https://github.com/FOCONIS/ebean into FOCONIS-fix-limit-constraint-names 2018-03-07 17:13:56 +13:00
Rob Bygrave baa7242939 #1338 - Regression since 11.12.1 - resolve expressions in Properties given to serverConfig.loadFromProperties() 2018-03-07 16:43:42 +13:00
Rob Bygrave 47e8d27212 #1337 - Fix YamlLoader ... such that it loads multi-part yml source 2018-03-07 16:21:00 +13:00
Rob Bygrave 70aed3906e [maven-release-plugin] prepare for next development iteration 2018-03-07 02:24:21 +13:00
Rob Bygrave 70c3860a65 [maven-release-plugin] prepare release ebean-11.14.1 2018-03-07 02:24:07 +13:00
Rob Bygrave 1ba21d5c43 Bump to 11.14.1-SNAPSHOT ... Modified DDL generation order of create index vs alter table add FK 2018-03-07 02:22:58 +13:00
Rob Bygrave 2019bc7bf1 #1336 - Change DDL generation such that it does create index before alter table add foreign key 2018-03-07 02:19:10 +13:00
Rob Bygrave 3cb52917e3 #1335 - Add Try catch to YAML loading ... add system property ebeanSkipYaml ... to enable skipping the read of application.yml (well, all yml) 2018-03-07 02:03:54 +13:00
Rob Bygrave 55a257a64c #1334 - ENH: Convert ORM query into DTO query ... with dynamic formula support 2018-03-07 01:52:18 +13:00
Rob Bygrave 83ef204f3c Merge branch 'master' of github.com:ebean-orm/ebean 2018-03-06 21:15:07 +13:00
Rob Bygrave a18cac035b #1333 - ENH: Support "dynamic formula" with findSingleAttributeList() ... e.g. .select("concat(lastName,', ',firstName)")
Support property alias via "AS" ...  concat(lastName,', ',firstName) as lastName
2018-03-06 21:14:26 +13:00
Rob Bygrave 873c14faaf #1333 - ENH: Support "dynamic formula" with findSingleAttributeList() ... e.g. .select("concat(lastName,', ',firstName)")
Support cast of formula like ... select("max(updtime)::Instant")
2018-03-06 20:58:30 +13:00
Rob Bygrave e1af7c29eb #1333 - ENH: Support "dynamic formula" with findSingleAttributeList() ... e.g. .select("concat(lastName,', ',firstName)")
Concat automatically maps to String ScalarType
2018-03-06 17:35:26 +13:00
Rob Bygrave c1c85b67c2 #1333 - ENH: Support "dynamic formula" with findSingleAttributeList() ... e.g. .select("concat(lastName,', ',firstName)") 2018-03-06 17:29:45 +13:00
Rob Bygrave 05b8adbf6e No effective change - change test from extends testcase to normal junit 2018-03-06 16:37:47 +13:00
Rob Bygrave 3ca4efc818 #1331 - ENH: Support Aggregation formula with findSingleAttribute() ... max, min, avg, count and count(distinct ..) 2018-03-06 12:58:43 +13:00
Rob Bygrave ec2c3b13d4 No effective change - add test for deploy parser 2018-03-06 01:08:42 +13:00
Rob Bygrave 5a3e386b7c No effective change - add test for selecting only some @Aggregation properties 2018-03-05 19:59:40 +13:00
Roland PramlandRob Bygrave 7e56a147be FIX: ReadOnlyDatasource must also be configured (#1323) 2018-03-05 19:29:40 +13:00
Rob Bygrave 62cdfb3209 #1330 - Update ANTLR dependency to 4.7.1 2018-03-05 19:22:38 +13:00
Rob Bygrave 740532da4b #1329 - Ebean 11.12.1 broken when using ScalarTypeConverter with enum 2018-03-05 19:19:27 +13:00
Rob Bygrave 130356cb3b [maven-release-plugin] prepare for next development iteration 2018-03-02 23:39:17 +13:00
Rob Bygrave ab84cfae52 [maven-release-plugin] prepare release ebean-11.13.1 2018-03-02 23:39:03 +13:00
Rob Bygrave ad21b7a3fd Merge branch 'master' of github.com:ebean-orm/ebean 2018-03-02 23:37:55 +13:00
Rob Bygrave 31581082d2 Bump to 11.13.1-SNAPSHOT ... added findDto() 2018-03-02 23:37:38 +13:00
Roland PramlandRob Bygrave aa84dfe7d8 Add: Configuration md that describes the ebean options (#1325) 2018-03-02 23:33:10 +13:00
Rob Bygrave aad5b33db2 #1297 - ENH: Add DtoQuery ... such that we can map native SQL queries automatically into "DTO beans" 2018-03-02 23:32:01 +13:00
Roland PramlandRob Bygrave 5801f7620d FIX: add columnDefaultValue to more places (#1327) 2018-03-02 16:39:53 +13:00
Roland PramlandRob Bygrave 514416a1e0 Testcase Fix for SqlServer (#1326)
Test change only - Testcase Fix for SqlServer
2018-03-02 16:38:59 +13:00
Roland PramlandRob Bygrave 8faa95adc1 ENH: new method AnnotationUtil.findMetaAnnotationsRecursive (#1319)
* ENH: new method AnnotationUtil.findMetaAnnotationsRecursive

* clarified in javadoc
2018-03-02 16:28:41 +13:00
Rob Bygrave ebaeafc11b #1303 - NEW: Ebean.checkUniqueness ... add example to javadoc 2018-03-02 16:25:13 +13:00
Roland Praml 20e46cad9b Merge remote-tracking branch 'ebean/master' into native-uuid-sqlserver 2018-03-02 03:18:20 +01:00
Rob Bygrave 98e014f8c8 #1300 - NEW: FetchCountDistinct ... add example to javadoc + support chaining use via ExpressionList 2018-03-02 14:30:38 +13:00
Rob Bygrave 78912d75e0 #1306 - No effective change - javadoc update 2018-03-02 13:45:31 +13:00
Rob Bygrave 09786a7062 #1301 - No effective change - format lines 2018-03-02 13:30:40 +13:00
Rob Bygrave 54530248a5 #1312 - ENH: added SqlRow factory method to RawSqlService
Support the PR added binaryOptimizedUUID
2018-03-02 13:25:55 +13:00
Roland Praml 9953ef35eb ENH: native UUID-support for SqlServer 2018-03-02 01:14:42 +01:00
Roland Praml fdafa776e1 Merge remote-tracking branch 'ebean/master' into fix-limit-constraint-names
# Conflicts:
#	src/test/resources/dbmigration/migrationtest/db2/1.0__initial.sql
#	src/test/resources/dbmigration/migrationtest/db2/1.1.sql
#	src/test/resources/dbmigration/migrationtest/db2/1.3.sql
2018-03-02 01:03:36 +01:00
Roland Praml 392eb2744d ADD: comment 2018-03-02 00:17:23 +01:00
Roland PramlandRob Bygrave b642b3c644 FIX: Splitcolumns must return an empty array if string was empty (#1315)
* Add test suite from rpraml

* FIX: Splitcolumns must return an empty array if string was empty

* Just the reference scripts
2018-03-02 12:16:29 +13:00
Roland PramlandRob Bygrave 0e1c815826 FIX: DataReader was read twice in exception-path (#1314) 2018-03-02 12:15:01 +13:00
Roland PramlandRob Bygrave 83b463040f ENH: Add sanity check to InExpression (#1313) 2018-03-02 12:14:09 +13:00
Roland PramlandRob Bygrave aea7d937eb ENH: added SqlRow factory method to RawSqlService (#1312)
* ENH: added SqlRow factory method to RawSqlService

* compile fixes

* ADD: sqlRow factory also to RawSqlBuilder
2018-03-02 12:13:16 +13:00
Roland PramlandRob Bygrave 78628ffad0 NEW: DB-with-Master option (#1311) 2018-03-02 12:12:34 +13:00
Roland PramlandRob Bygrave 56a742ad70 NEW: UUID version 1 generator (#1309)
* NEW: Uuid Type 1 generator

* Remove parameter (from other PR)

* FIX: Mac detection

* Have to use nodeId in generation
2018-03-02 12:09:21 +13:00
Roland Praml a4415b03ff FIX: limit the constraint names 2018-03-02 00:08:52 +01:00
Roland PramlandRob Bygrave e252f71792 ENH: Optimized binary form for UUID (Type 1) (#1308)
* ENH: Optimized binary form for UUID (Type 1)

* added missing parameter in test
2018-03-02 12:04:56 +13:00
Roland PramlandRob Bygrave 18ca3403ac NEW: flag to control, if javax.validation NotNull annotation should generate a NotNull column or not (#1306) 2018-03-02 12:02:02 +13:00
Roland PramlandRob Bygrave 94a118d635 FIX: do not set username and password for DbMigrationConfig (#1304) 2018-03-02 11:59:01 +13:00
Roland PramlandRob Bygrave efe325034b NEW: Ebean.checkUniqueness - you can check a bean, if save would work (#1303) 2018-03-02 11:57:44 +13:00
Roland PramlandRob Bygrave 0c368ed7b3 FIX: extra-ddl can contribute to "drop-all" script, otherwise the drop all script is not appyable to h2:file (#1301) 2018-03-02 11:48:35 +13:00
Roland PramlandRob Bygrave c1b022c123 NEW: FetchCountDistinct - query can return distinct values with their counts (#1300)
* NEW: FetchCountDistinct - query can return distinct values with their counts

* Have to disable asserts, because of #1298
2018-03-02 11:46:41 +13:00
Roland PramlandRob Bygrave 021d57f4b2 FIX: @Formula on @ManyToOne produces SQLException ... fix appends missing FROM clause for formula joins #1299 2018-03-02 11:43:08 +13:00
Roland PramlandRob Bygrave 11e180aa3f FIX: introduced TransactionalTestCase, so that changes to DB are not persisted (#1298)
* FIX: introduced TransactionalTestCase, so that changes to DB are not persisted

* removed license header
2018-03-02 09:10:21 +13:00
Rob Bygrave 9e2ddc9f8c [maven-release-plugin] prepare for next development iteration 2018-03-01 13:43:27 +13:00
Rob Bygrave d4e72eefa0 [maven-release-plugin] prepare release ebean-11.12.1 2018-03-01 13:43:14 +13:00
Rob Bygrave 525afbc00f #1296 - where().exampleLike(bean) ... with 'empty bean' produces invalid SQL 2018-03-01 13:38:09 +13:00
Rob Bygrave 6f2e1c0248 #1295 - Multiple platform DbMigration generation with non-native boolean type (BIT, INTEGER etc) produces incorrect DDL for other DB Platform with native boolean 2018-03-01 12:55:22 +13:00
Rob Bygrave 0d0a3422fc #1283 - ENH: Support simplified test configuration (with docker setup typically via application-test.yml)
Refactor tidy - no effective change on this commit.
2018-02-28 21:11:49 +13:00
Rob Bygrave 57b0190cd2 #1283 - ENH: Support simplified test configuration (with docker setup typically via application-test.yml) 2018-02-27 18:28:03 +13:00
Rob Bygrave c8e199177c #1294 - NPE when delete cascade from bean with SoftDelete to imported OneToOne without SoftDelete 2018-02-27 15:31:26 +13:00
Rob Bygrave 68a470a086 Test change only - No effective change, remove noop ServerConfig.loadTestProperties() 2018-02-27 15:00:13 +13:00
Rob Bygrave 45a023f0e4 #1282 - Not supported for @DbArray mapping when using kotlin var instead of val 2018-02-27 14:25:44 +13:00
Rob Bygrave 06bce35f5a #1293 - Refactor - move JdbcClose into io.ebean.util ... from io.ebeaninternal.util as it is used in public API (platform code, sequences etc) 2018-02-27 12:56:20 +13:00
Roland PramlandRob Bygrave 3dfdd0e2e8 #1292 - Fix for non-native / number boolean types (MySql, SqlServer, Oracle, Sqlite, SqlAnywhere) removing "default 0" + Fix for DB2 add foreign key update clause 2018-02-27 11:58:10 +13:00
Rob Bygrave a569c7fc96 #1275 - Additional refactor of DefaultOrmQuery.prepareForPaging() for - Add ServerConfig.setDefaultOrderById() ...
Remove use of SpiOrmQueryRequest<T> request
2018-02-27 11:35:10 +13:00
Rob Bygrave e751f991cb #1275 - Additional refactor for - Add ServerConfig.setDefaultOrderById() ...
Removes the cast on DefaultOrmQuery.prepare()
2018-02-27 11:31:30 +13:00
Roland PramlandRob Bygrave 83cf768369 Append preconfigured database to dbMigration (#1291) 2018-02-27 11:09:44 +13:00
Roland PramlandRob Bygrave bb418456e3 Misc fixes (#1290) 2018-02-27 11:06:35 +13:00
Roland PramlandRob Bygrave ac9f3408b2 FIX: reset cache statistics (fixes test cases in eclipse when run in different order) (#1289) 2018-02-27 11:03:27 +13:00
Roland PramlandRob Bygrave 78f8d48e2e FIX: more timing issues - mysql does not support resolution in millis (#1288) 2018-02-27 11:00:58 +13:00
Roland PramlandRob Bygrave 3f8b9529e1 Fix clock sync (#1287)
Test only change - Fix clock sync timing issues with tests using -DdbClockDelta
2018-02-27 10:59:19 +13:00
Roland PramlandRob Bygrave 10f3d85d9f No effective code change - add serialize/serialversionuid (#1286) 2018-02-27 10:57:07 +13:00
Roland PramlandRob Bygrave 0e3f47ee82 No effective code change: Fixwarnings, overrides, generics etc. (#1285) 2018-02-27 10:15:19 +13:00
Roland PramlandRob Bygrave cdbbd749a3 FIX: h2Merge test - which may fail due timing issues (#1284)
Test only change - FIX: h2Merge test - which may fail due timing issues
2018-02-27 10:11:10 +13:00
Roland PramlandRob Bygrave a712be2917 auomatically append "order by id" when paging and query.orderById = true (#1275)
Add ServerConfig.setDefaultOrderById() and query.orderById(boolean) ... to control automatically append "order by id" with paging query
2018-02-27 10:09:52 +13:00
Rob Bygrave 0cba0664f8 #1281 - Test change only - default back from sql server to h2 2018-02-26 15:06:17 +13:00
Rob Bygrave a3e5c3a786 #1281 - Test change only - Update DbMigrationTest for SQL Server using SEQUENCE based Identity 2018-02-26 15:04:57 +13:00
Rob Bygrave 58def02cd1 #1280 - Update test for - Remove "order by" clause of RawSql query when executing findCount()
The code fix associated with this is in CQueryBuilder line 276
2018-02-26 14:41:56 +13:00
Rob Bygrave cec65cc888 #1279 - Change ObjectFactory method to match, tidy format (no real change here) 2018-02-26 14:32:38 +13:00
Roland PramlandRob Bygrave da7bb834e7 DbMigration supports altering UniqueConstraints and foreign keys (#1279)
* NEW: Ebean reads version from pop.properties and prints it at start up

* DDL generation and migration can append a header and platformMigration is prepared to append epilog & prolog to scripts

* FIX: Set identity only, if it is not the platform default type

* Updated reference scripts

* ADD basic support for foreign key migration

* DbMigration detects alter foreign keys

* tests
2018-02-26 14:24:52 +13:00
Rob Bygrave a64a244745 Bump pom to 11.12.1-SNAPSHOT (Event listener change #1063, Yaml properties change #1246) 2018-02-26 13:26:26 +13:00
Rob Bygrave 1c19d4cf7e #1278 - Multi-tenant delete by id ... doesn't return 0 when no rows deleted
Where -1 (jdbc batch) is returned as true as per current behaviour
2018-02-26 13:20:49 +13:00
Rob Bygrave 347225efb2 #1278 - Multi-tenant delete by id ... doesn't return 0 when no rows deleted 2018-02-26 13:16:20 +13:00
Roland PramlandRob Bygrave 91cb5a23fd Fix dbmigration (#1277)
ENH: Support adding a '-- Generated by' comment to DDL including version and timestamp
2018-02-26 12:37:54 +13:00
Rob Bygrave 0e219a9bc6 Revert #1263 - ENH: Make Transaction API Fluid such that we can set multiple thing like batchSize and label in a fluid fashion #1276 2018-02-26 11:45:49 +13:00
Rob Bygrave 21182da793 Fix test LoaderTest 2018-02-26 09:18:45 +13:00
Roland PramlandRob Bygrave 0de084caec removed escapeLikeCharacter method, as it is covered by parent implementation (#1274) 2018-02-26 08:42:18 +13:00
Roland PramlandRob Bygrave e3425a8850 FIX: possible resource leaking in testcases (all created transactions are closed by followed try statement) (#1273) 2018-02-26 08:40:53 +13:00
Rob Bygrave 8e9843ab8a #1246 - Support use of application.yml and application-test.yml ... (as alternative to ebean.properties, test-ebean.properties) 2018-02-26 08:35:47 +13:00
Rob Bygrave 75462e7410 #1272 - ENH: Add built in support for Joda Period and java time Period 2018-02-23 17:54:02 +13:00
Rob Bygrave 265bda8cf2 #1272 - ENH: Add built in support for Joda Period 2018-02-23 17:41:01 +13:00
Rob Bygrave 7d0ed261b5 #1271 - ENH: Add BeanFinder and BeanRepository ... such that there is a read to go base class for DI repository style 2018-02-23 16:55:07 +13:00
Rob Bygrave ff111eaf33 #1063 - Add Event Listeners capable of being notified for delete by id
Adds BeanDeleteIdRequest and adds a method to BeanPersistController and BeanPersistAdapter
2018-02-23 14:34:08 +13:00
Rob Bygrave 8b18e907af #1063 - Add Event Listeners capable of being notified for delete by query or update by query
Adds QueryType and adds method query.getQueryType() which then can be used in a BeanQueryAdapter
2018-02-23 14:04:36 +13:00
Rob Bygrave 40704e2ef7 No Effective change - change test to use assertJ 2018-02-23 13:37:43 +13:00
Rob Bygrave 0e62d0579e [maven-release-plugin] prepare for next development iteration 2018-02-23 12:50:59 +13:00
Rob Bygrave 47d55a2f29 [maven-release-plugin] prepare release ebean-11.11.1 2018-02-23 12:50:45 +13:00
Rob Bygrave b037be5d3e No Effective change - bump agent in pom (with query bean enhancement of interface default methods) 2018-02-23 12:48:06 +13:00
Rob Bygrave 60a3c24cba No Effective change - Tidy pom removing commented out old sqlserver jdbc driver 2018-02-23 10:31:22 +13:00
Rob Bygrave 4a243a76a7 #1270 - Multi-tenant - partition mode - Delete by id does not include tenantId value in predicate 2018-02-23 10:26:47 +13:00
Rob Bygrave 9aee7c892d Test only - copy/add multi-tenant partition tests 2018-02-23 10:14:27 +13:00
Rob Bygrave 18d944f228 Test only - copy/add multi-tenant partition tests 2018-02-23 10:13:57 +13:00
Rob Bygrave 29bb9d3b48 #1268 - SQL Server fix for "for update" plus Sequences support plus refactor of sequences 2018-02-22 22:46:17 +13:00
Rob Bygrave f8ea5619d0 #1268 - SQL Server fix for "for update" plus Sequences support plus refactor of sequences 2018-02-22 22:45:44 +13:00
Rob Bygrave e3fac7c622 #1269 - Paging queries should not ALWAYS append an order by ID ... but only when the order by is empty 2018-02-22 22:43:14 +13:00
Rob Bygrave 8ee68ac5e1 #1269 - Paging queries should not ALWAYS append an order by ID ... but only when the order by is empty 2018-02-22 22:40:22 +13:00
Rob Bygrave ec7b376612 Test only change - fix test assert for sql server 2018-02-22 22:12:30 +13:00
Rob Bygrave f2d438f21a Test only change - fix test assert for sql server 2018-02-22 22:11:56 +13:00
Rob Bygrave 20bd2241e4 Test only change - fix test assert to support sequence and identity insert 2018-02-22 22:11:36 +13:00
Rob Bygrave dd907cc4bc Test only change - fix keys for testing against Oracle 2018-02-22 22:10:59 +13:00
Rob Bygrave 4d122ea05b #1267 - DDL issue on @OneToMany @JoinTable ... extra unnecessary index created on fk column 2018-02-22 22:09:53 +13:00
Rob Bygrave 83384c6f0e #323 - DDL Generation support for foreign key cascade options
Tidy up, no GLOBAL_DEFAULT.
2018-02-21 11:04:04 +13:00
Rob Bygrave eaa48468cd #1174 - ENH: Support mapping @TenantId to an entity bean via @ManyToOne 2018-02-21 09:44:37 +13:00
Rob Bygrave 0b1c3a4233 Bump version to 11.11.1-SNAPSHOT 2018-02-21 09:44:07 +13:00
Rob Bygrave 3e8b06e38e #994 - @OneToOne cacade does not honor orphanRemoval = true 2018-02-20 16:59:55 +13:00
Rob Bygrave 81d48d67a7 #123 - Mapping - Add support for OneToMany JoinTables 2018-02-20 14:40:21 +13:00
Rob Bygrave 8d0df6541e Merge branch 'issue/1263-transaction-api' 2018-02-19 22:47:42 +13:00
Rob Bygrave 2be3099d55 #1228 - Add support to not generate FK Constraint when @JoinColumn(foreignKey=@ForeignKey(ConstraintMode.NO_CONSTRAINT)) 2018-02-19 22:45:47 +13:00
Rob Bygrave 183d079b58 #323 - DDL Generation support for foreign key cascade options 2018-02-19 22:24:51 +13:00
Rob Bygrave 40634412f5 #323 - DDL Generation support for foreign key cascade options 2018-02-19 22:24:37 +13:00
Roland PramlandRob Bygrave b8aa822a30 [utf8mb4-support] limited the size of all indexed string columns, as max key length on mysql/mariadb is 767 bytes (which are <= 191 chars on utf8mb4) (#1264) 2018-02-19 16:15:28 +13:00
Rob Bygrave a1d0fbb194 [maven-release-plugin] prepare for next development iteration 2018-02-16 14:45:29 +13:00
Rob Bygrave 70ccc6588d [maven-release-plugin] prepare release ebean-11.10.6 2018-02-16 14:45:16 +13:00
Rob Bygrave 3d62e84d59 #1263 - ENH: Make Transaction API Fluid such that we can set multiple thing like batchSize and label in a fluid fashion 2018-02-16 14:40:35 +13:00
Rob Bygrave ac36172cc6 #997 - TypeReflectHelper does not resolve type variables correctly in non-trivial cases
Part 2 - Fix the failing test, swap in use of TypeResolver and remove all the unused features.
2018-02-16 12:47:10 +13:00
Rob Bygrave 1829c74694 #997 - TypeReflectHelper does not resolve type variables correctly in non-trivial cases
Initial failing test ... and TypeResolver prior to cleanup
2018-02-16 12:25:07 +13:00
Rob Bygrave cc7e22014d #997 - TypeReflectHelper does not resolve type variables correctly in non-trivial cases
Initial failing test ... and TypeResolver prior to cleanup
2018-02-16 12:24:57 +13:00
Rob Bygrave a5c6f483b0 #1258 - ENH: Add ServerConfig notifyL2CacheInForeground option ... was ServerCachePlugin BackgroundExecutor problem 2018-02-16 11:18:17 +13:00
Rob Bygrave 5237e8ba66 #1261 - ENH: Support use of getGeneratedKeys with SqlUpdate 2018-02-16 09:45:49 +13:00
Rob Bygrave 9926cad7f1 #1262 - ENH: Support firstRow maxRows with findNative() 2018-02-16 00:11:27 +13:00
Rob Bygrave 6c1b295d41 [maven-release-plugin] prepare for next development iteration 2018-02-15 22:32:56 +13:00
Rob Bygrave 49b568e7d4 [maven-release-plugin] prepare release ebean-11.10.5 2018-02-15 22:32:43 +13:00
Rob Bygrave 628af31ddd #1142 - Mapping - Add support for @OrderColumn (Ebean automatically maintains an order column) 2018-02-15 22:31:41 +13:00
Rob Bygrave 31cac60393 #107 - Mapping - Add support for @PrimaryKeyJoinColumn/@PrimaryKeyJoinColumns
Adds Bi-directional support
2018-02-15 00:49:51 +13:00
Rob Bygrave 6a067c0cf7 #107 - Mapping - Add support for @PrimaryKeyJoinColumn/@PrimaryKeyJoinColumns
Extra test with UUID and optional OneToOne so has left join
2018-02-14 23:09:10 +13:00
Rob Bygrave 842292ef6b #107 - Mapping - Add support for @PrimaryKeyJoinColumn/@PrimaryKeyJoinColumns 2018-02-14 22:59:57 +13:00
Rob Bygrave 6db9a60f4f #107 - Fix existing test - Ah ??? ... this PrimaryKeyJoinColumn was ignored and should never have been in this test. 2018-02-14 17:24:14 +13:00
Rob Bygrave d9125db957 [maven-release-plugin] prepare for next development iteration 2018-02-14 15:29:26 +13:00
Rob Bygrave 4bd9e67703 [maven-release-plugin] prepare release ebean-11.10.4 2018-02-14 15:29:12 +13:00
Rob Bygrave 2a986ab590 #1260 - Mark query.setForUpdate(true) as deprecated - migrate to query.forUpdate() 2018-02-14 15:28:13 +13:00
Rob Bygrave 7c477827fe #1259 - Throw explicit mapping error when an Enum is mapped to both ORDINAL and STRING 2018-02-14 12:39:35 +13:00
Rob Bygrave b2967dec1e #1257 - ServerConfig with register = true, defaultServer = false ... fails as it tries to create the default server 2018-02-13 16:22:52 +13:00
Rob Bygrave a95fd063ae #1256 - Query where many isNotEmpty() ... on ManyToMany with SoftDelete produces incorrect SQL (Part 2) 2018-02-13 14:52:18 +13:00
Rob Bygrave 17a54e3804 No effective change - extra tests for DeployPropertyParser 2018-02-13 14:09:08 +13:00
Rob Bygrave f1b2a09b30 Testing - modify .travis to run mysql as service (bump MySql version to 5.7) 2018-02-10 01:16:40 +13:00
Rob Bygrave e4d9e4f2de Testing - modify .travis to run mysql as service (bump MySql version to 5.7) 2018-02-10 01:04:19 +13:00
Rob Bygrave 6474f306b5 #1255 - Regression on raw LIKE expression with slashes on Postgres
Related update for Sqlite
2018-02-10 00:57:19 +13:00
Rob Bygrave f1c2f134ad #1255 - Regression on raw LIKE expression with slashes on Postgres
Related update for Sqlite
2018-02-10 00:56:05 +13:00
Rob Bygrave 0f7158ea18 Testing - modify .travis to run mysql as service 2018-02-10 00:34:34 +13:00
Rob Bygrave 3fdb76d18f Testing - modify .travis to run mysql as service 2018-02-10 00:31:39 +13:00
Rob Bygrave b1027a2f25 Testing - modify .travis to run mysql as docker container 2018-02-10 00:18:33 +13:00
Rob Bygrave e5a1f9f7cc Testing - modify .travis adding docker service 2018-02-10 00:07:27 +13:00
Rob Bygrave f78f24136a [maven-release-plugin] prepare for next development iteration 2018-02-09 23:42:42 +13:00
Rob Bygrave 5b2aa0c74d [maven-release-plugin] prepare release ebean-11.10.3 2018-02-09 23:42:28 +13:00
Rob Bygrave 175714046a #1254 - SpringJdbcTransactionManager inifinite recursion #1254
Yeah, nah. This is the real fix. Expose:

   SpiTransaction TransctionManager.getInScope();

... and have ebean-spring-txn SpringJdbcTransactionManager call it instead of getActive().
2018-02-09 23:03:07 +13:00
Rob Bygrave 73b2cc55f3 #1254 - SpringJdbcTransactionManager inifinite recursion #1254
Fix. Note tested in ebean-spring-txn.
2018-02-09 22:22:08 +13:00
Rob Bygrave cebe375856 No effective change - initial docker testing setup for oracle and sqlserver 2018-02-09 21:31:40 +13:00
Rob Bygrave 2f47235018 #1255 - Regression on raw LIKE expression with slashes on Postgres 2018-02-09 21:28:39 +13:00
Rob Bygrave 17abd6d977 #1255 - Regression on raw LIKE expression with slashes on Postgres
Tests
2018-02-09 21:25:36 +13:00
Rob Bygrave cc5f3689f3 No effective change - modify tests for SqlServer 2018-02-09 21:10:18 +13:00
Rob Bygrave abcc651e7f #1253 - Query where many isNotEmpty() ... on ManyToMany with SoftDelete produces incorrect SQL
Fix
2018-02-09 15:00:58 +13:00
Rob Bygrave caa36262c1 #1253 - Query where many isNotEmpty() ... on ManyToMany with SoftDelete produces incorrect SQL
Failing test
2018-02-09 15:00:29 +13:00
Rob Bygrave 66b6dba921 [maven-release-plugin] prepare for next development iteration 2018-02-07 16:54:44 +13:00
Rob Bygrave fc01f230f3 [maven-release-plugin] prepare release ebean-11.10.2 2018-02-07 16:54:31 +13:00
Rob Bygrave 7fe3e657d7 No effective change - put default test db back to default to h2 2018-02-07 16:49:49 +13:00
Rob Bygrave 9bade12c9d #1251 - Delete cascade with 11+ and Postgres throws exception
Fix
2018-02-07 16:47:59 +13:00
Rob Bygrave 7a816ae2da #1251 - Delete cascade with 11+ and Postgres throws exception
Failing test
2018-02-07 16:40:12 +13:00
Rob Bygrave b83412281e #1251 - Delete cascade with 11+ and Postgres throws exception
Failing test
2018-02-07 16:39:58 +13:00
Rob Bygrave 478bba292d #1250 - Add explicit coverage for Enum with abstract method - no new issue 2018-02-07 14:01:11 +13:00
Rob Bygrave 77a4e684bb [maven-release-plugin] prepare for next development iteration 2018-02-02 23:39:51 +13:00
Rob Bygrave a8254c4295 [maven-release-plugin] prepare release ebean-11.10.1 2018-02-02 23:39:38 +13:00
Rob Bygrave 2a5d0084ef #1249 - Bump db-migration to 11.3.1 ... with fix for not running empty sql statements (empty strings) 2018-02-02 23:38:11 +13:00
Rob Bygrave f9404639d7 Fix test for H2 select for update - my bad. 2018-02-02 23:36:12 +13:00
Rob Bygrave bbef5a6bbb #1243 - Add IDENTITY support for Oracle platform (since 12c Oracle supports auto generated identity) 2018-02-02 23:18:23 +13:00
Rob Bygrave 4645fd9725 Cleanup tests for Oracle 2018-02-02 23:17:21 +13:00
Rob Bygrave 823cb45221 Cleanup tests for Oracle 2018-02-02 23:17:03 +13:00
Rob Bygrave b2bbb05b83 #1248 - ENH: Additionally read "db" system property to determine default database (to use when testing with docker against different databases) 2018-02-02 20:49:39 +13:00
Rob Bygrave 5ff71324d0 #1247 - Unique index or primary key violation - when jdbc batch cascading to PrivateOwned child with unique constraint 2018-02-02 20:43:55 +13:00
Rob Bygrave 851f1c98b0 #1245 - Refactor internals - move Transaction ProfileStream creation
Stops the profileId parameter pollution, enables to potentially use transaction label
and runtime toggling of collecting transaction profiling detail.
2018-01-31 14:02:50 +13:00
Rob Bygrave a92e620f7e #1245 - Refactor internals - move logic to TransactionManager from DefaultServer 2018-01-31 13:36:23 +13:00
Rob Bygrave f9cd955f7a #1245 - Refactor internals - Add to TransactionManager externalRemoveTransaction() and externalBeginTransaction()
These provide a better/tidier way for external transaction managers (like ebean-spring-txn) to begin and end externally
managed transactions.
2018-01-31 13:28:42 +13:00
Rob Bygrave 71f66005e7 Merge branch 'master' of github.com:ebean-orm/ebean 2018-01-31 11:57:10 +13:00
Rob Bygrave b682293a32 #1245 - Refactor internals - move logic to TransactionManager from DefaultServer 2018-01-31 11:56:38 +13:00
Rob Bygrave 5bd7853ce8 #1245 - Refactor internals - move TransactionMangerScope to be part of TransactionManager 2018-01-31 11:30:11 +13:00
André CamiloandRob Bygrave 276c56161a DiscriminatorColumn length should be 31 (#1244) 2018-01-31 08:32:21 +13:00
Rob Bygrave 6b01821623 #1242 - Bump avaje-classpath-scanner dependency to 3.1.1 2018-01-26 11:51:28 +13:00
Rob Bygrave 8495ccced6 #1241 - ENH: Support using ebean_db system property to control docker container for testing 2018-01-24 19:17:14 +13:00
Rob Bygrave 2d929837c4 No effective change - Update testing for profile location enhancement (#1227) 2018-01-24 19:11:59 +13:00
Rob Bygrave 6754992b1c [maven-release-plugin] prepare for next development iteration 2018-01-22 23:02:52 +13:00
Rob Bygrave 08b7f4a95f [maven-release-plugin] prepare release ebean-11.9.1 2018-01-22 23:02:37 +13:00
Rob Bygrave 07e2605a30 #1240 - ENH: Add support for @Transactional skipCache and label 2018-01-22 22:57:35 +13:00
Rob Bygrave 9a0b742f14 #1240 - ENH: Add support for @Transactional skipCache and label 2018-01-22 15:07:50 +13:00
Rob Bygrave bce745e88d #1240 - ENH: Add support for @Transactional skipCache and label 2018-01-22 15:04:13 +13:00
Rob Bygrave 51d2e4c600 ENH: Add ProfileLocation - Part 2 - performance metrics for transactions with label and profileLocation 2018-01-22 14:54:27 +13:00
Rob Bygrave 4e33027fdf Bump to 11.9.1-SNAPSHOT, add test dependency for logback 2018-01-19 11:10:18 +13:00
Rob Bygrave 0a809b0fb3 #1239 - When Transaction.setSkipCache(true) ... Query with useQueryCache is still use L2 query cache 2018-01-19 10:46:49 +13:00
Rob Bygrave 13ddb915c8 No effective change - add javadoc 2018-01-19 09:38:50 +13:00
Rob Bygrave 07cdf64ece #1238 - Refactor MetaInfoManager - collect query plan stats, fix collection of stats on UpdateQuery 2018-01-19 01:07:37 +13:00
Rob Bygrave b9ae76d465 #1237 - ENH: Add ProfileLocation - support for relating performance metrics for queries and transactions back to source line of code 2018-01-18 18:10:03 +13:00
Rob Bygrave 82f5c21d26 No effective change - Improve exception error message when property is not found on a bean type
Typically using IDE enhancement plugin with incremental compilation where part of an inheritance
hierarchy has been changed but not all related classes recompiled and re-enhanced.
2018-01-12 01:27:24 +13:00
Rob Bygrave 14105eb1eb #1236 - ENH: Add Transaction.current() ... as alternative to obtain the current transaction 2018-01-11 22:34:31 +13:00
Rob Bygrave bab27f25ca [maven-release-plugin] prepare for next development iteration 2018-01-09 23:19:09 +13:00
Rob Bygrave eed8d69715 [maven-release-plugin] prepare release ebean-11.8.1 2018-01-09 23:18:54 +13:00
Rob Bygrave 7b93df2df7 Bump pom version to 11.8.1-SNAPSHOT 2018-01-09 23:17:53 +13:00
Rob Bygrave bb205ced54 #1235 - Thread deadlock on L2 cache load of many property 2018-01-09 23:16:35 +13:00
Rob Bygrave 0d4c50e19c #1234 - Remove deprecated CacheMode.QUERY_ONLY (migrate to CacheMode.GET) 2018-01-09 19:56:55 +13:00
Rob Bygrave 8cff85fdda #1233 - Remove deprecated CacheMode.RECACHE (migrate to CacheMode.PUT) 2018-01-09 19:50:26 +13:00
Rob Bygrave 932986a6b5 #1232 - Performance: Add support for a second read-only DataSource (for implicit query-only transactions) 2018-01-09 16:35:22 +13:00
Rob Bygrave 01539091ef #1231 - Performance: Only use CallStack when using AutoTune (automatic query tuning or profiling) 2018-01-09 13:28:57 +13:00
Rob Bygrave 7e69f71b51 #1230 - Add DB Migration non strict mode - IllegalArgumentException: non-null column has no default value 2018-01-07 15:33:18 +13:00
Rob Bygrave 58d6b2c24e Merge branch 'master' of github.com:ebean-orm/ebean 2018-01-06 12:52:38 +13:00
Rob Bygrave 3c7ef7d46e #1229 - Implement equals and hashCode on ModifyAwareMap, ModifyAwareList and ModifyAwareSet 2018-01-06 12:51:50 +13:00
Rob Bygrave db5db26fca No effective change - rename parameter fix typo 2018-01-06 12:21:14 +13:00
rob bygrave 7110f4a59b No effective change - remove unused HashQueryPlan etc 2017-12-28 16:17:00 +13:00
rob bygrave 9f91d8bcf9 No effective change - modify specific test to run with Postgres specific syntax 2017-12-27 23:23:01 +13:00
Rob Bygrave ac97444ad1 No effective change - add test for @Aggregation with order by clause 2017-12-27 13:49:46 +13:00
Rob Bygrave f6e9afcab6 #1226 - Version range in dependency makes sbt resolve very slow. Change slf4j-api dependency to provided scope.
Part 2, bring in new version of avaje-classpath-scanner which also has slf4j-api as provided scope.
2017-12-27 13:48:22 +13:00
Rob Bygrave a7226079fe [maven-release-plugin] prepare for next development iteration 2017-12-14 00:00:04 +13:00
Rob Bygrave fc915010d9 [maven-release-plugin] prepare release ebean-11.7.1 2017-12-13 23:59:49 +13:00
Rob Bygrave c1818bc309 #1226 - Version range in dependency makes sbt resolve very slow. Change slf4j-api dependency to provided scope. 2017-12-13 22:51:23 +13:00
Rob Bygrave 4a4134ee93 #1227 - NPE when using L2 Query cache with findOne() or findOneOrEmpty() 2017-12-13 22:19:25 +13:00
Rob Bygrave e07bd8f736 #1223 - Support mapping @DbArray to a List or Set of enums 2017-12-13 21:15:19 +13:00
Rob Bygrave 4d0b29624e #1222 - Extend L2 ServerCache API with putAll(), getAll() and removeAll() methods 2017-12-13 19:58:28 +13:00
Rob Bygrave c7f4b56dd1 #1225 - ENH: Extend L2 server cache (near caching) for clearing "near caches" 2017-12-13 02:09:10 +13:00
Rob Bygrave 69c045443c #1218 - ENH: Bump to migration 11.2.1 with support for options patchInsertOn and patchResetChecksumOn 2017-11-23 19:05:35 +13:00
Rob Bygrave fd2d083971 #1217 - L2 query cache not caching empty result set 2017-11-22 22:03:35 +13:00
Rob Bygrave b9380aa5b8 No effective change - add property test for ServerConfig jsonDateTime 2017-11-22 21:21:09 +13:00
Rob Bygrave 3a1368a342 [maven-release-plugin] prepare for next development iteration 2017-11-19 20:34:54 +13:00
Rob Bygrave 0e9fc31531 [maven-release-plugin] prepare release ebean-11.6.1 2017-11-19 20:34:39 +13:00
Rob Bygrave 5132107748 Bump to 11.6.1-SNAPSHOT 2017-11-19 20:33:27 +13:00
Rob Bygrave 7ff3d703f7 #1215 - ENH: Add Query setBeanCacheMode(CacheMode) ... with a view to it replacing the existing setUseCache(boolean) and setLoadBeanCache(boolean) 2017-11-19 20:16:40 +13:00
Rob Bygrave ef91c643ed #1214 - ENH: Add inPairs() expression - support L2 cache hits for complex natural key with findList() and in pairs expression 2017-11-19 16:47:32 +13:00
Rob Bygrave f0ddf6c7e6 #1213 - NPE with TxType SUPPORTS 2017-11-19 01:51:03 +13:00
Rob Bygrave fcff571664 #1212 - ENH: Add query findSingleAttribute() 2017-11-18 22:36:08 +13:00
Rob Bygrave d5555ed9a9 #1211 - ENH: Support L2 cache complex natural keys include findList() queries 2017-11-18 22:20:42 +13:00
Rob Bygrave c5a11aa5a8 No effective change - format and javadoc 2017-11-18 10:48:37 +13:00
Rob Bygrave d1099c8309 Merge branch 'master' of github.com:ebean-orm/ebean 2017-11-15 01:02:35 +13:00
Rob Bygrave 7ff8758797 No effective change - fix javadoc 2017-11-15 01:02:11 +13:00
Koen De GrooteandRob Bygrave f1ebe7929b Internal refactor / tidy - Suggestions from intellij code analysis. (#1209) 2017-11-14 18:19:38 +13:00
Rob Bygrave 0056568bc7 [maven-release-plugin] prepare for next development iteration 2017-11-13 23:18:10 +13:00
Rob Bygrave 4b72924529 [maven-release-plugin] prepare release ebean-11.5.1 2017-11-13 23:17:54 +13:00
Rob Bygrave a75ed676f8 Bump pom version to 11.5.1-SNAPSHOT 2017-11-13 23:16:38 +13:00
Rob Bygrave c3438b888d #995 - @OneToMany with constraints on the many side 2017-11-13 22:43:56 +13:00
Rob Bygrave 56be274acc No effective change - change internal use of ArrayList to List 2017-11-13 22:42:39 +13:00
Rob Bygrave 84bb4ff78c #1207 - Regression added in 11.4.1 with NPE on @transactional(type = TxType.SUPPORTS) 2017-11-13 21:33:39 +13:00
Rob Bygrave 4054eda1f6 #1207 - Regression added in 11.4.1 with NPE on @transactional(type = TxType.SUPPORTS) 2017-11-13 21:32:52 +13:00
Rob Bygrave a4b9354e43 #1206 - NPE when using @Encrypted with Enum property that is null 2017-11-13 19:12:57 +13:00
Rob Bygrave 06e033f23f #1181 - ENH: Add @FetchPreference support - Secondary query generation is based on order of fetch statements 2017-11-08 23:20:08 +13:00
Rob Bygrave 156f505394 #1181 - ENH: Add @FetchPreference support - Secondary query generation is based on order of fetch statements 2017-11-08 23:19:58 +13:00
Rob Bygrave 9b2b2f7787 #1205 - ENH: Add support for raw expression array binding with Postgres - e.g. raw(" foo = any(?) ", collection) 2017-11-08 00:56:13 +13:00
Rob Bygrave e68dae0baa Update ebean-annotation to 3.3 and tests to use 11.5.1 agent 2017-11-07 22:57:04 +13:00
Rob Bygrave 2cf864954f #1204 - Check presence of JAXB and javax @PostConstruct (which may not be present in minimal Java 9) 2017-11-07 20:08:10 +13:00
Rob Bygrave 2b94487573 #1202 - Automatically remove old query plans from Ebean's internal query plan cache 2017-11-06 22:59:42 +13:00
Rob Bygrave fcf730ec39 [maven-release-plugin] prepare for next development iteration 2017-11-06 14:49:08 +13:00
Rob Bygrave 7d343455ac [maven-release-plugin] prepare release ebean-11.4.1 2017-11-06 14:48:55 +13:00
Rob Bygrave 21e0b748a6 #1199 - Remove deprecated findUnique() method - please migrate to findOne() 2017-11-03 03:35:19 +13:00
Rob Bygrave 2fab733e4e Update agent and maven plugin for 11.4.1 enhancement (@Transactional and PropertyChangeListener changes) 2017-11-03 03:30:53 +13:00
Rob Bygrave 7260a1b6eb #1198 - Remove support for PropertyChangeListener from entity beans 2017-11-03 03:08:43 +13:00
Rob Bygrave 434a005366 #1198 - Remove support for PropertyChangeListener from entity beans 2017-11-03 03:05:59 +13:00
Rob Bygrave ff67ef60b0 #1197 - Refactor how @Transactional methods internally managed 2017-11-03 02:13:56 +13:00
Rob Bygrave 0a1747d8e3 #1194 - Change from using Jetbrains @Nullable to ... class retention based javax annotation @Nonnull 2017-11-02 15:56:15 +13:00
Rob Bygrave f36499f71f No effective change - remove use of jetbrains @NotNull in tests 2017-11-02 15:26:35 +13:00
rob bygrave da818f17c2 #1190 - MySql throwing DataIntegrityException when it should throw the more specific DuplicateKeyException
Ah, remove the 23000 SQLState to just use the error codes for MySql.
2017-11-02 01:16:52 +13:00
rob bygrave 10eb2bc21f #1193 - For RawSql ignore the Postgres cast double colon like ::text 2017-11-02 00:03:38 +13:00
rob bygrave 66fe278e3f #1192 - findNative() with @Embedded beans ... the embedded bean isn't loaded properly 2017-11-01 23:03:57 +13:00
rob bygrave 10607385e0 #1191 - Trim logged SQL removing new line chars (for sql from SqlUpdate) 2017-11-01 22:00:55 +13:00
rob bygrave db6562df76 #1190 - MySql throwing DataIntegrityException when it should throw the more specific DuplicateKeyException 2017-11-01 21:54:48 +13:00
rob bygrave c0ec87d4cd #1189 - ExpressionList.isNull and SoftDelete 2017-11-01 21:48:23 +13:00
rob bygrave 0dbba7a211 #1189 - ExpressionList.isNull and SoftDelete 2017-11-01 21:26:15 +13:00
rob bygrave e75670f207 #1188 - When using inheritance getReference() on a leaf type ... should not hit the DB 2017-11-01 20:42:18 +13:00
rob bygrave fb8db14f3a #1186 - Tidy, remove H2MultiValueBind for now 2017-10-31 22:14:01 +13:00
rob bygrave c00b1849ef Merge branch 'feature/1186-MultiValueBind' 2017-10-31 22:11:30 +13:00
rob bygrave 1e1c518641 #1186 - ENH: Support using TableValues / Array for select prop in (?) queries
Use Postgres Array ANY and ALL without select unnest
2017-10-31 22:09:35 +13:00
Rob Bygrave d5b42f9ba1 [maven-release-plugin] prepare for next development iteration 2017-10-31 10:52:44 +13:00
Rob Bygrave bda564d2c8 [maven-release-plugin] prepare release ebean-11.3.1 2017-10-31 10:52:31 +13:00
Rob Bygrave dce124cabd #1187 - Fix connection leak regression introduced in 11.2.3 for findEach() with invalid SQL 2017-10-31 10:50:20 +13:00
Rob Bygrave f5cfcbd56e #1187 - Fix connection leak regression introduced in 11.2.3 for findEach() with invalid SQL 2017-10-31 10:49:35 +13:00
rob bygrave 5bccdccbd6 #1186 - ENH: Support using TableValues / Array for select prop in (?) queries 2017-10-31 02:53:34 +13:00
rob bygrave 6e62b72fb9 #1186 - ENH: Support using TableValues / Array for select prop in (?) queries 2017-10-31 02:53:20 +13:00
rob bygrave 89dac3820b #1182 - Error when applied disjunction to filterMany 2017-10-30 22:06:57 +13:00
rob bygrave ea836a0078 No effective change - rename variable 2017-10-30 21:29:57 +13:00
rob bygrave 1ffd7c7720 git push origin masterMerge branch 'OndrejPacay-feature/1179_bugCollectionL2CacheNotInvalidatedAfterExternalChange' 2017-10-30 21:25:43 +13:00
rob bygrave 387582543c Merge branch 'feature/1179_bugCollectionL2CacheNotInvalidatedAfterExternalChange' of https://github.com/OndrejPacay/ebean into OndrejPacay-feature/1179_bugCollectionL2CacheNotInvalidatedAfterExternalChange 2017-10-30 21:25:30 +13:00
rob bygrave a215878a7c #1183 - ENH: Add support for transaction profiling 2017-10-30 21:21:12 +13:00
rob bygrave dbedb65922 #1183 - ENH: Add support for transaction profiling 2017-10-30 21:19:58 +13:00
Rob Bygrave 1d52b3a818 #1183 - Support transaction profiling, adjust output format 2017-10-27 00:27:21 +13:00
Rob Bygrave 6ce2b91fff #1183 - Support transaction profiling, move away from binary encoding 2017-10-26 23:32:54 +13:00
Rob Bygrave 55d66ae851 #1183 - Support transaction profiling, move away from binary encoding 2017-10-26 23:32:44 +13:00
Rob Bygrave 37d001f754 #1185 - Modify JDBC batch so it does not "auto flush" on non-Id non-generated property 2017-10-26 00:03:58 +13:00
rob bygrave c121618c0c #1183 - ENH: Add support for transaction profiling 2017-10-25 01:31:09 +13:00
rob bygrave 7ebef51859 #1183 - ENH: Add support for transaction profiling 2017-10-25 01:07:00 +13:00
rob bygrave 093f82a87f #1178 - Make the new changeLogAsync property default to true in ServerConfig 2017-10-19 22:26:13 +13:00
Ondrej Pacay b60f1f978f Bug Collection IDs L2 cache not cleared on external sql modification of the table #1179 2017-10-19 01:06:43 +02:00
Roland PramlandRob Bygrave 6ac146cabe Fix beanchange deser (#1178)
Fix / support JSON marshalling of BeanChange + add changeLogAsync option to ServerConfig
2017-10-19 09:40:27 +13:00
Roland PramlandRob Bygrave 2263d31f46 Improved the performance of findAnnotation (#1177) 2017-10-19 09:34:57 +13:00
rob bygrave 4a66d0be6b [maven-release-plugin] prepare for next development iteration 2017-10-19 01:26:28 +13:00
rob bygrave e68e496207 [maven-release-plugin] prepare release ebean-11.2.3 2017-10-19 01:26:12 +13:00
rob bygrave 088110385f Bump ebean-migration dependency to 11.1.1 2017-10-19 01:19:51 +13:00
rob bygrave a355f66561 #1176 - Allow script in extra-ddl.xml ... to not have trailing semi-colon 2017-10-19 01:11:14 +13:00
rob bygrave 00fdb632d7 #1173 - Ebean server should read ebean.mf entity-packages to locate entity beans 2017-10-18 23:58:22 +13:00
rob bygrave a54c4157e6 Refactor as part of - Ensure that Ebean.currentTransaction is available in lifecycle handlers (#1166) #1175 2017-10-18 23:27:59 +13:00
Rob Bygrave a89a9f0202 #1166 - Refactor to use beginServerTransaction() to make Ebean.currentTransaction available in lifecycle handlers 2017-10-17 01:07:48 +13:00
Rob Bygrave 331f49824f #1172 - Refactor - remove internal unused DefaultOrmQuery logSecondaryQuery (as we use LoggedSqlCollector) 2017-10-16 23:49:23 +13:00
Rob Bygrave 94a857d345 #1171 - ENH: Add Finder.update() method ... returning a UpdateQuery<T> 2017-10-16 23:25:56 +13:00
Rob Bygrave 1005f177fd #1170 - ENH: Add isIn() methods as alias to in() on ExpressionList (for use with Kotlin where in is a keyword) 2017-10-16 23:13:49 +13:00
Rob Bygrave 96a4b93c75 #1167 - BUG: query.setId(...).delete() does not work 2017-10-16 22:58:48 +13:00
Rob Bygrave 5869187368 [maven-release-plugin] prepare for next development iteration 2017-10-16 22:26:39 +13:00
Rob Bygrave eac50b8f5b [maven-release-plugin] prepare release ebean-11.2.2 2017-10-16 22:26:21 +13:00
Rob Bygrave 6e2712ea49 #1169 - Memory leak - DefaultTransactionThreadLocal holding reference to transaction 2017-10-16 22:14:48 +13:00
Rob Bygrave f6e5446dab #1169 - Memory leak - DefaultTransactionThreadLocal holding reference to transaction - test case 2017-10-16 22:13:41 +13:00
Koen De GrooteandRob Bygrave 4879d44da4 Bit of cleanup suggestions from intellij. (#1168) 2017-10-16 20:16:30 +13:00
rob bygrave 2c5bf98d0b Merge branch 'master' of github.com:ebean-orm/ebean 2017-10-09 21:13:32 +13:00
rob bygrave 45a571bd97 #1165 - ENH: Add to Finder - currentTransaction() and flush() methods ... (as useful shortcuts) 2017-10-09 21:13:12 +13:00
Roland PramlandRob Bygrave d0ca75c25b FIX: connection leak in query-iterator (#1164) 2017-10-09 20:46:02 +13:00
Roland PramlandRob Bygrave fb1c7667cc FIX: order by must be added in findEach also (#1163) 2017-10-09 20:28:36 +13:00
Roland PramlandRob Bygrave 1909ba1557 Fix like escaping for DB2, Oracle and MySql (#1162)
* Extended test case to show problem

* FIX: Proper escaping of backslash in like/contains queries

* Had to replace "like ?" assertions in tests with "like " as mysql will do a "like binary ? escape'|'" now to be case sensitive
2017-10-06 09:46:56 +13:00
Roland PramlandRob Bygrave e4eca4bbe9 FIX: Oto relations must match datatype (#1161) 2017-10-06 09:44:06 +13:00
Roland PramlandRob Bygrave b2438ecd71 FIX: do not generate unique-constraint for PK as it is useless (and oracle does not accept this) (#1160) 2017-10-06 09:43:30 +13:00
Roland PramlandRob Bygrave ed08567d06 FIX: bundle symbolic name in manifest (#1159) 2017-10-06 09:42:42 +13:00
Roland PramlandRob Bygrave bbe8abcc2e Can handle one to many & many to one relations in docstore only entities (#1158) 2017-10-06 09:42:05 +13:00
Roland PramlandRob Bygrave 1651d5e119 Misc platform fixes (#1157)
* Oracle does not return row count - so we probably cannot detect Optimistic locking

* DB2 wants a varchar null value (other platfroms are happy with this, too)

* FIX Test for DB2 platform
2017-10-05 21:51:09 +13:00
Roland PramlandRob Bygrave 64bf6d6a35 commit transaction only if active (#1156) 2017-10-05 11:04:12 +13:00
Roland PramlandRob Bygrave 47b0a917a2 No effective code change - fix imports and override annotations (#1155) 2017-10-05 10:55:48 +13:00
rob bygrave 2fe1a349c3 [maven-release-plugin] prepare for next development iteration 2017-10-05 01:36:46 +13:00
rob bygrave f168a8fd0d [maven-release-plugin] prepare release ebean-11.2.1 2017-10-05 01:36:30 +13:00
rob bygrave dda98c1dda Bump to 11.2.1-SNAPSHOT 2017-10-05 01:35:30 +13:00
rob bygrave 88a13c5416 #1154 - Remove deprecated TxCallable and TxRunnable - migrate to use Callable and Runnable 2017-10-05 01:24:53 +13:00
rob bygrave 16b8f5da35 Refactor EbeanServerFactory internals - use SpiContainerFactory interface and service loader 2017-10-05 01:12:07 +13:00
rob bygrave 3471f6d206 Refactor EbeanServerFactory internals - use SpiContainerShutdown interface for container shutdown mechanism 2017-10-05 00:57:40 +13:00
rob bygrave 0bf4c84bc8 #1153 - Refactor move SplitName into io.ebean.util 2017-10-05 00:41:32 +13:00
rob bygrave d366336ee5 #1153 - Refactor move ExtraTypeFactory out of io.ebean.plugin into io.ebeaninternal 2017-10-05 00:38:42 +13:00
rob bygrave bf3f8ecff5 Refactor plugin.BeanType addInheritanceWhere() to just take Query and not SpiQuery 2017-10-05 00:35:12 +13:00
rob bygrave 7524903aea #1152 - Refactor EJson internals extracting io.ebean.service.SpiJsonService 2017-10-05 00:29:43 +13:00
rob bygrave 90cf3fddc9 #1151 - Refactor add util AnnotationUtil ... moving common annotation searching methods there 2017-10-05 00:00:44 +13:00
rob bygrave 8e0f9f7591 Refactor - remove unused methods from StringHelper 2017-10-04 23:35:57 +13:00
rob bygrave 24936c0a41 Refactor - remove unused class ClassUtil 2017-10-04 23:34:13 +13:00
rob bygrave f02a552cdf #1150 - Refactor convert RawSql and RawSqlBuilder into interfaces and push the parsers into io.ebeaninternal 2017-10-04 23:03:12 +13:00
rob bygrave 5a5cb7ffbd #1149 - Refactor move PersistenceContextUtil into ... io.ebeaninternal 2017-10-04 21:12:39 +13:00
rob bygrave f85fa772bf #1147 - Refactor move DbMigration internals into io.ebeaninternal - change to use DbMigration.create() - move DbMigrationFactory.create() method 2017-10-04 21:06:55 +13:00
rob bygrave 9f9ec8ef9f #1147 - Refactor move DbMigration internals into io.ebeaninternal - change to use DbMigration.create() - move IdentityType handling into internal from DbIdentity 2017-10-04 20:49:04 +13:00
rob bygrave 62707caf64 #1147 - Refactor move DbMigration internals into io.ebeaninternal - change to use DbMigration.create() - move PlatformDdl into internal 2017-10-04 20:30:57 +13:00
rob bygrave c6fc7a032d #1147 - Refactor move DbMigration internals into io.ebeaninternal - change to use DbMigration.create() - DbOffline & ServerConfig 2017-10-04 19:44:29 +13:00
rob bygrave 10faa1fae6 #1147 - Refactor move DbMigration internals into io.ebeaninternal - change to use DbMigration.create() - initial move 2017-10-04 19:36:27 +13:00
Rob Bygrave 764f5ce4d4 [maven-release-plugin] prepare for next development iteration 2017-10-03 23:20:50 +13:00
Rob Bygrave 65ba231fc0 [maven-release-plugin] prepare release ebean-11.1.1 2017-10-03 23:20:35 +13:00
Rob Bygrave 1da2382e45 No effective change - javadoc only 2017-10-03 15:38:17 +13:00
Rob Bygrave a86af94a8c Reduce logging level only - no functional change 2017-10-03 15:35:21 +13:00
Rob Bygrave 8301cb634e #1027 - ENH: Add a Slow query event listener ... to log or listen to queries that exceed some defined execution time 2017-10-03 15:04:30 +13:00
Rob Bygrave 721654d033 #1140 - Error loading embedded instance
The issue was due to the loaded status not being recursively set on embedded
beans after inserts. The test case invoked lazy loading due to that which
lead to the issue.
2017-10-03 12:47:29 +13:00
Rob Bygrave fe1817ef02 No effective change - update test 2017-10-03 12:34:56 +13:00
Rob Bygrave fc996659f2 #1139 - NoSuchMethodError: javax.persistence.Embedded.prefix()Ljava/lang/String; 2017-10-03 11:02:38 +13:00
rob bygrave 368d22baa6 #1145 - Refactor @ChangeLog based on JSON documents for 'new values' and 'old values' 2017-10-03 01:31:37 +13:00
rob bygrave daf3d97266 #1144 - Refactor internals - move generated property setting into PersistRequestBean 2017-10-03 00:30:34 +13:00
rob bygrave f2179fca2d #1123 - 11.1.1 API change - moved PersistBatch, Platform, TxIsolation and TxType to io.ebean.annotation package 2017-09-15 21:48:53 +12:00
rob bygrave 2c436c3af5 #1123 - 11.1.1 API change - moved PersistBatch, Platform, TxIsolation and TxType to io.ebean.annotation package 2017-09-15 21:48:37 +12:00
Roland PramlandRob Bygrave 8d334ff2e8 Feature/contitional test runner (#1132)
* FIX: warnings (add generics, overrides, fix imports) - should be no effecive code change

* replaced deprecated methods by default methods

* FIX: more compiler warnings

* FIX more warnings - no code changes

* FIX: deprecated call to JsonParseException

* Remove unused code, check unused variables

* ADD: ContitonaltestRunner to skip tests for certain platforms

* Use annotations to control on which platforms a test shoud run

* FIX: compile errors
2017-09-15 21:03:03 +12:00
rob bygrave f3e4696498 [maven-release-plugin] prepare for next development iteration 2017-09-14 01:03:21 +12:00
rob bygrave 221260fa44 [maven-release-plugin] prepare release ebean-10.4.7 2017-09-14 01:03:07 +12:00
rob bygrave f8e7a79e9a #1131 - Migration broken in 10.4.6 due different classpath-scanner version 2017-09-14 00:56:37 +12:00
Roland PramlandRob Bygrave b66f18bfd6 Fix warnings 2 (#1130)
* FIX: warnings (add generics, overrides, fix imports) - should be no effecive code change

* replaced deprecated methods by default methods

* FIX: more compiler warnings

* FIX more warnings - no code changes

* FIX: deprecated call to JsonParseException

* Remove unused code, check unused variables
2017-09-14 00:32:48 +12:00
Roland PramlandRob Bygrave ac6708e0d0 Fix warnings (#1129)
* FIX: warnings (add generics, overrides, fix imports) - should be no effecive code change

* replaced deprecated methods by default methods

* FIX: more compiler warnings

* FIX more warnings - no code changes
2017-09-14 00:29:01 +12:00
rob bygrave a5f46c095d [maven-release-plugin] prepare for next development iteration 2017-09-13 23:02:39 +12:00
rob bygrave 3ac7ea6e60 [maven-release-plugin] prepare release ebean-10.4.6 2017-09-13 23:02:25 +12:00
rob bygrave b2e0271ce7 #1128 - Allow "2 word SQL" like TRUNCATE t, ANALYSE t etc 2017-09-13 21:40:17 +12:00
rob bygrave c7a7651602 #1127 - Remove the ebean.query.globallimit of 1 million "backstop" 2017-09-13 21:22:03 +12:00
rob bygrave 1e6678cbb4 #1126 - Regression bug in 10.4.5 with new line character use with SqlQuery, SqlUpdate and CallableSql 2017-09-13 21:14:19 +12:00
Roland PramlandRob Bygrave a6e4e181bf Feature/cache improvements 2 (#1067)
* New Mode to control queryCache behavior

* Collections form the cache have to be read only

* findCount not queried in query cache

* return modifiable collections from the cache

* FIX: Compile errors

* No effective code change: reformat code / javadoc
2017-09-12 23:40:18 +12:00
Roland PramlandRob Bygrave b8e1dffca2 replaced findUnique by "default" method in interfaces. (#1124) 2017-09-12 23:20:04 +12:00
rob bygrave 7e8ed72b7b #1125 - ENH: Add a SpiContainerBootup API ... to enable automatic startup of docker containers (for testing usually) 2017-09-12 22:44:37 +12:00
rob bygrave ec8dd30a04 [maven-release-plugin] prepare for next development iteration 2017-09-11 23:12:43 +12:00
rob bygrave f81d5c9f3a [maven-release-plugin] prepare release ebean-10.4.5 2017-09-11 23:12:29 +12:00
rob bygrave 74b24b1db1 #1120 - Bump classpath scanner dependency to 2.2.4 (fix for NPE on empty directory) 2017-09-11 23:09:28 +12:00
rob bygrave 179ef8c8a0 No effective change - javadoc update on Ebean 2017-09-10 21:23:37 +12:00
rob bygrave f77f3c3d6e #1119 - Deprecate TxRunnable and TxCallable - migrate to plan JDK Runnable and Callable. Add explicit executeCall() method 2017-09-10 20:47:26 +12:00
Roland PramlandRob Bygrave 9a7646195c Featur/dbmigration 3 (#1118)
* ADD: more test classes for Softdelete and History

* update reference models after adding test classes

* DbMigration:Improved History generation for sqlserver

* FIX: When DB supports Sql2011 platform, we must not alter the history-table (as this is handled by DB itself)

* DbMigration: When dropping a table, drop the sequence also.

* DbMigration: dropColumn is handled by platformDdl now, as SqlServerDdl needs to delete dependent objects (default constraints...) first

* FIX: DbMigration is not executed on history table

* DbMigration: can drop comment now.

* No effective code change: completed ObjectFactory / fixed imports

* FIX: drop table comment

* Committed the reference models
2017-09-10 15:26:01 +12:00
rob bygrave 84d3578e33 No effective change - add a test for saveAll() with existing batch mode on
Assert that it does not flush the batch.  We want the batch to continue and flush normally.
2017-09-09 14:14:57 +12:00
rob bygrave ef05b81014 #1117 - Refactor - moved DbDefault and DbMigration annotations to ebean-annotation 2017-09-09 13:27:09 +12:00
rob bygrave 726c682984 #1116 - Remove references to annotation EbeanDDL which is no longer needed 2017-09-09 13:18:39 +12:00
rob bygrave 0c22a99fdf #1116 - Remove references to annotation EbeanDDL which is no longer needed 2017-09-09 13:12:40 +12:00
rob bygrave c062c8e001 #1054 Java 9 - adding "Automatic-Module-Name" to MANIFEST.MF initial step
Update dependency to ebean-migration 10.2.1, avaje-classpath-scanner and avaje-datasource to avoid package name clash
2017-09-09 01:53:47 +12:00
rob bygrave 06f3c000f5 #1115 - Trim SQL for SqlUpdate, SqlQuery and CallableSql - also replace \n with space 2017-09-08 23:45:28 +12:00
rob bygrave 8c0232fdb8 #1114 - Deprecate findUnique() - please migrate to findOne() - update tests 2017-09-08 22:48:46 +12:00
rob bygrave 2470486f20 #1114 - Deprecate findUnique() - please migrate to findOne() 2017-09-08 22:37:50 +12:00
rob bygrave 8fbf0374dd No effective change - tidy around Db migration changes 2017-09-08 22:02:56 +12:00
Roland PramlandRob Bygrave dd8fff0277 Feature/ddl migration (#1111)
* REFACTOR: use functions from ddl-help

* NEW: Default values are written to DDL

* fix testcase for sqlserver as default constraints will get names in future

* Reading DbMigration

* ADD: DbmIgrationGenerateTest

* Tables must be created first

* Sanity checks and some getters

* DdlMigration gets applied now

* ADD: Testcase and reference migration scripts

* no effective code changes: add comments
2017-09-08 21:47:33 +12:00
Rob Bygrave 73b3d1d977 [maven-release-plugin] prepare for next development iteration 2017-09-07 00:41:49 +12:00
Rob Bygrave 2a76ae2192 [maven-release-plugin] prepare release ebean-10.4.4 2017-09-07 00:41:36 +12:00
Rob Bygrave 39931a3a2c No effective change - add test example of markUnset on version property (to avoid occ check) 2017-09-07 00:40:19 +12:00
Rob Bygrave 58eb49617b #1113 - SqlUpdate with leading spaces leads to Invalid event detection (which table was update for L2 cache invalidation etc) 2017-09-07 00:36:52 +12:00
Rob Bygrave 9b621d2ec7 #1112 - Enhance JDBC batch behavior when cascade persist is turned off (manual master/detail batch persisting) 2017-09-06 23:57:54 +12:00
Roland PramlandRob Bygrave f2e8b652fa FIX: DDL process comment change correctly & drop references when index is dropped (#1109) 2017-09-01 20:45:06 +12:00
Roland PramlandRob Bygrave f342d9d561 API-CHANGE: DbMigration returns which version was generated (#1108) 2017-09-01 20:42:02 +12:00
Roland PramlandRob Bygrave 8009bdf099 REFACTOR: Created a "splitNames" in StringHelper and use it in various places. Also wrote some tests for StringHelper. (#1107) 2017-09-01 20:40:39 +12:00
Roland PramlandRob Bygrave 7336ce81bd FIX: Do not add AssocOne-generatedProperties if they should not. (#1106) 2017-09-01 20:38:13 +12:00
Roland PramlandRob Bygrave f805bec8f2 FIX: Using correct datatype for null value when json is serialized to varchar column (#1105) 2017-09-01 20:36:41 +12:00
Roland PramlandRob Bygrave 46cdc84e6b Refactor/findannotation (#1104)
* refactor: renamed findAnnotation method that searches recursive to findAnnotationRecursive

* CHG: searching namedQueries & indices also recursive in superclasses

* FIX: Using the AnnotationBase methods on several places and documented them
2017-09-01 20:25:10 +12:00
Roland PramlandRob Bygrave e908d16ba8 Pr/add tests (#1103)
* ADD: Testcase for Sqlserver-6.2.0 driver

* CHG: Removed Row-limit - so we need no special handling when sqlserver-platform generates a "select top 100" statement

* ADD: additional asserts to TestQueryCache

* CHG: Ignore test for sqlserver
2017-09-01 20:17:56 +12:00
rob bygrave 96e3f4138f #1064 - Query table alias not used in update() or delete() queries 2017-08-31 21:29:08 +12:00
rob bygrave 977dd52890 No effective change - code reformat only 2017-08-31 21:10:13 +12:00
Roland PramlandRob Bygrave a9b7bb2175 FIX: Passing MDC through background-executor (#1102) 2017-08-31 21:09:04 +12:00
rob bygrave f83c7fdac8 #1100 - Refactor OrmQueryPlanKey to use string expression for where 2017-08-31 02:11:49 +12:00
rob bygrave a695fb59b2 [maven-release-plugin] prepare for next development iteration 2017-08-31 01:50:20 +12:00
rob bygrave e197bb2900 [maven-release-plugin] prepare release ebean-10.4.3 2017-08-31 01:50:06 +12:00
rob bygrave b54b8815d9 Merge branch 'master' of github.com:ebean-orm/ebean 2017-08-30 21:59:08 +12:00
rob bygrave 1d1fde61be #1101 - findNative() on a bean with an associated @OneToOne (with the PK being derived from the parent) maps incorrectly 2017-08-30 21:58:33 +12:00
rob bygrave 683186cbe9 No effective change - pom whitespace only 2017-08-30 21:14:20 +12:00
Roy de BokxandRob Bygrave 5e6be40454 Only throwing warning for autocommit when server is not set to use autocommit-friendly TransactionManager. (#1085) 2017-08-30 20:57:49 +12:00
Roland PramlandRob Bygrave c00febd95b ENH: Abort all tests if connection to db could not be esablished (#1099) 2017-08-30 20:04:50 +12:00
Roland PramlandRob Bygrave 4c8e1113bf FIX: deadlock in TestCommitAndContiune for sqlserver & hsqldb (#1098) 2017-08-30 20:03:41 +12:00
Roland PramlandRob Bygrave 6f854da70b Fix/corrected error codes (#1097)
* FIX: db2plaform error codes and dbtypes

* FIX: H2: Add error code for locking

* FIX: Mysql: Add DataIntegrity-error code
2017-08-30 20:02:34 +12:00
Roland PramlandRob Bygrave 3f5a162a4e Fix/connection to different platforms (#1096)
* ADD: Profile for oracle and db2 to pom file. Downgraded mysql driver

* FIX: connection string for several platforms

* ADD: Documentation
2017-08-30 20:00:58 +12:00
Roland PramlandRob Bygrave d14529b602 FIX: optimized unique constraint handling for platforms that does support them on nullable columns (#1095) 2017-08-30 19:54:53 +12:00
Roland PramlandRob Bygrave f471961f06 FIX: extra-ddl modified to be compatible with different platfoms (#1094) 2017-08-30 17:51:41 +12:00
Roland PramlandRob Bygrave 457c1356a4 Fix/shortened tablenames (#1093)
* FIX: Shortened tablename (will fail on oracle)

* FIX: renamed table, otherwise, in db2 he_link_doc & hi_link_ are both generating the same index ix_h_lnk_dc_h_dc
2017-08-30 17:50:40 +12:00
Roland PramlandRob Bygrave 419ac2bf50 FIX: Possible NPE in StringHelper (#1092) 2017-08-30 17:49:34 +12:00
Roland PramlandRob Bygrave 727d088577 FIX: add MAX-DATE as default value for ROW END (#1091) 2017-08-30 17:48:36 +12:00
Roland PramlandRob Bygrave 972d2dcc6b FIX: nvarchar(max) length specified differently, otherwise this leads to a ddl like this "nvarchar(max)(700)" (#1090) 2017-08-30 17:47:21 +12:00
Roland PramlandRob Bygrave a5bcd49ecb FIX: Clean up before running tests - otherwise tests will fail if a previous test did not clean up well. (This fixes test failures in Eclipse where tests are executed in different order than in maven) (#1089) 2017-08-30 17:44:30 +12:00
Roland PramlandRob Bygrave ff496ad2d3 FIX: EnumToDbIntegerMap did not set 'integerType' - this leads to an incompatible quoting. Constraints like "check in ('1','2','3')" were not accepted by hsqldb on integer columns. (#1088) 2017-08-30 17:42:25 +12:00
Roland PramlandRob Bygrave 24d438ba23 FIX: H2HistoryTrigger honors schema (#1087) 2017-08-30 17:38:52 +12:00
Roland PramlandRob Bygrave 591067e39e FIX: Typo in classname (#1086) 2017-08-30 17:37:45 +12:00
rob bygrave 38a95dc5c4 No effective change - Reformat code - ScalarTypeEnumStandard 2017-08-24 22:37:41 +12:00
icodeandRob Bygrave 53426d8493 use jackson configuration [SD]eserialization enum (#1079)
* use jackson configuration [SD]eserialization enum

https://github.com/FasterXML/jackson-databind/wiki/Serialization-features 
https://github.com/FasterXML/jackson-databind/wiki/Deserialization-Features

keep jackson and ebean [SD]eserialization same
`objectMapper.enable(SerializationFeature.WRITE_ENUMS_USING_INDEX);`

* Update ScalarTypeEnumStandard.java

* Update ScalarTypeEnumStandard.java

* Update ScalarTypeEnumStandard.java

* Update ScalarTypeEnumStandard.java
2017-08-24 22:35:36 +12:00
rob bygrave a06238558e No effective change - Jackson WRITE_ENUMS_USING_INDEX test 2017-08-24 22:34:57 +12:00
Yuan XueguiandRob Bygrave b3a3b19d5d Fix: query table entity or sql entity has no id (#1082)
When query table entity or sql entity,include NamedQuery which modified via code and RawSqlQuery which modified via code.
2017-08-24 22:18:46 +12:00
rob bygrave 57231c80a8 #1084 - NPE When DB Migration generation run with @WhoCreated mapping 2017-08-24 22:15:01 +12:00
rob bygrave dc96fb9ad5 No effective change - update test, better asserts 2017-08-15 21:47:21 +12:00
rob bygrave 567847b47a #1081 - Update jackson-core dependency to 2.9.0 2017-08-05 00:11:53 +12:00
rob bygrave b74fed7073 Bump to 10.4.1 agent (@Transient properties included in mapped superclass enhancement detection) 2017-08-04 22:59:53 +12:00
rob bygrave cdaf8ee6d5 [maven-release-plugin] prepare for next development iteration 2017-08-04 21:33:33 +12:00
rob bygrave c6c5073e47 [maven-release-plugin] prepare release ebean-10.4.2 2017-08-04 21:33:19 +12:00
rob bygrave 2a58b954e9 #1062 - Multi-tenant - Update statements should include tenantId in where clause 2017-08-04 21:16:14 +12:00
Koen De GrooteandRob Bygrave 9772623880 Added the Serializable interface to classes that extend/implement a Comparator with an anonymous/typed class. (#1078) 2017-08-03 23:29:56 +12:00
rob bygrave 27b6183aad Merge branch 'master' of github.com:ebean-orm/ebean 2017-08-03 23:28:35 +12:00
David HofmannandRob Bygrave 55e19618f8 fix connection leak in JTA managed transactions (#1077) 2017-08-03 23:28:21 +12:00
rob bygrave 5c60ba4d7f Update test for WriteJson to just use PathProperties 2017-08-03 23:01:22 +12:00
rob bygrave b9cc584086 #1080 - NOT IN expression using entity beans / reference beans uses "in" 2017-08-03 20:31:18 +12:00
Koen De GrooteandRob Bygrave bf5a8c2fad Changed some boolean checks to use the recommended method of comparing floating point values in Java. (#1075) 2017-07-22 13:00:24 +12:00
rob bygrave 66138e5ea2 #1070 Fix for - Create test for bean cache not being cleared with delete or update queries 2017-07-21 23:31:23 +12:00
Rien Nentjes 75fb89ef76 Create test for bean cache not being cleared with delete or update queries 2017-07-14 11:04:43 +02:00
rob bygrave a2cb468222 No effective change - add test resource ebean.mf to hint to enhancement agent packages to enhance 2017-07-11 21:11:54 +12:00
rob bygrave 166bcd7c45 #1061 - findCount query is not cached in L2 query cache 2017-07-06 21:51:52 +12:00
rob bygrave 95aed6af54 #1060 - findSingleAttributeList doesn't store result in L2 query cache 2017-07-06 21:35:20 +12:00
rob bygrave 7a697c12af No effective change - moved mssql-jdbc down with other test scope dependencies 2017-07-06 21:11:40 +12:00
rob bygrave 23278ce30b #1058 - Refactor - PlatformPrefix isn't actually used in PlatformDddlWriter, removing. 2017-07-06 20:30:20 +12:00
Koen De GrooteandRob Bygrave 36a5610e25 Using Regular expression objects for splitting and replacing in strings. (#1059)
* Where possible, replace .split() and .replace() methods with compiled Regex patterns.
This prevents a regular expression from being compiled multiple times during runtime.

* Forgot making one instance `private static final`.
2017-07-06 20:14:51 +12:00
rob bygrave 08263c4588 [maven-release-plugin] prepare for next development iteration 2017-07-05 21:41:12 +12:00
rob bygrave 1e88a52208 [maven-release-plugin] prepare release ebean-10.4.1 2017-07-05 21:40:58 +12:00
rob bygrave e770a42175 Bump to 10.4.1-SNAPSHOT (due to ServerConfig h2ProductionMode removal) 2017-07-05 21:39:12 +12:00
Thibault MeyerandRob Bygrave 35b467c04f JSON simple implementation for MSSQL (#1057)
- Use JSON_VALUE
  - Use NVARCHAR type

Signed-off-by: Thibault Meyer <meyer.thibault@gmail.com>
2017-07-03 20:45:48 +12:00
Roland PramlandRob Bygrave 2001539755 Sqlserver support (#1053)
* made some tests sqlserver ready (No effective code change in src/main)

* FIX enhance packages and let all testcases inherit from BaseTestCase, so that they can be launched directly from eclipse

* ADD sqldriver in pom and datasource

* FIX: DDL-generation for sqlserver - not yet all sqlserver tests passing
mvn verify -Ddatasource.default=mssql => Tests run: 1980, Failures: 22, Errors: 44, Skipped: 16

* BaseDdlHandlerTest checks against correct sqlserver-ddl now
2017-07-03 20:27:37 +12:00
rob bygrave e49c4bfe5a #867 - ENH: Add ability to globally use quoted identifiers on all tables and columns 2017-07-02 21:07:58 +12:00
rob bygrave 15be31fd5f #1051 - Remove ServerConfig h2ProductionMode ... means for testing with h2 explicitly set ddlGenerate and ddlRun 2017-07-02 11:42:56 +12:00
rob bygrave 4777ec46be #1050 - Bump db-migration to 10.1.10 2017-07-02 11:12:03 +12:00
rob bygrave 80ab731aec Use older postgres jdbc driver 2017-06-25 22:56:21 +12:00
rob bygrave 080bafe18f #1048 - Fix connection leak on failed findIterate() 2017-06-25 22:39:04 +12:00
rob bygrave e913f88f52 Fix test - TestCommitAndContinue ... close extra transactions used in asserts 2017-06-25 21:43:37 +12:00
rob bygrave e94c5484a0 #1047 - Fix connection leak on failed beginTransaction() 2017-06-25 21:42:51 +12:00
rob bygrave 4af00c51d3 travis - dist: trusty ... to get PG 9.6 2017-06-25 19:57:31 +12:00
rob bygrave 23d1256dbf Update to postgres 9.6 for travis test runs 2017-06-25 19:43:05 +12:00
rob bygrave ed0ef46d2e No effective change - update postgresql jdbc driver 2017-06-25 19:03:07 +12:00
rob bygrave 1860ded735 [maven-release-plugin] prepare for next development iteration 2017-06-25 16:01:50 +12:00
rob bygrave d432854b82 [maven-release-plugin] prepare release ebean-10.3.2 2017-06-25 16:01:37 +12:00
rob bygrave 93582c8ea3 Downgrade postgres jdbc driver for commit and continue test 2017-06-25 15:54:14 +12:00
rob bygrave 520d35b1d6 #963 - NullPointerException on no version provided (when setVersion(null) is used) 2017-06-25 14:44:13 +12:00
rob bygrave 8ca3599cbf #1046 Bump DB migration to 10.1.9 - fix for Checksum mismatch does not stop migration 2017-06-25 14:29:46 +12:00
rob bygrave 283ae74219 Update javadoc on ScalarTypeConverter. Should look to officially deprecate this in favor of AttributeConverter. 2017-06-24 11:35:58 +12:00
rob bygrave cebd3f92a4 #1045 - MySql - DbMigration generate wrong comment syntax - should be alter table comment = syntax 2017-06-24 11:23:21 +12:00
rob bygrave 4b2481d3ea #1039 Fix for - reset of dirty flag on L2 cached entities after lazy load 2017-06-23 23:20:17 +12:00
rob bygrave f1f2a416d3 No effective change - reformat only 2017-06-23 23:19:22 +12:00
rob bygrave 74dd97a55f No effective change 2017-06-23 23:18:57 +12:00
rob bygrave 3f04f7f363 Merge branch 'master' of https://github.com/SamhammerAG/ebean into SamhammerAG-master 2017-06-23 19:52:55 +12:00
rob bygrave 800f854a12 #1043 Additional test for RawSql with upper case SQL 2017-06-23 19:46:47 +12:00
rob bygrave bef9e6d54f Merge branch 'master' of github.com:ebean-orm/ebean 2017-06-23 19:43:45 +12:00
Tigran_DadaiantsandRob Bygrave 0e4c0ae6c3 #1043 RawSql should automatically map upper-case column alias to lower-case bean property (#1044) 2017-06-23 19:43:15 +12:00
rob bygrave a0ea9887df No effective change - remove unused imports 2017-06-23 19:37:24 +12:00
Roland PramlandRob Bygrave 0413c22e6e no effective code change - fixed warnings about serialization, override, raw-types (#1032) 2017-06-23 19:33:03 +12:00
rob bygrave 989ae44a6d Merge branch 'pr/id-in-as-collection' of https://github.com/FOCONIS/ebean into FOCONIS-pr/id-in-as-collection 2017-06-23 19:28:25 +12:00
rob bygrave 100d314e63 #1035 Update for - FIX: deleting and adding same bean in beanCollection leads to deletion in DB
If use Modify mode we need to listen for both adds and removes to support sorting (can't rely on undoDelete() due to ordering)
2017-06-19 23:34:44 +12:00
rob bygrave dbf4e99187 #1035 tests for - FIX: deleting and adding same bean in beanCollection leads to deletion in DB 2017-06-19 23:32:58 +12:00
Roland PramlandRob Bygrave 7b8a85106c FIX: deleting and adding same bean in beanCollection leads to deletion in DB (#1035) 2017-06-19 22:50:20 +12:00
rob bygrave 58c5f01e2b #1042 - JtaTransaction is TenantMode.DB aware 2017-06-19 22:28:15 +12:00
Roland PramlandRob Bygrave bc74d35651 FIX: correct behavior of "startsWith, "contains" etc (#1031)
* FIX: correct behavior of "startsWith" if string contains "like"-wildcards

* Removed likeClasues with disabled escaping in database platforms as bind values are properly escaped now.
2017-06-19 22:21:26 +12:00
Roland PramlandRob Bygrave a1f95bf25e Pr/id in as collection2 (#1034)
* ENH: Changed  idIn(List) to idIn(Collection)

* ADD: sanity checks in IdBinder & special case if ID-list is empty
2017-06-19 22:05:56 +12:00
rob bygrave c454e1f8a7 No effective change - add test 2017-06-19 21:53:35 +12:00
Koen De GrooteandRob Bygrave 5a3669e1db Noticed that this boolean parameter was ignored. (#1041)
After some quick analysis, implemented that way it probably should be used.

Of course, this could have been on purpose, please advise.
2017-06-19 21:39:58 +12:00
rob bygrave 7a2e0b3695 Bump to the later agent 2017-06-19 21:34:18 +12:00
AWoelfel ce6d6269cd Step to reproduce reset of dirty flag on L2 cached entities after lazy load 2017-06-08 15:07:32 +02:00
Roland Praml 7d800b7080 ENH: Changed idIn(List) to idIn(Collection) 2017-05-29 15:22:48 +02:00
rob bygrave 136154e247 [maven-release-plugin] prepare for next development iteration 2017-05-21 21:56:29 +12:00
rob bygrave 0a5ce1bee8 [maven-release-plugin] prepare release ebean-10.3.1 2017-05-21 21:56:16 +12:00
Koen De GrooteandRob Bygrave b4e2c89e2d Moved a few variables closer to the point where they are actually used, but only in cases where this means moving them past a (potential) return/throw statement. (#1029) 2017-05-21 21:51:58 +12:00
Koen De GrooteandRob Bygrave 9e2923f571 For debug and trace levels, either added isEnabled check or made arguments parameterized. (#1028) 2017-05-21 21:50:13 +12:00
rob bygrave d0c1ae76f4 #955 - Migration "add column" DDL with check constraint is missing constraint name 2017-05-21 01:23:55 +12:00
rob bygrave fe9500e6d0 #1011 - Create valid migration scripts for non-Postgres databases and @DbArray columns.
Merge branch 'test/dbarray-create-migration' of https://github.com/FOCONIS/ebean into FOCONIS-test/dbarray-create-migration

commit 3a8f32b173
Author: Michael Benz <michael.benz@foconis.de>
Date:   Wed Apr 19 18:16:51 2017 +0200

    adding dbmigration ddlgeneration test for Ebean @DbArray extension.
2017-05-20 23:40:02 +12:00
rob bygrave 79f7c73983 #999 - Refactor tidy for ... @DiscriminatorColumn columnDefinition is ignored for DDL generation 2017-05-20 15:22:06 +12:00
rob bygrave d04954e46f #999 - @DiscriminatorColumn columnDefinition is ignored for DDL generation 2017-05-20 15:03:21 +12:00
rob bygrave 88c6ec358c #981 Additional refactor to 981 - use composed key in multi tenant environment - Expose TenantAwareKey handling for plugins 2017-05-20 13:53:46 +12:00
Roland PramlandRob Bygrave d3ea01b76e use composed key in multi tenant environment instead a cache per tenant (#981) 2017-05-20 12:35:34 +12:00
rob bygrave 0c1a9786a3 #996 Add findOne() and findOneOrEmpty() - SqlQuery 2017-05-19 23:48:41 +12:00
rob bygrave db298a349e #996 Add findOne() and findOneOrEmpty() 2017-05-19 23:38:40 +12:00
rob bygrave c1bed9f578 #996 Add findOne() and findOneOrEmpty() 2017-05-19 23:38:24 +12:00
rob bygrave c7cbe4ead8 Read the new @Length annotation 2017-05-19 23:00:10 +12:00
rob bygrave 4064aaf714 #1004 - Ebean migrations can not be executed if they contain ';' into a string 2017-05-15 22:18:24 +12:00
rob bygrave 6ad808003a Refactor - remove unused ebeandeploy.dtd 2017-05-14 21:11:00 +12:00
rob bygrave 70de6101db Refactor, remove unused SqlReservedWords 2017-05-14 21:10:24 +12:00
Roland PramlandRob Bygrave 933595ceea ADD: Testcases for "fetchDistinct" (#1024)
* ADD: Testcases for "fetchDistinct"

* Updated the tests for #1024
2017-05-14 17:39:07 +12:00
rob bygrave 461c2aef60 #946 - Treat primitive numbers (long, int, short, float, double) as NOT NULL wrt DDL generation 2017-05-14 01:31:28 +12:00
Rob Bygrave 0c49b6514c [maven-release-plugin] prepare for next development iteration 2017-05-11 23:54:47 +12:00
Rob Bygrave 0ec425928b [maven-release-plugin] prepare release ebean-10.2.3 2017-05-11 23:54:33 +12:00
rob bygrave 711701932a #1023 - Bug with findSingleAttributeList() when used against @ManyToOne / foreign key 2017-05-11 23:20:19 +12:00
Koen De GrooteandRob Bygrave 951e517caf Replaced Tail Recursion while while/true loops. (#1019) 2017-05-11 22:07:10 +12:00
rob bygrave 8cef603d1c #1021 Fix for query plan clash with single inheritance and cached query 2017-05-11 21:57:24 +12:00
Rien Nentjes 2a64a02211 Discriminator query cache error 2017-05-04 14:16:38 +02:00
Rob Bygrave 67ef0cd5d9 Refactor - repackage / move test code only 2017-05-01 20:39:49 +12:00
Rob Bygrave 9f2334362a [maven-release-plugin] prepare for next development iteration 2017-04-30 23:15:34 +12:00
Rob Bygrave 44ff304423 [maven-release-plugin] prepare release ebean-10.2.2 2017-04-30 23:15:20 +12:00
Roland PramlandRob Bygrave f9c70d2a2b Fix/select distinct cascaded fetch (#1015)
Fix/select distinct cascaded fetch with findSingleAttributeList() on associated property path
2017-04-30 23:07:35 +12:00
Rob Bygrave e51f7f11f1 Fix tests for #1016 2017-04-30 22:56:07 +12:00
Yuan XueguiandRob Bygrave 54ef0e7465 FIX BUG:and blank space after 1=1 (#1016)
FIX BUG:and blank space after 1=1 (Noop expression for equals null with @SoftDelete)
2017-04-30 22:50:03 +12:00
OndrejPacayandRob Bygrave 63def00626 #1012 - Filtering on embedded values in a joined table does not produce a sql join (#1013) 2017-04-30 22:33:02 +12:00
Koen De GrooteandRob Bygrave 335c4de109 Static code analysis. (#1017) 2017-04-30 14:47:02 +12:00
Rob Bygrave a120c2aaee #947 - Treat primitive boolean as NOT NULL - DDL as not null 2017-04-25 13:17:58 +12:00
Koen De GrooteandRob Bygrave 43408fcb87 Java language level updates concerning Maps. (#1008)
* Java language level updates concerning Maps.

* Reverts when comments indicated no sync can happen.
2017-04-22 15:48:46 +12:00
Koen De GrooteandRob Bygrave 8432f7b0d5 Some changes that are possible in Java language level 7 and 8. (#1007) 2017-04-22 15:43:56 +12:00
Koen De GrooteandRob Bygrave bdd7884f42 Changes for ArrayStack. (#1006)
Removed old inspection suppression.
2017-04-22 15:42:25 +12:00
Alexander WinklerandRob Bygrave 485e62b5d6 Added multi tenant catalog support. (#987) 2017-04-01 00:41:08 +13:00
Roland PramlandRob Bygrave 0557e6cd08 Wrong alter table / alter column DDL was generated (#988)
* FIX: alter column type uses correct DB-type now.

* FIX: Oracle test case
2017-04-01 00:38:23 +13:00
Koen De GrooteandRob Bygrave b821702b8d Moving defaultservercache implementation to use nanoseconds to determine whether or not something needs to be evicted from the cache. (#998)
The old implementation used System.currentTimeMillis(), which might be unreliable, for instance during a jump in DST.
Thanks @rPraml for noticing and suggesting the fix.
2017-04-01 00:30:01 +13:00
Rob Bygrave c5b23c321e #1002 - Bump ebean-dbmigration to 10.1.6 (better support for schema & sql server) 2017-04-01 00:28:46 +13:00
Rob Bygrave 964d2d00a2 #1001 - Add @Length and @NotNull, (plus move @Transactional to ebean-annotation) 2017-03-31 21:56:30 +13:00
Rob Bygrave 1778afa17d [maven-release-plugin] prepare for next development iteration 2017-03-13 23:15:12 +13:00
Rob Bygrave 0d9f9982b7 [maven-release-plugin] prepare release ebean-10.2.1 2017-03-13 23:15:00 +13:00
Rob Bygrave 7178085680 #993 - ENH: Add flush() to EbeanServer and Model to make it more accessible than the current transaction.flushBatch() - Add Ebean.flush() 2017-03-13 23:13:41 +13:00
Rob Bygrave 4d82b86f81 #993 - ENH: Add flush() to EbeanServer and Model to make it more accessible than the current transaction.flushBatch() 2017-03-13 23:07:17 +13:00
Rob Bygrave 1d99a5c5a4 #992 - API Change - Change Transaction.close() to throw PersistenceException rather than IOException 2017-03-13 22:10:08 +13:00
Rob Bygrave 41a7f2c97e Bump to 10.2.1-SNAPSHOT 2017-03-13 21:11:34 +13:00
Rob Bygrave c8d01828b3 #991 ENH: Add forUpdateNoWait() and forUpdateSkipLocked() options ... #528 ENH: Improve exception handling 2017-03-13 20:50:22 +13:00
Péter CsubákandRob Bygrave a3dbd4538f Wrong cast to query and childid propblem fix (#990) 2017-03-11 12:21:34 +13:00
Rob Bygrave 3051412d90 #989 - ENH: Support @DbArray with Set ... (addition to the existing List support) 2017-03-10 20:50:07 +13:00
Rob Bygrave a22eb555d0 [maven-release-plugin] prepare for next development iteration 2017-03-05 22:44:48 +13:00
Rob Bygrave cb89300027 [maven-release-plugin] prepare release ebean-10.1.7 2017-03-05 22:44:37 +13:00
Rob Bygrave 27cb0d062d Bump ebean-dbmigration to 10.1.4 2017-03-05 22:42:00 +13:00
Rob Bygrave 140c1dd965 #985 - IllegalArgumentException when using @DbArray of type List<String> with @ChangeLog 2017-03-05 11:40:17 +13:00
Rob Bygrave 75b9e748f4 #985 - IllegalArgumentException when using @DbArray of type List<String> with @ChangeLog 2017-03-05 11:40:08 +13:00
Koen De GrooteandRob Bygrave 289c0253b1 Warning suppressions. (#986)
* Went over compilation warnings with Xlint. Only imports for DateMidnight are left, as they cannot receive a suppression annotation.

Not doing this one.

* Doing inline fully qualified path of the deprecated path.
2017-03-05 11:08:45 +13:00
Rob Bygrave 07ce758302 #984 - ENH: DocumentStore API - add RawDoc with findEach() and findEachWhile() 2017-03-02 01:12:02 +13:00
Rob Bygrave d91729f65d #983 - Add credentials configuration support for document store (like basic auth for ElasticSearch) 2017-03-01 22:15:28 +13:00
Rob Bygrave 9e64d09e07 Update maven plugin (with separate testEnhance goal and enhance goal) 2017-03-01 22:07:47 +13:00
Roland PramlandRob Bygrave 5f63d5c35f Fix multi tenant bean change (#982)
* FIX: beanChange has tenant-id

* FIX: NPE in DefaultServer.currentTenantId()
2017-02-26 13:12:26 +13:00
Rob Bygrave 23e1ab4bfd No effective change - imports 2017-02-26 13:10:42 +13:00
Rob Bygrave 0e2900d796 #980 - fix several bugs in findSingleAttibute - Refactor moving logic into DefaultOrmQuery setDefaultSelectClause() from findSingleAttributeList() (to support alternate calling via EbeanServer) 2017-02-26 13:08:10 +13:00
Roland PramlandRob Bygrave a46e086dc4 fix several bugs in findSingleAttibute (#980)
* add test case for distinct on id property

* suggested fix for "select distinct id"

* add test case for distinct with fetch

* FIX: .setDistinct(true) can be used in conjunction with fetch() now

* add test case for distinct with beans that have a disriminator column

* FIX: discriminator column is only read if also Id is read.

* fine tuned the test case

* added test cases for findSingleAttributeList without distinct

* improved fix to support also findSingleAttribute without distinct

* ADD: Bonus test case - assertion not yet verified
2017-02-26 12:37:36 +13:00
Roland PramlandRob Bygrave 40ca179509 FIX: do not hit database if inherited entity has no children (#974)
* FIX: do not hit database if inherited entity has no children

* ADD: Testcase for creating references of inherited beans
2017-02-26 12:25:55 +13:00
Roland PramlandRob Bygrave 7632910027 FIX: potential NPE - manager can be null - eg when creted with new ExternalJdbcTransaction(conn) (#979) 2017-02-24 12:53:35 +13:00
Roland PramlandRob Bygrave ca777d7967 no effective code change: add some try-with resources (#978)
* no effective code change: add some try-with resources

* moved return statement outside try-with-resources, because otherwise the order changes
2017-02-24 12:52:22 +13:00
Roland PramlandRob Bygrave a315c7c11e More small fixes (#977)
* no effecitve code change: add @FunctionalInterface to designated interfaces

* no effective code change: removed obsolete imports

* no effective code change: removed obsolete @SuppressWarnings

* no effective code change: add @SuppressWarnings to UUID_PLACEHOLDER
2017-02-24 08:42:27 +13:00
Rob Bygrave 35f3f53443 No effective change - format and imports only 2017-02-24 00:06:13 +13:00
Roland PramlandRob Bygrave 40f5596837 add missing @override (#975)
* no effective code change: add missing @override in "io.ebean.*" package
* no effective code change: add missing @override in "io.ebeaninternal.api.*" package
* no effective code change: add missing @override in "io.ebeaninternal.server.*" package
* no effective code change: add missing @override in "io.ebeaninternal.util.*" package
* no effective code change: add missing @override in "io.ebeanservice.*" package
* no effective code change: add missing @override in "src/test/java/"
2017-02-24 00:01:25 +13:00
maksym-kitandRob Bygrave 43c978e41a Pass dataType to DataBind for Types.OTHER (#923) 2017-02-23 23:50:43 +13:00
Koen De GrooteandRob Bygrave 6120a465e1 Simple fixes (#976)
* Should be only the really simple stuff.
* Final cleanups.
2017-02-23 23:46:51 +13:00
Rob Bygrave 8bb884374b #970 - FOR UPDATE queries are not honored when beans are already cached 2017-02-21 22:53:14 +13:00
Rob Bygrave 3d8db775f7 #966 - ENH: Add serverConfig.setDbOffline(true) ... for creating new EbeanServer without a DataSource (for DbMigration typically) 2017-02-21 22:04:28 +13:00
Rob Bygrave b3b8f6b154 #973 - Refactor - Tidy internals of DefaultBeanLoader 2017-02-21 21:57:11 +13:00
Rob Bygrave e4c80582a5 [maven-release-plugin] prepare for next development iteration 2017-02-13 22:18:56 +13:00
Rob Bygrave 1846427859 [maven-release-plugin] prepare release ebean-10.1.6 2017-02-13 22:18:44 +13:00
Rob Bygrave 82102340b8 #960 - Incorrect query when using '.betweenProperties' with '@SoftDelete' 2017-02-09 23:43:45 +13:00
Rob Bygrave d9e884b8bd #969 - ENH: Add Finder.query(String ormQuery) ... helper method 2017-02-09 23:27:13 +13:00
Rob Bygrave 6744c7886a #968 - Refactor - Update ANTLR 4 generated code to 4.6 2017-02-09 23:20:33 +13:00
Rob Bygrave 271b4ee095 Modify pom - bump java8-parent to 1.3 2017-02-09 23:12:11 +13:00
Rob Bygrave 7cfdd331ca Merge branch 'master' of github.com:ebean-orm/ebean 2017-02-09 22:37:58 +13:00
Rob Bygrave 7e15faa9a8 #967 - ENH: Add DocStoreConfig.setAllowAllCertificates(true) ... 2017-02-09 22:37:25 +13:00
Roland PramlandRob Bygrave 1292c86b76 removed duplicate StringHelper (#958) 2017-01-31 22:10:45 +13:00
Rob Bygrave 0260a73cb6 #957 - Javadoc update only 2017-01-27 00:36:25 +13:00
Rob Bygrave 085fdaf177 #956 - Bump dependencies - avaje-datasource and ebean-dbmigration 2017-01-26 23:30:58 +13:00
Rob Bygrave a4b49dfa27 No effective change - Fix javadoc issues in Finder 2017-01-12 18:53:34 +13:00
Rob Bygrave d056151852 [maven-release-plugin] prepare for next development iteration 2017-01-12 00:46:22 +13:00
Rob Bygrave f9ba6f9a3a [maven-release-plugin] prepare release ebean-10.1.5 2017-01-12 00:46:11 +13:00
Rob Bygrave 2fa4345742 #945 - Invalid SQL when using @Aggregation with a fetch() to a ManyToOne - missing columns in GROUP BY 2017-01-12 00:42:27 +13:00
Rob Bygrave d9147327c1 #944 - Incorrect join (should be outer join) when predicate only path traverses an optional relationship to a mandatory relationship 2017-01-11 23:21:50 +13:00
Rob Bygrave 5ad9a611f9 #941 - @Transactional( type = TxType.MANDATORY ) creates a new transaction even if there is one available 2017-01-11 22:41:22 +13:00
Rob Bygrave 3fb497b651 No effective change - style, merge ifs 2017-01-11 22:17:29 +13:00
Rob Bygrave fbfe5d1ff8 #943 - Refactor internals - Performance tweak / tidy for WhoCreated, WhoModified on OneToMany connections. #942 2017-01-11 21:42:23 +13:00
Rob Bygrave b6f21f8649 No effective change - refactor merge AnnotationFields initWhoModified() and initWhoCreated() methods 2017-01-11 20:59:11 +13:00
Nagy VilmosandRob Bygrave 8fd04807c7 WhoCreated, WhoModified on OneToMany connections. (#942)
* WhoCreated, WhoModified on OneToMany connections.

* PostgreSQL table name fix in tests.
2017-01-11 20:54:20 +13:00
Rob Bygrave e49c42302a [maven-release-plugin] prepare for next development iteration 2017-01-09 22:39:47 +13:00
Rob Bygrave d96abece75 [maven-release-plugin] prepare release ebean-10.1.4 2017-01-09 22:39:36 +13:00
Rob Bygrave c953da637e Bump ebean-annotation to 2.2 for meta-annotation support on @Formula 2017-01-09 22:37:10 +13:00
Rob Bygrave 8d39b0a996 #940 - Allow findNative to use @Formula properties (add test for MySql := use with RawSql and findNative) 2017-01-09 22:29:15 +13:00
Rob Bygrave 0efcf1eeb3 Merge branch 'master' of github.com:ebean-orm/ebean 2017-01-09 19:40:23 +13:00
Rob Bygrave 335cef870f #939 - Make ModifyAwareSet serializable ... (for serializable entity beans with @DbJson etc) 2017-01-09 19:39:54 +13:00
Michael BenzandRob Bygrave 4c40962f04 MigrationXmlWriter adds DOCTYPE xml to avoid warning of missing external DTD in eclipse IDE. (#937) 2017-01-05 09:16:39 +13:00
Thibault MeyerandRob Bygrave 9be0d22cfb Upgrade provided dependencies (#936)
- javax.validation from 1.0.0.GA to 1.1.0.Final
- servlet-api from 2.4 to javax.servlet-api 3.1.0
- joda-time from 1.6 to 2.9.7
- postgresql from 9.4.1202-jdbc41 to 9.4.1212.jre7
- h2 from 1.4.192 to 1.4.193

Signed-off-by: Thibault Meyer <meyer.thibault@gmail.com>
2017-01-01 19:57:02 +13:00
Thibault MeyerandRob Bygrave 2893d73fad Upgrade test dependencies (#935)
- avaje-agentloader from 2.1.1 to 2.1.2
- avaje-moduuid from 1.2 to 2.1
- commons-io from 2.4 to 2.5
- hsqldb from 2.0.0 to 2.3.4
- mysql-connector-java from 5.1.36 to 6.0.5
- sqlite-jdbc from 3.8.11.2 to 3.15.1

Signed-off-by: Thibault Meyer <meyer.thibault@gmail.com>
2017-01-01 19:55:56 +13:00
Thibault MeyerandRob Bygrave 33d66ea9d1 Upgrade antlr4-runtime to prior version 4.6 (#934)
Signed-off-by: Thibault Meyer <meyer.thibault@gmail.com>
2017-01-01 19:54:25 +13:00
Nagy VilmosandRob Bygrave 073ea9c550 SQL Server boolean mapping fix (#932) 2017-01-01 19:52:57 +13:00
Rob Bygrave 8467934021 [maven-release-plugin] prepare for next development iteration 2016-12-23 16:14:19 +13:00
Rob Bygrave 96ba63407f [maven-release-plugin] prepare release ebean-10.1.3 2016-12-23 16:14:10 +13:00
Rob Bygrave 88df6ffc6e #931 - Refactor internals - DefaultTypeManager ... 2016-12-23 13:33:11 +13:00
Rob Bygrave 3efcfec300 #930 - Refactor (renames etc) for SQL Server History support 2016-12-23 13:18:15 +13:00
Rob BygraveandGitHub e51eb00889 Merge pull request #929 from vilmosnagy/feature/sqlServer2016History
SqlServer 2016 history support.
2016-12-23 13:00:23 +13:00
vilmos.nagy 9ae27ddcdd SqlServer 2016 history support. 2016-12-22 19:22:44 +01:00
Rob Bygrave b9516e64a3 #928 - Pom - change over to io.ebean persistence-api from org.avaje.ebean one. 2016-12-22 23:45:35 +13:00
Rob Bygrave f7f5552bf0 #927 - Pom - bump ebean-dbmigration to 10.1.2 2016-12-22 23:38:18 +13:00
Rob Bygrave adec2ab1b8 #926 - Pom - bump avaje-datasource to 1.1.4 2016-12-22 22:42:24 +13:00
Rob Bygrave da6d7284f8 No effective change - update Readme to maven groupId io.ebean 2016-12-22 00:00:35 +13:00
Rob Bygrave 1c160fea5a No functional change - update enhancement agent to 10.1.2 2016-12-21 23:38:32 +13:00
Rob Bygrave cc87de76d7 [maven-release-plugin] prepare for next development iteration 2016-12-21 00:09:30 +13:00
Rob Bygrave 70b380e6e7 [maven-release-plugin] prepare release ebean-10.1.2 2016-12-21 00:09:19 +13:00
Rob Bygrave 3e419d3e3a No effective change - test ebean.properties back to H2 for default 2016-12-20 21:31:02 +13:00
Rob Bygrave 7e2be20b6e #925 - Change generated SQL for H2, Postgres and MySql to not use column alias' 2016-12-20 21:30:00 +13:00
Rob Bygrave ab2d5fb4c8 No effective change - update test to use trimmed sql (trim out sql column alias to allow it to be optional) 2016-12-20 21:14:12 +13:00
Rob Bygrave 809901ff13 No effective change - update H2 specific test 2016-12-20 21:02:36 +13:00
Rob Bygrave fcc58d77e8 No effective change - update tests using Platform enum rather than name 2016-12-20 20:41:55 +13:00
Rob Bygrave bc93a82b1a #900 - Error - Can't fetch JsonDB field - org.postgresql.util.PSQLException: ERROR: could not identify an equality operator for type json 2016-12-20 03:00:08 +13:00
Rob Bygrave 84e1e12b66 #900 - Error - Can't fetch JsonDB field - org.postgresql.util.PSQLException: ERROR: could not identify an equality operator for type json 2016-12-20 02:59:47 +13:00
Rob Bygrave 2eb0c12213 #924 - Bump ebean-dbmigration dependency to 10.1.1 (sql server fix) 2016-12-19 22:19:53 +13:00
Rob Bygrave 4941134ce1 #922 - NPE Issue with ebean-elastic and multi-tenant Ebean ... NPE at DLoadContext line 96 2016-12-14 00:53:30 +13:00
Rob Bygrave cf37fda3f4 #921 - Refactor internals - Change internal use of "findRowCount" to "findCount" 2016-12-13 19:51:11 +13:00
Rob Bygrave f429811f79 [maven-release-plugin] prepare for next development iteration 2016-12-12 02:10:10 +13:00
1728 changed files with 82253 additions and 26115 deletions
+1
View File
@@ -10,3 +10,4 @@ indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
spaces_around_operators = true
max_line_length = 130
+2 -1
View File
@@ -13,10 +13,11 @@ ebean-profiling*.xml
/db
/mydb.db
!src/test/ddl-review/*.sql
profiling/
# Intellij project files
*.iml
*.ipr
*.iws
.idea/
*uuid.state
+13 -1
View File
@@ -1,3 +1,4 @@
dist: trusty
sudo: required
language: java
jdk:
@@ -7,17 +8,28 @@ git:
depth: 3
addons:
postgresql: "9.4"
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
+298
View File
@@ -0,0 +1,298 @@
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
+4 -4
View File
@@ -6,12 +6,12 @@ Goto [https://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Web
## Maven cental links:
[Maven central - ebean](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.avaje.ebean%22%20AND%20a%3A%22ebean%22 "maven central ebean")
[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/org.avaje.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/org.avaje.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/org.avaje.ebean/ebean-maven-plugin/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-maven-plugin) - ebean-maven-plugin
* [![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
+153
View File
@@ -0,0 +1,153 @@
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
+133 -61
View File
@@ -4,100 +4,153 @@
<parent>
<groupId>org.avaje</groupId>
<artifactId>java8-parent</artifactId>
<version>1.1</version>
<version>1.3</version>
</parent>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>10.1.1</version>
<version>11.15.2</version>
<packaging>jar</packaging>
<name>ebean</name>
<url>http://ebean-orm.github.io/</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-10.1.1</tag>
<tag>ebean-11.15.2</tag>
</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.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>13.0</version>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
<scope>provided</scope>
</dependency>
<!--
Exclude snakeyaml if you desire - it is not strictly required.
-->
<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>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.avaje.ebean</groupId>
<groupId>io.ebean</groupId>
<artifactId>persistence-api</artifactId>
<version>2.1.3</version>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-annotation</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.avaje</groupId>
<artifactId>avaje-datasource-api</artifactId>
<version>1.1</version>
<version>3.11</version>
</dependency>
<dependency>
<groupId>org.avaje</groupId>
<artifactId>avaje-datasource</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>org.avaje</groupId>
<artifactId>avaje-classpath-scanner-api</artifactId>
<version>2.2</version>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.avaje</groupId>
<artifactId>avaje-classpath-scanner</artifactId>
<version>2.2.2</version>
<version>3.1.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-dbmigration</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>[1.7.1,1.7.99)</version>
<artifactId>ebean-migration</artifactId>
<version>11.5.1</version>
</dependency>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4-runtime</artifactId>
<version>4.5.3</version>
<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.6.5</version>
<version>2.9.0</version>
</dependency>
<!-- provided scope for JsonNode support -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.6.5</version>
<version>2.9.0</version>
<scope>provided</scope>
</dependency>
@@ -112,21 +165,21 @@
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.0.0.GA</version>
<version>1.1.0.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.4</version>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>1.6</version>
<version>2.9.7</version>
<scope>provided</scope>
</dependency>
@@ -134,7 +187,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4-1202-jdbc41</version>
<version>9.4.1212</version>
<scope>provided</scope>
</dependency>
@@ -147,24 +200,31 @@
<!--<scope>test</scope>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>microsoft</groupId>-->
<!--<artifactId>sqlserver-jdbc</artifactId>-->
<!--<version>4.2</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>
<dependency>
<groupId>org.avaje</groupId>
<artifactId>avaje-agentloader</artifactId>
<version>1.1.1</version>
<version>2.1.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-agent</artifactId>
<version>10.1.1</version>
<version>11.11.1</version>
<scope>test</scope>
</dependency>
@@ -173,28 +233,36 @@
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.192</version>
<version>1.4.196</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.8.11.2</version>
<version>3.15.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.0.0</version>
<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>
<version>5.1.36</version>
<!-- Do not upgrade to 6.0.6: https://bugs.mysql.com/bug.php?id=82896 -->
<version>5.1.43</version>
<scope>test</scope>
</dependency>
@@ -209,14 +277,14 @@
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
<version>2.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.avaje.moduuid</groupId>
<artifactId>avaje-moduuid</artifactId>
<version>1.2</version>
<version>2.1</version>
<scope>test</scope>
</dependency>
@@ -229,17 +297,16 @@
<plugin>
<groupId>io.ebean</groupId>
<artifactId>ebean-maven-plugin</artifactId>
<version>10.1.1</version>
<version>11.11.1</version>
<executions>
<execution>
<id>test</id>
<phase>process-test-classes</phase>
<configuration>
<classSource>target/test-classes</classSource>
<transformArgs>debug=1</transformArgs>
</configuration>
<goals>
<goal>enhance</goal>
<goal>testEnhance</goal>
</goals>
</execution>
</executions>
@@ -263,6 +330,11 @@
<name>datasource.default</name>
<value>${datasource.default}</value>
</property>
<property>
<!-- transfer dbClockDelta parameter -->
<name>dbClockDelta</name>
<value>${dbClockDelta}</value>
</property>
</systemProperties>
</configuration>
</plugin>
@@ -287,7 +359,7 @@
<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:io.ebean.dbmigration.ddlgeneration:io.ebean.dbmigration.migration:io.ebean.dbmigration.migrationreader:io.ebean.dbmigration.model</excludePackageNames>
<excludePackageNames>io.ebeaninternal.*:com.avaje.ebean.util</excludePackageNames>
<docletArtifact>
<groupId>org.avaje</groupId>
<artifactId>pygments-doclet</artifactId>
@@ -0,0 +1,21 @@
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);
}
}
+169
View File
@@ -0,0 +1,169 @@
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
@@ -0,0 +1,178 @@
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);
}
}
-11
View File
@@ -1,6 +1,5 @@
package io.ebean;
import java.beans.PropertyChangeListener;
import java.util.Map;
import java.util.Set;
@@ -99,16 +98,6 @@ public interface BeanState {
*/
void setReadOnly(boolean readOnly);
/**
* Add a propertyChangeListener.
*/
void addPropertyChangeListener(PropertyChangeListener listener);
/**
* Remove a propertyChangeListener.
*/
void removePropertyChangeListener(PropertyChangeListener listener);
/**
* Advanced - Used to programmatically build a partially or fully loaded
* entity bean. First create an entity bean via
+93
View File
@@ -0,0 +1,93 @@
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;
}
}
@@ -0,0 +1,27 @@
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
@@ -0,0 +1,33 @@
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;
}
}
@@ -0,0 +1,17 @@
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);
}
}
+25 -9
View File
@@ -1,7 +1,8 @@
package io.ebean;
import io.ebeanservice.docstore.api.DocQueryRequest;
import org.jetbrains.annotations.Nullable;
import io.ebeanservice.docstore.api.RawDoc;
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.List;
@@ -55,7 +56,7 @@ public interface DocumentStore {
* 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 findUnique() on the query.
* Typically this is called indirectly by findOne() on the query.
* </p>
* <pre>{@code
*
@@ -63,7 +64,7 @@ public interface DocumentStore {
* server.find(Customer.class)
* .setUseDocStore(true)
* .setId(42)
* .findUnique();
* .findOne();
*
* }</pre>
*/
@@ -122,11 +123,8 @@ public interface DocumentStore {
* server.find(Order.class)
* .setUseDocStore(true)
* .where()... // perhaps add predicates
* .findEach(new QueryEachConsumer<Order>() {
* @Override
* public void accept(Order bean) {
* // process the bean
* }
* .findEach((Order order) -> {
* // process the bean ...
* });
*
* }</pre>
@@ -150,7 +148,7 @@ public interface DocumentStore {
* server.find(Order.class)
* .setUseDocStore(true)
* .where()... // perhaps add predicates
* .findEachWhile(new QueryEachWhileConsumer<Order>() {
* .findEachWhile(new Predicate<Order>() {
* @Override
* public void accept(Order bean) {
* // process the bean
@@ -165,6 +163,24 @@ public interface DocumentStore {
*/
<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.
*/
+133
View File
@@ -0,0 +1,133 @@
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);
}
@@ -0,0 +1,15 @@
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);
}
}
+141 -36
View File
@@ -1,19 +1,24 @@
package io.ebean;
import io.ebean.annotation.TxIsolation;
import io.ebean.cache.ServerCacheManager;
import io.ebean.config.ServerConfig;
import io.ebean.plugin.Property;
import io.ebean.text.csv.CsvReader;
import io.ebean.text.json.JsonContext;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -112,6 +117,10 @@ import java.util.concurrent.ConcurrentHashMap;
public final class Ebean {
private static final Logger logger = LoggerFactory.getLogger(Ebean.class);
static {
EbeanVersion.getVersion(); // initalizes the version class and logs the version.
}
/**
* Manages creation and cache of EbeanServers.
*/
@@ -129,8 +138,7 @@ public final class Ebean {
private final ConcurrentHashMap<String, EbeanServer> concMap = new ConcurrentHashMap<>();
/**
* Cache for synchronized read, creation and put. Protected by the monitor
* object.
* Cache for synchronized read, creation and put. Protected by the monitor object.
*/
private final HashMap<String, EbeanServer> syncMap = new HashMap<>();
@@ -144,17 +152,10 @@ public final class Ebean {
private ServerManager() {
try {
// skipDefaultServer is set by EbeanServerFactory
// ... when it is creating the primaryServer
if (PrimaryServer.isSkip()) {
// primary server being created by EbeanServerFactory
// ... so we should not try and create it here
logger.debug("PrimaryServer.isSkip()");
} else {
if (!PrimaryServer.isSkip()) {
// look to see if there is a default server defined
String defaultName = PrimaryServer.getDefaultServerName();
logger.debug("defaultName:" + defaultName);
logger.debug("defaultName:{}", defaultName);
if (defaultName != null && !defaultName.trim().isEmpty()) {
defaultServer = getWithCreate(defaultName.trim());
}
@@ -289,7 +290,7 @@ public final class Ebean {
}
/**
* Backdoor for registering a mock implementation of EbeanServer as the default server.
* Backdoor for registering a mock implementation of EbeanServer as the default server.
*/
protected static EbeanServer mock(String name, EbeanServer server, boolean defaultServer) {
EbeanServer originalPrimaryServer = serverMgr.defaultServer;
@@ -371,9 +372,10 @@ public final class Ebean {
/**
* Start a transaction typically specifying REQUIRES_NEW or REQUIRED semantics.
* <p>
* Note that this provides an try finally alternative to using {@link #execute(TxScope, TxCallable)} or
* {@link #execute(TxScope, TxRunnable)}.
* Note that this provides an try finally alternative to using {@link #executeCall(TxScope, Callable)} or
* {@link #execute(TxScope, Runnable)}.
* </p>
* <p>
* <h3>REQUIRES_NEW example:</h3>
* <pre>{@code
* // Start a new transaction. If there is a current transaction
@@ -428,6 +430,24 @@ public final class Ebean {
return serverMgr.getDefaultServer().currentTransaction();
}
/**
* 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>
*/
public static void flush() {
currentTransaction().flush();
}
/**
* Register a TransactionCallback on the currently active transaction.
* <p/>
@@ -618,6 +638,16 @@ public final class Ebean {
serverMgr.getDefaultServer().updateAll(beans);
}
/**
* Merge the bean using the given merge options.
*
* @param bean The bean to merge
* @param options The options to control the merge
*/
public static void merge(Object bean, MergeOptions options) {
serverMgr.getDefaultServer().merge(bean, options);
}
/**
* Save all the beans from a Collection.
*/
@@ -625,6 +655,65 @@ public final class Ebean {
return serverMgr.getDefaultServer().saveAll(beans);
}
/**
* This method checks the uniqueness of a bean. I.e. if the save will work. It will return the
* properties that violates an unique / primary key. This may be done in an UI save action to
* validate if the user has entered correct values.
* <p>
* Note: This method queries the DB for uniqueness of all indices, so do not use it in a batch update.
* <p>
* Note: This checks only the root bean!
* <p>
* <pre>{@code
*
* // there is a unique constraint on title
*
* Document doc = new Document();
* doc.setTitle("One flew over the cuckoo's nest");
* doc.setBody("clashes with doc1");
*
* Set<Property> properties = server().checkUniqueness(doc);
*
* if (properties.isEmpty()) {
* // it is unique ... carry on
*
* } else {
* // build a user friendly message
* // to return message back to user
*
* String uniqueProperties = properties.toString();
*
* StringBuilder msg = new StringBuilder();
*
* properties.forEach((it)-> {
* Object propertyValue = it.getVal(doc);
* String propertyName = it.getName();
* msg.append(" property["+propertyName+"] value["+propertyValue+"]");
* });
*
* // uniqueProperties > [title]
* // custom msg > property[title] value[One flew over the cuckoo's nest]
*
* }
*
* }</pre>
*
* @param bean The entity bean to check uniqueness on
* @return a set of Properties if constraint validation was detected or empty list.
*/
@Nonnull
public static Set<Property> checkUniqueness(Object bean) {
return serverMgr.getDefaultServer().checkUniqueness(bean);
}
/**
* Same as {@link #checkUniqueness(Object)}. but with given transaction.
*/
@Nonnull
public static Set<Property> checkUniqueness(Object bean, Transaction transaction) {
return serverMgr.getDefaultServer().checkUniqueness(bean, transaction);
}
/**
* Delete the bean.
* <p>
@@ -804,7 +893,7 @@ public final class Ebean {
* }</pre>
* <p>
* If you want more control over the query then you can use createQuery() and
* Query.findUnique();
* Query.findOne();
* </p>
* <pre>{@code
*
@@ -825,7 +914,8 @@ public final class Ebean {
*
* // traverse the object graph...
*
* Order order = query.findUnique();
* Order order = query.findOne();
*
* Customer customer = order.getCustomer();
* Address shippingAddress = customer.getShippingAddress();
* List<OrderDetail> details = order.getDetails();
@@ -941,7 +1031,7 @@ public final class Ebean {
* predicates, order by, limits etc.
* </p>
* <p>
* You then use findList(), findSet(), findMap() and findUnique() to execute
* You then use findList(), findSet(), findMap() and findOne() to execute
* the query and return the collection or bean.
* </p>
* <p>
@@ -973,7 +1063,7 @@ public final class Ebean {
* Query<Order> query = Ebean.createQuery(Order.class, eql);
* query.setParameter("orderId", 2);
*
* Order order = query.findUnique();
* Order order = query.findOne();
*
* // This is the same as:
*
@@ -982,7 +1072,7 @@ public final class Ebean {
* .fetch("details")
* .fetch("detail.product", "name")
* .setId(2)
* .findUnique();
* .findOne();
*
* }</pre>
*
@@ -1036,6 +1126,21 @@ public final class Ebean {
return serverMgr.getDefaultServer().findNative(beanType, nativeSql);
}
/**
* Create a Query for DTO beans.
* <p>
* DTO beans are just normal bean like classes with public constructor(s) and setters.
* They do not need to be registered with Ebean before use.
* </p>
*
* @param dtoType The type of the DTO bean the rows will be mapped into.
* @param sql The SQL query to execute.
* @param <T> The type of the DTO bean.
*/
public static <T> DtoQuery<T> findDto(Class<T> dtoType, String sql) {
return serverMgr.getDefaultServer().findDto(dtoType, sql);
}
/**
* Create an Update query to perform a bulk update.
* <p>
@@ -1163,20 +1268,20 @@ public final class Ebean {
*
* }</pre>
*/
public static void execute(TxScope scope, TxRunnable r) {
public static void execute(TxScope scope, Runnable r) {
serverMgr.getDefaultServer().execute(scope, r);
}
/**
* Execute a TxRunnable in a Transaction with the default scope.
* Execute a Runnable in a Transaction with the default scope.
* <p>
* The default scope runs with REQUIRED and by default will rollback on any
* exception (checked or runtime).
* </p>
* <pre>{@code
*
* Ebean.execute(new TxRunnable() {
* public void run() {
* Ebean.execute(() -> {
*
* User u1 = Ebean.find(User.class, 1);
* User u2 = Ebean.find(User.class, 2);
*
@@ -1185,17 +1290,17 @@ public final class Ebean {
*
* Ebean.save(u1);
* Ebean.save(u2);
* }
*
* });
*
* }</pre>
*/
public static void execute(TxRunnable r) {
public static void execute(Runnable r) {
serverMgr.getDefaultServer().execute(r);
}
/**
* Execute a TxCallable in a Transaction with an explicit scope.
* Execute a Callable in a Transaction with an explicit scope.
* <p>
* The scope can control the transaction type, isolation and rollback
* semantics.
@@ -1205,7 +1310,7 @@ public final class Ebean {
* // set specific transactional scope settings
* TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
*
* Ebean.execute(scope, new TxCallable<String>() {
* Ebean.executeCall(scope, new Callable<String>() {
* public String call() {
* User u1 = Ebean.find(User.class, 1);
* ...
@@ -1215,12 +1320,12 @@ public final class Ebean {
*
* }</pre>
*/
public static <T> T execute(TxScope scope, TxCallable<T> c) {
return serverMgr.getDefaultServer().execute(scope, c);
public static <T> T executeCall(TxScope scope, Callable<T> c) {
return serverMgr.getDefaultServer().executeCall(scope, c);
}
/**
* Execute a TxCallable in a Transaction with the default scope.
* Execute a Callable in a Transaction with the default scope.
* <p>
* The default scope runs with REQUIRED and by default will rollback on any
* exception (checked or runtime).
@@ -1231,8 +1336,8 @@ public final class Ebean {
* </p>
* <pre>{@code
*
* Ebean.execute(new TxCallable<String>() {
* public String call() {
* Ebean.executeCall(() -> {
*
* User u1 = Ebean.find(User.class, 1);
* User u2 = Ebean.find(User.class, 2);
*
@@ -1243,13 +1348,13 @@ public final class Ebean {
* Ebean.save(u2);
*
* return u1.getEmail();
* }
*
* });
*
* }</pre>
*/
public static <T> T execute(TxCallable<T> c) {
return serverMgr.getDefaultServer().execute(c);
public static <T> T executeCall(Callable<T> c) {
return serverMgr.getDefaultServer().executeCall(c);
}
/**
+193 -62
View File
@@ -1,20 +1,25 @@
package io.ebean;
import io.ebean.annotation.TxIsolation;
import io.ebean.cache.ServerCacheManager;
import io.ebean.config.ServerConfig;
import io.ebean.meta.MetaInfoManager;
import io.ebean.plugin.Property;
import io.ebean.plugin.SpiServer;
import io.ebean.text.csv.CsvReader;
import io.ebean.text.json.JsonContext;
import org.jetbrains.annotations.Nullable;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.NonUniqueResultException;
import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -232,12 +237,12 @@ public interface EbeanServer {
*
* // Find order additionally fetching the customer, details and details.product name.
*
* String eql = "fetch customer fetch details fetch details.product (name) where id = :orderId ";
* String ormQuery = "fetch customer fetch details fetch details.product (name) where id = :orderId ";
*
* Query<Order> query = Ebean.createQuery(Order.class, eql);
* Query<Order> query = Ebean.createQuery(Order.class, ormQuery);
* query.setParameter("orderId", 2);
*
* Order order = query.findUnique();
* Order order = query.findOne();
*
* // This is the same as:
*
@@ -246,16 +251,16 @@ public interface EbeanServer {
* .fetch("details")
* .fetch("detail.product", "name")
* .setId(2)
* .findUnique();
* .findOne();
*
* }</pre>
*
* @param beanType The type of bean to fetch
* @param eql The Ebean query
* @param ormQuery The Ebean ORM query
* @param <T> The type of the entity bean
* @return The query with expressions defined as per the parsed query statement
*/
<T> Query<T> createQuery(Class<T> beanType, String eql);
<T> Query<T> createQuery(Class<T> beanType, String ormQuery);
/**
* Create a query for a type of entity bean.
@@ -264,7 +269,7 @@ public interface EbeanServer {
* predicates, order by, limits etc.
* </p>
* <p>
* You then use findList(), findSet(), findMap() and findUnique() to execute
* You then use findList(), findSet(), findMap() and findOne() to execute
* the query and return the collection or bean.
* </p>
* <p>
@@ -284,7 +289,7 @@ public interface EbeanServer {
* .fetch("details")
* .fetch("detail.product", "name")
* .setId(2)
* .findUnique();
* .findOne();
*
* // find some new orders ... with firstRow/maxRows
* List<Order> orders =
@@ -419,6 +424,32 @@ public interface EbeanServer {
*/
<T> Update<T> createUpdate(Class<T> beanType, String ormUpdate);
/**
* Create a Query for DTO beans.
* <p>
* DTO beans are just normal bean like classes with public constructor(s) and setters.
* They do not need to be registered with Ebean before use.
* </p>
*
* @param dtoType The type of the DTO bean the rows will be mapped into.
* @param sql The SQL query to execute.
* @param <T> The type of the DTO bean.
*/
<T> DtoQuery<T> findDto(Class<T> dtoType, String sql);
/**
* Create a named Query for DTO beans.
* <p>
* DTO beans are just normal bean like classes with public constructor(s) and setters.
* They do not need to be registered with Ebean before use.
* </p>
*
* @param dtoType The type of the DTO bean the rows will be mapped into.
* @param namedQuery The name of the query
* @param <T> The type of the DTO bean.
*/
<T> DtoQuery<T> createNamedDtoQuery(Class<T> dtoType, String namedQuery);
/**
* Create a SqlQuery for executing native sql
* query statements.
@@ -490,30 +521,44 @@ public interface EbeanServer {
* etc.
* </p>
* <p>
* <h3>Using try with resources</h3>
* <pre>{@code
*
* // start a transaction (stored in a ThreadLocal)
* ebeanServer.beginTransaction();
*
* try (Transaction txn = ebeanServer.beginTransaction()) {
*
* Order order = ebeanServer.find(Order.class,10);
* ...
* ebeanServer.save(order);
*
* txn.commit();
* }
*
* }</pre>
* <p>
* <h3>Using try finally block</h3>
* <pre>{@code
*
* // start a transaction (stored in a ThreadLocal)
* Transaction txn = ebeanServer.beginTransaction();
* try {
* Order order = ebeanServer.find(Order.class,10);
*
* ebeanServer.save(order);
*
* ebeanServer.commitTransaction();
* txn.commit();
*
* } finally {
* // rollback if we didn't commit
* // i.e. an exception occurred before commitTransaction().
* ebeanServer.endTransaction();
* txn.end();
* }
*
* }</pre>
* <p>
* <h3>Transaction options:</h3>
* <h3>Transaction options</h3>
* <pre>{@code
*
* Transaction txn = ebeanServer.beginTransaction();
* try {
* try (Transaction txn = ebeanServer.beginTransaction()) {
* // explicitly turn on/off JDBC batch use
* txn.setBatchMode(true);
* txn.setBatchSize(50);
@@ -534,10 +579,6 @@ public interface EbeanServer {
* ...
*
* txn.commit();
*
* } finally {
* // rollback if necessary
* txn.end();
* }
*
* }</pre>
@@ -559,27 +600,24 @@ public interface EbeanServer {
* Start a transaction typically specifying REQUIRES_NEW or REQUIRED semantics.
* <p>
* <p>
* Note that this provides an try finally alternative to using {@link #execute(TxScope, TxCallable)} or
* {@link #execute(TxScope, TxRunnable)}.
* Note that this provides an try finally alternative to using {@link #executeCall(TxScope, Callable)} or
* {@link #execute(TxScope, Runnable)}.
* </p>
* <p>
* <h3>REQUIRES_NEW example:</h3>
* <pre>{@code
* // Start a new transaction. If there is a current transaction
* // suspend it until this transaction ends
* Transaction txn = server.beginTransaction(TxScope.requiresNew());
* try {
* try (Transaction txn = server.beginTransaction(TxScope.requiresNew())) {
*
* ...
*
* // commit the transaction
* txn.commit();
*
* } finally {
* // end this transaction which:
* // A) will rollback transaction if it has not been committed already
* // At end this transaction will:
* // A) will rollback transaction if it has not been committed
* // B) will restore a previously suspended transaction
* txn.end();
* }
*
* }</pre>
@@ -588,20 +626,13 @@ public interface EbeanServer {
* <pre>{@code
*
* // start a new transaction if there is not a current transaction
* Transaction txn = server.beginTransaction(TxScope.required());
* try {
* try (Transaction txn = server.beginTransaction(TxScope.required())) {
*
* ...
*
* // commit the transaction if it was created or
* // do nothing if there was already a current transaction
* txn.commit();
*
* } finally {
* // end this transaction which will rollback the transaction
* // if it was created for this try finally scope and has not
* // already been committed
* txn.end();
* }
*
* }</pre>
@@ -613,6 +644,19 @@ public interface EbeanServer {
*/
Transaction currentTransaction();
/**
* Flush the JDBC batch on the current transaction.
* <p>
* This only is useful when JDBC batch is used. Flush occurs automatically when the
* transaction commits or batch size is reached. This manually flushes the JDBC batch
* buffer.
* </p>
* <p>
* This is the same as <code>currentTransaction().flush()</code>.
* </p>
*/
void flush();
/**
* Commit the current transaction.
*/
@@ -680,7 +724,7 @@ public interface EbeanServer {
* <p>
* <p>
* If you want more control over the query then you can use createQuery() and
* Query.findUnique();
* Query.findOne();
* </p>
* <p>
* <pre>{@code
@@ -700,7 +744,7 @@ public interface EbeanServer {
* query.fetch("details.product", "name");
*
*
* Order order = query.findUnique();
* Order order = query.findOne();
*
* // traverse the object graph...
*
@@ -716,6 +760,7 @@ public interface EbeanServer {
* @param beanType the type of entity bean to fetch
* @param id the id value
*/
@Nullable
<T> T find(Class<T> beanType, Object id);
/**
@@ -759,6 +804,7 @@ public interface EbeanServer {
* @param beanType the type of entity bean
* @param id the id value
*/
@Nonnull
<T> T getReference(Class<T> beanType, Object id);
/**
@@ -774,6 +820,7 @@ public interface EbeanServer {
*
* @see Query#findIds()
*/
@Nonnull
<A, T> List<A> findIds(Query<T> query, Transaction transaction);
/**
@@ -793,6 +840,7 @@ public interface EbeanServer {
* @see Query#findEach(Consumer)
* @see Query#findEachWhile(Predicate)
*/
@Nonnull
<T> QueryIterator<T> findIterate(Query<T> query, Transaction transaction);
/**
@@ -829,7 +877,7 @@ public interface EbeanServer {
* Execute the query visiting the each bean one at a time.
* <p>
* Compared to findEach() this provides the ability to stop processing the query
* results early by returning false for the QueryEachWhileConsumer.
* results early by returning false for the Predicate.
* </p>
* <p>
* Unlike findList() this is suitable for processing a query that will return
@@ -869,6 +917,7 @@ public interface EbeanServer {
* It will execute the query against the history returning the versions of the bean.
* </p>
*/
@Nonnull
<T> List<Version<T>> findVersions(Query<T> query, Transaction transaction);
/**
@@ -894,6 +943,7 @@ public interface EbeanServer {
* @return the list of fetched beans.
* @see Query#findList()
*/
@Nonnull
<T> List<T> findList(Query<T> query, Transaction transaction);
/**
@@ -909,6 +959,7 @@ public interface EbeanServer {
* @return a Future object for the row count query
* @see Query#findFutureCount()
*/
@Nonnull
<T> FutureRowCount<T> findFutureCount(Query<T> query, Transaction transaction);
/**
@@ -924,6 +975,7 @@ public interface EbeanServer {
* @return a Future object for the list of Id's
* @see Query#findFutureIds()
*/
@Nonnull
<T> FutureIds<T> findFutureIds(Query<T> query, Transaction transaction);
/**
@@ -940,6 +992,7 @@ public interface EbeanServer {
* @return a Future object for the list result of the query
* @see Query#findFutureList()
*/
@Nonnull
<T> FutureList<T> findFutureList(Query<T> query, Transaction transaction);
/**
@@ -971,6 +1024,7 @@ public interface EbeanServer {
* @return The PagedList
* @see Query#findPagedList()
*/
@Nonnull
<T> PagedList<T> findPagedList(Query<T> query, Transaction transaction);
/**
@@ -996,6 +1050,7 @@ public interface EbeanServer {
* @return the set of fetched beans.
* @see Query#findSet()
*/
@Nonnull
<T> Set<T> findSet(Query<T> query, Transaction transaction);
/**
@@ -1012,6 +1067,7 @@ public interface EbeanServer {
* @return the map of fetched beans.
* @see Query#findMap()
*/
@Nonnull
<K, T> Map<K, T> findMap(Query<T> query, Transaction transaction);
/**
@@ -1044,6 +1100,7 @@ public interface EbeanServer {
* @return the list of values for the selected property
* @see Query#findSingleAttributeList()
*/
@Nonnull
<A, T> List<A> findSingleAttributeList(Query<T> query, Transaction transaction);
/**
@@ -1053,7 +1110,7 @@ public interface EbeanServer {
* This will throw a NonUniqueResultException if the query finds more than one result.
* </p>
* <p>
* Generally you are able to use {@link Query#findUnique()} rather than
* Generally you are able to use {@link Query#findOne()} rather than
* explicitly calling this method. You could use this method if you wish to
* explicitly control the transaction used for the query.
* </p>
@@ -1063,10 +1120,16 @@ public interface EbeanServer {
* @param transaction the transaction to use (can be null).
* @return the list of fetched beans.
* @throws NonUniqueResultException if more than one result was found
* @see Query#findUnique()
* @see Query#findOne()
*/
@Nullable
<T> T findUnique(Query<T> query, Transaction transaction);
<T> T findOne(Query<T> query, Transaction transaction);
/**
* Similar to findOne() but returns an Optional (rather than nullable).
*/
@Nonnull
<T> Optional<T> findOneOrEmpty(Query<T> query, Transaction transaction);
/**
* Execute as a delete query deleting the 'root level' beans that match the predicates
@@ -1109,6 +1172,7 @@ public interface EbeanServer {
* @return the list of fetched MapBean.
* @see SqlQuery#findList()
*/
@Nonnull
List<SqlRow> findList(SqlQuery query, Transaction transaction);
/**
@@ -1137,7 +1201,7 @@ public interface EbeanServer {
* result.
* </p>
* <p>
* Generally you are able to use {@link SqlQuery#findUnique()} rather than
* Generally you are able to use {@link SqlQuery#findOne()} rather than
* explicitly calling this method. You could use this method if you wish to
* explicitly control the transaction used for the query.
* </p>
@@ -1145,10 +1209,10 @@ public interface EbeanServer {
* @param query the query to execute.
* @param transaction the transaction to use (can be null).
* @return the fetched MapBean or null if none was found.
* @see SqlQuery#findUnique()
* @see SqlQuery#findOne()
*/
@Nullable
SqlRow findUnique(SqlQuery query, Transaction transaction);
SqlRow findOne(SqlQuery query, Transaction transaction);
/**
* Either Insert or Update the bean depending on its state.
@@ -1423,6 +1487,61 @@ public interface EbeanServer {
*/
int saveAll(Collection<?> beans, Transaction transaction) throws OptimisticLockException;
/**
* This method checks the uniqueness of a bean. I.e. if the save will work. It will return the
* properties that violates an unique / primary key. This may be done in an UI save action to
* validate if the user has entered correct values.
* <p>
* Note: This method queries the DB for uniqueness of all indices, so do not use it in a batch update.
* <p>
* Note: This checks only the root bean!
* <p>
* <pre>{@code
*
* // there is a unique constraint on title
*
* Document doc = new Document();
* doc.setTitle("One flew over the cuckoo's nest");
* doc.setBody("clashes with doc1");
*
* Set<Property> properties = server().checkUniqueness(doc);
*
* if (properties.isEmpty()) {
* // it is unique ... carry on
*
* } else {
* // build a user friendly message
* // to return message back to user
*
* String uniqueProperties = properties.toString();
*
* StringBuilder msg = new StringBuilder();
*
* properties.forEach((it)-> {
* Object propertyValue = it.getVal(doc);
* String propertyName = it.getName();
* msg.append(" property["+propertyName+"] value["+propertyValue+"]");
* });
*
* // uniqueProperties > [title]
* // custom msg > property[title] value[One flew over the cuckoo's nest]
*
* }
*
* }</pre>
*
* @param bean The entity bean to check uniqueness on
* @return a set of Properties if constraint validation was detected or empty list.
*/
@Nonnull
Set<Property> checkUniqueness(Object bean);
/**
* Same as {@link #checkUniqueness(Object)}. but with given transaction.
*/
@Nonnull
Set<Property> checkUniqueness(Object bean, Transaction transaction);
/**
* Marks the entity bean as dirty.
* <p>
@@ -1509,6 +1628,22 @@ public interface EbeanServer {
*/
void updateAll(Collection<?> beans, Transaction transaction) throws OptimisticLockException;
/**
* Merge the bean using the given merge options.
*
* @param bean The bean to merge
* @param options The options to control the merge
*/
void merge(Object bean, MergeOptions options);
/**
* Merge the bean using the given merge options and a transaction.
*
* @param bean The bean to merge
* @param options The options to control the merge
*/
void merge(Object bean, MergeOptions options, Transaction transaction);
/**
* Insert the bean.
* <p>
@@ -1546,7 +1681,7 @@ public interface EbeanServer {
int execute(CallableSql callableSql, Transaction transaction);
/**
* Execute a TxRunnable in a Transaction with an explicit scope.
* Execute a Runnable in a Transaction with an explicit scope.
* <p>
* The scope can control the transaction type, isolation and rollback
* semantics.
@@ -1557,7 +1692,7 @@ public interface EbeanServer {
* // set specific transactional scope settings
* TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
*
* ebeanServer.execute(scope, new TxRunnable() {
* ebeanServer.execute(scope, new Runnable() {
* public void run() {
* User u1 = Ebean.find(User.class, 1);
* ...
@@ -1566,10 +1701,10 @@ public interface EbeanServer {
*
* }</pre>
*/
void execute(TxScope scope, TxRunnable runnable);
void execute(TxScope scope, Runnable runnable);
/**
* Execute a TxRunnable in a Transaction with the default scope.
* Execute a Runnable in a Transaction with the default scope.
* <p>
* The default scope runs with REQUIRED and by default will rollback on any
* exception (checked or runtime).
@@ -1577,8 +1712,8 @@ public interface EbeanServer {
* <p>
* <pre>{@code
*
* ebeanServer.execute(new TxRunnable() {
* public void run() {
* ebeanServer.execute(() -> {
*
* User u1 = ebeanServer.find(User.class, 1);
* User u2 = ebeanServer.find(User.class, 2);
*
@@ -1587,12 +1722,12 @@ public interface EbeanServer {
*
* ebeanServer.save(u1);
* ebeanServer.save(u2);
* }
*
* });
*
* }</pre>
*/
void execute(TxRunnable runnable);
void execute(Runnable runnable);
/**
* Execute a TxCallable in a Transaction with an explicit scope.
@@ -1606,7 +1741,7 @@ public interface EbeanServer {
* // set specific transactional scope settings
* TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
*
* ebeanServer.execute(scope, new TxCallable<String>() {
* ebeanServer.executeCall(scope, new Callable<String>() {
* public String call() {
* User u1 = ebeanServer.find(User.class, 1);
* ...
@@ -1616,7 +1751,7 @@ public interface EbeanServer {
*
* }</pre>
*/
<T> T execute(TxScope scope, TxCallable<T> callable);
<T> T executeCall(TxScope scope, Callable<T> callable);
/**
* Execute a TxCallable in a Transaction with the default scope.
@@ -1625,13 +1760,9 @@ public interface EbeanServer {
* exception (checked or runtime).
* </p>
* <p>
* This is basically the same as TxRunnable except that it returns an Object
* (and you specify the return type via generics).
* </p>
* <p>
* <pre>{@code
*
* ebeanServer.execute(new TxCallable<String>() {
* ebeanServer.executeCall(new Callable<String>() {
* public String call() {
* User u1 = ebeanServer.find(User.class, 1);
* User u2 = ebeanServer.find(User.class, 2);
@@ -1648,7 +1779,7 @@ public interface EbeanServer {
*
* }</pre>
*/
<T> T execute(TxCallable<T> callable);
<T> T executeCall(Callable<T> callable);
/**
* Return the manager of the server cache ("L2" cache).
+14 -17
View File
@@ -1,13 +1,14 @@
package io.ebean;
import io.ebean.common.SpiContainer;
import io.ebean.config.ContainerConfig;
import io.ebean.config.ServerConfig;
import io.ebeaninternal.server.lib.ShutdownManager;
import io.ebean.service.SpiContainer;
import io.ebean.service.SpiContainerFactory;
import javax.persistence.PersistenceException;
import java.lang.reflect.Constructor;
import java.util.Iterator;
import java.util.Properties;
import java.util.ServiceLoader;
/**
* Creates EbeanServer instances.
@@ -30,10 +31,12 @@ import java.util.Properties;
public class EbeanServerFactory {
private static final String DEFAULT_CONTAINER = "io.ebeaninternal.server.core.DefaultContainer";
private static SpiContainer container;
static {
EbeanVersion.getVersion(); // initalizes the version class and logs the version.
}
/**
* Initialise the container with clustering configuration.
* <p>
@@ -66,10 +69,8 @@ public class EbeanServerFactory {
EbeanServer server = createInternal(config);
if (config.isDefaultServer()) {
PrimaryServer.setSkip(true);
}
if (config.isRegister()) {
PrimaryServer.setSkip(true);
Ebean.register(server, config.isDefaultServer());
}
@@ -99,7 +100,7 @@ public class EbeanServerFactory {
* </p>
*/
public static synchronized void shutdown() {
ShutdownManager.shutdown();
container.shutdown();
}
@@ -135,14 +136,10 @@ public class EbeanServerFactory {
*/
protected static SpiContainer createContainer(ContainerConfig containerConfig) {
String implClassName = System.getProperty("ebean.container", DEFAULT_CONTAINER);
try {
Class<?> cls = Class.forName(implClassName);
Constructor<?> constructor = cls.getConstructor(ContainerConfig.class);
return (SpiContainer) constructor.newInstance(containerConfig);
} catch (Exception ex) {
throw new RuntimeException(ex);
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
@@ -0,0 +1,43 @@
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;
}
}
+31 -3
View File
@@ -7,7 +7,6 @@ import io.ebean.search.TextQueryString;
import io.ebean.search.TextSimple;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
@@ -247,6 +246,11 @@ public interface ExpressionFactory {
*/
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.
*/
@@ -308,9 +312,9 @@ public interface ExpressionFactory {
Expression idIn(Object... idValues);
/**
* Id IN a list of Id values.
* Id IN a collection of Id values.
*/
Expression idIn(List<?> idList);
Expression idIn(Collection<?> idCollection);
/**
* All Equal - Map containing property names and their values.
@@ -323,6 +327,30 @@ public interface ExpressionFactory {
*/
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>
+203 -8
View File
@@ -5,13 +5,15 @@ import io.ebean.search.MultiMatch;
import io.ebean.search.TextCommonTerms;
import io.ebean.search.TextQueryString;
import io.ebean.search.TextSimple;
import org.jetbrains.annotations.Nullable;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.NonUniqueResultException;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -118,6 +120,27 @@ public interface ExpressionList<T> {
*/
Query<T> asDraft();
/**
* Execute using "for update" clause which results in the DB locking the record.
*/
Query<T> forUpdate();
/**
* Execute using "for update" clause with No Wait option.
* <p>
* This is typically a Postgres and Oracle only option at this stage.
* </p>
*/
Query<T> forUpdateNoWait();
/**
* Execute using "for update" clause with Skip Locked option.
* <p>
* This is typically a Postgres and Oracle only option at this stage.
* </p>
*/
Query<T> forUpdateSkipLocked();
/**
* Execute the query including soft deleted rows.
*/
@@ -170,6 +193,7 @@ public interface ExpressionList<T> {
*
* @see Query#findList()
*/
@Nonnull
List<T> findList();
/**
@@ -177,6 +201,7 @@ public interface ExpressionList<T> {
*
* @see Query#findIds()
*/
@Nonnull
<A> List<A> findIds();
/**
@@ -192,6 +217,7 @@ public interface ExpressionList<T> {
*
* @see Query#findSet()
*/
@Nonnull
Set<T> findSet();
/**
@@ -199,6 +225,7 @@ public interface ExpressionList<T> {
*
* @see Query#findMap()
*/
@Nonnull
<K> Map<K, T> findMap();
/**
@@ -231,8 +258,27 @@ public interface ExpressionList<T> {
*
* @return the list of values for the selected property
*/
@Nonnull
<A> List<A> findSingleAttributeList();
/**
* Execute a query returning a single value of a single property/column.
* <p>
* <pre>{@code
*
* String name =
* Ebean.find(Customer.class)
* .select("name")
* .where().eq("id", 42)
* .findSingleAttribute();
*
* }</pre>
*/
default <A> A findSingleAttribute() {
List<A> list = findSingleAttributeList();
return !list.isEmpty() ? list.get(0) : null;
}
/**
* Execute the query returning a single bean or null (if no matching
* bean is found).
@@ -242,10 +288,16 @@ public interface ExpressionList<T> {
* </p>
*
* @throws NonUniqueResultException if more than one result was found
* @see Query#findUnique()
* @see Query#findOne()
*/
@Nullable
T findUnique();
T findOne();
/**
* Execute the query returning an optional bean.
*/
@Nonnull
Optional<T> findOneOrEmpty();
/**
* Execute find row count query in a background thread.
@@ -257,6 +309,7 @@ public interface ExpressionList<T> {
*
* @return a Future object for the row count query
*/
@Nonnull
FutureRowCount<T> findFutureCount();
/**
@@ -269,6 +322,7 @@ public interface ExpressionList<T> {
*
* @return a Future object for the list of Id's
*/
@Nonnull
FutureIds<T> findFutureIds();
/**
@@ -281,6 +335,7 @@ public interface ExpressionList<T> {
*
* @return a Future object for the list result of the query
*/
@Nonnull
FutureList<T> findFutureList();
/**
@@ -312,6 +367,7 @@ public interface ExpressionList<T> {
* @return The PagedList
* @see Query#findPagedList()
*/
@Nonnull
PagedList<T> findPagedList();
/**
@@ -321,6 +377,7 @@ public interface ExpressionList<T> {
* It will execute the query against the history returning the versions of the bean.
* </p>
*/
@Nonnull
List<Version<T>> findVersions();
/**
@@ -330,11 +387,13 @@ public interface ExpressionList<T> {
* It will execute the query against the history returning the versions of the bean.
* </p>
*/
@Nonnull
List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end);
/**
* Add some filter predicate expressions to the many property.
*/
@Nonnull
ExpressionList<T> filterMany(String prop);
/**
@@ -398,18 +457,67 @@ public interface ExpressionList<T> {
Query<T> setMapKey(String mapKey);
/**
* Set to true to use the query for executing this query.
* Set to true when this query should use the bean cache.
* <p>
* This is now the same as setUseBeanCache(CacheMode.ON) and will be deprecated.
* </p>
*
* @see Query#setUseCache(boolean)
*/
Query<T> setUseCache(boolean useCache);
/**
* Set to true to use the query for executing this query.
* Set the mode to use the bean cache when executing this query.
*
* @see Query#setBeanCacheMode(CacheMode)
*/
Query<T> setBeanCacheMode(CacheMode beanCacheMode);
/**
* Set the {@link CacheMode} to use the query cache for executing this query.
*
* @see Query#setUseQueryCache(boolean)
*/
Query<T> setUseQueryCache(boolean useCache);
Query<T> setUseQueryCache(CacheMode useCache);
/**
* Extended version for setDistinct in conjunction with "findSingleAttributeList";
* <p>
* <pre>{@code
*
* List<CountedValue<Order.Status>> orderStatusCount =
*
* Ebean.find(Order.class)
* .select("status")
* .where()
* .gt("orderDate", LocalDate.now().minusMonths(3))
*
* // fetch as single attribute with a COUNT
* .setCountDistinct(CountDistinctOrder.COUNT_DESC_ATTR_ASC)
* .findSingleAttributeList();
*
* for (CountedValue<Order.Status> entry : orderStatusCount) {
* System.out.println(" count:" + entry.getCount()+" orderStatus:" + entry.getValue() );
* }
*
* // produces
*
* count:3 orderStatus:NEW
* count:1 orderStatus:SHIPPED
* count:1 orderStatus:COMPLETE
*
* }</pre>
*/
Query<T> setCountDistinct(CountDistinctOrder orderBy);
/**
* Calls {@link #setUseQueryCache(CacheMode)} with <code>ON</code> or <code>OFF</code>.
*
* @see Query#setUseQueryCache(CacheMode)
*/
default Query<T> setUseQueryCache(boolean enabled) {
return setUseQueryCache(enabled ? CacheMode.ON : CacheMode.OFF);
}
/**
* Set to true if this query should execute against the doc store.
@@ -437,6 +545,11 @@ public interface ExpressionList<T> {
*/
Query<T> setDisableReadAuditing();
/**
* Set a label on the query (to help identify query execution statistics).
*/
Query<T> setLabel(String label);
/**
* Add expressions to the having clause.
* <p>
@@ -743,6 +856,11 @@ public interface ExpressionList<T> {
*/
ExpressionList<T> icontains(String propertyName, String value);
/**
* In expression using pairs of value objects.
*/
ExpressionList<T> inPairs(Pairs pairs);
/**
* In - using a subQuery.
*/
@@ -758,6 +876,36 @@ public interface ExpressionList<T> {
*/
ExpressionList<T> in(String propertyName, Collection<?> values);
/**
* In - using a subQuery.
* <p>
* This is exactly the same as in() and provided due to "in" being a Kotlin keyword
* (and hence to avoid the slightly ugly escaping when using in() in Kotlin)
*/
default ExpressionList<T> isIn(String propertyName, Query<?> subQuery) {
return in(propertyName, subQuery);
}
/**
* In - property has a value in the array of values.
* <p>
* This is exactly the same as in() and provided due to "in" being a Kotlin keyword
* (and hence to avoid the slightly ugly escaping when using in() in Kotlin)
*/
default ExpressionList<T> isIn(String propertyName, Object... values) {
return in(propertyName, values);
}
/**
* In - property has a value in the collection of values.
* <p>
* This is exactly the same as in() and provided due to "in" being a Kotlin keyword
* (and hence to avoid the slightly ugly escaping when using in() in Kotlin)
*/
default ExpressionList<T> isIn(String propertyName, Collection<?> values) {
return in(propertyName, values);
}
/**
* Not In - property has a value in the array of values.
*/
@@ -799,9 +947,9 @@ public interface ExpressionList<T> {
ExpressionList<T> idIn(Object... idValues);
/**
* Id IN a list of id values.
* Id IN a collection of id values.
*/
ExpressionList<T> idIn(List<?> idValues);
ExpressionList<T> idIn(Collection<?> idValues);
/**
* Id Equal to - ID property is equal to the value.
@@ -848,6 +996,53 @@ public interface ExpressionList<T> {
*/
ExpressionList<T> arrayIsNotEmpty(String propertyName);
/**
* Add expression for ANY of the given bit flags to be set.
* <pre>{@code
*
* where().bitwiseAny("flags", BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
*
* }</pre>
*
* @param propertyName The property that holds the flags value
* @param flags The flags we are looking for
*/
ExpressionList<T> bitwiseAny(String propertyName, long flags);
/**
* Add expression for ALL of the given bit flags to be set.
* <p>
* <pre>{@code
*
* where().bitwiseAll("flags", BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
*
* }</pre>
*
* @param propertyName The property that holds the flags value
* @param flags The flags we are looking for
*/
ExpressionList<T> bitwiseAll(String propertyName, long flags);
/**
* Add bitwise AND expression of the given bit flags to compare with the match/mask.
* <p>
* <pre>{@code
*
* // Flags Bulk + Size = Size
* // ... meaning Bulk is not set and Size is set
*
* long selectedFlags = BwFlags.HAS_BULK + BwFlags.HAS_SIZE;
* long mask = BwFlags.HAS_SIZE; // Only Size flag set
*
* where().bitwiseAnd("flags", selectedFlags, mask)
*
* }</pre>
*
* @param propertyName The property that holds the flags value
* @param flags The flags we are looking for
*/
ExpressionList<T> bitwiseAnd(String propertyName, long flags, long match);
/**
* Add raw expression with a single parameter.
* <p>
+51 -4
View File
@@ -1,6 +1,7 @@
package io.ebean;
import org.jetbrains.annotations.Nullable;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
@@ -18,7 +19,7 @@ import java.util.List;
* </p>
* <pre>{@code
*
* public class CustomerFinder extends Finder<Customer> {
* public class CustomerFinder extends Finder<Long,Customer> {
*
* public CustomerFinder() {
* super(Customer.class);
@@ -27,11 +28,11 @@ import java.util.List;
* // Add your customer finder methods ...
*
* public Customer byName(String name) {
* return query().eq("name", name).findUnique();
* return query().eq("name", name).findOne();
* }
*
* public List<Customer> findNew() {
* return query()
* return query().where()
* .eq("status", Customer.Status.NEW)
* .orderBy("name")
* .findList()
@@ -92,6 +93,20 @@ public class Finder<I, T> {
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>
@@ -118,6 +133,7 @@ public class Finder<I, T> {
* <p>
* Equivalent to {@link EbeanServer#getReference(Class, Object)}
*/
@Nonnull
public T ref(I id) {
return db().getReference(type, id);
}
@@ -144,10 +160,33 @@ public class Finder<I, T> {
/**
* 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>
@@ -163,4 +202,12 @@ public class Finder<I, T> {
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);
}
}
+4 -4
View File
@@ -6,22 +6,22 @@ package io.ebean;
public enum LikeType {
/**
* You need to put in your own wildcards.
* You need to put in your own wildcards - no escaping is performed.
*/
RAW,
/**
* The % wildcard is added to the end of the search word.
* 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.
* 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.
* The % wildcard is added to the beginning and end of the search word and search word is escaped.
*/
CONTAINS,
+29
View File
@@ -0,0 +1,29 @@
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();
}
@@ -0,0 +1,80 @@
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;
}
}
}
+11
View File
@@ -190,6 +190,17 @@ public abstract class Model {
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.
*
+3
View File
@@ -162,6 +162,7 @@ public final class OrderBy<T> implements Serializable {
list.add(p);
}
@Override
public String toString() {
return list.toString();
}
@@ -201,6 +202,7 @@ public final class OrderBy<T> implements Serializable {
* Return a hash value for this OrderBy. This can be to determine logical
* equality for OrderBy clauses.
*/
@Override
public int hashCode() {
return list.hashCode();
}
@@ -276,6 +278,7 @@ public final class OrderBy<T> implements Serializable {
return highLow != null ? highLow.equals(e.highLow) : e.highLow == null;
}
@Override
public String toString() {
return toStringFormat();
}
+3
View File
@@ -1,5 +1,6 @@
package io.ebean;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.concurrent.Future;
@@ -109,11 +110,13 @@ public interface PagedList<T> {
*
* }</pre>
*/
@Nonnull
Future<Integer> getFutureCount();
/**
* Return the list of entities for this page.
*/
@Nonnull
List<T> getList();
/**
+222
View File
@@ -0,0 +1,222 @@
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;
}
}
}
+5 -2
View File
@@ -1,6 +1,6 @@
package io.ebean;
import io.ebean.config.PropertyMap;
import io.ebean.config.properties.PropertiesLoader;
import java.util.Properties;
@@ -44,7 +44,7 @@ class PrimaryServer {
*/
static synchronized Properties getProperties() {
if (globalProperties == null) {
globalProperties = PropertyMap.defaultProperties();
globalProperties = PropertiesLoader.load();
}
if (defaultServerName == null) {
defaultServerName = determineDefaultServerName();
@@ -59,6 +59,8 @@ class PrimaryServer {
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)) {
@@ -74,6 +76,7 @@ class PrimaryServer {
if (defaultServerName == null) {
defaultServerName = "db";
}
System.setProperty("ebean_db", defaultServerName);
return defaultServerName;
}
@@ -0,0 +1,47 @@
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);
}
+203 -22
View File
@@ -1,11 +1,12 @@
package io.ebean;
import org.jetbrains.annotations.Nullable;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.NonUniqueResultException;
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -195,9 +196,24 @@ import java.util.function.Predicate;
public interface Query<T> {
/**
* Return the RawSql that was set to use for this query.
* For update mode.
*/
RawSql getRawSql();
enum ForUpdate {
/**
* Standard For update clause.
*/
BASE,
/**
* For update with No Wait option.
*/
NOWAIT,
/**
* For update with Skip Locked option.
*/
SKIPLOCKED
}
/**
* Set RawSql to use for this query.
@@ -220,6 +236,14 @@ public interface Query<T> {
*/
Query<T> asDraft();
/**
* Convert the query to a DTO bean query.
* <p>
* We effectively use the underlying ORM query to build the SQL and then execute
* and map it into DTO beans.
*/
<D> DtoQuery<D> asDto(Class<D> dtoClass);
/**
* Cancel the query execution if supported by the underlying database and
* driver.
@@ -581,6 +605,7 @@ public interface Query<T> {
*
* @see EbeanServer#findIds(Query, Transaction)
*/
@Nonnull
<A> List<A> findIds();
/**
@@ -621,6 +646,7 @@ public interface Query<T> {
*
* }</pre>
*/
@Nonnull
QueryIterator<T> findIterate();
/**
@@ -648,8 +674,7 @@ public interface Query<T> {
* </p>
* <p>
* This method is functionally equivalent to findIterate() but instead of using an
* iterator uses the QueryEachConsumer (SAM) interface which is better suited to use
* with Java8 closures.
* iterator uses the Consumer interface which is better suited to use with Java8 closures.
* </p>
* <pre>{@code
*
@@ -678,8 +703,7 @@ public interface Query<T> {
* </p>
* <p>
* This method is functionally equivalent to findIterate() but instead of using an
* iterator uses the QueryEachWhileConsumer (SAM) interface which is better suited to use
* with Java8 closures.
* iterator uses the Predicate (SAM) interface which is better suited to use with Java8 closures.
* </p>
* <pre>{@code
*
@@ -719,6 +743,7 @@ public interface Query<T> {
*
* @see EbeanServer#findList(Query, Transaction)
*/
@Nonnull
List<T> findList();
/**
@@ -737,6 +762,7 @@ public interface Query<T> {
*
* @see EbeanServer#findSet(Query, Transaction)
*/
@Nonnull
Set<T> findSet();
/**
@@ -759,6 +785,7 @@ public interface Query<T> {
*
* @see EbeanServer#findMap(Query, Transaction)
*/
@Nonnull
<K> Map<K, T> findMap();
/**
@@ -791,8 +818,29 @@ public interface Query<T> {
*
* @return the list of values for the selected property
*/
@Nonnull
<A> List<A> findSingleAttributeList();
/**
* Execute a query returning a single value of a single property/column.
* <p>
* <pre>{@code
*
* String name =
* Ebean.find(Customer.class)
* .select("name")
* .where().eq("id", 42)
* .findSingleAttribute();
*
* }</pre>
*/
<A> A findSingleAttribute();
/**
* Return true if this is countDistinct query.
*/
boolean isCountDistinct();
/**
* Execute the query returning either a single bean or null (if no matching
* bean is found).
@@ -810,7 +858,7 @@ public interface Query<T> {
* Product product =
* ebeanServer.find(Product.class)
* .where().eq("sku", "aa113")
* .findUnique();
* .findOne();
* ...
* }</pre>
* <p>
@@ -824,7 +872,7 @@ public interface Query<T> {
* ebeanServer.find(Order.class)
* .setId(1)
* .fetch("details")
* .findUnique();
* .findOne();
*
* // the order details were eagerly loaded
* List<OrderDetail> details = order.getDetails();
@@ -834,7 +882,13 @@ public interface Query<T> {
* @throws NonUniqueResultException if more than one result was found
*/
@Nullable
T findUnique();
T findOne();
/**
* Execute the query returning an optional bean.
*/
@Nonnull
Optional<T> findOneOrEmpty();
/**
* Return versions of a @History entity bean.
@@ -848,6 +902,7 @@ public interface Query<T> {
* It will execute the query against the history returning the versions of the bean.
* </p>
*/
@Nonnull
List<Version<T>> findVersions();
/**
@@ -857,6 +912,7 @@ public interface Query<T> {
* It will execute the query against the history returning the versions of the bean.
* </p>
*/
@Nonnull
List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end);
/**
@@ -894,6 +950,7 @@ public interface Query<T> {
*
* @return a Future object for the row count query
*/
@Nonnull
FutureRowCount<T> findFutureCount();
/**
@@ -906,6 +963,7 @@ public interface Query<T> {
*
* @return a Future object for the list of Id's
*/
@Nonnull
FutureIds<T> findFutureIds();
/**
@@ -917,6 +975,7 @@ public interface Query<T> {
*
* @return a Future object for the list result of the query
*/
@Nonnull
FutureList<T> findFutureList();
/**
@@ -946,6 +1005,7 @@ public interface Query<T> {
*
* @return The PagedList
*/
@Nonnull
PagedList<T> findPagedList();
/**
@@ -992,7 +1052,7 @@ public interface Query<T> {
Query<T> setParameter(int position, Object value);
/**
* Set the Id value to query. This is used with findUnique().
* Set the Id value to query. This is used with findOne().
* <p>
* You can use this to have further control over the query. For example adding
* fetch joins.
@@ -1003,7 +1063,7 @@ public interface Query<T> {
* ebeanServer.find(Order.class)
* .setId(1)
* .fetch("details")
* .findUnique();
* .findOne();
*
* // the order details were eagerly fetched
* List<OrderDetail> details = order.getDetails();
@@ -1225,6 +1285,37 @@ public interface Query<T> {
*/
Query<T> setDistinct(boolean isDistinct);
/**
* Extended version for setDistinct in conjunction with "findSingleAttributeList";
*
* <pre>{@code
*
* List<CountedValue<Order.Status>> orderStatusCount =
*
* Ebean.find(Order.class)
* .select("status")
* .where()
* .gt("orderDate", LocalDate.now().minusMonths(3))
*
* // fetch as single attribute with a COUNT
* .setCountDistinct(CountDistinctOrder.COUNT_DESC_ATTR_ASC)
* .findSingleAttributeList();
*
* for (CountedValue<Order.Status> entry : orderStatusCount) {
* System.out.println(" count:" + entry.getCount()+" orderStatus:" + entry.getValue() );
* }
*
* // produces
*
* count:3 orderStatus:NEW
* count:1 orderStatus:SHIPPED
* count:1 orderStatus:COMPLETE
*
* }</pre>
*
*/
Query<T> setCountDistinct(CountDistinctOrder orderBy);
/**
* Return the first row value.
*/
@@ -1258,7 +1349,7 @@ public interface Query<T> {
*
* // Assuming sku is unique for products...
*
* Map<?,Product> productMap =
* Map<String,Product> productMap =
* ebeanServer.find(Product.class)
* // use sku for keys...
* .setMapKey("sku")
@@ -1273,22 +1364,69 @@ public interface Query<T> {
/**
* Set this to false to not use the bean cache.
* <p>
* This method is now superseded by {@link #setBeanCacheMode(CacheMode)}
* which provides more explicit options controlled bean cache use.
* </p>
* <p>
* This method is likely to be deprecated in the future with migration
* over to setUseBeanCache().
* </p>
*/
default Query<T> setUseCache(boolean useCache) {
return setBeanCacheMode(useCache ? CacheMode.ON : CacheMode.OFF);
}
/**
* Set the mode to use the bean cache when executing this query.
* <p>
* By default "find by id" and "find by natural key" will use the bean cache
* when bean caching is enabled. Setting this to false means that the query
* will not use the bean cache and instead hit the database.
* </p>
* <p>
* In the case of other queries (findList(), findEach() etc) then setting this to
* false beans that the if lazy loading is invoked that lazy loading will not try
* to use the bean cache.
* By default findList() with natural keys will not use the bean cache. In that
* case we need to explicitly use the bean cache.
* </p>
*/
Query<T> setUseCache(boolean useCache);
Query<T> setBeanCacheMode(CacheMode beanCacheMode);
/**
* Set this to true to use the query cache.
* Set the {@link CacheMode} to use the query for executing this query.
*/
Query<T> setUseQueryCache(boolean useQueryCache);
Query<T> setUseQueryCache(CacheMode queryCacheMode);
/**
* Calls {@link #setUseQueryCache(CacheMode)} with <code>ON</code> or <code>OFF</code>.
*/
default Query<T> setUseQueryCache(boolean enabled) {
return setUseQueryCache(enabled ? CacheMode.ON : CacheMode.OFF);
}
/**
* Set an id to identify this query for profiling purposes.
* <p>
* The profileId is expected to be unique for a given bean type.
* </p>
* <p>
* Note that the profileId is treated as a short internally and has a MAX value of 32,767.
* </p>
*/
Query<T> setProfileId(int profileId);
/**
* Set the profile location of this query. This is used to relate query execution metrics
* back to a location like a specific line of code.
*/
Query<T> setProfileLocation(ProfileLocation profileLocation);
/**
* Set a label on the query.
* <p>
* This label can be used to help identify query performance metrics but we can also use
* profile location enhancement on Finders so for some that would be a better option.
* </p>
*/
Query<T> setLabel(String label);
/**
* Set to true if this query should execute against the doc store.
@@ -1304,8 +1442,9 @@ public interface Query<T> {
Query<T> setReadOnly(boolean readOnly);
/**
* When set to true all the beans from this query are loaded into the bean
* cache.
* Will be deprecated - migrate to use setBeanCacheMode(CacheMode.RECACHE).
* <p>
* When set to true all the beans from this query are loaded into the bean cache.
*/
Query<T> setLoadBeanCache(boolean loadBeanCache);
@@ -1350,16 +1489,45 @@ public interface Query<T> {
String getGeneratedSql();
/**
* Deprecated - migrate to forUpdate().
*
* executed the select with "for update" which should lock the record
* "on read"
*/
@Deprecated
Query<T> setForUpdate(boolean forUpdate);
/**
* Execute using "for update" clause which results in the DB locking the record.
*/
Query<T> forUpdate();
/**
* Execute using "for update" clause with "no wait" option.
* <p>
* This is typically a Postgres and Oracle only option at this stage.
* </p>
*/
Query<T> forUpdateNoWait();
/**
* Execute using "for update" clause with "skip locked" option.
* <p>
* This is typically a Postgres and Oracle only option at this stage.
* </p>
*/
Query<T> forUpdateSkipLocked();
/**
* Return true if this query has forUpdate set.
*/
boolean isForUpdate();
/**
* Return the "for update" mode to use.
*/
ForUpdate getForUpdateMode();
/**
* Set root table alias.
*/
@@ -1370,6 +1538,11 @@ public interface Query<T> {
*/
Class<T> getBeanType();
/**
* Return the type of query being executed.
*/
QueryType getQueryType();
/**
* Set true if you want to disable lazy loading.
* <p>
@@ -1387,4 +1560,12 @@ public interface Query<T> {
*/
Set<String> validate();
/**
* Controls, if paginated queries should always append an 'order by id' statement at the end to
* guarantee a deterministic sort result. This may affect performance.
* If this is not enabled, and an orderBy is set on the query, it's up to the programmer that
* this query provides a deterministic result.
*/
Query<T> orderById(boolean orderById);
}
@@ -61,20 +61,24 @@ 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
@@ -0,0 +1,22 @@
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
}
+1 -570
View File
@@ -1,16 +1,5 @@
package io.ebean;
import io.ebean.util.CamelCaseHelper;
import java.io.Serializable;
import java.sql.ResultSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Used to build object graphs based on a raw SQL statement (rather than
* generated by Ebean).
@@ -169,564 +158,6 @@ import java.util.Map;
* Note that lazy loading also works with object graphs built with RawSql.
* </p>
*/
public final class RawSql implements Serializable {
public interface RawSql {
private static final long serialVersionUID = 1L;
private final ResultSet resultSet;
private final Sql sql;
private final ColumnMapping columnMapping;
/**
* Construct with a ResultSet and properties that the columns map to.
* <p>
* The properties listed in the propertyNames must be in the same order as the columns in the
* resultSet.
* <p>
* When a query executes this RawSql object then it will close the resultSet.
*/
public RawSql(ResultSet resultSet, String... propertyNames) {
this.resultSet = resultSet;
this.sql = null;
this.columnMapping = new ColumnMapping(propertyNames);
}
protected RawSql(ResultSet resultSet, Sql sql, ColumnMapping columnMapping) {
this.resultSet = resultSet;
this.sql = sql;
this.columnMapping = columnMapping;
}
/**
* Return the Sql either unparsed or in parsed (broken up) form.
*/
public Sql getSql() {
return sql;
}
/**
* Return the key;
*/
public Key getKey() {
boolean parsed = sql != null && sql.parsed;
String unParsedSql = (sql == null) ? "" : sql.unparsedSql;
return new Key(parsed, unParsedSql, columnMapping);
}
/**
* Return the resultSet if this is a ResultSet based RawSql.
*/
public ResultSet getResultSet() {
return resultSet;
}
/**
* Return the column mapping for the SQL columns to bean properties.
*/
public ColumnMapping getColumnMapping() {
return columnMapping;
}
/**
* Represents the sql part of the query. For parsed RawSql the sql is broken
* up so that Ebean can insert extra WHERE and HAVING expressions into the
* SQL.
*/
public static final class Sql implements Serializable {
private static final long serialVersionUID = 1L;
private final boolean parsed;
private final String unparsedSql;
private final String preFrom;
private final String preWhere;
private final boolean andWhereExpr;
private final String preHaving;
private final boolean andHavingExpr;
private final String orderByPrefix;
private final String orderBy;
private final boolean distinct;
/**
* Construct for unparsed SQL.
*/
protected Sql(String unparsedSql) {
this.parsed = false;
this.unparsedSql = unparsedSql;
this.preFrom = null;
this.preHaving = null;
this.preWhere = null;
this.andHavingExpr = false;
this.andWhereExpr = false;
this.orderByPrefix = null;
this.orderBy = null;
this.distinct = false;
}
/**
* Construct for parsed SQL.
*/
protected Sql(String unparsedSql, String preFrom, String preWhere, boolean andWhereExpr,
String preHaving, boolean andHavingExpr, String orderByPrefix, String orderBy, boolean distinct) {
this.unparsedSql = unparsedSql;
this.parsed = true;
this.preFrom = preFrom;
this.preHaving = preHaving;
this.preWhere = preWhere;
this.andHavingExpr = andHavingExpr;
this.andWhereExpr = andWhereExpr;
this.orderByPrefix = orderByPrefix;
this.orderBy = orderBy;
this.distinct = distinct;
}
public String toString() {
if (!parsed) {
return "unparsed[" + unparsedSql + "]";
}
return "select[" + preFrom + "] preWhere[" + preWhere + "] preHaving[" + preHaving + "] orderBy[" + orderBy + "]";
}
public boolean isDistinct() {
return distinct;
}
/**
* Return true if the SQL is left completely unmodified.
* <p>
* This means Ebean can't add WHERE or HAVING expressions into the query -
* it will be left completely unmodified.
* </p>
*/
public boolean isParsed() {
return parsed;
}
/**
* Return the SQL when it is unparsed.
*/
public String getUnparsedSql() {
return unparsedSql;
}
/**
* Return the SQL prior to FROM clause.
*/
public String getPreFrom() {
return preFrom;
}
/**
* Return the SQL prior to WHERE clause.
*/
public String getPreWhere() {
return preWhere;
}
/**
* Return true if there is already a WHERE clause and any extra where
* expressions start with AND.
*/
public boolean isAndWhereExpr() {
return andWhereExpr;
}
/**
* Return the SQL prior to HAVING clause.
*/
public String getPreHaving() {
return preHaving;
}
/**
* Return true if there is already a HAVING clause and any extra having
* expressions start with AND.
*/
public boolean isAndHavingExpr() {
return andHavingExpr;
}
/**
* Return the 'order by' keywords.
* This can contain additional keywords, for example 'order siblings by' as Oracle syntax.
*/
public String getOrderByPrefix() {
return (orderByPrefix == null) ? "order by" : orderByPrefix;
}
/**
* Return the SQL ORDER BY clause.
*/
public String getOrderBy() {
return orderBy;
}
}
/**
* Defines the column mapping for raw sql DB columns to bean properties.
*/
public static final class ColumnMapping implements Serializable {
private static final long serialVersionUID = 1L;
private final LinkedHashMap<String, Column> dbColumnMap;
private final Map<String, String> propertyMap;
private final Map<String, Column> propertyColumnMap;
private final boolean parsed;
private final boolean immutable;
/**
* Construct from parsed sql where the columns have been identified.
*/
protected ColumnMapping(List<Column> columns) {
this.immutable = false;
this.parsed = true;
this.propertyMap = null;
this.propertyColumnMap = null;
this.dbColumnMap = new LinkedHashMap<>();
for (Column c : columns) {
dbColumnMap.put(c.getDbColumnKey(), c);
}
}
/**
* Construct for unparsed sql.
*/
protected ColumnMapping() {
this.immutable = false;
this.parsed = false;
this.propertyMap = null;
this.propertyColumnMap = null;
this.dbColumnMap = new LinkedHashMap<>();
}
/**
* Construct for ResultSet use.
*/
protected ColumnMapping(String... propertyNames) {
this.immutable = false;
this.parsed = false;
this.propertyMap = null;
this.dbColumnMap = new LinkedHashMap<>();
int pos = 0;
for (String prop : propertyNames) {
dbColumnMap.put(prop, new Column(pos++, prop, null, prop));
}
propertyColumnMap = dbColumnMap;
}
/**
* Construct an immutable ColumnMapping based on collected information.
*/
protected ColumnMapping(boolean parsed, LinkedHashMap<String, Column> dbColumnMap) {
this.immutable = true;
this.parsed = parsed;
this.dbColumnMap = dbColumnMap;
HashMap<String, Column> pcMap = new HashMap<>();
HashMap<String, String> pMap = new HashMap<>();
for (Column c : dbColumnMap.values()) {
pMap.put(c.getPropertyName(), c.getDbColumn());
pcMap.put(c.getPropertyName(), c);
}
this.propertyMap = Collections.unmodifiableMap(pMap);
this.propertyColumnMap = Collections.unmodifiableMap(pcMap);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ColumnMapping that = (ColumnMapping) o;
return dbColumnMap.equals(that.dbColumnMap);
}
@Override
public int hashCode() {
return dbColumnMap.hashCode();
}
/**
* Return true if the property is mapped.
*/
public boolean contains(String property) {
return this.propertyColumnMap.containsKey(property);
}
/**
* Creates an immutable copy of this ColumnMapping.
*
* @throws IllegalStateException when a propertyName has not been defined for a column.
*/
protected ColumnMapping createImmutableCopy() {
for (Column c : dbColumnMap.values()) {
c.checkMapping();
}
return new ColumnMapping(parsed, dbColumnMap);
}
protected void columnMapping(String dbColumn, String propertyName) {
if (immutable) {
throw new IllegalStateException("Should never happen");
}
if (!parsed) {
int pos = dbColumnMap.size();
dbColumnMap.put(dbColumn, new Column(pos, dbColumn, null, propertyName));
} else {
Column column = dbColumnMap.get(dbColumn);
if (column == null) {
String msg = "DB Column [" + dbColumn + "] not found in mapping. Expecting one of [" + dbColumnMap.keySet() + "]";
throw new IllegalArgumentException(msg);
}
column.setPropertyName(propertyName);
}
}
/**
* Returns true if the Columns where supplied by parsing the sql select
* clause.
* <p>
* In the case where the columns where parsed then we can do extra checks on
* the column mapping such as, is the column a valid one in the sql and
* whether all the columns in the sql have been mapped.
* </p>
*/
public boolean isParsed() {
return parsed;
}
/**
* Return the number of columns in this column mapping.
*/
public int size() {
return dbColumnMap.size();
}
/**
* Return the column mapping.
*/
protected Map<String, Column> mapping() {
return dbColumnMap;
}
/**
* Return the mapping by DB column.
*/
public Map<String, String> getMapping() {
return propertyMap;
}
/**
* Return the index position by bean property name.
*/
public int getIndexPosition(String property) {
Column c = propertyColumnMap.get(property);
return c == null ? -1 : c.getIndexPos();
}
/**
* Return an iterator of the Columns.
*/
public Iterator<Column> getColumns() {
return dbColumnMap.values().iterator();
}
/**
* 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>
*/
public void tableAliasMapping(String tableAlias, String path) {
String startMatch = tableAlias + ".";
for (Map.Entry<String, Column> entry : dbColumnMap.entrySet()) {
if (entry.getKey().startsWith(startMatch)) {
entry.getValue().tableAliasMapping(path);
}
}
}
/**
* A Column of the RawSql that is mapped to a bean property (or ignored).
*/
public static class Column implements Serializable {
private static final long serialVersionUID = 1L;
private final int indexPos;
private final String dbColumn;
private final String dbAlias;
private String propertyName;
/**
* Construct a Column.
*/
public Column(int indexPos, String dbColumn, String dbAlias) {
this(indexPos, dbColumn, dbAlias, derivePropertyName(dbAlias, dbColumn));
}
private Column(int indexPos, String dbColumn, String dbAlias, String propertyName) {
this.indexPos = indexPos;
this.dbColumn = dbColumn;
this.dbAlias = dbAlias;
if (propertyName == null && dbAlias != null) {
this.propertyName = dbAlias;
} else {
this.propertyName = propertyName;
}
}
protected static String derivePropertyName(String dbAlias, String dbColumn) {
if (dbAlias != null) {
return CamelCaseHelper.toCamelFromUnderscore(dbAlias);
}
int dotPos = dbColumn.indexOf('.');
if (dotPos > -1) {
dbColumn = dbColumn.substring(dotPos + 1);
}
return CamelCaseHelper.toCamelFromUnderscore(dbColumn);
}
private void checkMapping() {
if (propertyName == null) {
String msg = "No propertyName defined (Column mapping) for dbColumn [" + dbColumn + "]";
throw new IllegalStateException(msg);
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Column that = (Column) o;
if (indexPos != that.indexPos) return false;
if (!dbColumn.equals(that.dbColumn)) return false;
if (dbAlias != null ? !dbAlias.equals(that.dbAlias) : that.dbAlias != null) return false;
return propertyName != null ? propertyName.equals(that.propertyName) : that.propertyName == null;
}
@Override
public int hashCode() {
int result = indexPos;
result = 92821 * result + dbColumn.hashCode();
result = 92821 * result + (dbAlias != null ? dbAlias.hashCode() : 0);
result = 92821 * result + (propertyName != null ? propertyName.hashCode() : 0);
return result;
}
public String toString() {
return dbColumn + "->" + propertyName;
}
/**
* Return the index position of this column.
*/
public int getIndexPos() {
return indexPos;
}
/**
* Return the DB column alias if specified otherwise DB column.
* This is used as the key for mapping a column to a logical property.
*/
public String getDbColumnKey() {
return (dbAlias != null) ? dbAlias : dbColumn;
}
/**
* Return the DB column name including table alias (if it has one).
*/
public String getDbColumn() {
return dbColumn;
}
/**
* Return the bean property this column is mapped to.
*/
public String getPropertyName() {
return propertyName;
}
/**
* Set the property name mapped to this db column.
*/
private void setPropertyName(String propertyName) {
this.propertyName = propertyName;
}
/**
* Prepend the path to the property name.
* <p/>
* For example if path is "customer" then "name" becomes "customer.name".
*/
public void tableAliasMapping(String path) {
if (path != null) {
propertyName = path + "." + propertyName;
}
}
}
}
/**
* A key for the RawSql object using for the query plan.
*/
public static final class Key {
private final boolean parsed;
private final ColumnMapping columnMapping;
private final String unParsedSql;
Key(boolean parsed, String unParsedSql, ColumnMapping columnMapping) {
this.parsed = parsed;
this.unParsedSql = unParsedSql;
this.columnMapping = columnMapping;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Key that = (Key) o;
return parsed == that.parsed
&& columnMapping.equals(that.columnMapping)
&& unParsedSql.equals(that.unParsedSql);
}
@Override
public int hashCode() {
int result = (parsed ? 1 : 0);
result = 92821 * result + columnMapping.hashCode();
result = 92821 * result + unParsedSql.hashCode();
return result;
}
}
}
+19 -55
View File
@@ -1,9 +1,7 @@
package io.ebean;
import io.ebean.RawSql.ColumnMapping;
import io.ebean.RawSql.Sql;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* Builds RawSql instances from a SQL string and column mappings.
@@ -14,18 +12,7 @@ import java.sql.ResultSet;
*
* @see RawSql
*/
public class RawSqlBuilder {
/**
* Special property name assigned to a DB column that should be ignored.
*/
public static final String IGNORE_COLUMN = "$$_IGNORE_COLUMN_$$";
private final ResultSet resultSet;
private final Sql sql;
private final ColumnMapping columnMapping;
public interface RawSqlBuilder {
/**
* Create and return a RawSql object based on the resultSet and list of properties the columns in
@@ -34,8 +21,15 @@ public class RawSqlBuilder {
* The properties listed in the propertyNames must be in the same order as the columns in the
* resultSet.
*/
public static RawSql resultSet(ResultSet resultSet, String... propertyNames) {
return new RawSql(resultSet, propertyNames);
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);
}
/**
@@ -43,10 +37,8 @@ public class RawSqlBuilder {
* modified - so no additional WHERE or HAVING expressions can be added to
* this query.
*/
public static RawSqlBuilder unparsed(String sql) {
Sql s = new Sql(sql);
return new RawSqlBuilder(s, new ColumnMapping());
static RawSqlBuilder unparsed(String sql) {
return XServiceProvider.rawSql().unparsed(sql);
}
/**
@@ -62,19 +54,8 @@ public class RawSqlBuilder {
* correct column names are entered into the mapping.
* </p>
*/
public static RawSqlBuilder parse(String sql) {
Sql sql2 = DRawSqlParser.parse(sql);
String select = sql2.getPreFrom();
ColumnMapping mapping = DRawSqlColumnsParser.parse(select);
return new RawSqlBuilder(sql2, mapping);
}
private RawSqlBuilder(Sql sql, ColumnMapping columnMapping) {
this.sql = sql;
this.columnMapping = columnMapping;
this.resultSet = null;
static RawSqlBuilder parse(String sql) {
return XServiceProvider.rawSql().parsed(sql);
}
/**
@@ -87,17 +68,12 @@ public class RawSqlBuilder {
* @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.
*/
public RawSqlBuilder columnMapping(String dbColumn, String propertyName) {
columnMapping.columnMapping(dbColumn, propertyName);
return this;
}
RawSqlBuilder columnMapping(String dbColumn, String propertyName);
/**
* Ignore this DB column. It is not mapped to any bean property.
*/
public RawSqlBuilder columnMappingIgnore(String dbColumn) {
return columnMapping(dbColumn, IGNORE_COLUMN);
}
RawSqlBuilder columnMappingIgnore(String dbColumn);
/**
* Modify any column mappings with the given table alias to have the path prefix.
@@ -108,24 +84,12 @@ public class RawSqlBuilder {
* For the "Root type" you don't need to specify a tableAliasMapping.
* </p>
*/
public RawSqlBuilder tableAliasMapping(String tableAlias, String path) {
columnMapping.tableAliasMapping(tableAlias, path);
return this;
}
RawSqlBuilder tableAliasMapping(String tableAlias, String path);
/**
* Create the immutable RawSql object. Do this after all the column mapping
* has been defined.
*/
public RawSql create() {
return new RawSql(resultSet, sql, columnMapping.createImmutableCopy());
}
/**
* Return the internal parsed Sql object (for testing).
*/
protected Sql getSql() {
return sql;
}
RawSql create();
}
+17 -1
View File
@@ -1,7 +1,10 @@
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;
@@ -42,6 +45,7 @@ public interface SqlQuery extends Serializable {
/**
* Execute the query returning a list.
*/
@Nonnull
List<SqlRow> findList();
/**
@@ -70,7 +74,14 @@ public interface SqlQuery extends Serializable {
* PersistenceException.
* </p>
*/
SqlRow findUnique();
@Nullable
SqlRow findOne();
/**
* Execute the query returning an optional row.
*/
@Nonnull
Optional<SqlRow> findOneOrEmpty();
/**
* The same as bind for named parameters.
@@ -104,6 +115,11 @@ public interface SqlQuery extends Serializable {
*/
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>
+13
View File
@@ -39,16 +39,19 @@ public interface SqlRow extends Serializable, Map<String, Object> {
/**
* 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);
/**
@@ -118,51 +121,61 @@ public interface SqlRow extends Serializable, Map<String, Object> {
/**
* 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();
}
+60
View File
@@ -30,6 +30,35 @@ package io.ebean;
* 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
@@ -54,6 +83,25 @@ public interface 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.
@@ -88,6 +136,11 @@ public interface SqlUpdate {
*/
SqlUpdate setLabel(String label);
/**
* Set to true when we want to use getGeneratedKeys with this statement.
*/
SqlUpdate setGetGeneratedKeys(boolean getGeneratedKeys);
/**
* Return the sql statement.
*/
@@ -113,6 +166,13 @@ public interface SqlUpdate {
*/
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.
*/
+46 -6
View File
@@ -1,18 +1,34 @@
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 javax.persistence.RollbackException;
import java.io.Closeable;
import java.sql.Connection;
/**
* The Transaction object. Typically representing a JDBC or JTA transaction.
*/
public interface Transaction extends Closeable {
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
@@ -43,6 +59,14 @@ public interface Transaction extends Closeable {
*/
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.
*/
@@ -67,7 +91,7 @@ public interface Transaction extends Closeable {
* <li>Perform post-commit processing updating L2 cache, ElasticSearch etc</li>
* </ul>
*/
void commitAndContinue() throws RollbackException;
void commitAndContinue();
/**
* Commit the transaction.
@@ -85,7 +109,7 @@ public interface Transaction extends Closeable {
* <li>Mark the transaction as "Inactive"</li>
* </ul>
*/
void commit() throws RollbackException;
void commit();
/**
* Rollback the transaction.
@@ -125,7 +149,14 @@ public interface Transaction extends Closeable {
/**
* If the transaction is active then perform rollback. Otherwise do nothing.
*/
void end() throws PersistenceException;
void end();
/**
* Synonym for end() to support AutoClosable.
*/
@Override
void close();
/**
* Return true if the transaction is active.
@@ -423,8 +454,17 @@ public interface Transaction extends Closeable {
* <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;
/**
-47
View File
@@ -1,47 +0,0 @@
package io.ebean;
/**
* Execute a TxCallable in a Transaction scope.
* <p>
* Use this with the {@link Ebean#execute(TxCallable)} method.
* </p>
* <p>
* Note that this is basically the same as TxRunnable except that it returns an
* Object (and you specify the return type via generics).
* </p>
* <p>
* See also {@link TxRunnable}.
* </p>
* <p>
* <pre>{@code
*
* Ebean.execute(new TxCallable<String>() {
* public String call() {
* User u1 = Ebean.find(User.class, 1);
* User u2 = Ebean.find(User.class, 2);
*
* u1.setName("u1 mod");
* u2.setName("u2 mod");
*
* Ebean.save(u1);
* Ebean.save(u2);
*
* return u1.getEmail();
* }
* });
*
* }</pre>
*
* @see TxRunnable
*/
public interface TxCallable<T> {
/**
* Execute the method within a transaction scope returning the result.
* <p>
* If you do not want to return a result you should look to use TxRunnable
* instead.
* </p>
*/
T call();
}
-40
View File
@@ -1,40 +0,0 @@
package io.ebean;
/**
* Execute a TxRunnable in a Transaction scope.
* <p>
* Use this with the {@link Ebean#execute(TxRunnable)} method.
* </p>
* <p>
* See also {@link TxCallable}.
* </p>
* <p>
* <pre>{@code
*
* // this run method runs in a transaction scope
* // which by default is TxScope.REQUIRED
*
* Ebean.execute(new TxRunnable() {
* public void run() {
* User u1 = Ebean.find(User.class, 1);
* User u2 = Ebean.find(User.class, 2);
*
* u1.setName("u1 mod");
* u2.setName("u2 mod");
*
* Ebean.save(u1);
* Ebean.save(u2);
* }
* });
*
* }</pre>
*
* @see TxCallable
*/
public interface TxRunnable {
/**
* Run the method in a transaction sope.
*/
void run();
}
+116 -17
View File
@@ -1,46 +1,62 @@
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 TxRunnable or TxCallable via
* {@link Ebean#execute(TxScope, TxCallable)} or
* {@link Ebean#execute(TxScope, TxRunnable)}.
* 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 TxCallable
* @see TxRunnable
* @see Ebean#execute(TxScope, TxCallable)
* @see Ebean#execute(TxScope, TxRunnable)
* @see Ebean#execute(TxScope, Runnable)
* @see Ebean#executeCall(TxScope, Callable)
*/
public final class TxScope {
TxType type;
private int profileId;
String serverName;
private TxType type;
TxIsolation isolation;
private String serverName;
PersistBatch batch;
private TxIsolation isolation;
PersistBatch batchOnCascade;
private PersistBatch batch;
int batchSize;
private PersistBatch batchOnCascade;
boolean skipGeneratedKeys;
private int batchSize;
boolean readOnly;
private boolean skipGeneratedKeys;
ArrayList<Class<? extends Throwable>> rollbackFor;
private boolean readOnly;
ArrayList<Class<? extends Throwable>> noRollbackFor;
/**
* 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.
@@ -101,6 +117,7 @@ public final class TxScope {
/**
* Describes this TxScope instance.
*/
@Override
public String toString() {
return "TxScope[" + type + "] readOnly[" + readOnly + "] isolation[" + isolation
+ "] serverName[" + serverName + "] rollbackFor[" + rollbackFor + "] noRollbackFor[" + noRollbackFor + "]";
@@ -159,6 +176,66 @@ public final class TxScope {
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.
*/
@@ -234,6 +311,28 @@ public final class TxScope {
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.
*/
+5
View File
@@ -152,6 +152,11 @@ public interface Update<T> {
*/
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.
*/
+6
View File
@@ -148,6 +148,12 @@ public interface UpdateQuery<T> {
*/
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.
*/
+1
View File
@@ -51,6 +51,7 @@ public class ValuePair {
this.oldValue = oldValue;
}
@Override
public String toString() {
return newValue + "," + oldValue;
}
@@ -0,0 +1,50 @@
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,138 +0,0 @@
package io.ebean.annotation;
import io.ebean.TxIsolation;
import io.ebean.TxType;
import io.ebean.PersistBatch;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specify transaction scoping for a method.
* <p>
* <b><i> This is only supported if "Enhancement" is used via javaagent, ANT
* task or IDE enhancement plugin etc. </i></b>
* </p>
* <p>
* Note: Currently there are 3 known annotations that perform this role.
* <ul>
* <li>EJB's javax.ejb.TransactionAttribute</li>
* <li>Spring's org.springframework.transaction.annotation.Transactional</li>
* <li>and this one, Ebean's own Transactional</li>
* </ul>
* Spring created their one because the EJB annotation does not support features
* such as isolation level and specifying rollbackOn, noRollbackOn exceptions.
* This one exists for Ebean because I agree that the standard one is
* insufficient and don't want to include a dependency on Spring.
* </p>
* <p>
* The default behaviour of EJB (and hence Spring) is to NOT ROLLBACK on checked
* exceptions. I find this very counter-intuitive. Ebean will provide a property
* to set the default behaviour to rollback on any exception and optionally
* change the setting to be consistent with EJB/Spring if people wish to do so.
* </p>
* <p>
* <pre>{@code
*
* // a normal class
* public class MySimpleUserService {
*
* // this method is transactional automatically handling
* // transaction begin, commit and rollback etc
* @Transactional
* public void runInTrans() throws IOException {
*
* // tasks performed within the transaction
* ...
* // find some objects
* Customer cust = ebeanServer.find(Customer.class, 42);
*
* Order order = ...;
* ...
* // save some objects
* ebeanServer.save(customer);
* ebeanServer.save(order);
* }
*
* }</pre>
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Transactional {
/**
* The type of transaction scoping. Defaults to REQUIRED.
*/
TxType type() default TxType.REQUIRED;
/**
* Persist batch mode for the transaction.
*/
PersistBatch batch() default PersistBatch.INHERIT;
/**
* Persist batch mode for the request if not set on the transaction.
* <p>
* If batch is set to NONE then batchOnCascade can be set to INSERT or ALL
* and then each save(), delete(), insert(), update() request that cascades
* to child beans can use JDBC batch.
* </p>
*/
PersistBatch batchOnCascade() default PersistBatch.INHERIT;
/**
* The batch size to use when using JDBC batch mode.
* <p>
* If unset this defaults to the value set in ServerConfig.
* </p>
*/
int batchSize() default 0;
/**
* Set to false when we want to skip getting generatedKeys.
* <p>
* This is typically used in the case of large batch inserts where we get a
* performance benefit from not calling getGeneratedKeys (as we are going to
* insert a lot of rows and have no need for the Id values after the insert).
* </p>
*/
boolean getGeneratedKeys() default true;
/**
* The transaction isolation level this transaction should have.
* <p>
* This will only be used if this scope creates the transaction. If the
* transaction has already started then this will currently be ignored (you
* could argue that it should throw an exception).
* </p>
*/
TxIsolation isolation() default TxIsolation.DEFAULT;
/**
* Set this to true if the transaction should be only contain queries.
*/
boolean readOnly() default false;
/**
* The name of the server that you want the transaction to be created from.
* <p>
* If left blank the 'default' server is used.
* </p>
*/
String serverName() default "";
// int timeout() default 0;
/**
* The Throwable's that will explicitly cause a rollback to occur.
*/
Class<? extends Throwable>[] rollbackFor() default {};
/**
* The Throwable's that will explicitly NOT cause a rollback to occur.
*/
Class<? extends Throwable>[] noRollbackFor() default {};
}
@@ -72,6 +72,11 @@ public interface BeanCollection<E> extends Serializable {
*/
boolean isSkipSave();
/**
* Return true if the collection holds modifications.
*/
boolean holdsModifications();
/**
* Return the bean that owns this collection.
*/
@@ -191,6 +196,11 @@ public interface BeanCollection<E> extends Serializable {
*/
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>
@@ -226,4 +236,14 @@ public interface BeanCollection<E> extends Serializable {
* 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();
}
@@ -0,0 +1,22 @@
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();
}
+11 -1
View File
@@ -26,13 +26,16 @@ public final class CallStack implements Serializable {
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();
}
public int hashCode() {
private int computeHashCode() {
int hc = 0;
for (StackTraceElement aCallStack : callStack) {
hc = 92821 * hc + aCallStack.hashCode();
@@ -40,6 +43,12 @@ public final class CallStack implements Serializable {
return hc;
}
@Override
public int hashCode() {
return hc;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
@@ -79,6 +88,7 @@ public final class CallStack implements Serializable {
return pathHash;
}
@Override
public String toString() {
return zeroHash + ":" + pathHash + ":" + callStack[0];
}
+6 -11
View File
@@ -1,6 +1,5 @@
package io.ebean.bean;
import java.beans.PropertyChangeListener;
import java.io.Serializable;
/**
@@ -14,8 +13,14 @@ import java.io.Serializable;
*/
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);
/**
@@ -32,16 +37,6 @@ public interface EntityBean extends Serializable {
*/
Object _ebean_newInstance();
/**
* Add a PropertyChangeListener to this bean.
*/
void addPropertyChangeListener(PropertyChangeListener listener);
/**
* Remove a PropertyChangeListener from this bean.
*/
void removePropertyChangeListener(PropertyChangeListener listener);
/**
* Generated method that sets the loaded state on all the embedded beans on
* this entity bean by using EntityBeanIntercept.setEmbeddedLoaded(Object o);
@@ -5,12 +5,10 @@ import io.ebean.ValuePair;
import javax.persistence.EntityNotFoundException;
import javax.persistence.PersistenceException;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.Serializable;
import java.math.BigDecimal;
import java.net.URL;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
@@ -33,8 +31,6 @@ public final class EntityBeanIntercept implements Serializable {
private transient NodeUsageCollector nodeUsageCollector;
private transient PropertyChangeSupport pcs;
private transient PersistenceContext persistenceContext;
private transient BeanLoader beanLoader;
@@ -56,6 +52,8 @@ public final class EntityBeanIntercept implements Serializable {
*/
private int state;
private boolean forceUpdate;
private boolean readOnly;
private boolean dirty;
@@ -94,6 +92,7 @@ public final class EntityBeanIntercept implements Serializable {
private int lazyLoadProperty = -1;
private Object ownerId;
private int sortOrder;
/**
* Create a intercept with a given entity.
@@ -127,46 +126,6 @@ public final class EntityBeanIntercept implements Serializable {
this.persistenceContext = persistenceContext;
}
/**
* Add a property change listener for this entity bean.
*/
public void addPropertyChangeListener(PropertyChangeListener listener) {
if (pcs == null) {
pcs = new PropertyChangeSupport(owner);
}
pcs.addPropertyChangeListener(listener);
}
/**
* Add a property change listener for this entity bean for a specific
* property.
*/
public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
if (pcs == null) {
pcs = new PropertyChangeSupport(owner);
}
pcs.addPropertyChangeListener(propertyName, listener);
}
/**
* Remove a property change listener for this entity bean.
*/
public void removePropertyChangeListener(PropertyChangeListener listener) {
if (pcs != null) {
pcs.removePropertyChangeListener(listener);
}
}
/**
* Remove a property change listener for this entity bean for a specific
* property.
*/
public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
if (pcs != null) {
pcs.removePropertyChangeListener(propertyName, listener);
}
}
/**
* Turn on profile collection.
*/
@@ -174,6 +133,20 @@ public final class EntityBeanIntercept implements Serializable {
this.nodeUsageCollector = usageCollector;
}
/**
* Return the ownerId (IdClass).
*/
public Object getOwnerId() {
return ownerId;
}
/**
* Set the ownerId (IdClass).
*/
public void setOwnerId(Object ownerId) {
this.ownerId = ownerId;
}
/**
* Return the owning bean for an embedded bean.
*/
@@ -335,6 +308,20 @@ public final class EntityBeanIntercept implements Serializable {
this.readOnly = readOnly;
}
/**
* Set the bean to be updated when persisted (for merge).
*/
public void setForceUpdate(boolean forceUpdate) {
this.forceUpdate = forceUpdate;
}
/**
* Return true if the entity should be updated.
*/
public boolean isUpdate() {
return forceUpdate || state == STATE_LOADED;
}
/**
* Return true if the entity has been loaded.
*/
@@ -506,6 +493,15 @@ public final class EntityBeanIntercept implements Serializable {
loadedProps[propertyIndex] = true;
}
/**
* Set all properties to be loaded (post insert).
*/
public void setLoadedPropertyAll() {
for (int i = 0; i < loadedProps.length; i++) {
loadedProps[i] = true;
}
}
/**
* Return true if the property is loaded.
*/
@@ -563,6 +559,16 @@ public final class EntityBeanIntercept implements Serializable {
}
}
/**
* Set old value but force it to be set regardless if it already has a value.
*/
private void setOriginalValueForce(int propertyIndex, Object value) {
if (origValues == null) {
origValues = new Object[owner._ebean_getPropertyNames().length];
}
origValues[propertyIndex] = value;
}
/**
* For forced update on a 'New' bean set all the loaded properties to changed.
*/
@@ -693,6 +699,28 @@ public final class EntityBeanIntercept implements Serializable {
}
}
/**
* Recursively add dirty properties.
*/
public void addDirtyPropertyValues(BeanDiffVisitor visitor) {
int len = getPropertyLength();
for (int i = 0; i < len; i++) {
if (changedProps != null && changedProps[i]) {
// the property has been changed on this bean
Object newVal = owner._ebean_getField(i);
Object oldVal = getOrigValue(i);
visitor.visit(i, newVal, oldVal);
} else if (embeddedDirty != null && embeddedDirty[i]) {
// an embedded property has been changed - recurse
EntityBean embeddedBean = (EntityBean) owner._ebean_getField(i);
visitor.visitPush(i);
embeddedBean._ebean_getIntercept().addDirtyPropertyValues(visitor);
visitor.visitPop();
}
}
}
/**
* Return a dirty property hash taking into account embedded beans.
*/
@@ -706,6 +734,9 @@ public final class EntityBeanIntercept implements Serializable {
* Add and return a dirty property hash recursing into embedded beans.
*/
private void addDirtyPropertyKey(StringBuilder sb) {
if (sortOrder > 0) {
sb.append("s,");
}
int len = getPropertyLength();
for (int i = 0; i < len; i++) {
if (changedProps != null && changedProps[i]) {
@@ -859,9 +890,9 @@ public final class EntityBeanIntercept implements Serializable {
loadedProps[propertyIndex] = true;
}
private final void preGetterCallback() {
private void preGetterCallback(int propertyIndex) {
if (preGetterCallback != null) {
preGetterCallback.preGetterTrigger();
preGetterCallback.preGetterTrigger(propertyIndex);
}
}
@@ -869,14 +900,14 @@ public final class EntityBeanIntercept implements Serializable {
* Called prior to Id property getter.
*/
public void preGetId() {
preGetterCallback();
preGetterCallback(-1);
}
/**
* Method that is called prior to a getter method on the actual entity.
*/
public void preGetter(int propertyIndex) {
preGetterCallback();
preGetterCallback(propertyIndex);
if (state == STATE_NEW || disableLazyLoad) {
return;
}
@@ -888,49 +919,17 @@ public final class EntityBeanIntercept implements Serializable {
}
}
/**
* Called for "enhancement" postSetter processing. This is around a PUTFIELD
* so no need to check the newValue afterwards.
*/
public void postSetter(PropertyChangeEvent event) {
if (pcs != null && event != null) {
pcs.firePropertyChange(event);
}
}
/**
* Called for "subclassed" postSetter processing. Here the newValue has to be
* re-fetched (and passed into this method) in case there is code inside the
* setter that further mutates the value.
*/
public void postSetter(PropertyChangeEvent event, Object newValue) {
if (pcs != null && event != null) {
if (newValue != null && newValue.equals(event.getNewValue())) {
pcs.firePropertyChange(event);
} else {
pcs.firePropertyChange(event.getPropertyName(), event.getOldValue(), newValue);
}
}
}
/**
* OneToMany and ManyToMany don't have any interception so just check for
* PropertyChangeSupport.
*/
public PropertyChangeEvent preSetterMany(boolean interceptField, int propertyIndex, Object oldValue, Object newValue) {
public void preSetterMany(boolean interceptField, int propertyIndex, Object oldValue, Object newValue) {
if (readOnly) {
throw new IllegalStateException("This bean is readOnly");
}
setLoadedProperty(propertyIndex);
// Bean itself not considered dirty when many changed
if (pcs != null) {
return new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
} else {
return null;
}
}
private void setChangedPropertyValue(int propertyIndex, boolean setDirtyState, Object origValue) {
@@ -942,15 +941,19 @@ public final class EntityBeanIntercept implements Serializable {
if (setDirtyState) {
setOriginalValue(propertyIndex, origValue);
if (!dirty) {
dirty = true;
if (embeddedOwner != null) {
// Cascade dirty state from Embedded bean to parent bean
embeddedOwner._ebean_getIntercept().setEmbeddedDirty(embeddedOwnerIndex);
}
if (nodeUsageCollector != null) {
nodeUsageCollector.setModified();
}
setDirtyStatus();
}
}
private void setDirtyStatus() {
if (!dirty) {
dirty = true;
if (embeddedOwner != null) {
// Cascade dirty state from Embedded bean to parent bean
embeddedOwner._ebean_getIntercept().setEmbeddedDirty(embeddedOwnerIndex);
}
if (nodeUsageCollector != null) {
nodeUsageCollector.setModified();
}
}
}
@@ -959,210 +962,156 @@ public final class EntityBeanIntercept implements Serializable {
* Check to see if the values are not equal. If they are not equal then create
* the old values for use with ConcurrencyMode.ALL.
*/
public PropertyChangeEvent preSetter(boolean intercept, int propertyIndex, Object oldValue, Object newValue) {
public void preSetter(boolean intercept, int propertyIndex, Object oldValue, Object newValue) {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (!areEqual(oldValue, newValue)) {
setChangedPropertyValue(propertyIndex, intercept, oldValue);
} else {
return null;
}
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
}
/**
* Check for primitive boolean.
*/
public PropertyChangeEvent preSetter(boolean intercept, int propertyIndex, boolean oldValue, boolean newValue) {
public void preSetter(boolean intercept, int propertyIndex, boolean oldValue, boolean newValue) {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (oldValue != newValue) {
setChangedPropertyValue(propertyIndex, intercept, oldValue);
} else {
return null;
}
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
}
/**
* Check for primitive int.
*/
public PropertyChangeEvent preSetter(boolean intercept, int propertyIndex, int oldValue, int newValue) {
public void preSetter(boolean intercept, int propertyIndex, int oldValue, int newValue) {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (oldValue != newValue) {
setChangedPropertyValue(propertyIndex, intercept, oldValue);
} else {
return null;
}
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
}
/**
* long.
*/
public PropertyChangeEvent preSetter(boolean intercept, int propertyIndex, long oldValue, long newValue) {
public void preSetter(boolean intercept, int propertyIndex, long oldValue, long newValue) {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (oldValue != newValue) {
setChangedPropertyValue(propertyIndex, intercept, oldValue);
} else {
return null;
}
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
}
/**
* double.
*/
public PropertyChangeEvent preSetter(boolean intercept, int propertyIndex, double oldValue, double newValue) {
public void preSetter(boolean intercept, int propertyIndex, double oldValue, double newValue) {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (oldValue != newValue) {
} else if (Double.compare(oldValue, newValue) != 0) {
setChangedPropertyValue(propertyIndex, intercept, oldValue);
} else {
return null;
}
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
}
/**
* float.
*/
public PropertyChangeEvent preSetter(boolean intercept, int propertyIndex, float oldValue, float newValue) {
public void preSetter(boolean intercept, int propertyIndex, float oldValue, float newValue) {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (oldValue != newValue) {
} else if (Float.compare(oldValue, newValue) != 0) {
setChangedPropertyValue(propertyIndex, intercept, oldValue);
} else {
return null;
}
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
}
/**
* short.
*/
public PropertyChangeEvent preSetter(boolean intercept, int propertyIndex, short oldValue, short newValue) {
public void preSetter(boolean intercept, int propertyIndex, short oldValue, short newValue) {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (oldValue != newValue) {
setChangedPropertyValue(propertyIndex, intercept, oldValue);
} else {
return null;
}
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
}
/**
* char.
*/
public PropertyChangeEvent preSetter(boolean intercept, int propertyIndex, char oldValue, char newValue) {
public void preSetter(boolean intercept, int propertyIndex, char oldValue, char newValue) {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (oldValue != newValue) {
setChangedPropertyValue(propertyIndex, intercept, oldValue);
} else {
return null;
}
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
}
/**
* byte.
*/
public PropertyChangeEvent preSetter(boolean intercept, int propertyIndex, byte oldValue, byte newValue) {
public void preSetter(boolean intercept, int propertyIndex, byte oldValue, byte newValue) {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (oldValue != newValue) {
setChangedPropertyValue(propertyIndex, intercept, oldValue);
} else {
return null;
}
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
}
/**
* char[].
*/
public PropertyChangeEvent preSetter(boolean intercept, int propertyIndex, char[] oldValue, char[] newValue) {
public void preSetter(boolean intercept, int propertyIndex, char[] oldValue, char[] newValue) {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (!areEqualChars(oldValue, newValue)) {
} else if (!Arrays.equals(oldValue, newValue)) {
setChangedPropertyValue(propertyIndex, intercept, oldValue);
} else {
return null;
}
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
}
/**
* byte[].
*/
public PropertyChangeEvent preSetter(boolean intercept, int propertyIndex, byte[] oldValue, byte[] newValue) {
public void preSetter(boolean intercept, int propertyIndex, byte[] oldValue, byte[] newValue) {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (!areEqualBytes(oldValue, newValue)) {
} else if (!Arrays.equals(oldValue, newValue)) {
setChangedPropertyValue(propertyIndex, intercept, oldValue);
} else {
return null;
}
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
}
private static boolean areEqualBytes(byte[] b1, byte[] b2) {
if (b1 == null) {
return (b2 == null);
} else if (b2 == null) {
return false;
} else if (b1 == b2) {
return true;
} else if (b1.length != b2.length) {
return false;
}
for (int i = 0; i < b1.length; i++) {
if (b1[i] != b2[i]) {
return false;
}
}
return true;
/**
* Explicitly set an old value with force (the old value is forced even it is already set).
*/
public void setOldValue(int propertyIndex, Object oldValue) {
setChangedProperty(propertyIndex);
setOriginalValueForce(propertyIndex, oldValue);
setDirtyStatus();
}
private static boolean areEqualChars(char[] b1, char[] b2) {
if (b1 == null) {
return (b2 == null);
/**
* Return the sort order value for an order column.
*/
public int getSortOrder() {
return sortOrder;
}
} else if (b2 == null) {
return false;
} else if (b1 == b2) {
return true;
} else if (b1.length != b2.length) {
return false;
}
for (int i = 0; i < b1.length; i++) {
if (b1[i] != b2[i]) {
return false;
}
}
return true;
/**
* Set the sort order value for an order column.
*/
public void setSortOrder(int sortOrder) {
this.sortOrder = sortOrder;
}
}
@@ -120,6 +120,7 @@ public final class NodeUsageCollector {
return loadProperty;
}
@Override
public String toString() {
return node + " read:" + used + " modified:" + modified;
}
@@ -63,16 +63,19 @@ public final class ObjectGraphNode implements Serializable {
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;
@@ -57,10 +57,12 @@ public final class ObjectGraphOrigin implements Serializable {
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();
@@ -68,6 +70,7 @@ public final class ObjectGraphOrigin implements Serializable {
return hc;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
@@ -7,7 +7,9 @@ package io.ebean.bean;
public interface PreGetterCallback {
/**
* Trigger the callback.
* Trigger the callback based on a getter on a property.
*
* @param propertyIndex The index of the property
*/
void preGetterTrigger();
void preGetterTrigger(int propertyIndex);
}
+32 -2
View File
@@ -1,5 +1,9 @@
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>
@@ -13,20 +17,46 @@ package io.ebean.cache;
*/
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.
*/
Object put(Object id, Object value);
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.
*/
Object remove(Object id);
void remove(Object id);
/**
* Clear all entries from the cache.
+3 -1
View File
@@ -1,5 +1,7 @@
package io.ebean.cache;
import io.ebean.config.CurrentTenantProvider;
/**
* Defines method for constructing caches for beans and queries.
*/
@@ -8,6 +10,6 @@ public interface ServerCacheFactory {
/**
* Create the cache for the given type with options.
*/
ServerCache createCache(ServerCacheType type, String cacheKey, ServerCacheOptions cacheOptions);
ServerCache createCache(ServerCacheType type, String cacheKey, CurrentTenantProvider tenantProvider, ServerCacheOptions cacheOptions);
}
+15
View File
@@ -44,4 +44,19 @@ public interface ServerCacheManager {
*/
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);
}
@@ -39,6 +39,7 @@ public class ServerCacheStatistics {
protected long evictByLRU;
@Override
public String toString() {
//noinspection StringBufferReplaceableByString
StringBuilder sb = new StringBuilder(80);
+77
View File
@@ -0,0 +1,77 @@
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();
}
}
}
@@ -6,7 +6,6 @@ import io.ebean.bean.BeanCollection;
import io.ebean.bean.BeanCollectionLoader;
import io.ebean.bean.EntityBean;
import javax.persistence.PersistenceException;
import java.util.Set;
/**
@@ -47,8 +46,7 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
protected ModifyHolder<E> modifyHolder;
protected ModifyListenMode modifyListenMode;
protected boolean modifyAddListening;
protected boolean modifyRemoveListening;
protected boolean modifyListening;
/**
@@ -65,21 +63,25 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
this.ebeanServerName = loader.getName();
this.ownerBean = ownerBean;
this.propertyName = propertyName;
this.readOnly = ownerBean._ebean_getIntercept().isReadOnly();
this.readOnly = ownerBean != null && ownerBean._ebean_getIntercept().isReadOnly();
}
@Override
public EntityBean getOwnerBean() {
return ownerBean;
}
@Override
public String getPropertyName() {
return propertyName;
}
@Override
public ExpressionList<?> getFilterMany() {
return filterMany;
}
@Override
public void setFilterMany(ExpressionList<?> filterMany) {
this.filterMany = filterMany;
}
@@ -93,31 +95,28 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
if (loader == null) {
loader = (BeanCollectionLoader) Ebean.getServer(ebeanServerName);
}
if (loader == null) {
String msg = "Lazy loading but LazyLoadEbeanServer is null?"
+ " The LazyLoadEbeanServer needs to be set after deserialization"
+ " to support lazy loading.";
throw new PersistenceException(msg);
}
loader.loadMany(this, onlyIds);
checkEmptyLazyLoad();
}
@Override
public boolean isRegisteredWithLoadContext() {
return registeredWithLoadContext;
}
@Override
public void setLoader(BeanCollectionLoader loader) {
this.registeredWithLoadContext = true;
this.loader = loader;
this.ebeanServerName = loader.getName();
}
@Override
public boolean isReadOnly() {
return readOnly;
}
@Override
public void setReadOnly(boolean readOnly) {
this.readOnly = readOnly;
}
@@ -133,15 +132,19 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
// Support for modify additions deletions etc - ManyToMany
// ---------------------------------------------------------
@Override
public ModifyListenMode getModifyListening() {
return modifyListenMode;
}
/**
* set modifyListening to be on or off.
*/
@Override
public void setModifyListening(ModifyListenMode mode) {
this.modifyListenMode = mode;
this.modifyAddListening = ModifyListenMode.ALL.equals(mode);
this.modifyRemoveListening = modifyAddListening || ModifyListenMode.REMOVALS.equals(mode);
this.modifyListening = modifyRemoveListening || modifyAddListening;
this.modifyListening = mode != null && ModifyListenMode.NONE != mode;
if (modifyListening) {
// lose any existing modifications
modifyHolder = null;
@@ -162,24 +165,28 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
return modifyHolder;
}
@Override
public void modifyAddition(E bean) {
if (modifyAddListening) {
if (modifyListening) {
getModifyHolder().modifyAddition(bean);
}
}
@Override
public void modifyRemoval(Object bean) {
if (modifyRemoveListening) {
if (modifyListening) {
getModifyHolder().modifyRemoval(bean);
}
}
@Override
public void modifyReset() {
if (modifyHolder != null) {
modifyHolder.reset();
}
}
@Override
public Set<E> getModifyAdditions() {
if (modifyHolder == null) {
return null;
@@ -188,6 +195,7 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
}
}
@Override
public Set<E> getModifyRemovals() {
if (modifyHolder == null) {
return null;
@@ -199,7 +207,25 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
/**
* Return true if there are underlying additions or removals.
*/
boolean holdsModifications() {
@Override
public boolean holdsModifications() {
return modifyHolder != null && modifyHolder.hasModifications();
}
@Override
public boolean wasTouched() {
return modifyHolder != null && modifyHolder.wasTouched();
}
/**
* Copies all relevant properties for a clone. See {@link #getShallowCopy()}
* @param other
*/
protected void setFromOriginal(AbstractBeanCollection<E> other) {
this.disableLazyLoad = other.disableLazyLoad;
this.ebeanServerName = other.ebeanServerName;
this.loader = other.loader;
this.ownerBean = other.ownerBean;
this.propertyName = other.propertyName;
}
}
+57 -9
View File
@@ -59,6 +59,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return list == null || (list.isEmpty() && !holdsModifications());
}
@Override
@SuppressWarnings("unchecked")
public void addEntityBean(EntityBean bean) {
list.add((E) bean);
@@ -73,6 +74,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
list.addAll((Collection<? extends E>) other.getActualDetails());
}
@Override
@SuppressWarnings("unchecked")
public void internalAdd(Object bean) {
if (list == null) {
@@ -102,6 +104,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return false;
}
@Override
public boolean checkEmptyLazyLoad() {
if (list == null) {
list = new ArrayList<>();
@@ -153,6 +156,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return list;
}
@Override
public Collection<E> getActualDetails() {
return list;
}
@@ -165,6 +169,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
/**
* Return true if the underlying list is populated.
*/
@Override
public boolean isPopulated() {
return list != null;
}
@@ -173,10 +178,12 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
* Return true if this is a reference (lazy loading) bean collection. This is
* the same as !isPopulated();
*/
@Override
public boolean isReference() {
return list == null;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(50);
sb.append("BeanList ");
@@ -201,11 +208,13 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
* test.
* </p>
*/
@Override
public boolean equals(Object obj) {
init();
return list.equals(obj);
}
@Override
public int hashCode() {
init();
return list.hashCode();
@@ -219,10 +228,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
// proxy method for List
// -----------------------------------------------------//
@Override
public void add(int index, E element) {
checkReadOnly();
init();
if (modifyAddListening) {
if (modifyListening) {
modifyAddition(element);
}
list.add(index, element);
@@ -233,10 +243,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
add(bean);
}
@Override
public boolean add(E o) {
checkReadOnly();
init();
if (modifyAddListening) {
if (modifyListening) {
if (list.add(o)) {
modifyAddition(o);
return true;
@@ -247,32 +258,35 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return list.add(o);
}
@Override
public boolean addAll(Collection<? extends E> c) {
checkReadOnly();
init();
if (modifyAddListening) {
if (modifyListening) {
// all elements in c are added (no contains checking)
getModifyHolder().modifyAdditionAll(c);
}
return list.addAll(c);
}
@Override
public boolean addAll(int index, Collection<? extends E> c) {
checkReadOnly();
init();
if (modifyAddListening) {
if (modifyListening) {
// all elements in c are added (no contains checking)
getModifyHolder().modifyAdditionAll(c);
}
return list.addAll(index, c);
}
@Override
public void clear() {
checkReadOnly();
// TODO: when clear() and not initialised could be more clever
// and fetch just the Id's
initClear();
if (modifyRemoveListening) {
if (modifyListening) {
for (E aList : list) {
getModifyHolder().modifyRemoval(aList);
}
@@ -280,31 +294,37 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
list.clear();
}
@Override
public boolean contains(Object o) {
init();
return list.contains(o);
}
@Override
public boolean containsAll(Collection<?> c) {
init();
return list.containsAll(c);
}
@Override
public E get(int index) {
init();
return list.get(index);
}
@Override
public int indexOf(Object o) {
init();
return list.indexOf(o);
}
@Override
public boolean isEmpty() {
init();
return list.isEmpty();
}
@Override
public Iterator<E> iterator() {
init();
if (isReadOnly()) {
@@ -317,11 +337,13 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return list.iterator();
}
@Override
public int lastIndexOf(Object o) {
init();
return list.lastIndexOf(o);
}
@Override
public ListIterator<E> listIterator() {
init();
if (isReadOnly()) {
@@ -334,6 +356,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return list.listIterator();
}
@Override
public ListIterator<E> listIterator(int index) {
init();
if (isReadOnly()) {
@@ -353,10 +376,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
}
}
@Override
public E remove(int index) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
E o = list.remove(index);
modifyRemoval(o);
return o;
@@ -364,10 +388,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return list.remove(index);
}
@Override
public boolean remove(Object o) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
boolean isRemove = list.remove(o);
if (isRemove) {
modifyRemoval(o);
@@ -377,10 +402,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return list.remove(o);
}
@Override
public boolean removeAll(Collection<?> beans) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
boolean changed = false;
for (Object bean : beans) {
if (list.remove(bean)) {
@@ -394,10 +420,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return list.removeAll(beans);
}
@Override
public boolean retainAll(Collection<?> retainBeans) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
boolean changed = false;
Iterator<E> it = list.iterator();
while (it.hasNext()) {
@@ -414,6 +441,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return list.retainAll(retainBeans);
}
@Override
public E set(int index, E element) {
checkReadOnly();
init();
@@ -426,11 +454,13 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return list.set(index, element);
}
@Override
public int size() {
init();
return list.size();
}
@Override
public List<E> subList(int fromIndex, int toIndex) {
init();
if (isReadOnly()) {
@@ -442,11 +472,13 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return list.subList(fromIndex, toIndex);
}
@Override
public Object[] toArray() {
init();
return list.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
init();
//noinspection SuspiciousToArrayCall
@@ -463,41 +495,57 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
this.i = i;
}
@Override
public void add(E o) {
throw new IllegalStateException("This collection is in ReadOnly mode");
}
@Override
public void remove() {
throw new IllegalStateException("This collection is in ReadOnly mode");
}
@Override
public void set(E o) {
throw new IllegalStateException("This collection is in ReadOnly mode");
}
@Override
public boolean hasNext() {
return i.hasNext();
}
@Override
public boolean hasPrevious() {
return i.hasPrevious();
}
@Override
public E next() {
return i.next();
}
@Override
public int nextIndex() {
return i.nextIndex();
}
@Override
public E previous() {
return i.previous();
}
@Override
public int previousIndex() {
return i.previousIndex();
}
}
@Override
public BeanCollection<E> getShallowCopy() {
BeanList<E> copy = new BeanList<>(new CopyOnFirstWriteList<>(list));
copy.setFromOriginal(this);
return copy;
}
}
+30 -2
View File
@@ -47,6 +47,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
this.map = null;
}
@Override
public boolean isSkipSave() {
return map == null || (map.isEmpty() && !holdsModifications());
}
@@ -86,6 +87,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
throw new RuntimeException("Not allowed for map");
}
@Override
public void internalAdd(Object bean) {
throw new RuntimeException("Not allowed for map");
}
@@ -94,6 +96,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
* Return true if the underlying map has been populated. Returns false if it
* has a deferred fetch pending.
*/
@Override
public boolean isPopulated() {
return map != null;
}
@@ -102,10 +105,12 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
* Return true if this is a reference (lazy loading) bean collection. This is
* the same as !isPopulated();
*/
@Override
public boolean isReference() {
return map == null;
}
@Override
public boolean checkEmptyLazyLoad() {
if (map == null) {
map = new LinkedHashMap<>();
@@ -153,6 +158,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
/**
* Returns the collection of beans (map values).
*/
@Override
public Collection<E> getActualDetails() {
return map.values();
}
@@ -164,10 +170,12 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
* they don't need to be set twice).
* </p>
*/
@Override
public Collection<?> getActualEntries() {
return map.entrySet();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(50);
sb.append("BeanMap ");
@@ -187,20 +195,23 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
/**
* Equal if obj is a Map and equal in a Map sense.
*/
@Override
public boolean equals(Object obj) {
init();
return map.equals(obj);
}
@Override
public int hashCode() {
init();
return map.hashCode();
}
@Override
public void clear() {
checkReadOnly();
initClear();
if (modifyRemoveListening) {
if (modifyListening) {
// add all beans to the removal list
for (E bean : map.values()) {
modifyRemoval(bean);
@@ -209,16 +220,19 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
map.clear();
}
@Override
public boolean containsKey(Object key) {
init();
return map.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
init();
return map.containsValue(value);
}
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public Set<Entry<K, E>> entrySet() {
init();
@@ -232,16 +246,19 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
return map.entrySet();
}
@Override
public E get(Object key) {
init();
return map.get(key);
}
@Override
public boolean isEmpty() {
init();
return map.isEmpty();
}
@Override
public Set<K> keySet() {
init();
if (isReadOnly()) {
@@ -251,6 +268,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
return map.keySet();
}
@Override
public E put(K key, E value) {
checkReadOnly();
init();
@@ -265,6 +283,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
return map.put(key, value);
}
@Override
public void putAll(Map<? extends K, ? extends E> puts) {
checkReadOnly();
init();
@@ -290,10 +309,11 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
throw new IllegalStateException("Method not allowed on Map. Please use List instead.");
}
@Override
public E remove(Object key) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
E o = map.remove(key);
modifyRemoval(o);
return o;
@@ -301,11 +321,13 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
return map.remove(key);
}
@Override
public int size() {
init();
return map.size();
}
@Override
public Collection<E> values() {
init();
if (isReadOnly()) {
@@ -318,4 +340,10 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
return map.values();
}
@Override
public BeanCollection<E> getShallowCopy() {
BeanMap<K, E> copy = new BeanMap<>(new LinkedHashMap<>(map));
copy.setFromOriginal(this);
return copy;
}
}
+39 -7
View File
@@ -48,10 +48,12 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
this.set = null;
}
@Override
public boolean isSkipSave() {
return set == null || (set.isEmpty() && !holdsModifications());
}
@Override
@SuppressWarnings("unchecked")
public void addEntityBean(EntityBean bean) {
set.add((E) bean);
@@ -73,6 +75,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
}
}
@Override
@SuppressWarnings("unchecked")
public void internalAdd(Object bean) {
if (set == null) {
@@ -86,6 +89,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
/**
* Returns true if the underlying set has its data.
*/
@Override
public boolean isPopulated() {
return set != null;
}
@@ -94,10 +98,12 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
* Return true if this is a reference (lazy loading) bean collection. This is
* the same as !isPopulated();
*/
@Override
public boolean isReference() {
return set == null;
}
@Override
public boolean checkEmptyLazyLoad() {
if (set == null) {
set = new LinkedHashSet<>();
@@ -142,6 +148,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
return set;
}
@Override
public Collection<E> getActualDetails() {
return set;
}
@@ -151,6 +158,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
return set;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(50);
sb.append("BeanSet ");
@@ -170,11 +178,13 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
/**
* Equal if obj is a Set and equal in a Set sense.
*/
@Override
public boolean equals(Object obj) {
init();
return set.equals(obj);
}
@Override
public int hashCode() {
init();
return set.hashCode();
@@ -196,10 +206,11 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
// proxy method for map
// -----------------------------------------------------//
@Override
public boolean add(E o) {
checkReadOnly();
init();
if (modifyAddListening) {
if (modifyListening) {
if (set.add(o)) {
modifyAddition(o);
return true;
@@ -210,10 +221,11 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
return set.add(o);
}
@Override
public boolean addAll(Collection<? extends E> addCollection) {
checkReadOnly();
init();
if (modifyAddListening) {
if (modifyListening) {
boolean changed = false;
for (E bean : addCollection) {
if (set.add(bean)) {
@@ -227,10 +239,11 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
return set.addAll(addCollection);
}
@Override
public void clear() {
checkReadOnly();
initClear();
if (modifyRemoveListening) {
if (modifyListening) {
for (E bean : set) {
modifyRemoval(bean);
}
@@ -238,21 +251,25 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
set.clear();
}
@Override
public boolean contains(Object o) {
init();
return set.contains(o);
}
@Override
public boolean containsAll(Collection<?> c) {
init();
return set.containsAll(c);
}
@Override
public boolean isEmpty() {
init();
return set.isEmpty();
}
@Override
public Iterator<E> iterator() {
init();
if (isReadOnly()) {
@@ -264,10 +281,11 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
return set.iterator();
}
@Override
public boolean remove(Object o) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
if (set.remove(o)) {
modifyRemoval(o);
return true;
@@ -277,10 +295,11 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
return set.remove(o);
}
@Override
public boolean removeAll(Collection<?> beans) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
boolean changed = false;
for (Object bean : beans) {
if (set.remove(bean)) {
@@ -293,10 +312,11 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
return set.removeAll(beans);
}
@Override
public boolean retainAll(Collection<?> beans) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
boolean changed = false;
Iterator<?> it = set.iterator();
while (it.hasNext()) {
@@ -313,16 +333,19 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
return set.retainAll(beans);
}
@Override
public int size() {
init();
return set.size();
}
@Override
public Object[] toArray() {
init();
return set.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
init();
//noinspection SuspiciousToArrayCall
@@ -339,17 +362,26 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
this.it = it;
}
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
public E next() {
return it.next();
}
@Override
public void remove() {
throw new IllegalStateException("This collection is in ReadOnly mode");
}
}
@Override
public BeanCollection<E> getShallowCopy() {
BeanSet<E> copy = new BeanSet<>(new LinkedHashSet<>(set));
copy.setFromOriginal(this);
return copy;
}
}
@@ -0,0 +1,180 @@
package io.ebean.common;
import java.io.Serializable;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
/**
* List that copies itself on first write access. Needed to keep memory footprint low and the ability
* to modify lists from cache.
*
* @author Roland Praml, FOCONIS AG
*/
public final class CopyOnFirstWriteList<E> extends AbstractList<E> implements List<E>, Serializable {
private static final long serialVersionUID = 1L;
/**
* The underlying List implementation.
*/
private List<E> list;
public CopyOnFirstWriteList(List<E> list) {
super();
this.list = list;
}
private volatile boolean copied = false;
@Override
public int size() {
return list.size();
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
@Override
public boolean contains(Object o) {
return list.contains(o);
}
@Override
public Object[] toArray() {
return list.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return list.toArray(a);
}
@Override
public boolean add(E e) {
checkCopyOnWrite();
return list.add(e);
}
@Override
public boolean remove(Object o) {
checkCopyOnWrite();
return list.remove(o);
}
@Override
public boolean containsAll(Collection<?> c) {
return list.containsAll(c);
}
@Override
public boolean addAll(Collection<? extends E> c) {
checkCopyOnWrite();
return list.addAll(c);
}
@Override
public boolean addAll(int index, Collection<? extends E> c) {
checkCopyOnWrite();
return list.addAll(index, c);
}
@Override
public boolean removeAll(Collection<?> c) {
checkCopyOnWrite();
return list.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
checkCopyOnWrite();
return list.retainAll(c);
}
@Override
public void replaceAll(UnaryOperator<E> operator) {
checkCopyOnWrite();
list.replaceAll(operator);
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
checkCopyOnWrite();
return list.removeIf(filter);
}
@Override
public void sort(Comparator<? super E> c) {
checkCopyOnWrite();
list.sort(c);
}
@Override
public void clear() {
if (!copied) {
list = new ArrayList<>();
copied = true;
}
}
@Override
public boolean equals(Object o) {
return list.equals(o);
}
@Override
public int hashCode() {
return list.hashCode();
}
@Override
public E get(int index) {
return list.get(index);
}
@Override
public E set(int index, E element) {
checkCopyOnWrite();
return list.set(index, element);
}
@Override
public void add(int index, E element) {
checkCopyOnWrite();
list.add(index, element);
}
@Override
public E remove(int index) {
checkCopyOnWrite();
return list.remove(index);
}
@Override
public int indexOf(Object o) {
return list.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
private void checkCopyOnWrite() {
if (!copied) {
synchronized (this) {
if (!copied) {
list = new ArrayList<>(list);
copied = true;
}
}
}
}
}
@@ -30,6 +30,7 @@ class ModifyCollection<E> implements Collection<E> {
this.c = c;
}
@Override
public boolean add(E o) {
if (c.add(o)) {
owner.modifyAddition(o);
@@ -38,6 +39,7 @@ class ModifyCollection<E> implements Collection<E> {
return false;
}
@Override
public boolean addAll(Collection<? extends E> collection) {
boolean changed = false;
for (E o : collection) {
@@ -28,7 +28,10 @@ class ModifyHolder<E> implements Serializable {
*/
private Set<E> modifyAdditions = new LinkedHashSet<>();
private boolean touched;
void reset() {
touched = false;
modifyDeletions = new LinkedHashSet<>();
modifyAdditions = new LinkedHashSet<>();
}
@@ -44,21 +47,31 @@ class ModifyHolder<E> implements Serializable {
}
}
private boolean undoDeletion(E bean) {
return (bean != null) && modifyDeletions.remove(bean);
}
void modifyAddition(E bean) {
if (bean != null) {
touched = true;
// If it is to delete then just remove the deletion
if (!modifyDeletions.remove(bean)) {
if (!undoDeletion(bean)) {
// Insert
modifyAdditions.add(bean);
}
}
}
private boolean undoAddition(Object bean) {
return (bean != null) && modifyAdditions.remove(bean);
}
@SuppressWarnings("unchecked")
void modifyRemoval(Object bean) {
if (bean != null) {
touched = true;
// If it is to be added then just remove the addition
if (!modifyAdditions.remove(bean)) {
if (!undoAddition(bean)) {
modifyDeletions.add((E) bean);
}
}
@@ -72,6 +85,14 @@ class ModifyHolder<E> implements Serializable {
return modifyDeletions;
}
/**
* Return true if the collection was touched in some way. This is still true even if
* a bean was removed and then added (which is not held as a modification).
*/
boolean wasTouched() {
return touched;
}
/**
* Return true if there additions or removals.
*/
@@ -31,15 +31,18 @@ class ModifyIterator<E> implements Iterator<E> {
this.it = it;
}
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
public E next() {
last = it.next();
return last;
}
@Override
public void remove() {
owner.modifyRemoval(last);
it.remove();
@@ -33,11 +33,13 @@ class ModifyList<E> extends ModifyCollection<E> implements List<E> {
this.list = list;
}
@Override
public void add(int index, E element) {
list.add(index, element);
owner.modifyAddition(element);
}
@Override
public boolean addAll(int index, Collection<? extends E> addCollection) {
if (list.addAll(index, addCollection)) {
for (E bean : addCollection) {
@@ -48,32 +50,39 @@ class ModifyList<E> extends ModifyCollection<E> implements List<E> {
return false;
}
@Override
public E get(int index) {
return list.get(index);
}
@Override
public int indexOf(Object o) {
return list.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
@Override
public ListIterator<E> listIterator() {
return new ModifyListIterator<>(owner, list.listIterator());
}
@Override
public ListIterator<E> listIterator(int index) {
return new ModifyListIterator<>(owner, list.listIterator(index));
}
@Override
public E remove(int index) {
E o = list.remove(index);
owner.modifyRemoval(o);
return o;
}
@Override
public E set(int index, E element) {
E o = list.set(index, element);
owner.modifyAddition(element);
@@ -81,6 +90,7 @@ class ModifyList<E> extends ModifyCollection<E> implements List<E> {
return o;
}
@Override
public List<E> subList(int fromIndex, int toIndex) {
return new ModifyList<>(owner, list.subList(fromIndex, toIndex));
}
@@ -28,44 +28,53 @@ class ModifyListIterator<E> implements ListIterator<E> {
this.it = it;
}
@Override
public void add(E bean) {
owner.modifyAddition(bean);
last = null;
it.add(bean);
}
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
public boolean hasPrevious() {
return it.hasPrevious();
}
@Override
public E next() {
last = it.next();
return last;
}
@Override
public int nextIndex() {
return it.nextIndex();
}
@Override
public E previous() {
last = it.previous();
return last;
}
@Override
public int previousIndex() {
return it.previousIndex();
}
@Override
public void remove() {
owner.modifyRemoval(last);
last = null;
it.remove();
}
@Override
public void set(E o) {
if (last != null) {
owner.modifyRemoval(last);
@@ -1,11 +1,13 @@
package io.ebean.config;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.util.AnnotationUtil;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Inheritance;
import javax.persistence.Table;
import java.lang.annotation.Annotation;
/**
* Provides some base implementation for NamingConventions.
@@ -14,16 +16,15 @@ import java.lang.annotation.Annotation;
*/
public abstract class AbstractNamingConvention implements NamingConvention {
private static final Pattern TABLE_REPLACE = Pattern.compile("{table}", Pattern.LITERAL);
private static final Pattern COLUMN_REPLACE = Pattern.compile("{column}", Pattern.LITERAL);
/**
* The Constant DEFAULT_SEQ_FORMAT.
*/
public static final String DEFAULT_SEQ_FORMAT = "{table}_seq";
/**
* Sequence Format that includes the Primary Key column
*/
public static final String TABLE_PKCOLUMN_SEQ_FORMAT = "{table}_{column}_seq";
/**
* The catalog.
*/
@@ -76,16 +77,18 @@ public abstract class AbstractNamingConvention implements NamingConvention {
this(DEFAULT_SEQ_FORMAT);
}
@Override
public void setDatabasePlatform(DatabasePlatform databasePlatform) {
this.databasePlatform = databasePlatform;
}
@Override
public String getSequenceName(String tableName, String pkColumn) {
String s = sequenceFormat.replace("{table}", tableName);
String s = TABLE_REPLACE.matcher(sequenceFormat).replaceAll(Matcher.quoteReplacement(tableName));
if (pkColumn == null) {
pkColumn = "";
}
return s.replace("{column}", pkColumn);
return COLUMN_REPLACE.matcher(s).replaceAll(Matcher.quoteReplacement(pkColumn));
}
/**
@@ -152,6 +155,7 @@ public abstract class AbstractNamingConvention implements NamingConvention {
* column names.
* </p>
*/
@Override
public boolean isUseForeignKeyPrefix() {
return useForeignKeyPrefix;
}
@@ -180,47 +184,47 @@ public abstract class AbstractNamingConvention implements NamingConvention {
* @see #getTableNameFromAnnotation(Class)
* @see #getTableNameByConvention(Class)
*/
@Override
public TableName getTableName(Class<?> beanClass) {
while (true) {
TableName tableName = getTableNameFromAnnotation(beanClass);
if (tableName == null) {
Class<?> supCls = beanClass.getSuperclass();
if (hasInheritance(supCls)) {
// get the table as per inherited class in case there
// is not a table annotation in the inheritance hierarchy
return getTableName(supCls);
TableName tableName = getTableNameFromAnnotation(beanClass);
if (tableName == null) {
Class<?> supCls = beanClass.getSuperclass();
if (hasInheritance(supCls)) {
// get the table as per inherited class in case there
// is not a table annotation in the inheritance hierarchy
beanClass = supCls;
continue;
}
tableName = getTableNameByConvention(beanClass);
}
tableName = getTableNameByConvention(beanClass);
// Use naming convention for catalog or schema,
// if not set in the annotation.
String catalog = tableName.getCatalog();
if (isEmpty(catalog)) {
catalog = getCatalog();
}
String schema = tableName.getSchema();
if (isEmpty(schema)) {
schema = getSchema();
}
return new TableName(catalog, schema, tableName.getName());
}
// Use naming convention for catalog or schema,
// if not set in the annotation.
String catalog = tableName.getCatalog();
if (isEmpty(catalog)) {
catalog = getCatalog();
}
String schema = tableName.getSchema();
if (isEmpty(schema)) {
schema = getSchema();
}
return new TableName(catalog, schema, tableName.getName());
}
/**
* Return true if this class is part of entity inheritance.
*/
protected boolean hasInheritance(Class<?> supCls) {
return hasAnnotation(supCls, Inheritance.class) || hasAnnotation(supCls, DiscriminatorValue.class);
return AnnotationUtil.findAnnotationRecursive(supCls, Inheritance.class) != null
|| AnnotationUtil.findAnnotation(supCls, DiscriminatorValue.class) != null;
}
/**
* Return true if the class has the given annotation.
*/
protected boolean hasAnnotation(Class<?> supCls, Class<? extends Annotation> annotation) {
return supCls.getAnnotation(annotation) != null;
}
@Override
public TableName getM2MJoinTableName(TableName lhsTable, TableName rhsTable) {
StringBuilder buffer = new StringBuilder();
@@ -249,7 +253,7 @@ public abstract class AbstractNamingConvention implements NamingConvention {
*/
protected TableName getTableNameFromAnnotation(Class<?> beanClass) {
final Table t = findTableAnnotation(beanClass);
final Table t = AnnotationUtil.findAnnotationRecursive(beanClass, Table.class);
// Take the annotation if defined
if (t != null && !isEmpty(t.name())) {
@@ -262,20 +266,6 @@ public abstract class AbstractNamingConvention implements NamingConvention {
return null;
}
/**
* Search recursively for an @Table in the class hierarchy.
*/
protected Table findTableAnnotation(Class<?> cls) {
if (cls.equals(Object.class)) {
return null;
}
Table table = cls.getAnnotation(Table.class);
if (table != null) {
return table;
}
return findTableAnnotation(cls.getSuperclass());
}
/**
* Replace back ticks (if they are used) with database platform specific
* quoted identifiers.
@@ -0,0 +1,18 @@
package io.ebean.config;
/**
* Used to provide some automatic configuration early in the creation of an EbeanServer.
*/
public interface AutoConfigure {
/**
* Perform configuration for the ServerConfig prior to properties load.
*/
void preConfigure(ServerConfig serverConfig);
/**
* Provide some configuration the ServerConfig prior to server creation but after properties have been applied.
*/
void postConfigure(ServerConfig serverConfig);
}
@@ -32,6 +32,15 @@ public class AutoTuneConfig {
public AutoTuneConfig() {
}
/**
* Return true if we are profiling or query tuning.
*
* If we are not doing either then we don't need a CallStack.
*/
public boolean isActive() {
return profiling || queryTuning;
}
/**
* Return the name of the file that holds the query tuning information.
*/
@@ -54,6 +54,22 @@ public class ClassLoadConfig {
return isPresent("javax.validation.constraints.NotNull");
}
/**
* Return true if javax PostConstruct annotation is present (maybe not in java9).
* If not we don't support PostConstruct lifecycle events.
*/
public boolean isJavaxPostConstructPresent() {
return isPresent("javax.annotation.PostConstruct");
}
/**
* Return true if javax JAXB is present (maybe not in java9).
* If not we don't try to parse or support 'extra ddl'.
*/
public boolean isJavaxJAXBPresent() {
return isPresent("javax.xml.bind.JAXBException");
}
/**
* Return true if Jackson annotations like JsonIgnore are present.
*/
@@ -118,7 +134,7 @@ public class ClassLoadConfig {
/**
* Wraps the preferred, caller and context class loaders.
*/
protected class ClassLoaderContext {
protected static class ClassLoaderContext {
/**
* Optional - if set only use this classLoader (no fallback).
@@ -10,22 +10,82 @@ import java.util.Properties;
*/
public class ContainerConfig {
protected boolean clusterActive;
private boolean active;
private String serviceName;
private String namespace;
private String podName;
private int port;
protected Properties properties;
private Properties properties;
/**
* Return the service name.
*/
public String getServiceName() {
return serviceName;
}
/**
* Set the service name.
*/
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
/**
* Return the namespace.
*/
public String getNamespace() {
return namespace;
}
/**
* Set the namespace.
*/
public void setNamespace(String namespace) {
this.namespace = namespace;
}
/**
* Return the pod name.
*/
public String getPodName() {
return podName;
}
/**
* Set the pod name.
*/
public void setPodName(String podName) {
this.podName = podName;
}
/**
* Return the port to use.
*/
public int getPort() {
return port;
}
/**
* Set the port to use.
*/
public void setPort(int port) {
this.port = port;
}
/**
* Return true if clustering is active.
*/
public boolean isClusterActive() {
return clusterActive;
public boolean isActive() {
return active;
}
/**
* Set to true for clustering to be active.
*/
public void setClusterActive(boolean clusterActive) {
this.clusterActive = clusterActive;
public void setActive(boolean active) {
this.active = active;
}
/**
@@ -47,7 +107,14 @@ public class ContainerConfig {
*/
public void loadFromProperties(Properties properties) {
this.properties = properties;
this.clusterActive = getProperty(properties, "ebean.cluster.active", clusterActive);
this.active = getProperty(properties, "ebean.cluster.active", active);
this.serviceName = properties.getProperty("ebean.cluster.serviceName", serviceName);
this.namespace = properties.getProperty("ebean.cluster.namespace", namespace);
this.podName = properties.getProperty("ebean.cluster.podName", podName);
String portParam = properties.getProperty("ebean.cluster.port");
if (portParam != null) {
this.port = Integer.parseInt(portParam);
}
}
/**
@@ -3,6 +3,7 @@ package io.ebean.config;
/**
* Provides the Tenant Id for the current request based on the current user.
*/
@FunctionalInterface
public interface CurrentTenantProvider {
/**
@@ -3,6 +3,7 @@ package io.ebean.config;
/**
* Provides the current user in order to support 'Who created', 'Who modified' and other audit features.
*/
@FunctionalInterface
public interface CurrentUserProvider {
/**
@@ -1,7 +1,7 @@
package io.ebean.config;
import io.ebean.config.dbplatform.DbType;
import io.ebean.Platform;
import io.ebean.annotation.Platform;
/**
* Custom mappings for DB types that override the default.
@@ -1,12 +1,18 @@
package io.ebean.config;
import io.ebean.Platform;
import io.ebean.dbmigration.MigrationConfig;
import io.ebean.dbmigration.MigrationRunner;
import io.ebean.EbeanVersion;
import io.ebean.annotation.Platform;
import io.ebean.migration.MigrationConfig;
import io.ebean.migration.MigrationRunner;
import io.ebean.util.StringHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.Properties;
/**
* Configuration for the DB migration processing.
@@ -15,6 +21,8 @@ public class DbMigrationConfig {
protected static final Logger logger = LoggerFactory.getLogger(DbMigrationConfig.class);
protected MigrationConfig runnerConfig = new MigrationConfig();
/**
* The database platform to generate migration DDL for.
*/
@@ -104,6 +112,20 @@ public class DbMigrationConfig {
*/
protected String dbPassword;
protected String patchInsertOn;
protected String patchResetChecksumOn;
/**
* Mode used to check non-null columns added via migration have a default value specified etc.
*/
protected boolean strictMode = true;
/**
* Contains the DDL-header information.
*/
protected String ddlHeader;
/**
* Return the DB platform to generate migration DDL for.
* <p>
@@ -351,6 +373,73 @@ public class DbMigrationConfig {
this.dbPassword = dbPassword;
}
/**
* Return migration versions that should be added to history without running.
*/
public String getPatchInsertOn() {
return patchInsertOn;
}
/**
* Set migration versions that should be added to history without running.
* <p>
* Value can be a string containing comma delimited list of version numbers.
* </p>
*/
public void setPatchInsertOn(String patchInsertOn) {
this.patchInsertOn = patchInsertOn;
}
/**
* Return migration versions that should have their checksum reset and not run.
*/
public String getPatchResetChecksumOn() {
return patchResetChecksumOn;
}
/**
* Returns a DDL header prepend for each DDL. E.g. for copyright headers
* You can use placeholders like ${version} or ${timestamp} in properties file.
*/
public String getDdlHeader() {
return ddlHeader;
}
/**
* Set migration versions that should have their checksum reset and not run.
* <p>
* Value can be a string containing comma delimited list of version numbers.
* </p>
*/
public void setPatchResetChecksumOn(String patchResetChecksumOn) {
this.patchResetChecksumOn = patchResetChecksumOn;
}
/**
* Return true if strict mode is used which includes a check that non-null columns have a default value.
*/
public boolean isStrictMode() {
String envValue = readEnvironment("ddl.migration.strictMode");
if (!isEmpty(envValue)) {
return Boolean.parseBoolean(envValue.trim());
}
return strictMode;
}
/**
* Set to false to turn off strict mode allowing non-null columns to not have a default value.
*/
public void setStrictMode(boolean strictMode) {
this.strictMode = strictMode;
}
/**
* Return the underlying migration runner configuration allowing for more advanced settings.
*/
public MigrationConfig getRunnerConfig() {
return runnerConfig;
}
/**
* Load the settings from the PropertiesWrapper.
*/
@@ -369,18 +458,27 @@ public class DbMigrationConfig {
generate = properties.getBoolean("migration.generate", generate);
version = properties.get("migration.version", version);
name = properties.get("migration.name", name);
patchInsertOn = properties.get("migration.patchInsertOn", patchInsertOn);
patchResetChecksumOn = properties.get("migration.patchResetChecksumOn", patchResetChecksumOn);
runMigration = properties.getBoolean("migration.run", runMigration);
metaTable = properties.get("migration.metaTable", metaTable);
runPlaceholders = properties.get("migration.placeholders", runPlaceholders);
String adminUser = properties.get("datasource." + serverName + ".username", dbUsername);
adminUser = properties.get("datasource." + serverName + ".adminusername", adminUser);
//Do not set user and pass from "datasource.db.username"
//There is a null test in MigrationRunner::getConnection to handle this
//String adminUser = properties.get("datasource." + serverName + ".username", dbUsername);
String adminUser = properties.get("datasource." + serverName + ".adminusername", dbUsername);
dbUsername = properties.get("migration.dbusername", adminUser);
String adminPwd = properties.get("datasource." + serverName + ".password", dbPassword);
adminPwd = properties.get("datasource." + serverName + ".adminpassword", adminPwd);
//String adminPwd = properties.get("datasource." + serverName + ".password", dbPassword);
String adminPwd = properties.get("datasource." + serverName + ".adminpassword", dbPassword);
dbPassword = properties.get("migration.dbpassword", adminPwd);
ddlHeader = properties.get("ddl.header", ddlHeader);
if (ddlHeader != null && !ddlHeader.isEmpty()) {
ddlHeader = StringHelper.replaceString(ddlHeader, "${version}", EbeanVersion.getVersion());
ddlHeader = StringHelper.replaceString(ddlHeader, "${timestamp}", ZonedDateTime.now().format( DateTimeFormatter.ISO_INSTANT ));
}
}
/**
@@ -443,9 +541,8 @@ public class DbMigrationConfig {
/**
* Create the MigrationRunner to run migrations if necessary.
*/
public MigrationRunner createRunner(ClassLoader classLoader) {
public MigrationRunner createRunner(ClassLoader classLoader, Properties properties) {
MigrationConfig runnerConfig = new MigrationConfig();
runnerConfig.setMetaTable(metaTable);
runnerConfig.setApplySuffix(applySuffix);
runnerConfig.setMigrationPath(migrationPath);
@@ -454,6 +551,15 @@ public class DbMigrationConfig {
runnerConfig.setDbUsername(getDbUsername());
runnerConfig.setDbPassword(getDbPassword());
runnerConfig.setClassLoader(classLoader);
if (patchInsertOn != null) {
runnerConfig.setPatchInsertOn(patchInsertOn);
}
if (patchResetChecksumOn != null) {
runnerConfig.setPatchResetChecksumOn(patchResetChecksumOn);
}
if (properties != null) {
runnerConfig.load(properties);
}
return new MigrationRunner(runnerConfig);
}
}
@@ -1,124 +0,0 @@
package io.ebean.config;
import io.ebean.config.dbplatform.DbType;
import io.ebean.config.dbplatform.IdType;
import io.ebean.Platform;
import java.util.ArrayList;
import java.util.List;
/**
* Configuration for DB types such as UUID, Geometry etc.
*/
public class DbTypeConfig {
/**
* The Geometry SRID value (default 4326).
*/
private int geometrySRID = 4326;
/**
* Set for DB's that support both Sequence and Identity (and the default choice is not desired).
*/
private IdType idType;
/**
* Setting to indicate if UUID should be stored as binary(16) or varchar(40) or native DB type (for H2 and Postgres).
*/
private ServerConfig.DbUuid dbUuid = ServerConfig.DbUuid.AUTO_VARCHAR;
/**
* Modify the default mapping of standard types such as default precision for DECIMAL etc.
*/
private List<CustomDbTypeMapping> customDbTypeMappings = new ArrayList<>();
/**
* Return the Geometry SRID.
*/
public int getGeometrySRID() {
return geometrySRID;
}
/**
* Set the Geometry SRID.
*/
public void setGeometrySRID(int geometrySRID) {
this.geometrySRID = geometrySRID;
}
/**
* Return the DB type used to store UUID.
*/
public ServerConfig.DbUuid getDbUuid() {
return dbUuid;
}
/**
* Set the DB type used to store UUID.
*/
public void setDbUuid(ServerConfig.DbUuid dbUuid) {
this.dbUuid = dbUuid;
}
/**
* Return the IdType to use (or null for the default choice).
*/
public IdType getIdType() {
return idType;
}
/**
* Set the IdType to use (when the DB supports both SEQUENCE and IDENTITY and the default is not desired).
*/
public void setIdType(IdType idType) {
this.idType = idType;
}
/**
* Add a custom type mapping.
* <p>
* <pre>{@code
*
* // set the default mapping for BigDecimal.class/decimal
* serverConfig.addCustomMapping(DbType.DECIMAL, "decimal(18,6)");
*
* // set the default mapping for String.class/varchar but only for Postgres
* serverConfig.addCustomMapping(DbType.VARCHAR, "text", Platform.POSTGRES);
*
* }</pre>
*
* @param type The DB type this mapping should apply to
* @param columnDefinition The column definition that should be used
* @param platform Optionally specify the platform this mapping should apply to.
*/
public void addCustomMapping(DbType type, String columnDefinition, Platform platform) {
customDbTypeMappings.add(new CustomDbTypeMapping(type, columnDefinition, platform));
}
/**
* Add a custom type mapping that applies to all platforms.
* <p>
* <pre>{@code
*
* // set the default mapping for BigDecimal/decimal
* serverConfig.addCustomMapping(DbType.DECIMAL, "decimal(18,6)");
*
* // set the default mapping for String/varchar
* serverConfig.addCustomMapping(DbType.VARCHAR, "text");
*
* }</pre>
*
* @param type The DB type this mapping should apply to
* @param columnDefinition The column definition that should be used
*/
public void addCustomMapping(DbType type, String columnDefinition) {
customDbTypeMappings.add(new CustomDbTypeMapping(type, columnDefinition));
}
/**
* Return the list of custom type mappings.
*/
public List<CustomDbTypeMapping> getCustomTypeMappings() {
return customDbTypeMappings;
}
}
@@ -33,6 +33,21 @@ public class DocStoreConfig {
*/
protected String url;
/**
* Credential that be used for authentication to document store.
*/
protected String username;
/**
* Password credential that be used for authentication to document store.
*/
protected String password;
/**
* Set to true such that the client allows connections to invalid/self signed SSL certificates.
*/
protected boolean allowAllCertificates;
/**
* The default mode used by indexes.
*/
@@ -87,6 +102,34 @@ public class DocStoreConfig {
return url;
}
/**
* Return the user credential for connecting to the document store.
*/
public String getUsername() {
return username;
}
/**
* Set the user credential for connecting to the document store.
*/
public void setUsername(String username) {
this.username = username;
}
/**
* Return the password credential for connecting to the document store.
*/
public String getPassword() {
return password;
}
/**
* Set the password credential for connecting to the document store.
*/
public void setPassword(String password) {
this.password = password;
}
/**
* Set the URL to the Document store server.
* <p>
@@ -152,6 +195,20 @@ public class DocStoreConfig {
this.create = create;
}
/**
* Return true if the client allows connections to invalid/self signed SSL certificates.
*/
public boolean isAllowAllCertificates() {
return allowAllCertificates;
}
/**
* Set to true such that the client allows connections to invalid/self signed SSL certificates.
*/
public void setAllowAllCertificates(boolean allowAllCertificates) {
this.allowAllCertificates = allowAllCertificates;
}
/**
* Return the default batch size to use for calls to the Bulk API.
*/
@@ -248,11 +305,14 @@ public class DocStoreConfig {
active = properties.getBoolean("docstore.active", active);
url = properties.get("docstore.url", url);
username = properties.get("docstore.username", url);
password = properties.get("docstore.password", url);
persist = properties.getEnum(DocStoreMode.class, "docstore.persist", persist);
bulkBatchSize = properties.getInt("docstore.bulkBatchSize", bulkBatchSize);
generateMapping = properties.getBoolean("docstore.generateMapping", generateMapping);
dropCreate = properties.getBoolean("docstore.dropCreate", dropCreate);
create = properties.getBoolean("docstore.create", create);
allowAllCertificates = properties.getBoolean("docstore.allowAllCertificates", allowAllCertificates);
mappingPath = properties.get("docstore.mappingPath", mappingPath);
mappingSuffix = properties.get("docstore.mappingSuffix", mappingSuffix);
pathToResources = properties.get("docstore.pathToResources", pathToResources);
@@ -3,6 +3,7 @@ package io.ebean.config;
/**
* Programmatically define which database columns are encrypted.
*/
@FunctionalInterface
public interface EncryptDeployManager {
/**
@@ -6,6 +6,7 @@ package io.ebean.config;
* For simple cases this often represent a simple String key but depending on
* the encryption method this could contain other details.
*/
@FunctionalInterface
public interface EncryptKey {
/**
@@ -3,6 +3,7 @@ package io.ebean.config;
/**
* Determine keys used for encryption and decryption.
*/
@FunctionalInterface
public interface EncryptKeyManager {
/**
@@ -11,7 +12,7 @@ public interface EncryptKeyManager {
* This gives the EncryptKeyManager the opportunity to get keys etc.
* </p>
*/
void initialise();
default void initialise() {}
/**
* Return the key used to encrypt and decrypt a property mapping to the given
@@ -29,23 +29,29 @@ public class MatchingNamingConvention extends AbstractNamingConvention {
super(sequenceFormat);
}
@Override
public String getColumnFromProperty(Class<?> beanClass, String propertyName) {
return propertyName;
return quoteIdentifiers(propertyName);
}
@Override
public TableName getTableNameByConvention(Class<?> beanClass) {
return new TableName(getCatalog(), getSchema(), beanClass.getSimpleName());
}
@Override
public String getPropertyFromColumn(Class<?> beanClass, String dbColumnName) {
return dbColumnName;
}
@Override
public String getForeignKey(String prefix, String fkProperty) {
prefix = databasePlatform.unQuote(prefix);
fkProperty = databasePlatform.unQuote(fkProperty);
// add fkProperty as init caps
return prefix + fkProperty.substring(0, 1).toUpperCase() + fkProperty.substring(1);
String fullName = prefix + fkProperty.substring(0, 1).toUpperCase() + fkProperty.substring(1);
return quoteIdentifiers(fullName);
}
}
@@ -0,0 +1,335 @@
package io.ebean.config;
import io.ebean.annotation.Platform;
import io.ebean.config.dbplatform.DbType;
import io.ebean.config.dbplatform.IdType;
import io.ebean.util.StringHelper;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* Configuration for DB types such as UUID, Geometry etc.
*/
public class PlatformConfig {
private boolean allQuotedIdentifiers;
/**
* The database boolean true value (typically either 1, T, or Y).
*/
private String databaseBooleanTrue;
/**
* The database boolean false value (typically either 0, F or N).
*/
private String databaseBooleanFalse;
/**
* For DB's using sequences this is the number of sequence values prefetched.
*/
private int databaseSequenceBatchSize = 20;
/**
* Set for DB's that support both Sequence and Identity (and the default choice is not desired).
*/
private IdType idType;
/**
* The Geometry SRID value (default 4326).
*/
private int geometrySRID = 4326;
/**
* Setting to indicate if UUID should be stored as binary(16) or varchar(40) or native DB type (for H2 and Postgres).
*/
private DbUuid dbUuid = DbUuid.AUTO_VARCHAR;
/**
* Modify the default mapping of standard types such as default precision for DECIMAL etc.
*/
private List<CustomDbTypeMapping> customDbTypeMappings = new ArrayList<>();
/**
* Construct with defaults.
*/
public PlatformConfig() {
}
/**
* Construct based on given config - typically for DbMigration generation with many platforms.
*/
public PlatformConfig(PlatformConfig platformConfig) {
this.databaseBooleanFalse = platformConfig.databaseBooleanFalse;
this.databaseBooleanTrue = platformConfig.databaseBooleanTrue;
this.databaseSequenceBatchSize = platformConfig.databaseSequenceBatchSize;
this.idType = platformConfig.idType;
this.geometrySRID = platformConfig.geometrySRID;
this.dbUuid = platformConfig.dbUuid;
}
/**
* Return true if all DB column and table names should use quoted identifiers.
*/
public boolean isAllQuotedIdentifiers() {
return allQuotedIdentifiers;
}
/**
* Set to true if all DB column and table names should use quoted identifiers.
*/
public void setAllQuotedIdentifiers(boolean allQuotedIdentifiers) {
this.allQuotedIdentifiers = allQuotedIdentifiers;
}
/**
* Return a value used to represent TRUE in the database.
* <p>
* This is used for databases that do not support boolean natively.
* </p>
* <p>
* The value returned is either a Integer or a String (e.g. "1", or "T").
* </p>
*/
public String getDatabaseBooleanTrue() {
return databaseBooleanTrue;
}
/**
* Set the value to represent TRUE in the database.
* <p>
* This is used for databases that do not support boolean natively.
* </p>
* <p>
* The value set is either a Integer or a String (e.g. "1", or "T").
* </p>
*/
public void setDatabaseBooleanTrue(String databaseBooleanTrue) {
this.databaseBooleanTrue = databaseBooleanTrue;
}
/**
* Return a value used to represent FALSE in the database.
*/
public String getDatabaseBooleanFalse() {
return databaseBooleanFalse;
}
/**
* Set the value used to represent FALSE in the database.
*/
public void setDatabaseBooleanFalse(String databaseBooleanFalse) {
this.databaseBooleanFalse = databaseBooleanFalse;
}
/**
* Return the number of DB sequence values that should be preallocated.
*/
public int getDatabaseSequenceBatchSize() {
return databaseSequenceBatchSize;
}
/**
* Set the number of DB sequence values that should be preallocated.
*/
public void setDatabaseSequenceBatchSize(int databaseSequenceBatchSize) {
this.databaseSequenceBatchSize = databaseSequenceBatchSize;
}
/**
* Return the Geometry SRID.
*/
public int getGeometrySRID() {
return geometrySRID;
}
/**
* Set the Geometry SRID.
*/
public void setGeometrySRID(int geometrySRID) {
this.geometrySRID = geometrySRID;
}
/**
* Return the DB type used to store UUID.
*/
public DbUuid getDbUuid() {
return dbUuid;
}
/**
* Set the DB type used to store UUID.
*/
public void setDbUuid(DbUuid dbUuid) {
this.dbUuid = dbUuid;
}
/**
* Return the IdType to use (or null for the default choice).
*/
public IdType getIdType() {
return idType;
}
/**
* Set the IdType to use (when the DB supports both SEQUENCE and IDENTITY and the default is not desired).
*/
public void setIdType(IdType idType) {
this.idType = idType;
}
/**
* Add a custom type mapping.
* <p>
* <pre>{@code
*
* // set the default mapping for BigDecimal.class/decimal
* serverConfig.addCustomMapping(DbType.DECIMAL, "decimal(18,6)");
*
* // set the default mapping for String.class/varchar but only for Postgres
* serverConfig.addCustomMapping(DbType.VARCHAR, "text", Platform.POSTGRES);
*
* }</pre>
*
* @param type The DB type this mapping should apply to
* @param columnDefinition The column definition that should be used
* @param platform Optionally specify the platform this mapping should apply to.
*/
public void addCustomMapping(DbType type, String columnDefinition, Platform platform) {
customDbTypeMappings.add(new CustomDbTypeMapping(type, columnDefinition, platform));
}
/**
* Add a custom type mapping that applies to all platforms.
* <p>
* <pre>{@code
*
* // set the default mapping for BigDecimal/decimal
* serverConfig.addCustomMapping(DbType.DECIMAL, "decimal(18,6)");
*
* // set the default mapping for String/varchar
* serverConfig.addCustomMapping(DbType.VARCHAR, "text");
*
* }</pre>
*
* @param type The DB type this mapping should apply to
* @param columnDefinition The column definition that should be used
*/
public void addCustomMapping(DbType type, String columnDefinition) {
customDbTypeMappings.add(new CustomDbTypeMapping(type, columnDefinition));
}
/**
* Return the list of custom type mappings.
*/
public List<CustomDbTypeMapping> getCustomTypeMappings() {
return customDbTypeMappings;
}
public void loadSettings(PropertiesWrapper p) {
idType = p.getEnum(IdType.class, "idType", idType);
databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize);
databaseBooleanTrue = p.get("databaseBooleanTrue", databaseBooleanTrue);
databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse);
DbUuid dbUuid = p.getEnum(DbUuid.class, "dbuuid", null);
if (dbUuid != null) {
setDbUuid(dbUuid);
}
if (p.getBoolean("uuidStoreAsBinary", false)) {
setDbUuid(DbUuid.BINARY);
}
int srid = p.getInt("geometrySRID", 0);
if (srid > 0) {
setGeometrySRID(srid);
}
// Mapping is specified in the form: BOOLEAN=int(1);BIT=int(1);
String mapping = p.get("mapping");
if (mapping != null && !mapping.isEmpty()) {
Map<String, String> map = StringHelper.delimitedToMap(mapping, ";", "=");
for (Entry<String, String> entry : map.entrySet()) {
addCustomMapping(DbType.valueOf(entry.getKey()), entry.getValue());
}
}
boolean quotedIdentifiers = p.getBoolean("allQuotedIdentifiers", allQuotedIdentifiers);
if (quotedIdentifiers != allQuotedIdentifiers) {
// potentially also set to use matching naming convention
setAllQuotedIdentifiers(quotedIdentifiers);
}
}
/**
* Specify how UUID is stored.
*/
public enum DbUuid {
/**
* Store using native UUID in H2 and Postgres and otherwise fallback to VARCHAR(40).
*/
AUTO_VARCHAR(true, false, false),
/**
* Store using native UUID in H2 and Postgres and otherwise fallback to BINARY(16).
*/
AUTO_BINARY(true, true, false),
/**
* Store using native UUID in H2 and Postgres and otherwise fallback to BINARY(16) with optimized packing.
*/
AUTO_BINARY_OPTIMIZED(true, true, true),
/**
* Store using DB VARCHAR(40).
*/
VARCHAR(false, false, false),
/**
* Store using DB BINARY(16).
*/
BINARY(false, true, false),
/**
* Store using DB BINARY(16).
*/
BINARY_OPTIMIZED(false, true, true);
boolean nativeType;
boolean binary;
boolean binaryOptimized;
DbUuid(boolean nativeType, boolean binary, boolean binaryOptimized) {
this.nativeType = nativeType;
this.binary = binary;
this.binaryOptimized = binaryOptimized;
}
/**
* Return true if native UUID type is preferred.
*/
public boolean useNativeType() {
return nativeType;
}
/**
* Return true if BINARY(16) storage is preferred over VARCHAR(40).
*/
public boolean useBinary() {
return binary;
}
/**
* Return true, if optimized packing should be used.
*/
public boolean useBinaryOptimized() {
return binaryOptimized;
}
}
}
@@ -0,0 +1,148 @@
package io.ebean.config;
/**
* Configuration for transaction profiling.
*/
public class ProfilingConfig {
/**
* When true transaction profiling is enabled.
*/
private boolean enabled;
/**
* Set true for verbose mode.
*/
private boolean verbose;
/**
* The minimum transaction execution time to be included in profiling.
*/
private long minimumMicros;
/**
* A specific set of profileIds to include in profiling.
*/
private int[] includeProfileIds = {};
/**
* The number of profiles to write per file.
*/
private long profilesPerFile = 1000;
private String directory = "profiling";
/**
* Return true if transaction profiling is enabled.
*/
public boolean isEnabled() {
return enabled;
}
/**
* Set to true to enable transaction profiling.
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
/**
* Return true if verbose mode is used.
*/
public boolean isVerbose() {
return verbose;
}
/**
* Set to true to use verbose mode.
*/
public void setVerbose(boolean verbose) {
this.verbose = verbose;
}
/**
* Return the minimum transaction execution to be included in profiling.
*/
public long getMinimumMicros() {
return minimumMicros;
}
/**
* Set the minimum transaction execution to be included in profiling.
*/
public void setMinimumMicros(long minimumMicros) {
this.minimumMicros = minimumMicros;
}
/**
* Return the specific set of profileIds to include in profiling.
* When not set all transactions with profileIds are included.
*/
public int[] getIncludeProfileIds() {
return includeProfileIds;
}
/**
* Set a specific set of profileIds to include in profiling.
* When not set all transactions with profileIds are included.
*/
public void setIncludeProfileIds(int[] includeProfileIds) {
this.includeProfileIds = includeProfileIds;
}
/**
* Return the number of profiles to write to a single file.
*/
public long getProfilesPerFile() {
return profilesPerFile;
}
/**
* Set the number of profiles to write to a single file.
*/
public void setProfilesPerFile(long profilesPerFile) {
this.profilesPerFile = profilesPerFile;
}
/**
* Return the directory profiling files are put into.
*/
public String getDirectory() {
return directory;
}
/**
* Set the directory profiling files are put into.
*/
public void setDirectory(String directory) {
this.directory = directory;
}
/**
* Load setting from properties.
*/
public void loadSettings(PropertiesWrapper p, String name) {
enabled = p.getBoolean("profiling", enabled);
verbose = p.getBoolean("profiling.verbose", verbose);
directory = p.get("profiling.directory", directory);
profilesPerFile = p.getLong("profiling.profilesPerFile", profilesPerFile);
minimumMicros = p.getLong("profiling.minimumMicros", minimumMicros);
String includeIds = p.get("profiling.includeProfileIds");
if (includeIds != null) {
includeProfileIds = parseIds(includeIds);
}
}
private int[] parseIds(String includeIds) {
String[] ids = includeIds.split(",");
int[] vals = new int[ids.length];
for (int i = 0; i < ids.length; i++) {
vals[i] = Integer.parseInt(ids[i]);
}
return vals;
}
}
@@ -10,44 +10,23 @@ public class PropertiesWrapper {
protected final String serverName;
protected final PropertyMap propertyMap;
private final ClassLoadConfig classLoadConfig;
/**
* Construct with a prefix, serverName and properties.
*/
public PropertiesWrapper(String prefix, String serverName, Properties properties) {
public PropertiesWrapper(String prefix, String serverName, Properties properties, ClassLoadConfig classLoadConfig) {
this.serverName = serverName;
this.prefix = prefix;
this.propertyMap = PropertyMapLoader.load(null, properties);
this.properties = propertyMap.asProperties();
this.properties = properties;
this.classLoadConfig = classLoadConfig;
}
/**
* Construct without prefix of serverName.
*/
public PropertiesWrapper(Properties properties) {
this(null, null, properties);
}
/**
* Internal copy constructor when changing prefix.
*/
protected PropertiesWrapper(String prefix, String serverName, PropertyMap propertyMap, Properties properties) {
this.serverName = serverName;
this.prefix = prefix;
this.propertyMap = propertyMap;
this.properties = properties;
}
/**
* Return a PropertiesWrapper instance with a different prefix but same underlying properties.
* <p/>
* Used when wanting to use "datasource" as the prefix rather than "ebean".
* <p/>
* The returning instance should only be used in a read only fashion.
*/
public PropertiesWrapper withPrefix(String prefix) {
return new PropertiesWrapper(prefix, serverName, propertyMap, properties);
public PropertiesWrapper(Properties properties, ClassLoadConfig classLoadConfig) {
this(null, null, properties, classLoadConfig);
}
/**
@@ -57,16 +36,6 @@ public class PropertiesWrapper {
return serverName;
}
/**
* Return as Properties with lower case keys and after evaluation and additional properties loading has occurred.
* <p>
* Ebean has historically ignored the case of keys hence returning the Properties with all the keys lower cased.
* </p>
*/
public Properties asPropertiesLowerCase() {
return properties;
}
/**
* Get a property with no default value.
*/
@@ -90,17 +59,21 @@ public class PropertiesWrapper {
String value = null;
if (serverName != null && prefix != null) {
value = propertyMap.get(prefix + "." + serverName + "." + key, null);
value = internalGet(prefix + "." + serverName + "." + key);
}
if (value == null && prefix != null) {
value = propertyMap.get(prefix + "." + key, null);
value = internalGet(prefix + "." + key);
}
if (value == null) {
value = propertyMap.get(key, null);
value = internalGet(key);
}
return value == null ? defaultValue : value;
}
private String internalGet(String key) {
return properties.getProperty(key);
}
/**
* Return a double property value.
*/
@@ -145,4 +118,30 @@ public class PropertiesWrapper {
return (level == null) ? defaultValue : Enum.valueOf(enumType, level.toUpperCase());
}
/**
* Return the instance to use (can be null) for the given plugin.
*
* @param pluginType the type of plugin
* @param key properties key
* @param instance existing instance
*/
public <T> T createInstance(Class<T> pluginType, String key, T instance) {
if (instance != null) {
return instance;
}
String classname = get(key, null);
return createInstance(pluginType, classname);
}
/**
* Return the instance to use (can be null) for the given plugin.
*
* @param pluginType the type of plugin
* @param classname the implementation class as per properties
*/
@SuppressWarnings("unchecked")
public <T> T createInstance(Class<T> pluginType, String classname) {
return classname == null ? null : (T) classLoadConfig.newInstance(classname);
}
}
@@ -1,178 +0,0 @@
package io.ebean.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.naming.InitialContext;
import javax.naming.NamingException;
/**
* Helper used to evaluate expressions such as ${CATALINA_HOME}.
* <p>
* The expressions can contain environment variables, system properties or JNDI
* properties. JNDI expressions take the form ${jndi:propertyName} where you
* substitute propertyName with the name of the jndi property you wish to
* evaluate.
* </p>
*/
final class PropertyExpression {
private static final Logger logger = LoggerFactory.getLogger(PropertyExpression.class);
/**
* Prefix for looking up JNDI Environment variable.
*/
private static final String JAVA_COMP_ENV = "java:comp/env/";
/**
* Used to detect the start of an expression.
*/
private static final String START = "${";
/**
* Used to detect the end of an expression.
*/
private static final String END = "}";
/**
* Specify the PropertyHolder.
*/
private PropertyExpression() {
}
/**
* Return the property value evaluating and replacing any expressions such as
* ${CATALINA_HOME}.
*/
static String eval(String val, PropertyMap map) {
if (val == null) {
return null;
}
int sp = val.indexOf(START);
if (sp > -1) {
int ep = val.indexOf(END, sp + 1);
if (ep > -1) {
return eval(val, sp, ep, map);
}
}
return val;
}
/**
* Convert the expression using JNDI, Environment variables, System Properties
* or existing an property in SystemProperties itself.
*/
private static String evaluateExpression(String exp, PropertyMap map) {
if (isJndiExpression(exp)) {
// JNDI property lookup...
String val = getJndiProperty(exp);
if (val != null) {
return val;
}
}
// check Environment Variables first
String val = System.getenv(exp);
if (val == null) {
// then check system properties
val = System.getProperty(exp);
}
if (val == null && map != null) {
// then check PropertyMap
val = map.get(exp);
}
if (val != null) {
return val;
} else {
// unable to evaluate yet... but maybe later based on the order
// in which properties are being set/loaded. You can use
// GlobalProperties.evaluateExpressions() to get any unresolved
// expressions to be evaluated
logger.debug("Unable to evaluate expression [" + exp + "]");
return null;
}
}
private static String eval(String val, int sp, int ep, PropertyMap map) {
StringBuilder sb = new StringBuilder();
sb.append(val.substring(0, sp));
String cal = evalExpression(val, sp, ep, map);
sb.append(cal);
eval(val, ep + 1, sb, map);
return sb.toString();
}
private static void eval(String val, int startPos, StringBuilder sb, PropertyMap map) {
if (startPos < val.length()) {
int sp = val.indexOf(START, startPos);
if (sp > -1) {
// append what is between the last token and the new one (if startPos ==
// sp nothing gets added)
sb.append(val.substring(startPos, sp));
int ep = val.indexOf(END, sp + 1);
if (ep > -1) {
String cal = evalExpression(val, sp, ep, map);
sb.append(cal);
eval(val, ep + 1, sb, map);
return;
}
}
}
// append what is left...
sb.append(val.substring(startPos));
}
private static String evalExpression(String val, int sp, int ep, PropertyMap map) {
// trim off start and end ${ and }
String exp = val.substring(sp + START.length(), ep);
// evaluate the variable
String evaled = evaluateExpression(exp, map);
if (evaled != null) {
return evaled;
} else {
// unable to evaluate at this stage (maybe later)
return START + exp + END;
}
}
private static boolean isJndiExpression(String exp) {
return exp.startsWith("JNDI:") || exp.startsWith("jndi:");
}
/**
* Returns null if JNDI is not setup or if the property is not found.
*
* @param key the key of the JNDI Environment property including a JNDI: prefix.
*/
private static String getJndiProperty(String key) {
try {
// remove the JNDI: prefix
key = key.substring(5);
return (String) getJndiObject(key);
} catch (NamingException ex) {
return null;
}
}
/**
* Similar to getProperty but throws NamingException if JNDI is not setup or
* if the property is not found.
*/
private static Object getJndiObject(String key) throws NamingException {
InitialContext ctx = new InitialContext();
return ctx.lookup(JAVA_COMP_ENV + key);
}
}
@@ -1,167 +0,0 @@
package io.ebean.config;
import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
/**
* A map like structure of properties.
* <p/>
* Handles evaluation of expressions like ${home} and provides convenience methods for int, long and boolean.
*/
public final class PropertyMap implements Serializable {
private static final long serialVersionUID = 1L;
private final LinkedHashMap<String, String> map = new LinkedHashMap<>();
/**
* Return properties loaded from test-ebean.properties.
*/
public static Properties testProperties() {
PropertyMap propertyMap = PropertyMapLoader.loadTestProperties();
return (propertyMap == null) ? new Properties() : propertyMap.asProperties();
}
public static Properties defaultProperties() {
PropertyMap propertyMap = PropertyMapLoader.loadGlobalProperties();
return (propertyMap == null) ? new Properties() : propertyMap.asProperties();
}
public static boolean loadTestProperties() {
String disable = System.getProperty("disableTestProperties");
return (disable == null || !disable.equalsIgnoreCase("true"));
}
public String toString() {
return map.toString();
}
/**
* Return as standard Properties.
*/
public Properties asProperties() {
Properties properties = new Properties();
for (Entry<String, String> e : entrySet()) {
properties.put(e.getKey(), e.getValue());
}
return properties;
}
/**
* Go through all the properties and evaluate any expressions that have not
* been resolved.
*/
public void evaluateProperties() {
for (Entry<String, String> e : entrySet()) {
String key = e.getKey();
String val = e.getValue();
String eval = eval(val);
if (eval != null && !eval.equals(val)) {
put(key, eval);
}
}
}
/**
* Returns the value with expressions like ${home} evaluated using system properties and environment variables.
*/
public synchronized String eval(String val) {
return PropertyExpression.eval(val, this);
}
/**
* Return the boolean property value with a given default.
*/
public synchronized boolean getBoolean(String key, boolean defaultValue) {
String value = get(key);
if (value == null) {
return defaultValue;
} else {
return Boolean.parseBoolean(value);
}
}
/**
* Return the int property value with a given default.
*/
public synchronized int getInt(String key, int defaultValue) {
String value = get(key);
if (value == null) {
return defaultValue;
} else {
return Integer.parseInt(value);
}
}
/**
* Return the long property value with a given default.
*/
public synchronized long getLong(String key, long defaultValue) {
String value = get(key);
if (value == null) {
return defaultValue;
} else {
return Long.parseLong(value);
}
}
/**
* Return the string property value with a given default.
*/
public synchronized String get(String key, String defaultValue) {
String value = map.get(key.toLowerCase());
return value == null ? defaultValue : value;
}
/**
* Return the property value returning null if there is no value defined.
*/
public synchronized String get(String key) {
return map.get(key.toLowerCase());
}
/**
* Put all evaluating any expressions in the values.
*/
public synchronized void putEvalAll(Map<String, String> keyValueMap) {
for (Map.Entry<String, String> entry : keyValueMap.entrySet()) {
putEval(entry.getKey(), entry.getValue());
}
}
/**
* Put a single key value evaluating any expressions in the value.
*/
public synchronized String putEval(String key, String value) {
value = PropertyExpression.eval(value, this);
return map.put(key.toLowerCase(), value);
}
/**
* Put a single key value with no expression evaluation.
*/
public synchronized String put(String key, String value) {
return map.put(key.toLowerCase(), value);
}
/**
* Remove an entry.
*/
public synchronized String remove(String key) {
return map.remove(key.toLowerCase());
}
/**
* Return the entries.
*/
public synchronized Set<Entry<String, String>> entrySet() {
return map.entrySet();
}
}
@@ -1,159 +0,0 @@
package io.ebean.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Properties;
/**
* Helper used to load the ebean.properties into a PropertyMap.
*/
final class PropertyMapLoader {
private static final Logger logger = LoggerFactory.getLogger(PropertyMapLoader.class);
/**
* Load the <code>test-ebean.properties</code>.
*/
public static PropertyMap loadTestProperties() {
if (!PropertyMap.loadTestProperties()) {
return new PropertyMap();
}
return load(null, "test-ebean.properties");
}
/**
* Load the ebean.properties (and test-ebean.properties if present).
*/
public static PropertyMap loadGlobalProperties() {
boolean loadTestProperties = false;
String fileName = System.getenv("EBEAN_PROPS_FILE");
if (fileName == null) {
fileName = System.getProperty("ebean.props.file");
if (fileName == null) {
loadTestProperties = PropertyMap.loadTestProperties();
fileName = "ebean.properties";
}
}
PropertyMap map = load(null, fileName);
if (loadTestProperties) {
// load test properties if present in classpath
map = load(map, "test-ebean.properties");
}
return map;
}
/**
* Load the file returning the property map.
*
* @param p an existing property map to load into.
* @param fileName the name of the properties file to load.
*/
public static PropertyMap load(PropertyMap p, String fileName) {
InputStream is = findInputStream(fileName);
if (is == null) {
return p;
} else {
return load(p, is);
}
}
/**
* Load the InputStream returning the property map.
*
* @param p an existing property map to load into.
* @param in the InputStream of the properties file to load.
*/
public static PropertyMap load(PropertyMap p, InputStream in) {
Properties props = new Properties();
try {
props.load(in);
in.close();
return load(p, props);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static PropertyMap load(PropertyMap p, Properties props) {
if (p == null) {
p = new PropertyMap();
}
// put values in initially without any evaluation
for (Map.Entry<Object, Object> entry : props.entrySet()) {
String key = ((String) entry.getKey()).toLowerCase();
String val = ((String) entry.getValue());
if (val != null) {
val = val.trim();
}
p.put(key, val);
}
p.evaluateProperties();
String otherProps = p.remove("load.properties");
if (otherProps == null) {
otherProps = p.remove("load.properties.override");
}
if (otherProps != null) {
otherProps = otherProps.replace("\\", "/");
InputStream is = findInputStream(otherProps);
if (is != null) {
logger.debug("loading properties from " + otherProps);
load(p, is);
} else {
logger.error("load.properties " + otherProps + " not found.");
}
}
return p;
}
/**
* Find the input stream given the file name.
*/
private static InputStream findInputStream(String fileName) {
if (fileName == null) {
throw new NullPointerException("fileName is null?");
}
try {
File f = new File(fileName);
if (f.exists()) {
logger.debug(fileName + " found in file system");
return new FileInputStream(f);
} else {
InputStream in = findInClassPath(fileName);
if (in != null) {
logger.debug(fileName + " found in classpath");
}
return in;
}
} catch (FileNotFoundException ex) {
// already made the check so this
// should never be thrown
throw new RuntimeException(ex);
}
}
private static InputStream findInClassPath(String fileName) {
return Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
}
}
@@ -1,37 +1,27 @@
package io.ebean.config;
/**
* Matches the functionality of javax.persistence.AttributeConverter
* <p>
* In general AttributeConverter should be used in preference to this
* ScalarTypeConverter as it is JPA standard and offers the same functionality.
* </p>
* <p>
* For Ebean we will look to deprecate this interface in preference to AttributeConverter.
* </p>
* <p>
* Used to convert between a value object and a known scalar type. The value
* object is the logical type used in your application and the scalar type is
* the value used to persist than to the DB.
* </p>
* <p>
* The Value object should be immutable and scalar (aka not compound) and
* converts to and from a known scalar type which Ebean will use to persist the
* value.
* </p>
* <p>
* This is an easier alternative to implementing the
* io.ebean.server.type.ScalarType interface.
* </p>
* <p>
* Note that Ebean will automatically try to detect Immutable Scalar Value
* Objects and automatically support them via reflection. This however would not
* be appropriate when the logical type is different from the type you wish to
* use for persistence - for example, if the logical type was long and you
* wanted to use java.sql.Timestamp for persistence. In this case you would want
* to implement this interface rather than let Ebean automatically support that
* type via reflection.
* </p>
* <p>
* If you want to support a Compound Type rather than a Scalar Type refer to
* {@link CompoundType}.
* </p>
*
* @param <B> The value object type.
* @param <S> The scalar object type that is used to persist the value object.
* @author rbygrave
* @see CompoundType
* @see CompoundTypeProperty
*/
public interface ScalarTypeConverter<B, S> {
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,59 @@
package io.ebean.config;
import io.ebean.bean.ObjectGraphNode;
/**
* Slow query event.
*/
public class SlowQueryEvent {
private final String sql;
private final long timeMillis;
private final int rowCount;
private final ObjectGraphNode originNode;
/**
* Construct with the SQL and execution time in millis.
*/
public SlowQueryEvent(String sql, long timeMillis, int rowCount, ObjectGraphNode originNode) {
this.sql = sql;
this.timeMillis = timeMillis;
this.rowCount = rowCount;
this.originNode = originNode;
}
/**
* Return the SQL for the slow query.
*/
public String getSql() {
return sql;
}
/**
* Return the execution time in millis.
*/
public long getTimeMillis() {
return timeMillis;
}
/**
* Return the total row count associated with the query.
*/
public int getRowCount() {
return rowCount;
}
/**
* Return the origin point for the root query.
* <p>
* Typically the <code>originNode.getOriginQueryPoint().getFirstStackElement()</code> provides the stack line that
* shows the code that invoked the query.
* </p>
*/
public ObjectGraphNode getOriginNode() {
return originNode;
}
}
@@ -0,0 +1,13 @@
package io.ebean.config;
/**
* Listener for slow query events.
*/
@FunctionalInterface
public interface SlowQueryListener {
/**
* Process a slow query event.
*/
void process(SlowQueryEvent event);
}

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