Compare commits

...
Author SHA1 Message Date
rob bygrave 98b4ac5029 [maven-release-plugin] prepare release ebean-parent-12.6.4 2020-12-23 20:25:22 +13:00
rob bygrave fe874c946d #2140 - Bump ebean-migration dependency of ebean-ddl-generator to 12.4.0 (update ebean-test) 2020-12-23 20:22:50 +13:00
rob bygrave 53386e9bf4 Update ebean-core-type name and description only 2020-12-22 16:12:20 +13:00
rob bygrave 5435055f5c Add ebean-redis, ebean-postgis and ebean-core-type to ebean-bom 2020-12-22 16:08:59 +13:00
rob bygrave 583e10f5c6 #2139 - Fix for - Failing testcase that shows wipe of all children on save (related to #2127) 2020-12-22 15:49:37 +13:00
Rob BygraveandGitHub 5393d709a3 Merge pull request #2139 from tobias-/failing_cascade_test_case
Failing testcase that shows wipe of all children on save
2020-12-22 14:55:12 +13:00
Tobias fc1c9392aa Failing testcase that shows wipe of all children on save
When adding a newly saved bean (A) to another bean (B), all children
in A are wiped on saving B.
2020-12-21 15:32:40 +01:00
rob bygrave 6b2c48d4f6 #2135 - ebean doest not support Spring @Transactional(propagation = Propagation.REQUIRES_NEW) 2020-12-21 16:40:19 +13:00
rob bygrave 400ae3cf4b #2138 - Mark Transaction.flushBatch() as deprecated - migrate to flush(); 2020-12-21 14:58:04 +13:00
rob bygrave f22a322104 No effective change - Refactor tidy AbstractSqlQueryRequest after #2137
- Rename trans to transaction
- Tidy whitespace
2020-12-21 14:18:13 +13:00
rob bygrave e98ff952bf #2137 - Expected Transaction flush on SqlQuery and DtoQuery not occurring 2020-12-21 14:11:28 +13:00
rob bygrave 573e1b553c [maven-release-plugin] prepare for next development iteration 2020-12-18 15:04:05 +13:00
rob bygrave a674d0d696 [maven-release-plugin] prepare release ebean-parent-12.6.3 2020-12-18 15:03:53 +13:00
Rob BygraveandGitHub 5393161c16 Merge pull request #2132 from ebean-orm/feature/redisModule
Add ebean-redis as module
2020-12-18 14:58:07 +13:00
rob bygrave 1bdc6d8f7f #2134 - Modify ChangeLog to send the last set of changes Pre Commit (rather than post commit). Expose this for spring transactions. 2020-12-18 14:54:44 +13:00
rob bygrave e9081a176f #2133 - Spring transactions not getting ChangeLog changeSet as part of postCommit() processing 2020-12-18 14:14:43 +13:00
rob bygrave 3e7db2887f Add ebean-redis as module 2020-12-17 14:38:54 +13:00
rob bygrave fcf14ac222 Add ebean-redis as module 2020-12-17 11:56:34 +13:00
Rob BygraveandGitHub 55324653a5 #2127 - Adding a new list of children to @OneToMany with orphanRemoval true does not delete existing orphans (#2131) 2020-12-16 15:36:44 +13:00
SnōwballandGitHub a132f09b03 Ignore javax.persistence.Transient in query beans (#2129)
* Add failing tests for transient types

* Ignore jpa @Transient fields in query beans

Any field marked with jpa @Transient should be ignored
2020-12-15 12:40:06 +13:00
rob bygrave 48eac84930 #2128 - Bump avaje-config dependency to 1.3 - Fix for - Repeated calls to Config.get() with no value, expect to return passed default value 2020-12-14 09:31:08 +13:00
rob bygrave 948619a125 [maven-release-plugin] prepare for next development iteration 2020-12-09 13:11:19 +13:00
rob bygrave 0cd0741f18 [maven-release-plugin] prepare release ebean-parent-12.6.2 2020-12-09 13:11:07 +13:00
rob bygrave 01a3455ecb Bump test dependency for kotlin-querybean-generator release 2020-12-08 20:51:52 +13:00
rob bygrave 610f7db1cb Bump test dependency kotlin version to 1.4.21 after issues downloading 1.4.10 from maven central? 2020-12-08 20:46:36 +13:00
rob bygrave 373ef6d1eb #2126 - Bump ebean-migration to 12.4.0 2020-12-08 20:29:34 +13:00
rob bygrave f1b1cee2fd Bump enhancement tile 2020-12-08 15:43:31 +13:00
rob bygrave a73e4f23ff Bump agent version in BOM 2020-12-08 15:41:59 +13:00
rob bygrave 9a5d3498c1 #2125 - Bump ebean-test-docker dependency to 4.1 2020-12-07 23:00:02 +13:00
rob bygrave 0b24d635ad Tests only - update ddl review 2020-12-07 22:48:32 +13:00
rob bygrave b623e19dae update git ignore 2020-12-07 22:47:43 +13:00
rob bygrave 7389a8b344 #2124 - ENH: Add name() attribute to @DbArray, @DbJson, @DbJsonB, @DbMap 2020-12-07 22:46:04 +13:00
rob bygrave d68f477e8e #2120 - DbEnumValue without database constraint 2020-12-07 21:53:03 +13:00
rob bygrave dbe273bb56 #2123 - Modify BackgroundExecutor API - add scheduleWithFixedDelay() and mark executePeriodically() as deprecated 2020-12-07 17:14:03 +13:00
rob bygrave 1a4377da29 Improve tests TestQueryForUpdate and TestSoftDeleteBasic 2020-12-07 13:29:47 +13:00
rob bygrave c3cdecaa60 Fix test TestSqlUpdateBatch with correct bind type for Postgres 2020-12-07 10:06:15 +13:00
rob bygrave 9d706056c6 No functional change, replace new ReentrantLock(false) with new ReentrantLock() 2020-12-04 21:18:55 +13:00
rob bygrave cb0100f02a Refactor tidy BeanDescriptor, no effective change 2020-12-04 21:11:02 +13:00
rob bygrave 9c6dd0989a Refactor tidy BeanDescriptorManager whitespace and raw types 2020-12-04 21:03:08 +13:00
rob bygrave a23a179bbf Fix test bump kotlin-querybean-generator 12.6.2-SNAPSHOT 2020-12-04 20:45:38 +13:00
rob bygrave 365b7c4600 #2122 - Metrics for ElementCollection query not included in reporting (via MetaInfoManager) 2020-12-04 20:41:40 +13:00
rob bygrave ed2455f460 #2121 - Refactor internals move DefaultBackgroundExecutor etc 2020-12-03 15:47:14 +13:00
rob bygrave 046033627a Update tests - generated sql for add constraint foreign key 2020-12-03 13:22:13 +13:00
Rob BygraveandGitHub 786444a6b9 Refactor BackgroundExecutor add submit() methods returning Future (#2121)
- Adds submit() methods that return Future
- Refactor internals to use DaemonScheduleThreadPool
- Delete the now unused DaemonExecutorService
- Tidy internals using wrapMDC() methods
2020-12-03 13:16:51 +13:00
rob bygrave 9ab26cfb9d #2118 - Fix test only PlatformDdl_AlterColumnTest 2020-12-03 09:48:41 +13:00
rob bygrave aa1e3ea1bc #2118 - Generated code for @DbForeignKey reading onDelete and Ignores onUpdate 2020-12-01 22:04:07 +13:00
Rob BygraveandGitHub c66875449b Add Query.withLock(LockType) and withLock(LockType, LockWait) (#2116)
Add Query.withLock(LockType) and withLock(LockType, LockWait)
2020-12-01 21:31:53 +13:00
rob bygrave f6c4024ae5 No effective change - tidy test only, TestStatelessUpdate 2020-12-01 21:17:19 +13:00
rob bygrave 2c8cc793ab No effective change - tidy test only, TestStatelessUpdate 2020-12-01 14:29:37 +13:00
rob bygrave 66454d2e61 No effective change - bump test dependency for ebean-ddl-generator 2020-11-26 08:57:19 +13:00
rob bygrave e7b13cf2d9 [maven-release-plugin] prepare for next development iteration 2020-11-25 22:48:17 +13:00
rob bygrave 04cd520719 [maven-release-plugin] prepare release ebean-parent-12.6.1 2020-11-25 22:48:05 +13:00
rob bygrave 838af0478e #2113 - Refactor rename Query.LockType enum names 2020-11-25 22:32:59 +13:00
rob bygrave 9064e96b90 #2113 - Refactor rename Query.ForUpdate to Query.LockWait
Slightly improve the name of the enum. Note that although this is on public Query it's only internally used.
2020-11-25 22:23:17 +13:00
Rob BygraveandGitHub 8e91268979 #2110 Part2 - addBatch() does not auto flush (#2115) 2020-11-25 22:18:05 +13:00
rob bygrave cc637d56e1 Tidy tests only TestInsertSqlLogging and TestSqlUpdateExceptions 2020-11-25 21:11:16 +13:00
Rob BygraveandGitHub 9846ebd65d Merge pull request #2112 from ebean-orm/FOCONIS-bug-ebean/sql_update_batch_flush
2110 - Fix and test for executeBatch() on SqlUpdate
2020-11-25 20:40:02 +13:00
rob bygrave b568e2efc7 #2114 - Fix PreparedStatement leak when findEach() with invalid SQL 2020-11-25 20:19:20 +13:00
rob bygrave 20fc74219a #2089 - Postgres - Use NO KEY with FOR UPDATE clauses with Postgres
Rename PlatformConfig.defaultLockWithKey to PlatformConfig.forUpdateNoKey
2020-11-24 23:58:58 +13:00
Rob BygraveandGitHub 92a4bfb38e Merge pull request #2113 from ebean-orm/feature/QueryLockType
Add support for Postgres lock types (no key, share, key share) with FOR UPDATE
2020-11-24 23:48:55 +13:00
rob bygrave 5c34b0daa5 Add support for Postgres lock types (no key, share, key share) with FOR UPDATE 2020-11-24 23:36:54 +13:00
rob bygrave f4ea674d60 #2108 - ebean-k8scache and ebean-cluster not invalidated when only remoteTableMod or remoteCacheEvent 2020-11-24 22:16:14 +13:00
Rob BygraveandGitHub 21f43dc395 Merge pull request #2107 from ebean-orm/feature/ModifyAwareType
Refactor io.ebeaninternal.json.ModifyAwareOwner to io.ebean.ModifyAwareType
2020-11-24 22:05:04 +13:00
rob bygrave 5082ce4280 #2089 Postgres - Support NO KEY option with FOR UPDATE clauses with Postgres 2020-11-24 22:02:06 +13:00
Rob BygraveandGitHub ed061fb3b1 Merge pull request #2090 from ebean-orm/feature/2089
#2089 - Postgres - Use NO KEY with FOR UPDATE clauses with Postgres
2020-11-24 21:49:28 +13:00
rob bygrave 247e96f5db #2110 - Fix for executeBatch() on SqlUpdate + refactor
- Changes to generally not close BatchedPstmt on executeBatch() and instead closed on commit/rollback
2020-11-24 16:40:10 +13:00
Jonas Pöhler (JPo) ce60eac583 ADD: failing testcases for executeBatch() on SqlUpdate
Signed-off-by: Jonas Pöhler (JPo) <jonas.poehler@foconis.de>
2020-11-20 15:56:08 +01:00
rob bygrave c34fcdf7b7 #2089 - Add PlatformConfig.lockWithKey configuration option for - Postgres - Use NO KEY with FOR UPDATE clauses 2020-11-19 22:47:15 +13:00
rob bygrave dcfada0b52 Refactor io.ebeaninternal.json.ModifyAwareOwner to io.ebean.ModifyAwareType
- Rename ModifyAwareOwner to ModifyAwareType
- Move to io.ebean (making it properly public)
- Remove the requirement for Serializable
- Simplify to effectively a getter/setter pair (dirty state flag)
- Simplify to reset the dirty state flag via
2020-11-19 21:50:29 +13:00
Rob BygraveandGitHub fb3fd439bb Merge pull request #2106 from ebean-orm/feature/2105-ebean-core-type
Refactor extract ebean-core-type module moving ScalarType and related interfaces to io.ebean.core.type
2020-11-19 19:56:09 +13:00
rob bygrave 6226672d27 Fix kotlin-querybean-generator version in test 2020-11-19 17:28:44 +13:00
rob bygrave bf72794a4c #2105 - Fix kotlin-querybean-generator version in test 2020-11-19 17:27:53 +13:00
rob bygrave 30a00cb092 #2105 - Refactor extract ebean-core-type module
- Move ScalarType, DataBinder, DataReader, ExtraTypeFactory to ebean-core-type module
- Update the ebean-postgis and other modules
2020-11-19 16:10:00 +13:00
rob bygrave 0bfb6895ad #2105 - Refactor extract interface DataBinder from DataBind 2020-11-19 14:52:19 +13:00
rob bygrave 29345c823e Bump test dependency on ebean-ddl-generator 2020-11-19 09:53:19 +13:00
rob bygrave e71cb4f2ff [maven-release-plugin] prepare for next development iteration 2020-11-19 09:29:27 +13:00
rob bygrave 108a1c7181 [maven-release-plugin] prepare release ebean-parent-12.6.0 2020-11-19 09:29:16 +13:00
rob bygrave 5ce07afed8 Bump ebean-agent version in BOM 2020-11-19 09:23:55 +13:00
rob bygrave d9c4798d4e Bump ebean-test-docker dependency with io.ebean groupId 2020-11-19 09:15:02 +13:00
rob bygrave 6ecd849499 #2104 - Refactor rename ebean-ddlgen module to ebean-ddl-generator 2020-11-18 22:28:33 +13:00
rob bygrave e5b0b31da6 Improve javadoc for DbMigration for pending drops 2020-11-18 22:20:18 +13:00
rob bygrave 1371cb4ff6 #2103 - Bump dependency avaje-config to 1.2 - no effective change, added JPMS Java module support 2020-11-18 22:13:10 +13:00
rob bygrave c788d339fe #2102 - Add to BOM entries for ebean-ddl-runner, ebean-datasource, ebean-migration, ebean-test-docker 2020-11-18 22:09:54 +13:00
rob bygrave 35580fa62b #2101 - Refactor to make ebean-migration optional dependency 2020-11-18 21:52:32 +13:00
rob bygrave b61ae74d3d Tidy only - organise imports in ebean-api 2020-11-17 19:20:28 +13:00
rob bygrave fead4350ce Tidy remove unused imports 2020-11-17 19:15:10 +13:00
rob bygrave 04a651c40d #2100 - Refactor move io.ebean.dbmigration.DbMigration [generation] from ebean-api to ebean-ddlgen module 2020-11-12 22:54:36 +13:00
rob bygrave f394e7f39b #2099 - Refactor internals introduce use of ebean-ddl-runner 2020-11-12 22:42:00 +13:00
rob bygrave 8f7827d3d9 No effective change - bump provided dependency slf4j-api to 1.7.30 2020-11-12 21:19:05 +13:00
rob bygrave 06b54bd824 No effective change - tidy test properties 2020-11-12 14:51:16 +13:00
rob bygrave f473e40bfc #2098 - Refactor simplify SequenceIdGenerator.loadInBackground() to use AtomicBoolean 2020-11-12 13:58:16 +13:00
rob bygrave 1eb5cf1d22 Fix test TransactionManagerTest - close leaked connection
Connection properties to help find leaks are capturestacktrace and maxStackTraceSize, e.g.

datasource.h2.capturestacktrace=true
datasource.h2.maxStackTraceSize=20
2020-11-12 13:55:10 +13:00
rob bygrave b540d70b2d #2097 - Split ebean-datasource dependency to ebean-datasource-api and ebean-datasource 2020-11-12 12:53:32 +13:00
rob bygrave 7b5a8aef73 Bump parent to java8-oss 2.3 with autoReleaseAfterClose false 2020-11-12 12:20:42 +13:00
rob bygrave 3e4daf6947 Revert/Post deploy of ebean-querybean 12.5.2 2020-11-12 12:11:23 +13:00
rob bygrave 0918cbf221 Prepare deploy of ebean-querybean 12.5.2 2020-11-12 11:28:17 +13:00
rob bygrave 3e078e41ff [maven-release-plugin] prepare for next development iteration 2020-11-11 22:47:24 +13:00
rob bygrave a80ab94479 [maven-release-plugin] prepare release ebean-parent-12.5.2 2020-11-11 22:47:12 +13:00
rob bygrave e6f0ab90dc #2094 - Refactor remove isJavaTimePresent() ... we are Java 8+ so removing effectively redundant code 2020-10-23 01:25:28 +13:00
rob bygrave 53f4739c8f #2093 - Refactor remove isJava7Present() ... we are Java 8+ so Java 7 types are always present - Removing effectively redundant code 2020-10-23 01:21:48 +13:00
rob bygrave c6e33ba3ac Modify pom names of modules for more consistency 2020-10-23 00:33:16 +13:00
rob bygrave 0e2528e542 #2092 - Add support for mocking Database interface to MockiEbean 2020-10-23 00:10:50 +13:00
rob bygrave 6ecc10a35c #2091 - Using Postgis types with query gives PersistenceException Caused by: java.sql.SQLException: Unhandled data type [6000] bind number[0] 2020-10-22 22:48:53 +13:00
rob bygrave 59bd2bb251 Add ebean-postgis module 2020-10-22 21:22:41 +13:00
rob bygrave 9fa83cdd5a Move into ebean-postgres sub directory 2020-10-22 21:18:18 +13:00
Rob BygraveandGitHub f383f3f759 Merge pull request #3 from tobias-/failing_test
Failing tests for query with postgis types
2020-10-22 20:56:22 +13:00
rob bygrave c044bc52f7 #2089 - Postgres - Use NO KEY with FOR UPDATE clauses with Postgres 2020-10-22 16:37:18 +13:00
rob bygrave 0abcc9e06e #2085 - Refactor promote getDataSource() and getReadOnlyDataSource() to Database from plugin.SpiServer interface 2020-10-20 12:08:21 +13:00
rob bygrave 4a594b32ef Refactor modify SpiServer to extend Database (rather than EbeanServer) 2020-10-20 11:36:01 +13:00
rob bygrave 8b9f760cb2 Update tests for DatabaseFactory.create() with shutdown 2020-10-19 12:12:00 +13:00
rob bygrave 1d1cf76b5e Update poms adding name, description, change to use explicit snapshot version rather than project.version 2020-10-19 11:21:18 +13:00
rob bygrave 194c14b99a Post manual release of autotune, externalmapping-xml, querybean and test modules 2020-10-19 10:16:25 +13:00
rob bygrave fa8c6839dd [maven-release-plugin] prepare for next development iteration 2020-10-19 09:44:18 +13:00
rob bygrave f8e4ce6b4c [maven-release-plugin] prepare release ebean-test-12.5.1 2020-10-19 09:44:07 +13:00
rob bygrave cce496016d [maven-release-plugin] prepare for next development iteration 2020-10-19 09:38:53 +13:00
rob bygrave 2c4d5dc304 [maven-release-plugin] prepare release ebean-querybean-12.5.1 2020-10-19 09:38:42 +13:00
rob bygrave 1c981130b6 [maven-release-plugin] prepare for next development iteration 2020-10-19 09:34:13 +13:00
rob bygrave c18d1fa288 [maven-release-plugin] prepare release ebean-externalmapping-xml-12.5.1 2020-10-19 09:34:01 +13:00
rob bygrave 5287d93a58 [maven-release-plugin] prepare for next development iteration 2020-10-19 09:30:52 +13:00
rob bygrave 6e6055fb84 [maven-release-plugin] prepare release ebean-autotune-12.5.1 2020-10-19 09:30:40 +13:00
rob bygrave c2ea8b3d56 Prepare manual release of autotune, externalmapping-xml, querybean and test modules 2020-10-19 09:29:54 +13:00
rob bygrave 5885d724c4 Prepare manual release of autotune, externalmapping-xml, querybean and test modules 2020-10-19 09:27:58 +13:00
rob bygrave 90d028640d No effective change - bump maven tiles plugin to 2.18 2020-10-16 18:11:01 +13:00
rob bygrave b8d92f1846 [maven-release-plugin] prepare for next development iteration 2020-10-16 16:08:33 +13:00
rob bygrave e41d2eed7f [maven-release-plugin] prepare release ebean-parent-12.5.1 2020-10-16 16:08:22 +13:00
rob bygrave 8c7a84be9c No effective change - tidy tests that create unregistered Database instances (shutdown) 2020-10-16 16:04:52 +13:00
rob bygrave 63116f25ec Bump ebean-datasource to 6.1 2020-10-16 15:39:29 +13:00
rob bygrave eac05571c8 Update tests for kotlin-querybean-generator to use junit5 2020-10-16 15:38:52 +13:00
rob bygrave a6ad043142 #2082 - Test scope for kotlin-querybean-generator ebean-querybean dependency 2020-10-16 12:23:59 +13:00
SnōwballandGitHub bcc8040afe Scalar type querybeans generics error (#2082)
* Add failing test case for generic querybeans

Types with generics arguments have not been processed correctly, they
will lose their generics. This is not critical in Java, as the language
has to be backwards compatible with Java 1.4, but will still become
highlighted as a warning in all common IDEs.

In Kotlin however, it's not a warning but a compile error.

* Fix problem with generics in scalar type arg

This fixes the issue introduced with ScalarType aware querybeans.
2020-10-16 09:57:32 +13:00
rob bygrave ee73fd47d5 No effective change - tidy javadoc 2020-10-16 00:53:55 +13:00
rob bygrave 064b3ceaa4 #2080 - Refactor convert from sychronized to ReentrantLock
DatabaseFactory, DbPrimary, ScalarTypeArrayList etc
2020-10-16 00:46:13 +13:00
rob bygrave 54ada6e07b #2080 - ebean-autotune - Refactor convert from sychronized to ReentrantLock 2020-10-16 00:28:23 +13:00
Rob BygraveandGitHub 14181932ec Refactor synchronized to ReentrantLock (#2081) 2020-10-16 00:20:42 +13:00
rob bygrave 0faa6a8efd Reset back pom after manual release of ebean-autotune 2020-10-16 00:16:21 +13:00
rob bygrave f94eb9b75e [maven-release-plugin] prepare for next development iteration 2020-10-16 00:03:55 +13:00
rob bygrave 817436b00d [maven-release-plugin] prepare release ebean-autotune-12.5.0 2020-10-16 00:03:42 +13:00
rob bygrave a089a36f9d Prepare manual release of ebean-autotune 2020-10-16 00:03:07 +13:00
rob bygrave 1f1868fdd3 #2079 - Refactor to make Jackson core an optional dependency 2020-10-15 22:04:36 +13:00
rob bygrave 8ac49e537d #2078 - Bump to avaje-config 1.1 - makes snakeyaml dependency optional 2020-10-15 16:51:48 +13:00
Tobias 1e44b81e87 Failing tests for the rest of the gis-types
Simple query tests for:
* Polygon
* LineString
* MultiPoint
* MultiPolygon
* MultiLineString
2020-10-13 15:29:18 +02:00
rob bygrave 133cf95c6d Reset poms for externalmapping-xml querybean and ebean-test modules after manual release take 2 2020-10-14 00:00:17 +13:00
rob bygrave 2caf4bcccd [maven-release-plugin] prepare for next development iteration 2020-10-13 23:29:19 +13:00
rob bygrave e8f0e2f4bf [maven-release-plugin] prepare release ebean-test-12.5.0 2020-10-13 23:29:05 +13:00
rob bygrave 8bde42fb16 [maven-release-plugin] prepare for next development iteration 2020-10-13 23:25:06 +13:00
rob bygrave 2bb1e40c44 [maven-release-plugin] prepare release ebean-querybean-12.5.0 2020-10-13 23:24:52 +13:00
rob bygrave 1ac1e19db0 Manually release ebean-test and ebean-querybean module 12.5.0 by itself
Take 2 with correct groupId
2020-10-13 23:23:58 +13:00
rob bygrave 85a0eb0afb [maven-release-plugin] prepare for next development iteration 2020-10-13 23:16:42 +13:00
Tobias 85b21a02e8 Failing testcase for ebean query serializer 2020-10-12 13:23:49 +02:00
Tobias 4313fb6f58 Add .editorconfig 2020-10-12 11:51:44 +02:00
rob bygrave ee19fd17fa [maven-release-plugin] prepare for next development iteration 2020-09-18 01:22:40 +12:00
rob bygrave a7c6f9835a [maven-release-plugin] prepare release ebean-postgis-12.4.1 2020-09-18 01:22:29 +12:00
rob bygrave 06b1babed9 Bump to 12.4.1 2020-09-18 01:21:50 +12:00
rob bygrave 73ea91d4c9 [maven-release-plugin] prepare for next development iteration 2020-03-13 11:23:01 +13:00
rob bygrave 14839f0c0f [maven-release-plugin] prepare release ebean-postgis-12.2.1 2020-03-13 11:22:51 +13:00
rob bygrave db8f4e141d Bump to 12.2.1 2020-03-13 11:22:22 +13:00
rob bygrave 09fa406f84 [maven-release-plugin] prepare for next development iteration 2019-10-14 15:18:46 +13:00
rob bygrave 50d22ba357 [maven-release-plugin] prepare release ebean-postgis-12.1.1 2019-10-14 15:18:37 +13:00
rob bygrave c6f9d193be Bump to sync to Ebean 12.1.1 2019-10-14 15:18:01 +13:00
rob bygrave 5e1aa47c05 No effective change - update application-test.yml with dbSchema and ddlMode 2018-08-02 12:10:48 +12:00
rob bygrave 21dd8cee37 [maven-release-plugin] prepare for next development iteration 2018-08-02 11:51:10 +12:00
rob bygrave ece82996c2 [maven-release-plugin] prepare release ebean-postgis-11.1.1 2018-08-02 11:50:57 +12:00
rob bygrave fa520c95ea Bump to 11.1.1-SNAPSHOT 2018-08-02 11:50:25 +12:00
rob bygrave a6685141a4 #2 - No effective change - for running tests update to use docker postgis and application-test.yml 2018-08-02 11:48:49 +12:00
rob bygrave 78ab0ad923 No effective change - test logging config update 2018-08-02 11:44:25 +12:00
rob bygrave 4fb67a4c8c #1 - Support Ebean 11.x API - due to Ebean #1153 - Refactor move ExtraTypeFactory out of io.ebean.plugin into io.ebeaninternal 2018-08-02 11:43:52 +12:00
Rob Bygrave dd94e60d16 [maven-release-plugin] prepare for next development iteration 2016-12-13 21:59:31 +13:00
Rob Bygrave aa70e17657 [maven-release-plugin] prepare release ebean-postgis-0.1.3 2016-12-13 21:59:22 +13:00
Rob Bygrave 016cd3fb71 Update for Ebean 10.1.1 2016-12-13 21:58:56 +13:00
Rob Bygrave 17f28ba0aa [maven-release-plugin] prepare for next development iteration 2016-12-01 01:11:15 +13:00
Rob Bygrave ab88a879e9 [maven-release-plugin] prepare release ebean-postgis-0.1.2 2016-12-01 01:11:05 +13:00
Rob Bygrave 5b85f3c8dd Bump to java8 parent, update scm to ssh 2016-12-01 01:10:28 +13:00
Rob Bygrave 16a5100f35 Modify ScalarTypePgisBase to support the older protocol / objects when reading 2016-12-01 01:07:55 +13:00
Rob Bygrave 86b2c5d5b5 [maven-release-plugin] prepare for next development iteration 2016-10-25 22:53:16 +13:00
Rob Bygrave e0c3198ee6 [maven-release-plugin] prepare release ebean-postgis-0.1.1 2016-10-25 22:53:08 +13:00
Rob Bygrave 12bdd847b5 Update pom for initial release 2016-10-25 22:42:17 +13:00
Rob Bygrave 9860816ab7 Update 2016-10-25 22:36:38 +13:00
Rob Bygrave e17283726a Initial add 2016-10-21 02:37:13 +13:00
Rob Bygrave eff61ae5fc Initial commit 2016-10-21 01:32:47 +13:00
838 changed files with 51151 additions and 3529 deletions
+1 -4
View File
@@ -1,6 +1,4 @@
*.autofetch
*create-all.sql
*drop-all.sql
*.orig
.classpath
.project
@@ -12,7 +10,6 @@ ebean-autotune.xml
ebean-profiling*.xml
/db
/mydb.db
!src/test/ddl-review/*.sql
profiling/
# Intellij project files
@@ -20,4 +17,4 @@ profiling/
*.ipr
*.iws
.idea/
*uuid.state
*uuid.state
+12 -15
View File
@@ -1,17 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.5.1-SNAPSHOT</version>
<version>12.6.4</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<name>ebean api</name>
<description>ebean api</description>
<artifactId>ebean-api</artifactId>
<properties>
<jackson-core.version>2.10.0</jackson-core.version>
<jackson-databind.version>2.10.0</jackson-databind.version>
<jackson-core.version>2.11.3</jackson-core.version>
<jackson-databind.version>2.11.3</jackson-databind.version>
</properties>
<dependencies>
@@ -23,14 +25,14 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
<version>1.7.30</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-config</artifactId>
<version>1.0</version>
<version>1.3</version>
</dependency>
<!--
@@ -53,7 +55,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-annotation</artifactId>
<version>6.13</version>
<version>6.15</version>
</dependency>
<dependency>
@@ -64,14 +66,8 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-datasource</artifactId>
<version>5.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-migration</artifactId>
<version>12.1.4</version>
<artifactId>ebean-datasource-api</artifactId>
<version>${ebean-datasource.version}</version>
</dependency>
<!-- Jackson core used internally by Ebean -->
@@ -79,6 +75,7 @@
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson-core.version}</version>
<optional>true</optional>
</dependency>
<!-- provided scope for JsonNode support -->
@@ -1,33 +1,43 @@
package io.ebean;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
* Background thread pool service for executing of tasks asynchronously.
* Background executor service for executing of tasks asynchronously.
* <p>
* This service is used internally by Ebean for executing background tasks such
* as the {@link Query#findFutureList()} and also for executing background tasks
* periodically.
* </p>
* This service can be used to execute tasks in the background.
* <p>
* This service has been made available so you can use it for your application
* code if you want. It can be useful for some server caching implementations
* (background population and trimming of the cache etc).
* </p>
*
* @author rbygrave
* This service is managed by Ebean and will perform a clean shutdown
* waiting for background tasks to complete with a default 30 second
* timeout. Shutdown occurs prior to DataSource shutdown.
* <p>
* This also propagates MDC context from the current thread to the
* background task if defined.
*/
public interface BackgroundExecutor {
/**
* Execute a task in the background.
* Execute a callable task in the background returning the Future.
*/
void execute(Runnable r);
<T> Future<T> submit(Callable<T> task);
/**
* Execute a runnable task in the background returning the Future.
*/
Future<?> submit(Runnable task);
/**
* Execute a task in the background. Effectively the same as
* {@link BackgroundExecutor#submit(Runnable)} but returns void.
*/
void execute(Runnable task);
/**
* Deprecated - migrate to scheduleWithFixedDelay().
* Execute a task periodically with a fixed delay between each execution.
* <p>
* For example, execute a runnable every minute.
@@ -36,27 +46,64 @@ public interface BackgroundExecutor {
* That is, this method has the same behaviour characteristics as
* {@link ScheduledExecutorService#scheduleWithFixedDelay(Runnable, long, long, TimeUnit)}
*/
void executePeriodically(Runnable r, long delay, TimeUnit unit);
@Deprecated
void executePeriodically(Runnable task, long delay, TimeUnit unit);
/**
* Deprecated - migrate to scheduleWithFixedDelay().
* Execute a task periodically additionally with an initial delay different from delay.
*/
void executePeriodically(Runnable r, long initialDelay, long delay, TimeUnit unit);
@Deprecated
void executePeriodically(Runnable task, long initialDelay, long delay, TimeUnit unit);
/**
* Execute a task periodically with a given delay.
*
* @param task the task to execute
* @param initialDelay the time to delay first execution
* @param delay the delay between the termination of one
* execution and the commencement of the next
* @param unit the time unit of the initialDelay and delay parameters
* @return a ScheduledFuture representing pending completion of
* the series of repeated tasks. The future's {@link
* Future#get() get()} method will never return normally,
* and will throw an exception upon task cancellation or
* abnormal termination of a task execution.
*/
ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long initialDelay, long delay, TimeUnit unit);
/**
* Execute a task periodically with a given period.
*
* <p>If any execution of this task takes longer than its period, then
* subsequent executions may start late, but will not concurrently
* execute.
*
* @param task the task to execute
* @param initialDelay the time to delay first execution
* @param period the period between successive executions
* @param unit the time unit of the initialDelay and period parameters
* @return a ScheduledFuture representing pending completion of
* the series of repeated tasks. The future's {@link
* Future#get() get()} method will never return normally,
* and will throw an exception upon task cancellation or
* abnormal termination of a task execution.
*/
ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long initialDelay, long period, TimeUnit unit);
/**
* Schedules a Runnable for one-shot action that becomes enabled after the given delay.
*
* @return a ScheduledFuture representing pending completion of the task and
* whose get() method will return null upon completion
* whose get() method will return null upon completion
*/
ScheduledFuture<?> schedule(Runnable r, long delay, TimeUnit unit);
ScheduledFuture<?> schedule(Runnable task, long delay, TimeUnit unit);
/**
* Schedules a Callable for one-shot action that becomes enabled after the given delay.
*
* @return a ScheduledFuture that can be used to extract result or cancel
*/
<V> ScheduledFuture<V> schedule(Callable<V> c, long delay, TimeUnit unit);
<V> ScheduledFuture<V> schedule(Callable<V> task, long delay, TimeUnit unit);
}
+7
View File
@@ -70,6 +70,13 @@ public final class DB {
private DB() {
}
/**
* Backdoor for registering a mock implementation of Database as the default database.
*/
protected static Database mock(String name, Database server, boolean defaultServer) {
return context.mock(name, server, defaultServer);
}
/**
* Return the default database.
*/
@@ -14,6 +14,7 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceException;
import javax.sql.DataSource;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -121,6 +122,16 @@ public interface Database {
*/
AutoTune getAutoTune();
/**
* Return the associated DataSource for this Database instance.
*/
DataSource getDataSource();
/**
* Return the associated read only DataSource for this Database instance (can be null).
*/
DataSource getReadOnlyDataSource();
/**
* Return the name. This is used with {@link DB#byName(String)} to get a
* Database that was registered with the DB singleton.
@@ -9,6 +9,7 @@ import javax.persistence.PersistenceException;
import java.util.Iterator;
import java.util.Properties;
import java.util.ServiceLoader;
import java.util.concurrent.locks.ReentrantLock;
/**
* Creates Database instances.
@@ -30,6 +31,7 @@ import java.util.ServiceLoader;
*/
public class DatabaseFactory {
private static final ReentrantLock lock = new ReentrantLock();
private static SpiContainer container;
static {
@@ -42,44 +44,63 @@ public class DatabaseFactory {
* Call this prior to creating any Database instances or alternatively set the
* ContainerConfig on the DatabaseConfig when creating the first Database instance.
*/
public static synchronized void initialiseContainer(ContainerConfig containerConfig) {
getContainer(containerConfig);
public static void initialiseContainer(ContainerConfig containerConfig) {
lock.lock();
try {
getContainer(containerConfig);
} finally {
lock.unlock();
}
}
/**
* Create using properties to configure the database.
*/
public static synchronized Database create(String name) {
// construct based on loading properties files
return getContainer(null).createServer(name);
public static Database create(String name) {
lock.lock();
try {
return getContainer(null).createServer(name);
} finally {
lock.unlock();
}
}
/**
* Create using the DatabaseConfig object to configure the database.
*/
public static synchronized Database create(DatabaseConfig config) {
if (config.getName() == null) {
throw new PersistenceException("The name is null (it is required)");
public static Database create(DatabaseConfig config) {
lock.lock();
try {
if (config.getName() == null) {
throw new PersistenceException("The name is null (it is required)");
}
Database server = createInternal(config);
if (config.isRegister()) {
DbPrimary.setSkip(true);
DbContext.getInstance().register(server, config.isDefaultServer());
}
return server;
} finally {
lock.unlock();
}
Database server = createInternal(config);
if (config.isRegister()) {
DbPrimary.setSkip(true);
DbContext.getInstance().register(server, config.isDefaultServer());
}
return server;
}
/**
* Create using the DatabaseConfig additionally specifying a classLoader to use as the context class loader.
*/
public static synchronized Database createWithContextClassLoader(DatabaseConfig config, ClassLoader classLoader) {
ClassLoader currentContextLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);
public static Database createWithContextClassLoader(DatabaseConfig config, ClassLoader classLoader) {
lock.lock();
try {
return DatabaseFactory.create(config);
ClassLoader currentContextLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);
try {
return DatabaseFactory.create(config);
} finally {
// set the currentContextLoader back
Thread.currentThread().setContextClassLoader(currentContextLoader);
}
} finally {
// set the currentContextLoader back
Thread.currentThread().setContextClassLoader(currentContextLoader);
lock.unlock();
}
}
@@ -89,8 +110,13 @@ public class DatabaseFactory {
* This is typically invoked via JVM shutdown hook and not explicitly called.
* </p>
*/
public static synchronized void shutdown() {
container.shutdown();
public static void shutdown() {
lock.lock();
try {
container.shutdown();
} finally {
lock.unlock();
}
}
private static Database createInternal(DatabaseConfig config) {
@@ -103,8 +129,7 @@ public class DatabaseFactory {
* @param containerConfig the configuration controlling clustering communication
*/
private static SpiContainer getContainer(ContainerConfig containerConfig) {
// thread safe in that all calling methods are synchronized
// thread safe in that all calling methods hold lock
if (container != null) {
return container;
}
@@ -123,7 +148,6 @@ public class DatabaseFactory {
* Create the container instance using the configuration.
*/
protected static SpiContainer createContainer(ContainerConfig containerConfig) {
Iterator<SpiContainerFactory> factories = ServiceLoader.load(SpiContainerFactory.class).iterator();
if (factories.hasNext()) {
return factories.next().create(containerConfig);
+12 -13
View File
@@ -8,6 +8,7 @@ import org.slf4j.LoggerFactory;
import javax.persistence.PersistenceException;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
/**
* Holds Database instances.
@@ -22,17 +23,11 @@ final class DbContext {
private static final DbContext INSTANCE = new DbContext();
/**
* Cache for fast concurrent read access.
*/
private final ConcurrentHashMap<String, Database> concMap = new ConcurrentHashMap<>();
/**
* Cache for synchronized read, creation and put. Protected by the monitor object.
*/
private final HashMap<String, Database> syncMap = new HashMap<>();
private final Object monitor = new Object();
private final ReentrantLock lock = new ReentrantLock();
/**
* The 'default' Database.
@@ -91,27 +86,28 @@ final class DbContext {
if (name == null || name.isEmpty()) {
return defaultDatabase;
}
// non-synchronized read
Database server = concMap.get(name);
if (server != null) {
return server;
}
// synchronized read, create and put
return getWithCreate(name);
}
/**
* Synchronized read, create and put of Databases.
* Read, create and put of Databases.
*/
private Database getWithCreate(String name) {
synchronized (monitor) {
lock.lock();
try {
Database server = syncMap.get(name);
if (server == null) {
// register when creating server this way
server = EbeanServerFactory.create(name);
server = DatabaseFactory.create(name);
register(server, false);
}
return server;
} finally {
lock.unlock();
}
}
@@ -123,12 +119,15 @@ final class DbContext {
}
private void registerWithName(String name, Database server, boolean isDefault) {
synchronized (monitor) {
lock.lock();
try {
concMap.put(name, server);
syncMap.put(name, server);
if (isDefault) {
defaultDatabase = server;
}
} finally {
lock.unlock();
}
}
+33 -13
View File
@@ -3,6 +3,7 @@ package io.ebean;
import io.avaje.config.Config;
import java.util.Properties;
import java.util.concurrent.locks.ReentrantLock;
/**
* Provides singleton state for the default database.
@@ -11,47 +12,66 @@ import java.util.Properties;
*/
class DbPrimary {
private static final ReentrantLock lock = new ReentrantLock();
private static String defaultServerName;
private static boolean skip;
/**
* Set whether to skip automatically creating the primary database.
*/
static synchronized void setSkip(boolean skip) {
DbPrimary.skip = skip;
static void setSkip(boolean skip) {
lock.lock();
try {
DbPrimary.skip = skip;
} finally {
lock.unlock();
}
}
/**
* Return true to skip automatically creating the primary database.
*/
static synchronized boolean isSkip() {
return skip;
static boolean isSkip() {
lock.lock();
try {
return skip;
} finally {
lock.unlock();
}
}
/**
* Return the default database name.
*/
static synchronized String getDefaultServerName() {
getProperties();
return defaultServerName;
static String getDefaultServerName() {
lock.lock();
try {
getProperties();
return defaultServerName;
} finally {
lock.unlock();
}
}
/**
* Return the default configuration Properties.
*/
static synchronized Properties getProperties() {
if (defaultServerName == null) {
defaultServerName = determineDefaultServerName();
static Properties getProperties() {
lock.lock();
try {
if (defaultServerName == null) {
defaultServerName = determineDefaultServerName();
}
return Config.asProperties();
} finally {
lock.unlock();
}
return Config.asProperties();
}
/**
* Determine and return the default server name checking system environment variables and then global properties.
*/
private static String determineDefaultServerName() {
String defaultServerName = System.getenv("EBEAN_DB");
defaultServerName = System.getProperty("db", defaultServerName);
defaultServerName = System.getProperty("ebean_db", defaultServerName);
@@ -2,8 +2,8 @@ package io.ebean;
import io.ebean.docstore.DocQueryContext;
import io.ebean.docstore.RawDoc;
import javax.annotation.Nullable;
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.List;
import java.util.Map;
@@ -2,13 +2,6 @@ package io.ebean;
import io.ebean.config.ContainerConfig;
import io.ebean.config.ServerConfig;
import io.ebean.service.SpiContainer;
import io.ebean.service.SpiContainerFactory;
import javax.persistence.PersistenceException;
import java.util.Iterator;
import java.util.Properties;
import java.util.ServiceLoader;
/**
* Deprecated - please migrate to DatabaseFactory.
@@ -39,28 +32,28 @@ public class EbeanServerFactory {
* Call this prior to creating any EbeanServer instances or alternatively set the
* ContainerConfig on the ServerConfig when creating the first EbeanServer instance.
*/
public static synchronized void initialiseContainer(ContainerConfig containerConfig) {
public static void initialiseContainer(ContainerConfig containerConfig) {
DatabaseFactory.initialiseContainer(containerConfig);
}
/**
* Create using ebean.properties to configure the database.
*/
public static synchronized EbeanServer create(String name) {
public static EbeanServer create(String name) {
return (EbeanServer)DatabaseFactory.create(name);
}
/**
* Create using the ServerConfig object to configure the database.
*/
public static synchronized EbeanServer create(ServerConfig config) {
public static EbeanServer create(ServerConfig config) {
return (EbeanServer)DatabaseFactory.create(config);
}
/**
* Create using the ServerConfig additionally specifying a classLoader to use as the context class loader.
*/
public static synchronized EbeanServer createWithContextClassLoader(ServerConfig config, ClassLoader classLoader) {
public static EbeanServer createWithContextClassLoader(ServerConfig config, ClassLoader classLoader) {
return (EbeanServer)DatabaseFactory.createWithContextClassLoader(config, classLoader);
}
@@ -70,7 +63,7 @@ public class EbeanServerFactory {
* This is typically invoked via JVM shutdown hook and not explicitly called.
* </p>
*/
public static synchronized void shutdown() {
public static void shutdown() {
DatabaseFactory.shutdown();
}
@@ -169,11 +169,40 @@ public interface ExpressionList<T> {
*/
UpdateQuery<T> asUpdate();
/**
* Execute the query with the given lock type and WAIT.
* <p>
* Note that <code>forUpdate()</code> is the same as
* <code>withLock(LockType.UPDATE)</code>.
* <p>
* Provides us with the ability to explicitly use Postgres
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
*/
Query<T> withLock(Query.LockType lockType);
/**
* Execute the query with the given lock type and lock wait.
* <p>
* Note that <code>forUpdateNoWait()</code> is the same as
* <code>withLock(LockType.UPDATE, LockWait.NOWAIT)</code>.
* <p>
* Provides us with the ability to explicitly use Postgres
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
*/
Query<T> withLock(Query.LockType lockType, Query.LockWait lockWait);
/**
* Execute using "for update" clause which results in the DB locking the record.
*/
Query<T> forUpdate();
/**
* Deprecated - migrate to withLock().
* Execute using "for update" with given lock type (currently Postgres only).
*/
@Deprecated
Query<T> forUpdate(Query.LockType lockType);
/**
* Execute using "for update" clause with No Wait option.
* <p>
@@ -182,6 +211,13 @@ public interface ExpressionList<T> {
*/
Query<T> forUpdateNoWait();
/**
* Deprecated - migrate to withLock().
* Execute using "for update nowait" with given lock type (currently Postgres only).
*/
@Deprecated
Query<T> forUpdateNoWait(Query.LockType lockType);
/**
* Execute using "for update" clause with Skip Locked option.
* <p>
@@ -190,6 +226,13 @@ public interface ExpressionList<T> {
*/
Query<T> forUpdateSkipLocked();
/**
* Deprecated - migrate to withLock().
* Execute using "for update skip locked" with given lock type (currently Postgres only).
*/
@Deprecated
Query<T> forUpdateSkipLocked(Query.LockType lockType);
/**
* Execute the query including soft deleted rows.
*/
@@ -1,11 +1,9 @@
package io.ebeaninternal.json;
import java.io.Serializable;
package io.ebean;
/**
* Owner object notified when a modification is detected.
*/
public interface ModifyAwareOwner extends Serializable {
public interface ModifyAwareType {
/**
* Return true if the value is considered dirty.
@@ -16,11 +14,6 @@ public interface ModifyAwareOwner extends Serializable {
/**
* Marks the object as modified.
*/
void markAsModified();
/**
* Reset the dirty state to clean.
*/
void resetMarkedDirty();
void setMarkedDirty(boolean markedDirty);
}
+87 -7
View File
@@ -180,13 +180,44 @@ import java.util.stream.Stream;
public interface Query<T> {
/**
* For update mode.
* The lock type (strength) to use with query FOR UPDATE row locking.
*/
enum ForUpdate {
enum LockType {
/**
* The default lock type being either UPDATE or NO_KEY_UPDATE based on
* PlatformConfig.forUpdateNoKey configuration (Postgres option).
*/
DEFAULT,
/**
* FOR UPDATE.
*/
UPDATE,
/**
* FOR NO KEY UPDATE (Postgres only).
*/
NO_KEY_UPDATE,
/**
* FOR SHARE (Postgres only).
*/
SHARE,
/**
* FOR KEY SHARE (Postgres only).
*/
KEY_SHARE
}
/**
* FOR UPDATE wait mode.
*/
enum LockWait {
/**
* Standard For update clause.
*/
BASE,
WAIT,
/**
* For update with No Wait option.
@@ -1613,36 +1644,85 @@ public interface Query<T> {
*/
String getGeneratedSql();
/**
* Execute the query with the given lock type and WAIT.
* <p>
* Note that <code>forUpdate()</code> is the same as
* <code>withLock(LockType.UPDATE)</code>.
* <p>
* Provides us with the ability to explicitly use Postgres
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
*/
Query<T> withLock(LockType lockType);
/**
* Execute the query with the given lock type and lock wait.
* <p>
* Note that <code>forUpdateNoWait()</code> is the same as
* <code>withLock(LockType.UPDATE, LockWait.NOWAIT)</code>.
* <p>
* Provides us with the ability to explicitly use Postgres
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
*/
Query<T> withLock(LockType lockType, LockWait lockWait);
/**
* Execute using "for update" clause which results in the DB locking the record.
* <p>
* The same as <code>withLock(LockType.UPDATE, LockWait.WAIT)</code>.
*/
Query<T> forUpdate();
/**
* Execute using "for update" with given lock type (currently Postgres only).
*/
@Deprecated
Query<T> forUpdate(LockType lockType);
/**
* Execute using "for update" clause with "no wait" option.
* <p>
* This is typically a Postgres and Oracle only option at this stage.
* </p>
* <p>
* The same as <code>withLock(LockType.UPDATE, LockWait.NOWAIT)</code>.
*/
Query<T> forUpdateNoWait();
/**
* Execute using "for update nowait" with given lock type (currently Postgres only).
*/
@Deprecated
Query<T> forUpdateNoWait(LockType lockType);
/**
* Execute using "for update" clause with "skip locked" option.
* <p>
* This is typically a Postgres and Oracle only option at this stage.
* </p>
* <p>
* The same as <code>withLock(LockType.UPDATE, LockWait.SKIPLOCKED)</code>.
*/
Query<T> forUpdateSkipLocked();
/**
* Execute using "for update skip locked" with given lock type (currently Postgres only).
*/
@Deprecated
Query<T> forUpdateSkipLocked(LockType lockType);
/**
* Return true if this query has forUpdate set.
*/
boolean isForUpdate();
/**
* Return the "for update" mode to use.
* Return the "for update" wait mode to use.
*/
ForUpdate getForUpdateMode();
LockWait getForUpdateLockWait();
/**
* Return the lock type (strength) to use with "for update".
*/
LockType getForUpdateLockType();
/**
* Set root table alias.
@@ -2,8 +2,8 @@ package io.ebean;
import io.ebean.annotation.DocStoreMode;
import io.ebean.annotation.PersistBatch;
import io.ebean.config.DocStoreConfig;
import io.ebean.config.DatabaseConfig;
import io.ebean.config.DocStoreConfig;
import javax.persistence.PersistenceException;
import java.sql.Connection;
@@ -519,11 +519,11 @@ public interface Transaction extends AutoCloseable {
void flush() throws PersistenceException;
/**
* This is a synonym for flush() and will be deprecated.
* Deprecated - migrate to flush().
* <p>
* flush() is preferred as it matches the JPA flush() method.
* </p>
*/
@Deprecated
void flushBatch() throws PersistenceException;
/**
@@ -1,5 +1,7 @@
package io.ebean.bean;
import java.util.concurrent.locks.Lock;
/**
* Loads a entity bean.
* <p>
@@ -18,4 +20,9 @@ public interface BeanLoader {
*/
void loadBean(EntityBeanIntercept ebi);
/**
* Obtain a lock on the loader.
*/
Lock lock();
}
@@ -14,6 +14,8 @@ import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* This is the object added to every entity bean using byte code enhancement.
@@ -30,6 +32,8 @@ public final class EntityBeanIntercept implements Serializable {
private static final int STATE_REFERENCE = 1;
private static final int STATE_LOADED = 2;
private transient final ReentrantLock lock = new ReentrantLock();
private transient NodeUsageCollector nodeUsageCollector;
private transient PersistenceContext persistenceContext;
@@ -803,7 +807,8 @@ public final class EntityBeanIntercept implements Serializable {
* Load the bean when it is a reference.
*/
protected void loadBean(int loadProperty) {
synchronized (this) {
lock.lock();
try {
if (beanLoader == null) {
final Database database = DB.byName(ebeanServerName);
if (database == null) {
@@ -811,14 +816,19 @@ public final class EntityBeanIntercept implements Serializable {
}
// For stand alone reference bean or after deserialisation lazy load
// using the ebeanServer. Synchronise only on the bean.
loadBeanInternal(loadProperty, database.getPluginApi());
loadBeanInternal(loadProperty, database.getPluginApi().beanLoader());
return;
}
} finally {
lock.unlock();
}
synchronized (beanLoader) {
final Lock lock = beanLoader.lock();
try {
// Lazy loading using LoadBeanContext which supports batch loading
// Synchronise on the beanLoader (a 'node' of the LoadBeanContext 'tree')
loadBeanInternal(loadProperty, beanLoader);
} finally {
lock.unlock();
}
}
@@ -2,11 +2,16 @@ package io.ebean.bean;
import io.ebean.Database;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* BeanLoader used when single beans are loaded (which is usually not ideal / N+1).
*/
public abstract class SingleBeanLoader implements BeanLoader {
private final ReentrantLock lock = new ReentrantLock();
protected final Database database;
SingleBeanLoader(Database database) {
@@ -18,6 +23,12 @@ public abstract class SingleBeanLoader implements BeanLoader {
return database.getName();
}
@Override
public Lock lock() {
lock.lock();
return lock;
}
/**
* Single bean lazy loaded when bean from L2 cache.
*/
@@ -45,4 +56,18 @@ public abstract class SingleBeanLoader implements BeanLoader {
database.getPluginApi().loadBeanRef(ebi);
}
}
/**
* Single bean lazy loaded when a reference bean.
*/
public static class Dflt extends SingleBeanLoader {
public Dflt(Database database) {
super(database);
}
@Override
public void loadBean(EntityBeanIntercept ebi) {
database.getPluginApi().loadBean(ebi);
}
}
}
@@ -7,6 +7,7 @@ import io.ebean.bean.BeanCollectionLoader;
import io.ebean.bean.EntityBean;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
/**
* Base class for List Set and Map implementations of BeanCollection.
@@ -15,6 +16,8 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
private static final long serialVersionUID = 3365725236140187588L;
protected final ReentrantLock lock = new ReentrantLock();
protected boolean readOnly;
protected boolean disableLazyLoad;
@@ -115,7 +115,8 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
}
private void initClear() {
synchronized (this) {
lock.lock();
try {
if (list == null) {
if (!disableLazyLoad && modifyListening) {
lazyLoadCollection(true);
@@ -123,11 +124,14 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
list = new ArrayList<>();
}
}
} finally {
lock.unlock();
}
}
private void init() {
synchronized (this) {
lock.lock();
try {
if (list == null) {
if (disableLazyLoad) {
list = new ArrayList<>();
@@ -135,6 +139,8 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
lazyLoadCollection(false);
}
}
} finally {
lock.unlock();
}
}
@@ -121,7 +121,8 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
}
private void initClear() {
synchronized (this) {
lock.lock();
try {
if (map == null) {
if (!disableLazyLoad && modifyListening) {
lazyLoadCollection(true);
@@ -129,11 +130,14 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
map = new LinkedHashMap<>();
}
}
} finally {
lock.unlock();
}
}
private void init() {
synchronized (this) {
lock.lock();
try {
if (map == null) {
if (disableLazyLoad) {
map = new LinkedHashMap<>();
@@ -141,6 +145,8 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
lazyLoadCollection(false);
}
}
} finally {
lock.unlock();
}
}
@@ -114,7 +114,8 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
}
private void initClear() {
synchronized (this) {
lock.lock();
try {
if (set == null) {
if (!disableLazyLoad && modifyListening) {
lazyLoadCollection(true);
@@ -122,11 +123,14 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
set = new LinkedHashSet<>();
}
}
} finally {
lock.unlock();
}
}
private void init() {
synchronized (this) {
lock.lock();
try {
if (set == null) {
if (disableLazyLoad) {
set = new LinkedHashSet<>();
@@ -134,6 +138,8 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
lazyLoadCollection(true);
}
}
} finally {
lock.unlock();
}
}
@@ -6,25 +6,27 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
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;
private final ReentrantLock lock = new ReentrantLock();
/**
* The underlying List implementation.
*/
private List<E> list;
public CopyOnFirstWriteList(List<E> list) {
super();
this.list = list;
@@ -166,14 +168,17 @@ public final class CopyOnFirstWriteList<E> extends AbstractList<E> implements Li
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
private void checkCopyOnWrite() {
if (!copied) {
synchronized (this) {
lock.lock();
try {
if (!copied) {
list = new ArrayList<>(list);
copied = true;
}
} finally {
lock.unlock();
}
}
}
@@ -26,20 +26,6 @@ public class ClassLoadConfig {
this.context = new ClassLoaderContext(classLoader);
}
/**
* Return true if the Java.time types are available and should be supported.
*/
public boolean isJavaTimePresent() {
return isPresent("java.time.LocalDate");
}
/**
* Return true if Java7 is present.
*/
public boolean isJava7Present() {
return isPresent("java.nio.file.Path");
}
/**
* Return true if the Joda types are available and should be supported.
*/
@@ -69,6 +55,10 @@ public class ClassLoadConfig {
return isPresent("com.fasterxml.jackson.annotation.JsonIgnore");
}
public boolean isJacksonCorePresent() {
return isPresent("com.fasterxml.jackson.core.JsonParser");
}
/**
* Return true if Jackson ObjectMapper is present.
*/
@@ -1,7 +1,7 @@
package io.ebean.config;
import io.ebean.config.dbplatform.DbType;
import io.ebean.annotation.Platform;
import io.ebean.config.dbplatform.DbType;
/**
* Custom mappings for DB types that override the default.
@@ -3,6 +3,7 @@ package io.ebean.config;
import com.fasterxml.jackson.core.JsonFactory;
import io.avaje.config.Config;
import io.ebean.DatabaseFactory;
import io.ebean.EbeanVersion;
import io.ebean.PersistenceContextScope;
import io.ebean.Query;
import io.ebean.Transaction;
@@ -28,12 +29,13 @@ import io.ebean.event.changelog.ChangeLogPrepare;
import io.ebean.event.changelog.ChangeLogRegister;
import io.ebean.event.readaudit.ReadAuditLogger;
import io.ebean.event.readaudit.ReadAuditPrepare;
import io.ebean.migration.MigrationRunner;
import io.ebean.util.StringHelper;
import javax.persistence.EnumType;
import javax.sql.DataSource;
import java.time.Clock;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -277,6 +279,25 @@ public class DatabaseConfig {
private String ddlSeedSql;
private String ddlHeader;
/**
* Mode used to check non-null columns added via migration have a default value specified etc.
*/
private boolean ddlStrictMode = true;
/**
* Comma and equals delimited key/value placeholders to replace in DDL scripts.
*/
private String ddlPlaceholders;
/**
* Map of key/value placeholders to replace in DDL scripts.
*/
private Map<String, String> ddlPlaceholderMap;
private boolean runMigration;
/**
* When true L2 bean cache use is skipped after a write has occurred on a transaction.
*/
@@ -322,11 +343,6 @@ public class DatabaseConfig {
*/
private String dbSchema;
/**
* The db migration config (migration resource path etc).
*/
private DbMigrationConfig migrationConfig = new DbMigrationConfig();
/**
* The ClassLoadConfig used to detect Joda, Java8, Jackson etc and create plugin instances given a className.
*/
@@ -1212,20 +1228,6 @@ public class DatabaseConfig {
this.dbSchema = dbSchema;
}
/**
* Return the DB migration configuration.
*/
public DbMigrationConfig getMigrationConfig() {
return migrationConfig;
}
/**
* Set the DB migration configuration.
*/
public void setMigrationConfig(DbMigrationConfig migrationConfig) {
this.migrationConfig = migrationConfig;
}
/**
* Return the Geometry SRID.
*/
@@ -2026,7 +2028,15 @@ public class DatabaseConfig {
* as it is often the only thing we need to configure for migrations.
*/
public void setRunMigration(boolean runMigration) {
migrationConfig.setRunMigration(runMigration);
this.runMigration = runMigration;
}
/**
* Return true if the DB migration should run on server start.
*/
public boolean isRunMigration() {
final String run = System.getProperty("ebean.migration.run");
return (run != null) ? Boolean.parseBoolean(run) : runMigration;
}
/**
@@ -2134,6 +2144,67 @@ public class DatabaseConfig {
return ddlExtra;
}
/**
* Set the header to use with DDL generation.
*/
public void setDdlHeader(String ddlHeader) {
this.ddlHeader = ddlHeader;
}
/**
* Return the header to use with DDL generation.
*/
public String getDdlHeader() {
if (ddlHeader != null && !ddlHeader.isEmpty()) {
String header = ddlHeader.replace("${version}", EbeanVersion.getVersion());
header = header.replace("${timestamp}", ZonedDateTime.now().format(DateTimeFormatter.ISO_INSTANT));
return header;
}
return ddlHeader;
}
/**
* Return true if strict mode is used which includes a check that non-null columns have a default value.
*/
public boolean isDdlStrictMode() {
return ddlStrictMode;
}
/**
* Set to false to turn off strict mode allowing non-null columns to not have a default value.
*/
public void setDdlStrictMode(boolean ddlStrictMode) {
this.ddlStrictMode = ddlStrictMode;
}
/**
* Return a comma and equals delimited placeholders that are substituted in DDL scripts.
*/
public String getDdlPlaceholders() {
return ddlPlaceholders;
}
/**
* Set a comma and equals delimited placeholders that are substituted in DDL scripts.
*/
public void setDdlPlaceholders(String ddlPlaceholders) {
this.ddlPlaceholders = ddlPlaceholders;
}
/**
* Return a map of placeholder values that are substituted in DDL scripts.
*/
public Map<String, String> getDdlPlaceholderMap() {
return ddlPlaceholderMap;
}
/**
* Set a map of placeholder values that are substituted in DDL scripts.
*/
public void setDdlPlaceholderMap(Map<String, String> ddlPlaceholderMap) {
this.ddlPlaceholderMap = ddlPlaceholderMap;
}
/**
* Return true if the class path search should be disabled.
*/
@@ -2699,13 +2770,8 @@ public class DatabaseConfig {
* Load the configuration settings from the properties file.
*/
protected void loadSettings(PropertiesWrapper p) {
dbSchema = p.get("dbSchema", dbSchema);
if (dbSchema != null) {
migrationConfig.setDefaultDbSchema(dbSchema);
}
profilingConfig.loadSettings(p, name);
migrationConfig.loadSettings(p, name);
platformConfig.loadSettings(p);
if (platformConfig.isAllQuotedIdentifiers()) {
adjustNamingConventionForAllQuoted();
@@ -2807,12 +2873,16 @@ public class DatabaseConfig {
jsonDateTime = p.getEnum(JsonConfig.DateTime.class, "jsonDateTime", jsonDateTime);
jsonDate = p.getEnum(JsonConfig.Date.class, "jsonDate", jsonDate);
runMigration = p.getBoolean("migration.run", runMigration);
ddlGenerate = p.getBoolean("ddl.generate", ddlGenerate);
ddlRun = p.getBoolean("ddl.run", ddlRun);
ddlExtra = p.getBoolean("ddl.extra", ddlExtra);
ddlCreateOnly = p.getBoolean("ddl.createOnly", ddlCreateOnly);
ddlInitSql = p.get("ddl.initSql", ddlInitSql);
ddlSeedSql = p.get("ddl.seedSql", ddlSeedSql);
ddlStrictMode = p.getBoolean("ddl.strictMode", ddlStrictMode);
ddlPlaceholders = p.get("ddl.placeholders", ddlPlaceholders);
ddlHeader = p.get("ddl.header", ddlHeader);
// read tenant-configuration from config:
// tenant.mode = NONE | DB | SCHEMA | CATALOG | PARTITION
@@ -3034,17 +3104,6 @@ public class DatabaseConfig {
this.queryPlanTTLSeconds = queryPlanTTLSeconds;
}
/**
* Run the DB migration against the DataSource.
*/
public DataSource runDbMigration(DataSource dataSource) {
if (migrationConfig.isRunMigration()) {
MigrationRunner runner = migrationConfig.createRunner(getClassLoadConfig().getClassLoader(), properties);
runner.run(dataSource);
}
return dataSource;
}
/**
* Create a new PlatformConfig based of the one held but with overridden properties by reading
* properties with the given path and prefix.
@@ -1,509 +0,0 @@
package io.ebean.config;
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;
import static io.ebean.util.StringHelper.replace;
/**
* Configuration for the DB migration processing.
*/
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.
*/
protected Platform platform;
/**
* Resource path for the migration xml and sql.
*/
protected String migrationPath = "dbmigration";
protected String migrationInitPath = "dbinit";
/**
* Subdirectory the model xml files go into.
*/
protected String modelPath = "model";
protected String applySuffix = ".sql";
/**
* Set this to "V" to be compatible with FlywayDB.
*/
protected String applyPrefix = "";
protected String modelSuffix = ".model.xml";
/**
* For running migration the DB table that holds migration execution status.
*/
protected String metaTable = "db_migration";
/**
* Flag set to true means to run any outstanding migrations on startup.
*/
protected boolean runMigration;
/**
* Comma and equals delimited key/value placeholders to replace in DDL scripts.
*/
protected String runPlaceholders;
/**
* Map of key/value placeholders to replace in DDL scripts.
*/
protected Map<String, String> runPlaceholderMap;
/**
* DB schema used for the migration (and testing).
*/
protected String dbSchema;
/**
* Set to true if we consider this the 'default schema' (Postgres schema that matches DB username)
*/
protected boolean defaultDbSchema;
/**
* DB user used to run the DB migration.
*/
protected String dbUsername;
/**
* DB password used to run the DB migration.
*/
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>
* We typically need to explicitly specify this as migration can often be generated
* when running against H2.
*/
public Platform getPlatform() {
return platform;
}
/**
* Set the DB platform to generate migration DDL for.
*/
public void setPlatform(Platform platform) {
this.platform = platform;
}
/**
* Return the path for normal migrations or dbinit migrations.
*
* @param dbinitMigration When true return the path for dbinit migrations.
*/
public String getMigrationPath(boolean dbinitMigration) {
return dbinitMigration ? migrationInitPath : migrationPath;
}
/**
* Return the resource path for db migrations.
*/
public String getMigrationPath() {
return migrationPath;
}
/**
* Set the resource path for db migrations.
* <p>
* The default of "dbmigration" is reasonable in most cases. You may look to set this
* to be something like "dbmigration/myapp" where myapp gives it a unique resource path
* in the case there are multiple Database applications in the single classpath.
* </p>
*/
public void setMigrationPath(String migrationPath) {
this.migrationPath = migrationPath;
}
/**
* Return the relative path for the model files (defaults to model).
*/
public String getModelPath() {
return modelPath;
}
/**
* Set the relative path for the model files.
*/
public void setModelPath(String modelPath) {
this.modelPath = modelPath;
}
/**
* Return the model suffix (defaults to model.xml)
*/
public String getModelSuffix() {
return modelSuffix;
}
/**
* Set the model suffix.
*/
public void setModelSuffix(String modelSuffix) {
this.modelSuffix = modelSuffix;
}
/**
* Return the apply script suffix (defaults to sql).
*/
public String getApplySuffix() {
return applySuffix;
}
/**
* Set the apply script suffix (defaults to sql).
*/
public void setApplySuffix(String applySuffix) {
this.applySuffix = applySuffix;
}
/**
* Return the apply prefix.
*/
public String getApplyPrefix() {
return applyPrefix;
}
/**
* Set the apply prefix. This might be set to "V" for use with FlywayDB.
*/
public void setApplyPrefix(String applyPrefix) {
this.applyPrefix = applyPrefix;
}
/**
* Return the table name that holds the migration run details
* (used by DB Migration runner only).
*/
public String getMetaTable() {
return metaTable;
}
/**
* Set the table name that holds the migration run details
* (used by DB Migration runner only).
*/
public void setMetaTable(String metaTable) {
this.metaTable = metaTable;
}
/**
* Return a comma and equals delimited placeholders that are substituted in SQL scripts when running migration
* (used by DB Migration runner only).
*/
public String getRunPlaceholders() {
// environment properties take precedence
String placeholders = readEnvironment("ddl.migration.placeholders");
if (placeholders != null) {
return placeholders;
}
return runPlaceholders;
}
/**
* Set a comma and equals delimited placeholders that are substituted in SQL scripts when running migration
* (used by DB Migration runner only).
*/
public void setRunPlaceholders(String runPlaceholders) {
this.runPlaceholders = runPlaceholders;
}
/**
* Return a map of placeholder values that are substituted in SQL scripts when running migration
* (used by DB Migration runner only).
*/
public Map<String, String> getRunPlaceholderMap() {
return runPlaceholderMap;
}
/**
* Set a map of placeholder values that are substituted when running migration
* (used by DB Migration runner only).
*/
public void setRunPlaceholderMap(Map<String, String> runPlaceholderMap) {
this.runPlaceholderMap = runPlaceholderMap;
}
/**
* Return true if the DB migration should be run on startup.
*/
public boolean isRunMigration() {
// environment properties take precedence
String run = readEnvironment("ddl.migration.run");
if (run != null) {
return "true".equalsIgnoreCase(run.trim());
}
return runMigration;
}
/**
* Set to true to run the DB migration on startup.
*/
public void setRunMigration(boolean runMigration) {
this.runMigration = runMigration;
}
/**
* Return the DB username to use for running DB migrations.
*/
public String getDbUsername() {
// environment properties take precedence
String user = readEnvironment("ddl.migration.user");
if (user != null) {
return user;
}
return dbUsername;
}
/**
* Set the DB username to use for running DB migrations.
*/
public void setDbUsername(String dbUsername) {
this.dbUsername = dbUsername;
}
/**
* Return the DB password to use for running DB migrations.
*/
public String getDbPassword() {
String user = readEnvironment("ddl.migration.password");
if (user != null) {
return user;
}
return dbPassword;
}
/**
* Set the DB password to use for running DB migrations.
*/
public void setDbPassword(String dbPassword) {
this.dbPassword = dbPassword;
}
/**
* Return the DB schema to use (for migration, testing etc).
*/
public String getDbSchema() {
String schema = readEnvironment("ddl.migration.schema");
if (schema != null) {
return schema;
}
return dbSchema;
}
/**
* Set the Db schema to use.
*/
public void setDbSchema(String dbSchema) {
this.dbSchema = dbSchema;
}
/**
* Set the Db schema if it hasn't already been defined.
*/
public void setDefaultDbSchema(String dbSchema) {
this.defaultDbSchema = true;
this.dbSchema = dbSchema;
}
/**
* Return true if this is considered the default DB schema (Postgres schema matching DB username).
*/
public boolean isDefaultDbSchema() {
return defaultDbSchema;
}
/**
* 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() {
if (ddlHeader != null && !ddlHeader.isEmpty()) {
ddlHeader = replace(ddlHeader, "${version}", EbeanVersion.getVersion());
ddlHeader = replace(ddlHeader, "${timestamp}", ZonedDateTime.now().format( DateTimeFormatter.ISO_INSTANT ));
}
return ddlHeader;
}
/**
* Set the header prepended to the DDL.
*/
public void setDdlHeader(String ddlHeader) {
this.ddlHeader = 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.
*/
public void loadSettings(PropertiesWrapper properties, String serverName) {
migrationPath = properties.get("migration.migrationPath", migrationPath);
migrationInitPath = properties.get("migration.migrationInitPath", migrationInitPath);
modelPath = properties.get("migration.modelPath", modelPath);
applyPrefix = properties.get("migration.applyPrefix", applyPrefix);
applySuffix = properties.get("migration.applySuffix", applySuffix);
modelSuffix = properties.get("migration.modelSuffix", modelSuffix);
platform = properties.getEnum(Platform.class, "migration.platform", platform);
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);
dbSchema = properties.get("migration.dbSchema", dbSchema);
//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);
String adminPwd = properties.get("datasource." + serverName + ".adminpassword", dbPassword);
dbPassword = properties.get("migration.dbpassword", adminPwd);
ddlHeader = properties.get("ddl.header", ddlHeader);
}
/**
* Return the system or environment property.
*/
protected String readEnvironment(String key) {
String val = System.getProperty(key);
if (val == null) {
val = System.getenv(key);
}
return val;
}
/**
* Return true if the string is null or empty.
*/
protected boolean isEmpty(String val) {
return val == null || val.trim().isEmpty();
}
/**
* Create the MigrationRunner to run migrations if necessary.
*/
public MigrationRunner createRunner(ClassLoader classLoader, Properties properties) {
runnerConfig.setMetaTable(metaTable);
runnerConfig.setApplySuffix(applySuffix);
runnerConfig.setMigrationPath(migrationPath);
runnerConfig.setMigrationInitPath(migrationInitPath);
runnerConfig.setRunPlaceholderMap(runPlaceholderMap);
runnerConfig.setRunPlaceholders(runPlaceholders);
runnerConfig.setDbUsername(getDbUsername());
runnerConfig.setDbPassword(getDbPassword());
runnerConfig.setDbSchema(getDbSchema());
if (defaultDbSchema) {
runnerConfig.setSetCurrentSchema(false);
}
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);
}
}
@@ -17,6 +17,11 @@ public class PlatformConfig {
private boolean allQuotedIdentifiers;
/**
* Set this to true for Postgres FOR UPDATE to use NO KEY option.
*/
private boolean forUpdateNoKey;
private DbConstraintNaming constraintNaming;
/**
@@ -77,6 +82,7 @@ public class PlatformConfig {
* Construct based on given config - typically for DbMigration generation with many platforms.
*/
public PlatformConfig(PlatformConfig platformConfig) {
this.forUpdateNoKey = platformConfig.forUpdateNoKey;
this.databaseBooleanFalse = platformConfig.databaseBooleanFalse;
this.databaseBooleanTrue = platformConfig.databaseBooleanTrue;
this.databaseSequenceBatchSize = platformConfig.databaseSequenceBatchSize;
@@ -133,14 +139,26 @@ public class PlatformConfig {
this.caseSensitiveCollation = caseSensitiveCollation;
}
/**
* Return true if Postgres FOR UPDATE should use the NO KEY option.
*/
public boolean isForUpdateNoKey() {
return forUpdateNoKey;
}
/**
* Set to true such that Postgres FOR UPDATE should use the NO KEY option.
*/
public void setForUpdateNoKey(boolean forUpdateNoKey) {
this.forUpdateNoKey = forUpdateNoKey;
}
/**
* 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;
@@ -150,10 +168,8 @@ public class PlatformConfig {
* 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;
@@ -245,7 +261,6 @@ public class PlatformConfig {
/**
* Add a custom type mapping.
* <p>
* <pre>{@code
*
* // set the default mapping for BigDecimal.class/decimal
@@ -266,7 +281,6 @@ public class PlatformConfig {
/**
* Add a custom type mapping that applies to all platforms.
* <p>
* <pre>{@code
*
* // set the default mapping for BigDecimal/decimal
@@ -294,6 +308,7 @@ public class PlatformConfig {
public void loadSettings(PropertiesWrapper p) {
idType = p.getEnum(IdType.class, "idType", idType);
forUpdateNoKey = p.getBoolean("forUpdateNoKey", forUpdateNoKey);
databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize);
databaseBooleanTrue = p.get("databaseBooleanTrue", databaseBooleanTrue);
databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse);
@@ -334,7 +349,6 @@ public class PlatformConfig {
*/
public enum DbUuid {
/**
* Store using native UUID in H2 and Postgres and otherwise fallback to VARCHAR(40).
*/
@@ -1,47 +1,6 @@
package io.ebean.config;
import com.fasterxml.jackson.core.JsonFactory;
import io.avaje.config.Config;
import io.ebean.DatabaseFactory;
import io.ebean.PersistenceContextScope;
import io.ebean.Query;
import io.ebean.Transaction;
import io.ebean.annotation.Encrypted;
import io.ebean.annotation.PersistBatch;
import io.ebean.annotation.Platform;
import io.ebean.cache.ServerCachePlugin;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.DbEncrypt;
import io.ebean.config.dbplatform.DbType;
import io.ebean.config.dbplatform.IdType;
import io.ebean.datasource.DataSourceConfig;
import io.ebean.event.BeanFindController;
import io.ebean.event.BeanPersistController;
import io.ebean.event.BeanPersistListener;
import io.ebean.event.BeanPostConstructListener;
import io.ebean.event.BeanPostLoad;
import io.ebean.event.BeanQueryAdapter;
import io.ebean.event.BulkTableEventListener;
import io.ebean.event.ServerConfigStartup;
import io.ebean.event.changelog.ChangeLogListener;
import io.ebean.event.changelog.ChangeLogPrepare;
import io.ebean.event.changelog.ChangeLogRegister;
import io.ebean.event.readaudit.ReadAuditLogger;
import io.ebean.event.readaudit.ReadAuditPrepare;
import io.ebean.migration.MigrationRunner;
import io.ebean.util.StringHelper;
import javax.persistence.EnumType;
import javax.sql.DataSource;
import java.time.Clock;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.ServiceLoader;
/**
* Deprecated - please migrate to <code>io.ebean.DatabaseConfig</code>.
@@ -679,21 +679,20 @@ public class DatabasePlatform {
public String completeSql(String sql, Query<?> query) {
if (query.isForUpdate()) {
sql = withForUpdate(sql, query.getForUpdateMode());
sql = withForUpdate(sql, query.getForUpdateLockWait(), query.getForUpdateLockType());
}
return sql;
}
/**
* For update hint on the FROM clause (SQL server only).
*/
public String fromForUpdate(Query.ForUpdate forUpdateMode) {
public String fromForUpdate(Query.LockWait lockWait) {
// return null except for sql server
return null;
}
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
// silently assume the database does not support the "for update" clause.
logger.info("it seems your database does not support the 'for update' clause");
return sql;
@@ -16,6 +16,8 @@ import java.util.Collections;
import java.util.List;
import java.util.NavigableSet;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
/**
* Database sequence based IdGenerator.
@@ -24,15 +26,7 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
protected static final Logger logger = LoggerFactory.getLogger("io.ebean.SEQ");
/**
* Used to synchronise the idList access.
*/
protected final Object monitor = new Object();
/**
* Used to synchronise background loading (loadBatchInBackground).
*/
protected final Object backgroundLoadMonitor = new Object();
private final ReentrantLock lock = new ReentrantLock();
/**
* The actual sequence name.
@@ -47,7 +41,7 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
protected final int allocationSize;
protected boolean currentlyBackgroundLoading;
protected AtomicBoolean currentlyBackgroundLoading = new AtomicBoolean(false);
/**
* Construct given a dataSource and sql to return the next sequence value.
@@ -97,7 +91,8 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
*/
@Override
public Object nextId(Transaction t) {
synchronized (monitor) {
lock.lock();
try {
int size = idList.size();
if (size > 0) {
maybeLoadMoreInBackground(size);
@@ -105,6 +100,8 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
loadMore(allocationSize);
}
return idList.pollFirst();
} finally {
lock.unlock();
}
}
@@ -118,8 +115,11 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
private void loadMore(int requestSize) {
List<Long> newIds = getMoreIds(requestSize);
synchronized (monitor) {
lock.lock();
try {
idList.addAll(newIds);
} finally {
lock.unlock();
}
}
@@ -127,24 +127,16 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
* Load another batch of Id's using a background thread.
*/
protected void loadInBackground(final int requestSize) {
// single threaded processing...
synchronized (backgroundLoadMonitor) {
if (currentlyBackgroundLoading) {
// skip as already background loading
logger.debug("... skip background sequence load (another load in progress)");
return;
}
currentlyBackgroundLoading = true;
backgroundExecutor.execute(() -> {
loadMore(requestSize);
synchronized (backgroundLoadMonitor) {
currentlyBackgroundLoading = false;
}
});
if (currentlyBackgroundLoading.get()) {
// skip as already background loading
logger.debug("... skip background sequence load (another load in progress)");
return;
}
currentlyBackgroundLoading.set(true);
backgroundExecutor.execute(() -> {
loadMore(requestSize);
currentlyBackgroundLoading.set(false);
});
}
/**
@@ -51,7 +51,7 @@ public class H2Platform extends DatabasePlatform {
}
@Override
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
// NOWAIT and SKIP LOCKED currently not supported with H2
return sql + " for update";
}
@@ -1,6 +1,7 @@
package io.ebean.config.dbplatform.hana;
import io.ebean.Query.ForUpdate;
import io.ebean.Query;
import io.ebean.Query.LockWait;
import io.ebean.annotation.PersistBatch;
import io.ebean.annotation.Platform;
import io.ebean.config.PlatformConfig;
@@ -68,16 +69,16 @@ public class HanaPlatform extends DatabasePlatform {
}
@Override
protected String withForUpdate(String sql, ForUpdate forUpdateMode) {
switch (forUpdateMode) {
case BASE:
protected String withForUpdate(String sql, LockWait lockWait, Query.LockType lockType) {
switch (lockWait) {
case WAIT:
return sql + " for update";
case NOWAIT:
return sql + " for update nowait";
case SKIPLOCKED:
return sql + " for update ignore locked";
default:
throw new IllegalArgumentException("Unknown update mode: " + forUpdateMode.name());
throw new IllegalArgumentException("Unknown update mode: " + lockWait);
}
}
@@ -60,7 +60,7 @@ public abstract class BaseMySqlPlatform extends DatabasePlatform {
}
@Override
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
// NOWAIT and SKIP LOCKED currently not supported with MySQL
return sql + " for update";
}
@@ -48,8 +48,8 @@ public class NuoDbPlatform extends DatabasePlatform {
}
@Override
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
switch (forUpdateMode) {
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
switch (lockWait) {
case NOWAIT:
return sql + " for update nowait";
case SKIPLOCKED:
@@ -79,8 +79,8 @@ public class OraclePlatform extends DatabasePlatform {
}
@Override
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
switch (forUpdateMode) {
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
switch (lockWait) {
case SKIPLOCKED:
return sql + " for update skip locked";
case NOWAIT:
@@ -4,6 +4,7 @@ import io.ebean.BackgroundExecutor;
import io.ebean.Query;
import io.ebean.annotation.PartitionMode;
import io.ebean.annotation.Platform;
import io.ebean.config.PlatformConfig;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.DbPlatformType;
import io.ebean.config.dbplatform.DbType;
@@ -25,6 +26,15 @@ import java.sql.Types;
*/
public class PostgresPlatform extends DatabasePlatform {
private static final String SKIP_LOCKED = " skip locked";
private static final String NO_WAIT = " nowait";
private static final String FOR_UPDATE = " for update";
private static final String FOR_NO_KEY_UPDATE = " for no key update";
private static final String FOR_SHARE = " for share";
private static final String FOR_KEY_SHARE = " for key share";
private boolean forUpdateNoKey;
public PostgresPlatform() {
super();
this.platform = Platform.POSTGRES;
@@ -81,6 +91,12 @@ public class PostgresPlatform extends DatabasePlatform {
dbTypeMap.put(DbType.LONGVARCHAR, dbTypeText);
}
@Override
public void configure(PlatformConfig config) {
super.configure(config);
forUpdateNoKey = config.isForUpdateNoKey();
}
@Override
protected void addGeoTypes(int srid) {
dbTypeMap.put(DbType.POINT, geoType("point", srid));
@@ -108,22 +124,32 @@ public class PostgresPlatform extends DatabasePlatform {
*/
@Override
public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, int stepSize, String seqName) {
return new PostgresSequenceIdGenerator(be, ds, seqName, sequenceBatchSize);
}
@Override
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
switch (forUpdateMode) {
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
switch (lockWait) {
case SKIPLOCKED:
return sql + " for update skip locked";
return sql + lock(lockType) + SKIP_LOCKED;
case NOWAIT:
return sql + " for update nowait";
return sql + lock(lockType) + NO_WAIT;
default:
return sql + " for update";
return sql + lock(lockType);
}
}
private String lock(Query.LockType lockType) {
switch (lockType) {
case UPDATE: return FOR_UPDATE;
case NO_KEY_UPDATE: return FOR_NO_KEY_UPDATE;
case SHARE: return FOR_SHARE;
case KEY_SHARE: return FOR_KEY_SHARE;
case DEFAULT: return forUpdateNoKey ? FOR_NO_KEY_UPDATE : FOR_UPDATE;
}
return FOR_UPDATE;
}
@Override
public boolean tablePartitionsExist(Connection connection, String table) throws SQLException {
try (PreparedStatement statement = connection.prepareStatement("select count(*) from pg_inherits i WHERE i.inhparent = ?::regclass")) {
@@ -105,8 +105,8 @@ abstract class SqlServerBasePlatform extends DatabasePlatform {
* For update is part of the FROM clause on the base table for sql server.
*/
@Override
public String fromForUpdate(Query.ForUpdate forUpdateMode) {
switch (forUpdateMode) {
public String fromForUpdate(Query.LockWait lockWait) {
switch (lockWait) {
case SKIPLOCKED:
return "with (updlock,readpast)";
case NOWAIT:
@@ -117,7 +117,7 @@ abstract class SqlServerBasePlatform extends DatabasePlatform {
}
@Override
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
// for update are hints on from clause of base table
return sql;
}
@@ -11,6 +11,7 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
/**
* Manages the shutdown of the JVM Runtime.
@@ -22,6 +23,8 @@ public final class ShutdownManager {
private static final Logger logger = LoggerFactory.getLogger(ShutdownManager.class);
private static final ReentrantLock lock = new ReentrantLock();
private static final List<Database> databases = new ArrayList<>();
private static final ShutdownHook shutdownHook = new ShutdownHook();
@@ -56,9 +59,11 @@ public final class ShutdownManager {
* Return true if the system is in the process of stopping.
*/
public static boolean isStopping() {
//noinspection SynchronizationOnStaticField
synchronized (databases) {
lock.lock();
try {
return stopping;
} finally {
lock.unlock();
}
}
@@ -74,15 +79,15 @@ public final class ShutdownManager {
* </p>
*/
public static void deregisterShutdownHook() {
//noinspection SynchronizationOnStaticField
synchronized (databases) {
try {
Runtime.getRuntime().removeShutdownHook(shutdownHook);
} catch (IllegalStateException ex) {
if (!ex.getMessage().equals("Shutdown in progress")) {
throw ex;
}
lock.lock();
try {
Runtime.getRuntime().removeShutdownHook(shutdownHook);
} catch (IllegalStateException ex) {
if (!ex.getMessage().equals("Shutdown in progress")) {
throw ex;
}
} finally {
lock.unlock();
}
}
@@ -90,18 +95,18 @@ public final class ShutdownManager {
* Register the shutdown hook with the Runtime.
*/
protected static void registerShutdownHook() {
//noinspection SynchronizationOnStaticField
synchronized (databases) {
try {
String value = System.getProperty("ebean.registerShutdownHook");
if (value == null || !value.trim().equalsIgnoreCase("false")) {
Runtime.getRuntime().addShutdownHook(shutdownHook);
}
} catch (IllegalStateException ex) {
if (!ex.getMessage().equals("Shutdown in progress")) {
throw ex;
}
lock.lock();
try {
String value = System.getProperty("ebean.registerShutdownHook");
if (value == null || !value.trim().equalsIgnoreCase("false")) {
Runtime.getRuntime().addShutdownHook(shutdownHook);
}
} catch (IllegalStateException ex) {
if (!ex.getMessage().equals("Shutdown in progress")) {
throw ex;
}
} finally {
lock.unlock();
}
}
@@ -112,8 +117,8 @@ public final class ShutdownManager {
* </p>
*/
public static void shutdown() {
//noinspection SynchronizationOnStaticField
synchronized (databases) {
lock.lock();
try {
if (stopping) {
// Already run shutdown...
return;
@@ -157,6 +162,8 @@ public final class ShutdownManager {
if ("true".equalsIgnoreCase(System.getProperty("ebean.datasource.deregisterAllDrivers", "false"))) {
deregisterAllJdbcDrivers();
}
} finally {
lock.unlock();
}
}
@@ -178,9 +185,11 @@ public final class ShutdownManager {
* Register an ebeanServer to be shutdown when the JVM is shutdown.
*/
public static void registerDatabase(Database server) {
//noinspection SynchronizationOnStaticField
synchronized (databases) {
lock.lock();
try {
databases.add(server);
} finally {
lock.unlock();
}
}
@@ -191,9 +200,11 @@ public final class ShutdownManager {
* </p>
*/
public static void unregisterDatabase(Database server) {
//noinspection SynchronizationOnStaticField
synchronized (databases) {
lock.lock();
try {
databases.remove(server);
} finally {
lock.unlock();
}
}
@@ -2,11 +2,11 @@ package io.ebean.plugin;
import io.ebean.Query;
import io.ebean.config.dbplatform.IdType;
import io.ebean.docstore.DocMapping;
import io.ebean.event.BeanFindController;
import io.ebean.event.BeanPersistController;
import io.ebean.event.BeanPersistListener;
import io.ebean.event.BeanQueryAdapter;
import io.ebean.docstore.DocMapping;
import javax.annotation.Nonnull;
import java.util.Collection;
@@ -1,18 +1,17 @@
package io.ebean.plugin;
import io.ebean.EbeanServer;
import io.ebean.Database;
import io.ebean.bean.BeanLoader;
import io.ebean.bean.EntityBeanIntercept;
import io.ebean.config.DatabaseConfig;
import io.ebean.config.dbplatform.DatabasePlatform;
import javax.sql.DataSource;
import java.util.List;
/**
* Extensions to Database API made available to plugins.
*/
public interface SpiServer extends EbeanServer, BeanLoader {
public interface SpiServer extends Database {
/**
* Return the DatabaseConfig.
@@ -45,14 +44,9 @@ public interface SpiServer extends EbeanServer, BeanLoader {
BeanType<?> getBeanTypeForQueueId(String queueId);
/**
* Return the associated DataSource for this Database instance.
* Return a BeanLoader.
*/
DataSource getDataSource();
/**
* Return the associated read only DataSource for this Database instance (can be null).
*/
DataSource getReadOnlyDataSource();
BeanLoader beanLoader();
/**
* Invoke lazy loading on this single bean (reference bean).
@@ -1,7 +1,7 @@
package io.ebean.text.json;
import io.ebean.bean.PersistenceContext;
import com.fasterxml.jackson.core.JsonParser;
import io.ebean.bean.PersistenceContext;
/**
* Provides a JSON reader that can hold a persistence context and load context while reading JSON.
@@ -1,9 +1,9 @@
package io.ebean.text.json;
import io.ebean.FetchPath;
import io.ebean.plugin.BeanType;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import io.ebean.FetchPath;
import io.ebean.plugin.BeanType;
import java.io.IOException;
import java.io.Reader;
+25 -5
View File
@@ -1,12 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.5.1-SNAPSHOT</version>
<version>12.6.4</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<!-- <parent>-->
<!-- <groupId>org.avaje</groupId>-->
<!-- <artifactId>java8-oss</artifactId>-->
<!-- <version>2.2</version>-->
<!-- </parent>-->
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.6.4</tag>
</scm>
<name>ebean autotune</name>
<description>ebean automatic query tuning module</description>
<artifactId>ebean-autotune</artifactId>
<dependencies>
@@ -14,7 +26,8 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>${project.version}</version>
<version>12.6.4</version>
<scope>provided</scope>
</dependency>
<!-- needed for java 11+ -->
@@ -25,6 +38,13 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-datasource</artifactId>
<version>${ebean-datasource.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.avaje.composite</groupId>
<artifactId>junit</artifactId>
@@ -39,12 +59,12 @@
<plugin>
<groupId>io.repaint.maven</groupId>
<artifactId>tiles-maven-plugin</artifactId>
<version>2.17</version>
<version>2.18</version>
<extensions>true</extensions>
<configuration>
<tiles>
<!-- other tiles ... -->
<tile>io.ebean.tile:enhancement:12.5.0</tile>
<tile>io.ebean.tile:enhancement:12.6.0</tile>
</tiles>
</configuration>
</plugin>
@@ -14,6 +14,7 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* Implementation of the AutoTuneService which is comprised of profiling and query tuning.
@@ -22,6 +23,8 @@ public class DefaultAutoTuneService implements AutoTuneService {
private static final Logger logger = LoggerFactory.getLogger(DefaultAutoTuneService.class);
private final ReentrantLock lock = new ReentrantLock();
private final SpiEbeanServer server;
private final long defaultGarbageCollectionWait;
@@ -74,7 +77,7 @@ public class DefaultAutoTuneService implements AutoTuneService {
loadTuningFile();
if (isRuntimeTuningUpdates()) {
// periodically gather and update query tuning
server.getBackgroundExecutor().executePeriodically(new ProfilingUpdate(), profilingUpdateFrequency, TimeUnit.SECONDS);
server.getBackgroundExecutor().scheduleWithFixedDelay(new ProfilingUpdate(), profilingUpdateFrequency, profilingUpdateFrequency, TimeUnit.SECONDS);
}
}
}
@@ -127,8 +130,8 @@ public class DefaultAutoTuneService implements AutoTuneService {
* Collect profiling, check for new/diff to existing tuning and apply changes.
*/
private void runtimeTuningUpdate() {
synchronized (this) {
lock.lock();
try {
try {
long start = System.currentTimeMillis();
@@ -150,12 +153,14 @@ public class DefaultAutoTuneService implements AutoTuneService {
} catch (Throwable e) {
logger.error("Error collecting or applying automatic query tuning", e);
}
} finally {
lock.unlock();
}
}
private void saveProfilingOnShutdown(boolean reset) {
synchronized (this) {
lock.lock();
try {
if (isRuntimeTuningUpdates()) {
runtimeTuningUpdate();
outputAllTuning();
@@ -174,6 +179,8 @@ public class DefaultAutoTuneService implements AutoTuneService {
logger.info("writing new:{} diff:{} profiling entries for server:{}", event.getNewCount(), event.getDiffCount(), serverName);
}
}
} finally {
lock.unlock();
}
}
@@ -11,12 +11,15 @@ import io.ebeaninternal.server.deploy.BeanDescriptor;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
/**
* Manages the collection of object graph usage profiling.
*/
public class ProfileManager implements ProfilingListener {
private final ReentrantLock lock = new ReentrantLock();
private final boolean queryTuningAddVersion;
/**
@@ -32,8 +35,6 @@ public class ProfileManager implements ProfilingListener {
*/
private final Map<String, ProfileOrigin> profileMap = new ConcurrentHashMap<>();
private final Object monitor = new Object();
private final SpiEbeanServer server;
public ProfileManager(AutoTuneConfig config, SpiEbeanServer server) {
@@ -101,8 +102,11 @@ public class ProfileManager implements ProfilingListener {
}
private ProfileOrigin getProfileOrigin(ObjectGraphOrigin originQueryPoint) {
synchronized (monitor) {
lock.lock();
try {
return profileMap.computeIfAbsent(originQueryPoint.getKey(), k -> new ProfileOrigin(originQueryPoint, queryTuningAddVersion, profilingBase, profilingRate));
} finally {
lock.unlock();
}
}
@@ -12,9 +12,12 @@ import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;
public class ProfileOrigin {
private final ReentrantLock lock = new ReentrantLock();
private static final long RESET_COUNT = -1000000000L;
private final ObjectGraphOrigin origin;
@@ -29,8 +32,6 @@ public class ProfileOrigin {
private final Map<String, ProfileOriginNodeUsage> nodeUsageMap = new ConcurrentHashMap<>();
private final Object monitor = new Object();
private final AtomicLong requestCount = new AtomicLong();
private final AtomicLong profileCount = new AtomicLong();
@@ -74,8 +75,8 @@ public class ProfileOrigin {
* Collect profiling information with the option to reset the underlying profiling detail.
*/
public void profilingCollection(BeanDescriptor<?> rootDesc, AutoTuneCollection req, boolean reset) {
synchronized (monitor) {
lock.lock();
try {
if (nodeUsageMap.isEmpty()) {
return;
}
@@ -94,6 +95,8 @@ public class ProfileOrigin {
profileCount.set(0);
}
}
} finally {
lock.unlock();
}
}
@@ -155,8 +158,8 @@ public class ProfileOrigin {
}
private ProfileOriginNodeUsage getNodeStats(String path) {
synchronized (monitor) {
lock.lock();
try {
// handle null paths as using ConcurrentHashMap
path = (path == null) ? "" : path;
ProfileOriginNodeUsage nodeStats = nodeUsageMap.get(path);
@@ -165,6 +168,8 @@ public class ProfileOrigin {
nodeUsageMap.put(path, nodeStats);
}
return nodeStats;
} finally {
lock.unlock();
}
}
@@ -12,6 +12,7 @@ import org.slf4j.LoggerFactory;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
/**
* Collects usages statistics for a given node in the object graph.
@@ -20,7 +21,7 @@ public class ProfileOriginNodeUsage {
private static final Logger logger = LoggerFactory.getLogger(ProfileOriginNodeUsage.class);
private final Object monitor = new Object();
private final ReentrantLock lock = new ReentrantLock();
private final String path;
@@ -38,9 +39,8 @@ public class ProfileOriginNodeUsage {
}
protected void buildTunedFetch(PathProperties pathProps, BeanDescriptor<?> rootDesc, boolean addVersionProperty) {
synchronized (monitor) {
lock.lock();
try {
BeanDescriptor<?> desc = rootDesc;
if (path != null) {
ElPropertyValue elGetValue = rootDesc.getElGetValue(path);
@@ -95,6 +95,8 @@ public class ProfileOriginNodeUsage {
ElPropertyValue assocOne = rootDesc.getElGetValue(path);
pathProps.addToPath(SplitName.parent(path), assocOne.getName());
}
} finally {
lock.unlock();
}
}
@@ -102,9 +104,8 @@ public class ProfileOriginNodeUsage {
* Collect usage from a node.
*/
protected void collectUsageInfo(NodeUsageCollector profile) {
synchronized (monitor) {
lock.lock();
try {
Set<String> used = profile.getUsed();
profileCount++;
@@ -115,6 +116,8 @@ public class ProfileOriginNodeUsage {
if (profile.isModified()) {
modified = true;
}
} finally {
lock.unlock();
}
}
+77 -16
View File
@@ -1,18 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.5.1-SNAPSHOT</version>
<version>12.6.4</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<name>ebean bom</name>
<description>ebean bill of materials pom</description>
<artifactId>ebean-bom</artifactId>
<packaging>pom</packaging>
<properties>
<ebean-agent.version>12.5.0</ebean-agent.version>
<ebean-maven-plugin.version>12.5.0</ebean-maven-plugin.version>
<ebean-ddl-runner.version>1.0</ebean-ddl-runner.version>
<ebean-migration-auto.version>1.0</ebean-migration-auto.version>
<ebean-migration.version>12.4.0</ebean-migration.version>
<ebean-test-docker.version>4.1</ebean-test-docker.version>
<ebean-datasource.version>7.0</ebean-datasource.version>
<ebean-agent.version>12.6.2</ebean-agent.version>
<ebean-maven-plugin.version>12.6.2</ebean-maven-plugin.version>
</properties>
<dependencyManagement>
@@ -21,6 +28,36 @@
<!-- dependencies external to this ebean.git build -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-runner</artifactId>
<version>${ebean-ddl-runner.version}</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-migration-auto</artifactId>
<version>${ebean-migration-auto.version}</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-migration</artifactId>
<version>${ebean-migration.version}</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-datasource-api</artifactId>
<version>${ebean-datasource.version}</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-datasource</artifactId>
<version>${ebean-datasource.version}</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-agent</artifactId>
@@ -33,77 +70,101 @@
<version>${ebean-maven-plugin.version}</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test-docker</artifactId>
<version>${ebean-test-docker.version}</version>
</dependency>
<!-- modules -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>${project.version}</version>
<version>12.6.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>${project.version}</version>
<version>12.6.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>${project.version}</version>
<version>12.6.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddlgen</artifactId>
<version>${project.version}</version>
<artifactId>ebean-core-type</artifactId>
<version>12.6.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.6.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>${project.version}</version>
<version>12.6.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-xml</artifactId>
<version>${project.version}</version>
<version>12.6.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-autotune</artifactId>
<version>${project.version}</version>
<version>12.6.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>${project.version}</version>
<version>12.6.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>${project.version}</version>
<version>12.6.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId>
<version>${project.version}</version>
<version>12.6.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>${project.version}</version>
<version>12.6.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis</artifactId>
<version>12.6.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-redis</artifactId>
<version>12.6.4</version>
</dependency>
</dependencies>
</dependencyManagement>
+36
View File
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.4</version>
</parent>
<artifactId>ebean-core-type</artifactId>
<name>ebean core type</name>
<description>ebean scalar types api</description>
<properties>
<jackson-core.version>2.11.3</jackson-core.version>
<jackson-databind.version>2.11.3</jackson-databind.version>
</properties>
<dependencies>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.6.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson-core.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,166 @@
package io.ebean.core.type;
import java.io.InputStream;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.List;
/**
* Data binder for ScalarTypes generally to an underlying PreparedStatement.
*/
public interface DataBinder {
/**
* Add something to the binding log.
*/
StringBuilder append(Object entry);
/**
* Return the binding log.
*/
StringBuilder log();
/**
* Close the underlying prepared statement.
*/
void close() throws SQLException;
/**
* Return the current position. Effectively column binding position.
*/
int currentPos();
/**
* Return the next position.
*/
int nextPos();
/**
* Decrement the position.
*/
void decrementPos();
/**
* Execute as a dml statement.
*/
int executeUpdate() throws SQLException;
/**
* Return the underlying PreparedStatement.
*/
PreparedStatement getPstmt();
/**
* Return any inputStreams that have been bound (and should be closed).
* This is used for batched statement execution only.
*/
List<InputStream> getInputStreams();
/**
* Bind an object.
*/
void setObject(Object value) throws SQLException;
/**
* Bind an object with given sql type.
*/
void setObject(Object value, int sqlType) throws SQLException;
/**
* Bind null.
*/
void setNull(int jdbcType) throws SQLException;
/**
* Bind a string value.
*/
void setString(String value) throws SQLException;
/**
* Bind a int value.
*/
void setInt(int value) throws SQLException;
/**
* Bind a long value.
*/
void setLong(long value) throws SQLException;
/**
* Bind a short value.
*/
void setShort(short value) throws SQLException;
/**
* Bind a float value.
*/
void setFloat(float value) throws SQLException;
/**
* Bind a double value.
*/
void setDouble(double value) throws SQLException;
/**
* Bind a BigDecimal value.
*/
void setBigDecimal(BigDecimal value) throws SQLException;
/**
* Bind a date value.
*/
void setDate(java.sql.Date value) throws SQLException;
/**
* Bind a timestamp value.
*/
void setTimestamp(Timestamp value) throws SQLException;
/**
* Bind a time value.
*/
void setTime(Time value) throws SQLException;
/**
* Bind a boolean value.
*/
void setBoolean(boolean value) throws SQLException;
/**
* Bind a byte array value.
*/
void setBytes(byte[] value) throws SQLException;
/**
* Bind a byte value.
*/
void setByte(byte value) throws SQLException;
/**
* Bind a char value.
*/
void setChar(char value) throws SQLException;
/**
* Bind a InputStream value.
*/
void setBinaryStream(InputStream inputStream, long length) throws SQLException;
/**
* Bind a byte array value.
*/
void setBlob(byte[] bytes) throws SQLException;
/**
* Bind a string clob value.
*/
void setClob(String content) throws SQLException;
/**
* Bind an array value.
*/
void setArray(String arrayType, Object[] elements) throws SQLException;
}
@@ -1,4 +1,4 @@
package io.ebeaninternal.server.type;
package io.ebean.core.type;
import java.io.InputStream;
import java.math.BigDecimal;
@@ -1,4 +1,4 @@
package io.ebeanservice.docstore.api.mapping;
package io.ebean.core.type;
/**
* Types as defined for document store property types.
@@ -1,7 +1,6 @@
package io.ebeaninternal.api;
package io.ebean.core.type;
import io.ebean.config.DatabaseConfig;
import io.ebeaninternal.server.type.ScalarType;
import java.util.List;
@@ -1,4 +1,4 @@
package io.ebeaninternal.server.type;
package io.ebean.core.type;
import java.sql.SQLException;
@@ -10,6 +10,6 @@ public interface ScalarDataReader<T> {
/**
* Read and return the appropriate value from the dataReader.
*/
T read(DataReader dataReader) throws SQLException;
T read(DataReader reader) throws SQLException;
}
@@ -1,10 +1,9 @@
package io.ebeaninternal.server.type;
package io.ebean.core.type;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import io.ebean.text.StringFormatter;
import io.ebean.text.StringParser;
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
import java.io.DataInput;
import java.io.DataOutput;
@@ -112,7 +111,7 @@ public interface ScalarType<T> extends StringParser, StringFormatter, ScalarData
* JDBC type.
* </p>
*/
void bind(DataBind bind, T value) throws SQLException;
void bind(DataBinder binder, T value) throws SQLException;
/**
* Convert the value as necessary to the JDBC type.
+55 -21
View File
@@ -3,23 +3,24 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.5.1-SNAPSHOT</version>
<version>12.6.4</version>
</parent>
<artifactId>ebean-core</artifactId>
<packaging>jar</packaging>
<name>ebean-core</name>
<url>http://ebean-orm.github.io/</url>
<name>ebean core</name>
<description>ebean core module</description>
<url>https://ebean.io/</url>
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>HEAD</tag>
<tag>ebean-parent-12.6.4</tag>
</scm>
<properties>
<jackson-core.version>2.10.0</jackson-core.version>
<jackson-databind.version>2.10.0</jackson-databind.version>
<jackson-core.version>2.11.3</jackson-core.version>
<jackson-databind.version>2.11.3</jackson-databind.version>
</properties>
<profiles>
@@ -47,14 +48,40 @@
</profiles>
<dependencies>
<!-- keep testing in core using ebean-ddlgen -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddlgen</artifactId>
<version>12.5.0</version>
<artifactId>ebean-ddl-runner</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>io.avaje</groupId>
<artifactId>classpath-scanner</artifactId>
<version>4.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-migration-auto</artifactId>
<version>1.0</version>
</dependency>
<!-- keep testing in core using ebean-ddl-generator & ebean-migration -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-migration</artifactId>
<version>12.4.0</version>
<scope>test</scope>
</dependency>
<!-- test scope for supporting ebean-ddlgen -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.6.1</version>
<scope>test</scope>
</dependency>
<!-- test scope for supporting ebean-ddl-generator -->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
@@ -65,13 +92,19 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>${project.version}</version>
<version>12.6.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>12.6.4</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>${project.version}</version>
<version>12.6.4</version>
</dependency>
<dependency>
@@ -91,12 +124,6 @@
<scope>provided</scope>
</dependency>
<!-- <dependency>-->
<!-- <groupId>io.ebean</groupId>-->
<!-- <artifactId>ebean-migration</artifactId>-->
<!-- <version>12.1.4</version>-->
<!-- </dependency>-->
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
@@ -131,9 +158,9 @@
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson-core.version}</version>
<optional>true</optional>
</dependency>
<!-- provided scope for JsonNode support -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
@@ -151,6 +178,13 @@
<!-- Test scope -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-datasource</artifactId>
<version>${ebean-datasource.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.nuodb.jdbc</groupId>
<artifactId>nuodb-jdbc</artifactId>
@@ -166,9 +200,9 @@
</dependency>
<dependency>
<groupId>io.ebean.test</groupId>
<groupId>io.ebean</groupId>
<artifactId>ebean-test-docker</artifactId>
<version>3.1.5</version>
<version>4.1</version>
<scope>test</scope>
</dependency>
@@ -0,0 +1,15 @@
package io.ebeaninternal.api;
import io.ebean.config.DatabaseConfig;
import io.ebeaninternal.server.type.GeoTypeBinder;
/**
* Provider of Geometry type binder support.
*/
public interface GeoTypeProvider {
/**
* Create a binder for binding geometry types.
*/
GeoTypeBinder createBinder(DatabaseConfig config);
}
@@ -237,7 +237,7 @@ public interface SpiQuery<T> extends Query<T>, TxnProfileEventCodes {
* Return the ForUpdate mode.
*/
@Override
ForUpdate getForUpdateMode();
LockWait getForUpdateLockWait();
/**
* Return the bean descriptor for this query.
@@ -318,4 +318,20 @@ public interface SpiTransaction extends Transaction {
* Return true if explicitly set to skip cache (ignores skipOnWrite).
*/
boolean isSkipCacheExplicit();
/**
* Fire pre commit processing/listeners.
*/
void preCommit();
/**
* Fire post commit events and listeners.
*/
void postCommit();
/**
* Fire post rollback events and listeners.
*/
void postRollback(Throwable cause);
}
@@ -418,4 +418,18 @@ public abstract class SpiTransactionProxy implements SpiTransaction {
transaction.flushBatchOnCollection();
}
@Override
public void preCommit() {
transaction.preCommit();
}
@Override
public void postCommit() {
transaction.postCommit();
}
@Override
public void postRollback(Throwable cause) {
transaction.postRollback(cause);
}
}
@@ -3,6 +3,7 @@ package io.ebeaninternal.json;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import io.ebean.ModifyAwareType;
import java.io.IOException;
import java.io.Reader;
@@ -145,7 +146,7 @@ class EJsonReader {
currentContext = stack.pop(currentContext);
}
if (modifyAwareOwner != null) {
modifyAwareOwner.resetMarkedDirty();
modifyAwareOwner.setMarkedDirty(false);
}
}
@@ -296,7 +297,7 @@ class EJsonReader {
map = new LinkedHashMap<>();
}
ObjectContext(ModifyAwareOwner owner) {
ObjectContext(ModifyAwareType owner) {
map = new ModifyAwareMap<>(owner, new LinkedHashMap<>());
}
@@ -334,7 +335,7 @@ class EJsonReader {
values = new ArrayList<>();
}
ArrayContext(ModifyAwareOwner owner) {
ArrayContext(ModifyAwareType owner) {
values = new ModifyAwareList<>(owner, new ArrayList<>());
}
@@ -1,28 +1,26 @@
package io.ebeaninternal.json;
import io.ebean.ModifyAwareType;
import java.io.Serializable;
/**
* Detects when content has been modified and as such needs to be persisted (included in an update).
*/
public class ModifyAwareFlag implements ModifyAwareOwner {
public class ModifyAwareFlag implements ModifyAwareType, Serializable {
private static final long serialVersionUID = 1;
boolean dirty;
private boolean markedDirty;
@Override
public boolean isMarkedDirty() {
if (!dirty) return false;
dirty = false;
return true;
return markedDirty;
}
@Override
public void markAsModified() {
dirty = true;
public void setMarkedDirty(boolean markedDirty) {
this.markedDirty = markedDirty;
}
@Override
public void resetMarkedDirty() {
dirty = false;
}
}
@@ -1,5 +1,7 @@
package io.ebeaninternal.json;
import io.ebean.ModifyAwareType;
import java.util.Iterator;
/**
@@ -7,7 +9,7 @@ import java.util.Iterator;
*/
public class ModifyAwareIterator<E> implements Iterator<E> {
private final ModifyAwareOwner owner;
private final ModifyAwareType owner;
private final Iterator<E> it;
@@ -17,7 +19,7 @@ public class ModifyAwareIterator<E> implements Iterator<E> {
* The owner is notified of the removals.
* </p>
*/
public ModifyAwareIterator(ModifyAwareOwner owner, Iterator<E> it) {
public ModifyAwareIterator(ModifyAwareType owner, Iterator<E> it) {
this.owner = owner;
this.it = it;
}
@@ -34,7 +36,7 @@ public class ModifyAwareIterator<E> implements Iterator<E> {
@Override
public void remove() {
owner.markAsModified();
owner.setMarkedDirty(true);
it.remove();
}
@@ -1,5 +1,8 @@
package io.ebeaninternal.json;
import io.ebean.ModifyAwareType;
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
@@ -10,20 +13,20 @@ import java.util.Objects;
/**
* Modify aware wrapper of a list.
*/
public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
public class ModifyAwareList<E> implements List<E>, ModifyAwareType, Serializable {
private static final long serialVersionUID = 1;
final List<E> list;
final ModifyAwareOwner owner;
final ModifyAwareType owner;
public ModifyAwareList(List<E> list) {
this.list = list;
this.owner = new ModifyAwareFlag();
}
public ModifyAwareList(ModifyAwareOwner owner, List<E> list) {
public ModifyAwareList(ModifyAwareType owner, List<E> list) {
this.list = list;
this.owner = owner;
}
@@ -56,13 +59,12 @@ public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
}
@Override
public void markAsModified() {
owner.markAsModified();
public void setMarkedDirty(boolean markedDirty) {
owner.setMarkedDirty(markedDirty);
}
@Override
public void resetMarkedDirty() {
owner.resetMarkedDirty();
private void markAsDirty() {
owner.setMarkedDirty(true);
}
@Override
@@ -98,13 +100,13 @@ public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
@Override
public boolean add(E e) {
owner.markAsModified();
markAsDirty();
return list.add(e);
}
@Override
public boolean remove(Object o) {
owner.markAsModified();
markAsDirty();
return list.remove(o);
}
@@ -115,31 +117,31 @@ public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
@Override
public boolean addAll(Collection<? extends E> c) {
owner.markAsModified();
markAsDirty();
return list.addAll(c);
}
@Override
public boolean addAll(int index, Collection<? extends E> c) {
owner.markAsModified();
markAsDirty();
return list.addAll(index, c);
}
@Override
public boolean removeAll(Collection<?> c) {
owner.markAsModified();
markAsDirty();
return list.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
owner.markAsModified();
markAsDirty();
return list.retainAll(c);
}
@Override
public void clear() {
owner.markAsModified();
markAsDirty();
list.clear();
}
@@ -150,19 +152,19 @@ public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
@Override
public E set(int index, E element) {
owner.markAsModified();
markAsDirty();
return list.set(index, element);
}
@Override
public void add(int index, E element) {
owner.markAsModified();
markAsDirty();
list.add(index, element);
}
@Override
public E remove(int index) {
owner.markAsModified();
markAsDirty();
return list.remove(index);
}
@@ -195,7 +197,6 @@ public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
* Create an return a modify aware Set.
*/
public ModifyAwareSet<E> asSet() {
return new ModifyAwareSet<>(owner, new LinkedHashSet<>(list));
}
}
@@ -1,5 +1,7 @@
package io.ebeaninternal.json;
import io.ebean.ModifyAwareType;
import java.util.ListIterator;
/**
@@ -7,11 +9,11 @@ import java.util.ListIterator;
*/
public class ModifyAwareListIterator<E> implements ListIterator<E> {
final ModifyAwareOwner owner;
final ModifyAwareType owner;
final ListIterator<E> iterator;
public ModifyAwareListIterator(ModifyAwareOwner owner, ListIterator<E> iterator) {
public ModifyAwareListIterator(ModifyAwareType owner, ListIterator<E> iterator) {
this.owner = owner;
this.iterator = iterator;
}
@@ -48,19 +50,19 @@ public class ModifyAwareListIterator<E> implements ListIterator<E> {
@Override
public void remove() {
owner.markAsModified();
owner.setMarkedDirty(true);
iterator.remove();
}
@Override
public void set(E e) {
owner.markAsModified();
owner.setMarkedDirty(true);
iterator.set(e);
}
@Override
public void add(E e) {
owner.markAsModified();
owner.setMarkedDirty(true);
iterator.add(e);
}
}
@@ -1,5 +1,8 @@
package io.ebeaninternal.json;
import io.ebean.ModifyAwareType;
import java.io.Serializable;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Map;
@@ -9,11 +12,11 @@ import java.util.Set;
/**
* Map that is wraps an underlying map for the purpose of detecting changes.
*/
public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareType, Serializable {
private static final long serialVersionUID = 1;
final ModifyAwareOwner owner;
final ModifyAwareType owner;
/**
* The underlying map.
@@ -25,7 +28,7 @@ public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
this.owner = new ModifyAwareFlag();
}
public ModifyAwareMap(ModifyAwareOwner owner, Map<K, V> underlying) {
public ModifyAwareMap(ModifyAwareType owner, Map<K, V> underlying) {
this.owner = owner;
this.map = underlying;
}
@@ -58,13 +61,12 @@ public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
}
@Override
public void markAsModified() {
owner.markAsModified();
public void setMarkedDirty(boolean markedDirty) {
owner.setMarkedDirty(markedDirty);
}
@Override
public void resetMarkedDirty() {
owner.resetMarkedDirty();
private void markAsDirty() {
owner.setMarkedDirty(true);
}
@Override
@@ -94,7 +96,7 @@ public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
@Override
public V put(K key, V value) {
markAsModified();
markAsDirty();
return map.put(key, value);
}
@@ -102,14 +104,14 @@ public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
public V remove(Object key) {
V value = map.remove(key);
if (value != null) {
markAsModified();
markAsDirty();
}
return value;
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
markAsModified();
markAsDirty();
map.putAll(m);
}
@@ -117,7 +119,7 @@ public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
@Override
public void clear() {
if (!map.isEmpty()) {
markAsModified();
markAsDirty();
}
map.clear();
}
@@ -1,5 +1,8 @@
package io.ebeaninternal.json;
import io.ebean.ModifyAwareType;
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.Objects;
@@ -8,11 +11,11 @@ import java.util.Set;
/**
* Wraps a Set for the purposes of detecting modifications.
*/
public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
public class ModifyAwareSet<E> implements Set<E>, ModifyAwareType, Serializable {
private static final long serialVersionUID = 1;
protected final ModifyAwareOwner owner;
protected final ModifyAwareType owner;
protected final Set<E> set;
@@ -26,7 +29,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
/**
* Create with an Owner that is notified of modifications.
*/
public ModifyAwareSet(ModifyAwareOwner owner, Set<E> underlying) {
public ModifyAwareSet(ModifyAwareType owner, Set<E> underlying) {
this.owner = owner;
this.set = underlying;
}
@@ -37,16 +40,14 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
}
@Override
public void markAsModified() {
owner.markAsModified();
public void setMarkedDirty(boolean markedDirty) {
owner.setMarkedDirty(markedDirty);
}
@Override
public void resetMarkedDirty() {
owner.resetMarkedDirty();
private void markAsDirty() {
owner.setMarkedDirty(true);
}
@Override
public String toString() {
return set.toString();
@@ -72,7 +73,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
@Override
public boolean add(E o) {
if (set.add(o)) {
owner.markAsModified();
markAsDirty();
return true;
}
return false;
@@ -83,7 +84,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
boolean changed = false;
for (E o : collection) {
if (set.add(o)) {
owner.markAsModified();
markAsDirty();
changed = true;
}
}
@@ -93,7 +94,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
@Override
public void clear() {
if (!set.isEmpty()) {
owner.markAsModified();
markAsDirty();
}
set.clear();
}
@@ -121,7 +122,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
@Override
public boolean remove(Object o) {
if (set.remove(o)) {
owner.markAsModified();
markAsDirty();
return true;
}
return false;
@@ -132,7 +133,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
boolean changed = false;
for (Object element : collection) {
if (set.remove(element)) {
owner.markAsModified();
markAsDirty();
changed = true;
}
}
@@ -147,7 +148,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
Object o = it.next();
if (!collection.contains(o)) {
it.remove();
owner.markAsModified();
markAsDirty();
changed = true;
}
}
@@ -18,6 +18,7 @@ import org.slf4j.LoggerFactory;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.locks.ReentrantLock;
/**
* Manages the construction of caches.
@@ -26,17 +27,14 @@ class DefaultCacheHolder {
private static final Logger log = LoggerFactory.getLogger("io.ebean.cache.ALL");
private final ReentrantLock lock = new ReentrantLock();
private final ConcurrentHashMap<String, ServerCache> allCaches = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, Set<String>> collectIdCaches = new ConcurrentHashMap<>();
private final ServerCacheFactory cacheFactory;
private final ServerCacheOptions beanDefault;
private final ServerCacheOptions queryDefault;
private final CurrentTenantProvider tenantProvider;
private final QueryCacheEntryValidate queryCacheEntryValidate;
DefaultCacheHolder(CacheManagerOptions builder) {
@@ -87,8 +85,11 @@ class DefaultCacheHolder {
private ServerCache createCache(Class<?> beanType, ServerCacheType type, String key, String shortName) {
ServerCacheOptions options = getCacheOptions(beanType, type);
if (type == ServerCacheType.COLLECTION_IDS) {
synchronized (this) {
lock.lock();
try {
collectIdCaches.computeIfAbsent(beanType.getName(), s -> new ConcurrentSkipListSet<>()).add(key);
} finally {
lock.unlock();
}
}
return cacheFactory.createCache(new ServerCacheConfig(type, key, shortName, options, tenantProvider, queryCacheEntryValidate));
@@ -86,7 +86,7 @@ public class DefaultServerCache implements ServerCache {
// default to trimming the cache every 60 seconds
long trimFreqSecs = (trimFrequency == 0) ? 60 : trimFrequency;
executor.executePeriodically(trim, trimFreqSecs, TimeUnit.SECONDS);
executor.scheduleWithFixedDelay(trim, trimFreqSecs, trimFreqSecs, TimeUnit.SECONDS);
}
@Override
@@ -9,6 +9,7 @@ import org.slf4j.LoggerFactory;
import java.util.Iterator;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
/**
* Manages the cluster service.
@@ -17,6 +18,8 @@ public class ClusterManager implements ServerLookup {
private static final Logger clusterLogger = LoggerFactory.getLogger("io.ebean.Cluster");
private final ReentrantLock lock = new ReentrantLock();
private final ConcurrentHashMap<String, EbeanServer> serverMap = new ConcurrentHashMap<>();
private final Object monitor = new Object();
@@ -51,18 +54,24 @@ public class ClusterManager implements ServerLookup {
}
public void registerServer(EbeanServer server) {
synchronized (monitor) {
lock.lock();
try {
serverMap.put(server.getName(), server);
if (!started) {
startup();
}
} finally {
lock.unlock();
}
}
@Override
public EbeanServer getServer(String name) {
synchronized (monitor) {
lock.lock();
try {
return serverMap.get(name);
} finally {
lock.unlock();
}
}
@@ -27,7 +27,7 @@ public abstract class AbstractSqlQueryRequest {
protected final SpiEbeanServer server;
protected SpiTransaction trans;
protected SpiTransaction transaction;
private boolean createdTransaction;
@@ -47,18 +47,18 @@ public abstract class AbstractSqlQueryRequest {
AbstractSqlQueryRequest(SpiEbeanServer server, SpiSqlBinding query, Transaction t) {
this.server = server;
this.query = query;
this.trans = (SpiTransaction) t;
this.transaction = (SpiTransaction) t;
}
/**
* Create a transaction if none currently exists.
*/
public void initTransIfRequired() {
if (trans == null) {
trans = server.currentServerTransaction();
if (trans == null || !trans.isActive()) {
if (transaction == null) {
transaction = server.currentServerTransaction();
if (transaction == null || !transaction.isActive()) {
// create a local readOnly transaction
trans = server.createReadOnlyTransaction(null);
transaction = server.createReadOnlyTransaction(null);
createdTransaction = true;
}
}
@@ -69,20 +69,18 @@ public abstract class AbstractSqlQueryRequest {
*/
public void endTransIfRequired() {
if (createdTransaction) {
trans.commit();
transaction.commit();
}
}
public EbeanServer getServer() {
return server;
}
public SpiTransaction getTransaction() {
return trans;
protected void flushJdbcBatchOnQuery() {
if (transaction.isFlushOnQuery()) {
transaction.flush();
}
}
public boolean isLogSql() {
return trans.isLogSql();
return transaction.isLogSql();
}
/**
@@ -120,7 +118,6 @@ public abstract class AbstractSqlQueryRequest {
* Prepare the SQL taking into account named bind parameters.
*/
private void prepareSql() {
String sql = query.getQuery();
BindParams bindParams = query.getBindParams();
if (!bindParams.isEmpty()) {
@@ -131,7 +128,6 @@ public abstract class AbstractSqlQueryRequest {
}
private String limitOffset(String sql) {
int firstRow = query.getFirstRow();
int maxRows = query.getMaxRows();
if (firstRow > 0 || maxRows > 0) {
@@ -149,10 +145,8 @@ public abstract class AbstractSqlQueryRequest {
}
protected void executeAsSql(Binder binder) throws SQLException {
prepareSql();
Connection conn = trans.getInternalConnection();
Connection conn = transaction.getInternalConnection();
pstmt = conn.prepareStatement(sql);
if (query.getTimeout() > 0) {
pstmt.setQueryTimeout(query.getTimeout());
@@ -160,14 +154,12 @@ public abstract class AbstractSqlQueryRequest {
if (query.getBufferFetchSizeHint() > 0) {
pstmt.setFetchSize(query.getBufferFetchSizeHint());
}
BindParams bindParams = query.getBindParams();
if (!bindParams.isEmpty()) {
this.bindLog = binder.bind(bindParams, pstmt, conn);
}
if (isLogSql()) {
trans.logSql(Str.add(TrimLogSql.trim(sql), "; --bind(", bindLog, ")"));
transaction.logSql(Str.add(TrimLogSql.trim(sql), "; --bind(", bindLog, ")"));
}
setResultSet(pstmt.executeQuery(), null);
@@ -1,8 +1,8 @@
package io.ebeaninternal.server.core;
import io.ebean.ScriptRunner;
import io.ebean.migration.ddl.DdlRunner;
import io.ebean.migration.runner.ScriptTransform;
import io.ebean.ddlrunner.DdlRunner;
import io.ebean.ddlrunner.ScriptTransform;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.util.UrlHelper;
@@ -102,7 +102,7 @@ class DScriptRunner implements ScriptRunner {
private Connection obtainConnection() {
try {
return server.getPluginApi().getDataSource().getConnection();
return server.getDataSource().getConnection();
} catch (SQLException e) {
throw new PersistenceException("Failed to obtain connection to run script", e);
}
@@ -1,112 +0,0 @@
package io.ebeaninternal.server.core;
import io.ebeaninternal.api.SpiBackgroundExecutor;
import io.ebeaninternal.server.lib.DaemonExecutorService;
import io.ebeaninternal.server.lib.DaemonScheduleThreadPool;
import org.slf4j.MDC;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
* The default implementation of the BackgroundExecutor.
*/
public class DefaultBackgroundExecutor implements SpiBackgroundExecutor {
private final DaemonScheduleThreadPool schedulePool;
private final DaemonExecutorService pool;
/**
* Construct the default implementation of BackgroundExecutor.
*/
public DefaultBackgroundExecutor(int schedulePoolSize, int shutdownWaitSeconds, String namePrefix) {
this.pool = new DaemonExecutorService(shutdownWaitSeconds, namePrefix);
this.schedulePool = new DaemonScheduleThreadPool(schedulePoolSize, shutdownWaitSeconds, namePrefix + "-periodic-");
}
/**
* Execute a Runnable using a background thread.
*/
@Override
public void execute(Runnable r) {
final Map<String, String> map = MDC.getCopyOfContextMap();
if (map == null) {
pool.execute(r);
} else {
pool.execute(() -> {
MDC.setContextMap(map);
try {
r.run();
} finally {
MDC.clear();
}
});
}
}
@Override
public void executePeriodically(Runnable r, long delay, TimeUnit unit) {
executePeriodically(r, delay, delay, unit);
}
@Override
public void executePeriodically(Runnable r, long initialDelay, long delay, TimeUnit unit) {
final Map<String, String> map = MDC.getCopyOfContextMap();
if (map == null) {
schedulePool.scheduleWithFixedDelay(r, initialDelay, delay, unit);
} else {
schedulePool.scheduleWithFixedDelay(() -> {
MDC.setContextMap(map);
try {
r.run();
} finally {
MDC.clear();
}
}, initialDelay, delay, unit);
}
}
@Override
public ScheduledFuture<?> schedule(Runnable r, long delay, TimeUnit unit) {
final Map<String, String> map = MDC.getCopyOfContextMap();
if (map == null) {
return schedulePool.schedule(r, delay, unit);
} else {
return schedulePool.schedule(() -> {
MDC.setContextMap(map);
try {
r.run();
} finally {
MDC.clear();
}
}, delay, unit);
}
}
@Override
public <V> ScheduledFuture<V> schedule(Callable<V> c, long delay, TimeUnit unit) {
final Map<String, String> map = MDC.getCopyOfContextMap();
if (map == null) {
return schedulePool.schedule(c, delay, unit);
} else {
return schedulePool.schedule(() -> {
MDC.setContextMap(map);
try {
return c.call();
} finally {
MDC.clear();
}
}, delay, unit);
}
}
@Override
public void shutdown() {
pool.shutdown();
schedulePool.shutdown();
}
}
@@ -10,14 +10,15 @@ import io.ebean.config.TenantMode;
import io.ebean.config.UnderscoreNamingConvention;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.h2.H2Platform;
import io.ebean.event.ShutdownManager;
import io.ebean.service.SpiContainer;
import io.ebeaninternal.api.DbOffline;
import io.ebeaninternal.api.SpiBackgroundExecutor;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.DbOffline;
import io.ebeaninternal.server.cluster.ClusterManager;
import io.ebeaninternal.server.core.bootup.BootupClassPathSearch;
import io.ebeaninternal.server.core.bootup.BootupClasses;
import io.ebean.event.ShutdownManager;
import io.ebeaninternal.server.executor.DefaultBackgroundExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -26,6 +27,7 @@ import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.ServiceLoader;
import java.util.concurrent.locks.ReentrantLock;
/**
* Default Server side implementation of ServerFactory.
@@ -34,6 +36,7 @@ public class DefaultContainer implements SpiContainer {
private static final Logger logger = LoggerFactory.getLogger("io.ebean.internal.DefaultContainer");
private final ReentrantLock lock = new ReentrantLock();
private final ClusterManager clusterManager;
public DefaultContainer(ContainerConfig containerConfig) {
@@ -72,7 +75,8 @@ public class DefaultContainer implements SpiContainer {
*/
@Override
public SpiEbeanServer createServer(DatabaseConfig config) {
synchronized (this) {
lock.lock();
try {
applyConfigServices(config);
setNamingConvention(config);
BootupClasses bootupClasses = getBootupClasses(config);
@@ -114,6 +118,8 @@ public class DefaultContainer implements SpiContainer {
}
DbOffline.reset();
return server;
} finally {
lock.unlock();
}
}
@@ -36,11 +36,13 @@ import io.ebean.Version;
import io.ebean.annotation.Platform;
import io.ebean.annotation.TxIsolation;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.BeanLoader;
import io.ebean.bean.CallOrigin;
import io.ebean.bean.EntityBean;
import io.ebean.bean.EntityBeanIntercept;
import io.ebean.bean.PersistenceContext;
import io.ebean.bean.PersistenceContext.WithOption;
import io.ebean.bean.SingleBeanLoader;
import io.ebean.cache.ServerCacheManager;
import io.ebean.common.CopyOnFirstWriteList;
import io.ebean.config.CurrentTenantProvider;
@@ -59,6 +61,7 @@ import io.ebean.meta.MetaQueryPlan;
import io.ebean.meta.MetricVisitor;
import io.ebean.meta.QueryPlanInit;
import io.ebean.meta.QueryPlanRequest;
import io.ebean.migration.auto.AutoMigrationRunner;
import io.ebean.plugin.BeanType;
import io.ebean.plugin.Plugin;
import io.ebean.plugin.Property;
@@ -142,6 +145,7 @@ import java.util.Optional;
import java.util.Set;
import java.util.Spliterator;
import java.util.concurrent.Callable;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -157,98 +161,47 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
private static final Logger logger = LoggerFactory.getLogger(DefaultServer.class);
private final ReentrantLock lock = new ReentrantLock();
private final DatabaseConfig config;
private final String serverName;
private final DatabasePlatform databasePlatform;
private final TransactionManager transactionManager;
private final QueryPlanManager queryPlanManager;
private final ExtraMetrics extraMetrics;
private final DataTimeZone dataTimeZone;
/**
* Clock to use for WhenModified and WhenCreated.
*/
private final ClockService clockService;
private final CallOriginFactory callStackFactory;
/**
* Handles the save, delete, updateSql CallableSql.
*/
private final Persister persister;
private final OrmQueryEngine queryEngine;
private final RelationalQueryEngine relationalQueryEngine;
private final DtoQueryEngine dtoQueryEngine;
private final ServerCacheManager serverCacheManager;
private final DtoBeanManager dtoBeanManager;
private final BeanDescriptorManager beanDescriptorManager;
private final AutoTuneService autoTuneService;
private final ReadAuditPrepare readAuditPrepare;
private final ReadAuditLogger readAuditLogger;
private final CQueryEngine cqueryEngine;
private final List<Plugin> serverPlugins;
private final SpiDdlGenerator ddlGenerator;
private final ScriptRunner scriptRunner;
private final ExpressionFactory expressionFactory;
private final SpiBackgroundExecutor backgroundExecutor;
private final DefaultBeanLoader beanLoader;
private final EncryptKeyManager encryptKeyManager;
private final SpiJsonContext jsonContext;
private final DocumentStore documentStore;
private final MetaInfoManager metaInfoManager;
private final CurrentTenantProvider currentTenantProvider;
private final SpiLogManager logManager;
/**
* The default PersistenceContextScope used if it is not explicitly set on a query.
*/
private final PersistenceContextScope defaultPersistenceContextScope;
/**
* Flag set when the server has shutdown.
*/
private boolean shutdown;
/**
* The default batch size for lazy loading beans or collections.
*/
private final int lazyLoadBatchSize;
private final int queryBatchSize;
private final boolean updateAllPropertiesInBatch;
private final long slowQueryMicros;
private final SlowQueryListener slowQueryListener;
private final boolean disableL2Cache;
private boolean shutdown;
/**
* Create the DefaultServer.
@@ -445,15 +398,27 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
* Start any services after registering with the ClusterManager.
*/
public void start() {
if (TenantMode.DB != config.getTenantMode()) {
config.runDbMigration(config.getDataSource());
if (config.isRunMigration() && TenantMode.DB != config.getTenantMode()) {
final AutoMigrationRunner migrationRunner = config.service(AutoMigrationRunner.class);
if (migrationRunner == null) {
throw new IllegalStateException("No AutoMigrationRunner found. Probably ebean-migration is not in the classpath?");
}
final String dbSchema = config.getDbSchema();
if (dbSchema != null) {
migrationRunner.setDefaultDbSchema(dbSchema);
}
migrationRunner.loadProperties(config.getProperties());
migrationRunner.run(config.getDataSource());
}
}
@Override
public void shutdown() {
synchronized (this) {
lock.lock();
try {
shutdownInternal(true, false);
} finally {
lock.unlock();
}
}
@@ -462,10 +427,12 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
*/
@Override
public void shutdown(boolean shutdownDataSource, boolean deregisterDriver) {
synchronized (this) {
// Unregister from JVM Shutdown hook
lock.lock();
try {
ShutdownManager.unregisterDatabase(this);
shutdownInternal(shutdownDataSource, deregisterDriver);
} finally {
lock.unlock();
}
}
@@ -484,16 +451,20 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
backgroundExecutor.shutdown();
// shutdown DataSource (if its an Ebean one)
transactionManager.shutdown(shutdownDataSource, deregisterDriver);
dumpMetrics();
shutdown = true;
if (shutdownDataSource) {
config.setDataSource(null);
}
}
private void shutdownPlugins() {
private void dumpMetrics() {
if (config.isDumpMetricsOnShutdown()) {
new DumpMetrics(this, config.getDumpMetricsOptions()).dump();
}
}
private void shutdownPlugins() {
for (Plugin plugin : serverPlugins) {
try {
plugin.shutdown();
@@ -575,6 +546,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
beanLoader.loadBean(loadRequest);
}
@Override
public BeanLoader beanLoader() {
return new SingleBeanLoader.Dflt(this);
}
@Override
public void loadBean(EntityBeanIntercept ebi) {
beanLoader.loadBean(ebi);
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.core;
import io.ebean.core.type.DataReader;
import io.ebeaninternal.api.SpiDtoQuery;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiQuery;
@@ -8,7 +9,6 @@ import io.ebeaninternal.server.dto.DtoMappingRequest;
import io.ebeaninternal.server.dto.DtoQueryPlan;
import io.ebeaninternal.server.persist.Binder;
import io.ebeaninternal.server.query.DtoQueryEngine;
import io.ebeaninternal.server.type.DataReader;
import io.ebeaninternal.server.type.RsetDataReader;
import java.sql.ResultSet;
@@ -50,7 +50,7 @@ public final class DtoQueryRequest<T> extends AbstractSqlQueryRequest {
ormQuery.setManualId();
// execute the underlying ORM query returning the ResultSet
SpiResultSet result = server.findResultSet(ormQuery, trans);
SpiResultSet result = server.findResultSet(ormQuery, transaction);
this.pstmt = result.getStatement();
this.sql = ormQuery.getGeneratedSql();
setResultSet(result.getResultSet(), ormQuery.getQueryPlanKey());
@@ -88,14 +88,17 @@ public final class DtoQueryRequest<T> extends AbstractSqlQueryRequest {
}
public void findEach(Consumer<T> consumer) {
flushJdbcBatchOnQuery();
queryEngine.findEach(this, consumer);
}
public void findEachWhile(Predicate<T> consumer) {
flushJdbcBatchOnQuery();
queryEngine.findEachWhile(this, consumer);
}
public List<T> findList() {
flushJdbcBatchOnQuery();
return queryEngine.findList(this);
}
@@ -1,6 +1,7 @@
package io.ebeaninternal.server.core;
import java.util.HashMap;
import java.util.concurrent.locks.ReentrantLock;
/**
* Used to reduce memory consumption of strings used in deployment processing.
@@ -12,6 +13,8 @@ public final class InternString {
private static final HashMap<String, String> map = new HashMap<>();
private static final ReentrantLock lock = new ReentrantLock();
/**
* Return the shared instance of this string.
*/
@@ -19,8 +22,8 @@ public final class InternString {
if (s == null) {
return null;
}
//noinspection SynchronizationOnStaticField
synchronized (map) {
lock.lock();
try {
String v = map.get(s);
if (v != null) {
return v;
@@ -28,6 +31,8 @@ public final class InternString {
map.put(s, s);
return s;
}
} finally {
lock.unlock();
}
}
}
@@ -118,69 +118,41 @@ public class InternalConfiguration {
private static final Logger logger = LoggerFactory.getLogger(InternalConfiguration.class);
private final TableModState tableModState;
private final boolean online;
private final DatabaseConfig config;
private final BootupClasses bootupClasses;
private final DatabasePlatform databasePlatform;
private final DeployInherit deployInherit;
private final TypeManager typeManager;
private final DtoBeanManager dtoBeanManager;
private final ClockService clockService;
private final DataTimeZone dataTimeZone;
private final Binder binder;
private final DeployCreateProperties deployCreateProperties;
private final DeployUtil deployUtil;
private final BeanDescriptorManager beanDescriptorManager;
private final CQueryEngine cQueryEngine;
private final ClusterManager clusterManager;
private final SpiCacheManager cacheManager;
private final ServerCachePlugin serverCachePlugin;
private ServerCacheNotify cacheNotify;
private boolean localL2Caching;
private final boolean jacksonCorePresent;
private final ExpressionFactory expressionFactory;
private final SpiBackgroundExecutor backgroundExecutor;
private final JsonFactory jsonFactory;
private final DocStoreFactory docStoreFactory;
/**
* List of plugins (that ultimately the DefaultServer configures late in construction).
*/
private final List<Plugin> plugins = new ArrayList<>();
private final MultiValueBind multiValueBind;
private final SpiLogManager logManager;
private final ExtraMetrics extraMetrics = new ExtraMetrics();
private ServerCacheNotify cacheNotify;
private boolean localL2Caching;
InternalConfiguration(boolean online, ClusterManager clusterManager, SpiBackgroundExecutor backgroundExecutor,
DatabaseConfig config, BootupClasses bootupClasses) {
this.online = online;
this.config = config;
this.jacksonCorePresent = config.getClassLoadConfig().isJacksonCorePresent();
this.clockService = new ClockService(config.getClock());
this.tableModState = new TableModState();
this.logManager = initLogManager();
@@ -210,6 +182,10 @@ public class InternalConfiguration {
this.cQueryEngine = new CQueryEngine(config, databasePlatform, binder, asOfTableMapping, draftTableMap);
}
public boolean isJacksonCorePresent() {
return jacksonCorePresent;
}
private InternalConfigXmlMap initExternalMapping() {
final List<XmapEbean> xmEbeans = readExternalMapping();
return new InternalConfigXmlMap(xmEbeans, config.getClassLoadConfig().getClassLoader());
@@ -307,7 +283,7 @@ public class InternalConfiguration {
* Return the ChangeLogListener to use with a default implementation if none defined.
*/
public ChangeLogListener changeLogListener(ChangeLogListener listener) {
return plugin((listener != null) ? listener : new DefaultChangeLogListener());
return plugin((listener != null) ? listener : jacksonCorePresent ? new DefaultChangeLogListener() : null);
}
/**
@@ -315,7 +291,7 @@ public class InternalConfiguration {
*/
ReadAuditLogger getReadAuditLogger() {
ReadAuditLogger found = bootupClasses.getReadAuditLogger();
return plugin(found != null ? found : new DefaultReadAuditLogger());
return plugin(found != null ? found : jacksonCorePresent? new DefaultReadAuditLogger(): null);
}
/**
@@ -356,7 +332,7 @@ public class InternalConfiguration {
}
SpiJsonContext createJsonContext(SpiEbeanServer server) {
return new DJsonContext(server, jsonFactory, typeManager);
return jacksonCorePresent ? new DJsonContext(server, jsonFactory, typeManager) : null;
}
AutoTuneService createAutoTuneService(SpiEbeanServer server) {
@@ -104,7 +104,6 @@ public abstract class PersistRequest extends BeanRequest implements BatchPostExe
return transaction.isLogSummary();
}
/**
* Return true if this persist request should use JDBC batch.
*/
@@ -119,23 +118,22 @@ public abstract class PersistRequest extends BeanRequest implements BatchPostExe
return transaction.translate(e.getMessage(), e);
}
/**
* Execute the statement.
*/
int executeStatement() {
return executeStatement(false);
}
int executeStatement(boolean addBatch) {
boolean batch = isBatchThisRequest();
try {
int rows;
BatchControl control = transaction.getBatchControl();
if (control != null) {
rows = control.executeStatementOrBatch(this, batch);
rows = control.executeStatementOrBatch(this, batch, addBatch);
} else if (batch) {
// need to create the BatchControl
control = persistExecute.createBatchControl(transaction);
rows = control.executeStatementOrBatch(this, true);
rows = control.executeStatementOrBatch(this, true, addBatch);
} else {
rows = executeNow();
}
@@ -388,7 +388,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
@Override
public void preGetterTrigger(int propertyIndex) {
if (flushBatchOnGetter(propertyIndex)) {
transaction.flushBatch();
transaction.flush();
}
}
@@ -59,7 +59,7 @@ public final class PersistRequestUpdateSql extends PersistRequest {
*/
public int addBatch() {
this.addBatch = true;
return executeOrQueue();
return executeStatement(true);
}
/**
@@ -73,13 +73,13 @@ public final class PersistRequestUpdateSql extends PersistRequest {
/**
* Add this request to BatchControl to flush later.
*/
public void addToFlushQueue(boolean early) {
public void addToFlushQueue(int pos) {
BatchControl control = transaction.getBatchControl();
if (control == null) {
control = persistExecute.createBatchControl(transaction);
}
flushQueue = true;
control.addToFlushQueue(this, early);
control.addToFlushQueue(this, pos);
}
@Override
@@ -104,18 +104,14 @@ public interface Persister {
void executeOrQueue(SpiSqlUpdate update, SpiTransaction t, boolean queue);
/**
* Queue the SqlUpdate for early execution (with JDBC batch).
* Queue the SqlUpdate for execution with position 0, 1 or 2 defining
* when it executes relative to the flush of beans .
*/
void addToFlushQueue(SpiSqlUpdate update, SpiTransaction t);
void addToFlushQueue(SpiSqlUpdate update, SpiTransaction t, int pos);
/**
* Queue the SqlUpdate for late execution (with JDBC batch).
* Add the statement to JDBC batch for later execution via executeBatch.
*/
void addToFlushQueueLast(SpiSqlUpdate update, SpiTransaction t);
/**
* Add the statement to JDBC batch for later execution via executeBatch.
*/
void addBatch(SpiSqlUpdate sqlUpdate, SpiTransaction transaction);
/**
@@ -56,35 +56,43 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
}
boolean findEachRow(RowConsumer mapper) {
flushJdbcBatchOnQuery();
queryEngine.findEachRow(this, mapper);
return true;
}
<T> List<T> findListMapper(RowMapper<T> mapper) {
flushJdbcBatchOnQuery();
return queryEngine.findListMapper(this, mapper);
}
<T> T findOneMapper(RowMapper<T> mapper) {
flushJdbcBatchOnQuery();
return queryEngine.findOneMapper(this, mapper);
}
public <T> List<T> findSingleAttributeList(Class<T> cls) {
flushJdbcBatchOnQuery();
return queryEngine.findSingleAttributeList(this, cls);
}
public <T> T findSingleAttribute(Class<T> cls) {
flushJdbcBatchOnQuery();
return queryEngine.findSingleAttribute(this, cls);
}
public void findEach(Consumer<SqlRow> consumer) {
flushJdbcBatchOnQuery();
queryEngine.findEach(this, consumer);
}
public void findEachWhile(Predicate<SqlRow> consumer) {
flushJdbcBatchOnQuery();
queryEngine.findEach(this, consumer);
}
public List<SqlRow> findList() {
flushJdbcBatchOnQuery();
return queryEngine.findList(this);
}
@@ -92,9 +100,7 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
* Build the list of property names.
*/
private String[] getPropertyNames() throws SQLException {
ResultSetMetaData metaData = resultSet.getMetaData();
int columnsPlusOne = metaData.getColumnCount() + 1;
ArrayList<String> propNames = new ArrayList<>(columnsPlusOne - 1);
for (int i = 1; i < columnsPlusOne; i++) {
@@ -107,9 +113,7 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
* Read and return the next SqlRow.
*/
public SqlRow createNewRow() throws SQLException {
rows++;
SqlRow sqlRow = queryEngine.createSqlRow(estimateCapacity);
int index = 0;
for (String propertyName : propertyNames) {
@@ -121,9 +125,9 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
}
public void logSummary() {
if (trans.isLogSummary()) {
if (transaction.isLogSummary()) {
long micros = (System.nanoTime() - startNano) / 1000L;
trans.logSummary("SqlQuery rows[" + rows + "] micros[" + micros + "] bind[" + bindLog + "]");
transaction.logSummary("SqlQuery rows[" + rows + "] micros[" + micros + "] bind[" + bindLog + "]");
}
}
@@ -136,7 +140,6 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
}
public <T> List<T> mapList(RowMapper<T> mapper) throws SQLException {
List<T> list = new ArrayList<>();
while (next()) {
list.add(mapper.map(resultSet, rows++));
@@ -5,6 +5,7 @@ import io.ebean.annotation.DocStore;
import io.ebean.config.DatabaseConfig;
import io.ebean.config.IdGenerator;
import io.ebean.config.ScalarTypeConverter;
import io.ebean.core.type.ScalarType;
import io.ebean.event.BeanFindController;
import io.ebean.event.BeanPersistController;
import io.ebean.event.BeanPersistListener;
@@ -18,7 +19,6 @@ import io.ebean.event.changelog.ChangeLogRegister;
import io.ebean.event.readaudit.ReadAuditLogger;
import io.ebean.event.readaudit.ReadAuditPrepare;
import io.ebean.util.AnnotationUtil;
import io.ebeaninternal.server.type.ScalarType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -223,12 +223,9 @@ public class BootupClasses implements ClassFilter {
*/
private <T> T create(Class<T> cls, boolean logOnException) {
try {
// instantiate via found class
Constructor<T> constructor = cls.getConstructor();
return constructor.newInstance();
return cls.getConstructor().newInstance();
} catch (NoSuchMethodException e) {
logger.debug("Ignore/expected - no default constructor", e);
logger.debug("Ignore/expected - no default constructor: " +e.getMessage());
return null;
} catch (Exception e) {
@@ -2,8 +2,8 @@ package io.ebeaninternal.server.deploy;
import io.ebean.bean.EntityBean;
import io.ebean.bean.PersistenceContext;
import io.ebean.core.type.DataReader;
import io.ebeaninternal.server.query.SqlJoinType;
import io.ebeaninternal.server.type.DataReader;
import java.sql.SQLException;
@@ -1,7 +1,7 @@
package io.ebeaninternal.server.deploy;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.server.type.DataReader;
import io.ebean.core.type.DataReader;
import java.sql.SQLException;
@@ -16,6 +16,8 @@ import io.ebean.config.DatabaseConfig;
import io.ebean.config.EncryptKey;
import io.ebean.config.dbplatform.IdType;
import io.ebean.config.dbplatform.PlatformIdGenerator;
import io.ebean.core.type.DocPropertyType;
import io.ebean.core.type.ScalarType;
import io.ebean.event.BeanFindController;
import io.ebean.event.BeanPersistController;
import io.ebean.event.BeanPersistListener;
@@ -82,7 +84,6 @@ import io.ebeaninternal.server.querydefn.OrmQueryDetail;
import io.ebeaninternal.server.querydefn.OrmQueryProperties;
import io.ebeaninternal.server.rawsql.SpiRawSql;
import io.ebeaninternal.server.type.DataBind;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeaninternal.util.SortByClause;
import io.ebeaninternal.util.SortByClauseParser;
import io.ebeanservice.docstore.api.DocStoreBeanAdapter;
@@ -90,7 +91,6 @@ import io.ebeanservice.docstore.api.DocStoreUpdateContext;
import io.ebeanservice.docstore.api.DocStoreUpdates;
import io.ebeanservice.docstore.api.mapping.DocMappingBuilder;
import io.ebeanservice.docstore.api.mapping.DocPropertyMapping;
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
import io.ebeanservice.docstore.api.mapping.DocumentMapping;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -432,7 +432,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
boolean noRelationships = propertiesOne.length + propertiesMany.length == 0;
this.cacheSharableBeans = noRelationships && deploy.getCacheOptions().isReadOnly();
this.cacheHelp = new BeanDescriptorCacheHelp<>(this, owner.getCacheManager(), deploy.getCacheOptions(), cacheSharableBeans, propertiesOneImported);
this.jsonHelp = new BeanDescriptorJsonHelp<>(this);
this.jsonHelp = initJsonHelp();
this.draftHelp = new BeanDescriptorDraftHelp<>(this);
this.docStoreAdapter = owner.createDocStoreBeanAdapter(this, deploy);
this.docStoreQueueId = docStoreAdapter.getQueueId();
@@ -469,6 +469,14 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
}
}
public boolean isJacksonCorePresent() {
return owner.isJacksonCorePresent();
}
private BeanDescriptorJsonHelp<T> initJsonHelp() {
return isJacksonCorePresent() ? new BeanDescriptorJsonHelp<>(this) : null;
}
/**
* Return true if the bean should be treated as a reference bean when it only has its id populated.
* To be true it has other scalar properties that are not generated on insert.
@@ -514,7 +522,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
return null;
}
try {
return (EntityBean) beanType.newInstance();
return (EntityBean) beanType.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new IllegalStateException("Error trying to create the prototypeEntityBean for " + beanType, e);
}
@@ -806,7 +814,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
int propertyLength = toEbi.getPropertyLength();
String[] names = getProperties();
for (int i = 0; i < propertyLength; i++) {
if (fromEbi.isLoadedProperty(i)) {
BeanProperty property = getBeanProperty(names[i]);
if (!toEbi.isLoadedProperty(i)) {
@@ -1857,17 +1864,12 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
}
/**
* We actually need to do a query because we don't know the type without the discriminator
* value, just select the id property and discriminator column (auto added)
* We actually need to do a query because we don't know the type without the discriminator value.
*/
private T findReferenceBean(Object id, PersistenceContext pc) {
DefaultOrmQuery<T> query = new DefaultOrmQuery<>(this, ebeanServer, ebeanServer.getExpressionFactory());
query.setPersistenceContext(pc);
return query
// .select(getIdProperty().getName())
// we do not select the id because we
// probably have to load the entire bean
.setId(id).findOne();
return query.setId(id).findOne();
}
/**
@@ -2079,6 +2081,13 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
return name;
}
/**
* Return the simple name of the entity bean.
*/
public String getSimpleName() {
return beanType.getSimpleName();
}
/**
* Summary description.
*/
@@ -2263,8 +2272,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
*/
public void lazyLoadRegister(String prefix, EntityBeanIntercept ebi, EntityBean bean, LoadContext loadContext) {
// load the List/Set/Map proxy objects (deferred fetching of lists)
BeanPropertyAssocMany<?>[] manys = propertiesMany();
for (BeanPropertyAssocMany<?> many : manys) {
for (BeanPropertyAssocMany<?> many : propertiesMany()) {
if (!ebi.isLoadedProperty(many.getPropertyIndex())) {
BeanCollection<?> ref = many.createReferenceIfNull(bean);
if (ref != null && !ref.isRegisteredWithLoadContext()) {
@@ -1,8 +1,8 @@
package io.ebeaninternal.server.deploy;
import io.ebean.bean.EntityBean;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
import io.ebeaninternal.server.type.ScalarType;
import java.util.Arrays;
@@ -14,13 +14,32 @@ import java.util.Arrays;
*/
abstract class BeanDescriptorElement<T> extends BeanDescriptor<T> {
private final String simpleName;
final ElementHelp elementHelp;
BeanDescriptorElement(BeanDescriptorMap owner, DeployBeanDescriptor<T> deploy, ElementHelp elementHelp) {
super(owner, deploy);
this.simpleName = shortName(deploy.getName());
this.elementHelp = elementHelp;
}
private String shortName(String name) {
int pos = name.lastIndexOf('.');
if (pos > 1) {
pos = name.lastIndexOf('.', pos - 1);
if (pos > 1) {
return name.substring(pos + 1);
}
}
return name;
}
@Override
public String getSimpleName() {
return simpleName;
}
@Override
public boolean isJsonReadCollection() {
return true;
@@ -1,12 +1,11 @@
package io.ebeaninternal.server.deploy;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import io.ebean.bean.EntityBean;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.api.json.SpiJsonReader;
import io.ebeaninternal.api.json.SpiJsonWriter;
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
import io.ebeaninternal.server.type.ScalarType;
import java.io.IOException;
import java.util.Map;
@@ -5,10 +5,10 @@ import com.fasterxml.jackson.core.JsonToken;
import io.ebean.PersistenceIOException;
import io.ebean.SqlUpdate;
import io.ebean.bean.EntityBean;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.api.json.SpiJsonReader;
import io.ebeaninternal.api.json.SpiJsonWriter;
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
import io.ebeaninternal.server.type.ScalarType;
import java.io.IOException;
@@ -2,10 +2,10 @@ package io.ebeaninternal.server.deploy;
import com.fasterxml.jackson.core.JsonParser;
import io.ebean.bean.EntityBean;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.api.json.SpiJsonReader;
import io.ebeaninternal.api.json.SpiJsonWriter;
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
import io.ebeaninternal.server.type.ScalarType;
import java.io.IOException;
import java.util.Arrays;
@@ -16,6 +16,7 @@ import io.ebean.config.dbplatform.DbHistorySupport;
import io.ebean.config.dbplatform.DbIdentity;
import io.ebean.config.dbplatform.IdType;
import io.ebean.config.dbplatform.PlatformIdGenerator;
import io.ebean.core.type.ScalarType;
import io.ebean.event.changelog.ChangeLogFilter;
import io.ebean.event.changelog.ChangeLogListener;
import io.ebean.event.changelog.ChangeLogPrepare;
@@ -56,7 +57,6 @@ import io.ebeaninternal.server.persist.platform.MultiValueBind;
import io.ebeaninternal.server.properties.BeanPropertiesReader;
import io.ebeaninternal.server.properties.BeanPropertyAccess;
import io.ebeaninternal.server.properties.EnhanceBeanPropertyAccess;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeaninternal.server.type.ScalarTypeInteger;
import io.ebeaninternal.server.type.TypeManager;
import io.ebeaninternal.xmapping.api.XmapEbean;
@@ -95,87 +95,48 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
private static final BeanDescComparator beanDescComparator = new BeanDescComparator();
private final ReadAnnotations readAnnotations;
private final TransientProperties transientProperties;
/**
* Helper to derive inheritance information.
*/
private final DeployInherit deplyInherit;
private final BeanPropertyAccess beanPropertyAccess = new EnhanceBeanPropertyAccess();
private final DeployUtil deployUtil;
private final PersistControllerManager persistControllerManager;
private final PostLoadManager postLoadManager;
private final PostConstructManager postConstructManager;
private final BeanFinderManager beanFinderManager;
private final PersistListenerManager persistListenerManager;
private final BeanQueryAdapterManager beanQueryAdapterManager;
private final NamingConvention namingConvention;
private final DeployCreateProperties createProperties;
private final BeanManagerFactory beanManagerFactory;
private final DatabaseConfig config;
private final ChangeLogListener changeLogListener;
private final ChangeLogRegister changeLogRegister;
private final ChangeLogPrepare changeLogPrepare;
private final DocStoreFactory docStoreFactory;
private final MultiValueBind multiValueBind;
private final TypeManager typeManager;
private int entityBeanCount;
private final BootupClasses bootupClasses;
private final String serverName;
private final List<BeanDescriptor<?>> elementDescriptors = new ArrayList<>();
private final Map<Class<?>, BeanTable> beanTableMap = new HashMap<>();
private final Map<String, BeanDescriptor<?>> descMap = new HashMap<>();
private final Map<String, BeanDescriptor<?>> descQueueMap = new HashMap<>();
private final Map<String, BeanManager<?>> beanManagerMap = new HashMap<>();
private final Map<String, List<BeanDescriptor<?>>> tableToDescMap = new HashMap<>();
private final Map<String, List<BeanDescriptor<?>>> tableToViewDescMap = new HashMap<>();
private List<BeanDescriptor<?>> immutableDescriptorList;
private final DbIdentity dbIdentity;
private final DataSource dataSource;
private final DatabasePlatform databasePlatform;
private final SpiCacheManager cacheManager;
private final BackgroundExecutor backgroundExecutor;
private final EncryptKeyManager encryptKeyManager;
private final IdBinderFactory idBinderFactory;
private final BeanLifecycleAdapterFactory beanLifecycleAdapterFactory;
private final String asOfViewSuffix;
private final boolean jacksonCorePresent;
private final int queryPlanTTLSeconds;
private int entityBeanCount;
private List<BeanDescriptor<?>> immutableDescriptorList;
/**
* Map of base tables to 'with history views' used to support 'as of' queries.
@@ -187,8 +148,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
*/
private final Map<String, String> draftTableMap = new HashMap<>();
private final int queryPlanTTLSeconds;
// temporary collections used during startup and then cleared
private Map<Class<?>, DeployBeanInfo<?>> deployInfoMap = new HashMap<>();
@@ -232,13 +191,19 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
this.changeLogPrepare = config.changeLogPrepare(bootupClasses.getChangeLogPrepare());
this.changeLogListener = config.changeLogListener(bootupClasses.getChangeLogListener());
this.changeLogRegister = config.changeLogRegister(bootupClasses.getChangeLogRegister());
this.jacksonCorePresent = config.isJacksonCorePresent();
}
@Override
public boolean isJacksonCorePresent() {
return jacksonCorePresent;
}
/**
* Run periodic trim of query plans.
*/
public void scheduleBackgroundTrim() {
backgroundExecutor.executePeriodically(this::trimQueryPlans, 117L, 60L, TimeUnit.SECONDS);
backgroundExecutor.scheduleWithFixedDelay(this::trimQueryPlans, 117L, 60L, TimeUnit.SECONDS);
}
private void trimQueryPlans() {
@@ -273,7 +238,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* Return the versions between timestamp suffix based on the DbHistorySupport.
*/
private String getVersionsBetweenSuffix(DatabasePlatform databasePlatform, DatabaseConfig serverConfig) {
DbHistorySupport historySupport = databasePlatform.getHistorySupport();
// with historySupport returns a simple view suffix or the sql2011 versions between timestamp suffix
return (historySupport == null) ? serverConfig.getAsOfViewSuffix() : historySupport.getVersionsBetweenSuffix(serverConfig.getAsOfViewSuffix());
@@ -397,7 +361,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
private void readEntityMapping(ClassLoader classLoader, XmapEntity entityDeploy) {
String entityClassName = entityDeploy.getClazz();
Class<?> entityClass;
try {
@@ -447,7 +410,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* For SQL based modifications we need to invalidate appropriate parts of the cache.
*/
public void cacheNotify(TransactionEventTable.TableIUD tableIUD, CacheChangeSet changeSet) {
String tableName = tableIUD.getTableName().toLowerCase();
List<BeanDescriptor<?>> normalBeanTypes = tableToDescMap.get(tableName);
if (normalBeanTypes != null) {
@@ -483,7 +445,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* Invalidate entity beans based on views via their dependent tables.
*/
public void processViewInvalidation(Set<String> viewInvalidation) {
for (String depTable : viewInvalidation) {
List<BeanDescriptor<?>> list = tableToViewDescMap.get(depTable.toLowerCase());
if (list != null) {
@@ -496,12 +457,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
/**
* Build a map of table names to BeanDescriptors.
* <p>
* This is generally used to maintain caches from table names.
* </p>
*/
private void readTableToDescriptor() {
for (BeanDescriptor<?> desc : descMap.values()) {
String baseTable = desc.getBaseTable();
if (baseTable != null) {
@@ -525,7 +482,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
private void readForeignKeys() {
for (BeanDescriptor<?> d : descMap.values()) {
d.initialiseFkeys();
}
@@ -536,18 +492,14 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* <p>
* This occurs after all the BeanDescriptors have been created. This resolves
* circular relationships between BeanDescriptors.
* </p>
* <p>
* Also responsible for creating all the BeanManagers which contain the
* persister, listener etc.
* </p>
*/
private void initialiseAll() {
// now that all the BeanDescriptors are in their map
// we can initialise them which sorts out circular
// dependencies for OneToMany and ManyToOne etc
BeanDescriptorInitContext initContext = new BeanDescriptorInitContext(asOfTableMap, draftTableMap, asOfViewSuffix);
// PASS 1:
@@ -605,7 +557,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
private void checkMissingHashCodeOrEquals(Exception source, Class<?> idType, Class<?> beanType) {
String msg = "SERIOUS ERROR: The hashCode() and equals() methods *MUST* be implemented ";
msg += "on Embedded bean " + idType + " as it is used as an Id for " + beanType;
throw new PersistenceException(msg, source);
@@ -639,7 +590,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
@SuppressWarnings("unchecked")
public <T> BeanManager<T> getBeanManager(Class<T> entityType) {
return (BeanManager<T>) getBeanManager(entityType.getName());
}
@@ -651,14 +601,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* Create the BeanControllers, BeanFinders and BeanListeners.
*/
private void createListeners() {
int qa = beanQueryAdapterManager.getRegisterCount();
int cc = persistControllerManager.getRegisterCount();
int pl = postLoadManager.getRegisterCount();
int pc = postConstructManager.getRegisterCount();
int lc = persistListenerManager.getRegisterCount();
int fc = beanFinderManager.getRegisterCount();
logger.debug("BeanPersistControllers[{}] BeanFinders[{}] BeanPersistListeners[{}] BeanQueryAdapters[{}] BeanPostLoaders[{}] BeanPostConstructors[{}]", cc, fc, lc, qa, pl, pc);
}
@@ -675,11 +623,16 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
private void registerBeanDescriptor(DeployBeanInfo<?> info) {
BeanDescriptor desc = new BeanDescriptor<>(this, info.getDescriptor());
BeanDescriptor<?> desc = new BeanDescriptor<>(this, info.getDescriptor());
descMap.put(desc.getBeanType().getName(), desc);
if (desc.isDocStoreMapped()) {
descQueueMap.put(desc.getDocStoreQueueId(), desc);
}
for (BeanPropertyAssocMany<?> many : desc.propertiesMany()) {
if (many.isElementCollection()) {
elementDescriptors.add(many.getElementDescriptor());
}
}
}
/**
@@ -687,10 +640,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* <p>
* This stops short of reading relationship meta data until after the
* BeanTables have all been created.
* </p>
*/
private void readEntityDeploymentInitial() {
for (Class<?> entityClass : bootupClasses.getEntities()) {
DeployBeanInfo<?> info = createDeployBeanInfo(entityClass);
deployInfoMap.put(entityClass, info);
@@ -723,15 +674,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* Create the BeanTable information which has the base table and id.
* <p>
* This is determined prior to resolving relationship information.
* </p>
*/
private void readEntityBeanTable() {
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
BeanTable beanTable = createBeanTable(info);
beanTableMap.put(beanTable.getBeanType(), beanTable);
}
// register non-id embedded beans (after bean tables are created)
for (DeployBeanInfo<?> info : embeddedBeans) {
registerEmbeddedBean(info);
@@ -742,17 +690,14 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* Create the BeanTable information which has the base table and id.
* <p>
* This is determined prior to resolving relationship information.
* </p>
*/
private void readEntityDeploymentAssociations() {
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
readDeployAssociations(info);
}
}
private void readInheritedIdGenerators() {
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
DeployBeanDescriptor<?> descriptor = info.getDescriptor();
InheritInfo inheritInfo = descriptor.getInheritInfo();
@@ -770,17 +715,14 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* Create the BeanTable from the deployment information gathered so far.
*/
private BeanTable createBeanTable(DeployBeanInfo<?> info) {
DeployBeanDescriptor<?> deployDescriptor = info.getDescriptor();
DeployBeanTable beanTable = deployDescriptor.createDeployBeanTable();
return new BeanTable(beanTable, this);
}
private void readEntityRelationships() {
// We only perform 'circular' checks etc after we have
// all the DeployBeanDescriptors created and in the map.
List<DeployBeanPropertyAssocOne<?>> primaryKeyJoinCheck = new ArrayList<>();
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
checkMappedBy(info, primaryKeyJoinCheck);
@@ -788,15 +730,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
for (DeployBeanPropertyAssocOne<?> prop : primaryKeyJoinCheck) {
checkUniDirectionalPrimaryKeyJoin(prop);
}
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
secondaryPropsJoins(info);
}
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
setInheritanceInfo(info);
}
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
if (!info.isEmbedded()) {
registerBeanDescriptor(info);
@@ -805,12 +744,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
/**
* Sets the inheritance info. ~EMG fix for join problem
*
* @param info the new inheritance info
* Sets the inheritance info.
*/
private void setInheritanceInfo(DeployBeanInfo<?> info) {
for (DeployBeanPropertyAssocOne<?> oneProp : info.getDescriptor().propertiesAssocOne()) {
if (!oneProp.isTransient()) {
DeployBeanInfo<?> assoc = deployInfoMap.get(oneProp.getTargetType());
@@ -819,7 +755,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
}
}
for (DeployBeanPropertyAssocMany<?> manyProp : info.getDescriptor().propertiesAssocMany()) {
if (!manyProp.isTransient()) {
DeployBeanInfo<?> assoc = deployInfoMap.get(manyProp.getTargetType());
@@ -831,7 +766,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
private void secondaryPropsJoins(DeployBeanInfo<?> info) {
DeployBeanDescriptor<?> descriptor = info.getDescriptor();
for (DeployBeanProperty prop : descriptor.propertiesBase()) {
if (prop.isSecondaryTable()) {
@@ -855,10 +789,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* This will read join information defined on the 'owning/other' side of the
* relationship. It also does some extra work for unidirectional
* relationships.
* </p>
*/
private void checkMappedBy(DeployBeanInfo<?> info, List<DeployBeanPropertyAssocOne<?>> primaryKeyJoinCheck) {
for (DeployBeanPropertyAssocOne<?> oneProp : info.getDescriptor().propertiesAssocOne()) {
if (!oneProp.isTransient()) {
if (oneProp.getMappedBy() != null) {
@@ -881,14 +813,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
private DeployBeanDescriptor<?> getTargetDescriptor(DeployBeanPropertyAssoc<?> prop) {
Class<?> targetType = prop.getTargetType();
DeployBeanInfo<?> info = deployInfoMap.get(targetType);
if (info == null) {
String msg = "Can not find descriptor [" + targetType + "] for " + prop.getFullBeanName();
throw new PersistenceException(msg);
}
return info.getDescriptor();
}
@@ -897,10 +827,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* mark it as unidirectional.
*/
private boolean findMappedBy(DeployBeanPropertyAssocMany<?> prop) {
// this is the entity bean type - that owns this property
Class<?> owningType = prop.getOwningType();
Set<String> matchSet = new HashSet<>();
// get the bean descriptor that holds the mappedBy property
@@ -954,7 +882,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
return true;
}
}
}
}
// multiple options so should specify mappedBy property
@@ -966,12 +893,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
private void makeOrderColumn(DeployBeanPropertyAssocMany<?> oneToMany) {
DeployBeanDescriptor<?> targetDesc = getTargetDescriptor(oneToMany);
DeployOrderColumn orderColumn = oneToMany.getOrderColumn();
DeployBeanProperty orderProperty = new DeployBeanProperty(targetDesc, Integer.class, ScalarTypeInteger.INSTANCE, null);
orderProperty.setName(DeployOrderColumn.LOGICAL_NAME);
orderProperty.setDbColumn(orderColumn.getName());
orderProperty.setNullable(orderColumn.isNullable());
@@ -979,7 +903,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
orderProperty.setDbUpdateable(orderColumn.isUpdatable());
orderProperty.setDbRead(true);
orderProperty.setOwningType(targetDesc.getBeanType());
final InheritInfo targetInheritInfo = targetDesc.getInheritInfo();
if (targetInheritInfo != null) {
for (InheritInfo child : targetInheritInfo.getChildren()) {
@@ -987,7 +910,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
childDescriptor.setOrderColumn(orderProperty);
}
}
targetDesc.setOrderColumn(orderProperty);
}
@@ -996,19 +918,14 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* unidirectional.
* <p>
* This means that inserts MUST cascade for this property.
* </p>
* <p>
* Create a "Shadow"/Unidirectional property on the target. It is used with
* inserts to set the foreign key value (e.g. inserts the foreign key value
* into the order_id column on the order_lines table).
* </p>
*/
private void makeUnidirectional(DeployBeanPropertyAssocMany<?> oneToMany) {
DeployBeanDescriptor<?> targetDesc = getTargetDescriptor(oneToMany);
Class<?> owningType = oneToMany.getOwningType();
if (!oneToMany.getCascadeInfo().isSave()) {
// The property MUST have persist cascading so that inserts work.
@@ -1056,11 +973,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
private void checkMappedByOneToOne(DeployBeanPropertyAssocOne<?> prop) {
// check that the mappedBy property is valid and read
// its associated join information if it is available
String mappedBy = prop.getMappedBy();
// get the mappedBy property
DeployBeanDescriptor<?> targetDesc = getTargetDescriptor(prop);
DeployBeanProperty mappedProp = targetDesc.getBeanProperty(mappedBy);
@@ -1113,10 +1028,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* <p>
* We can use the join information from the mappedBy property and reverse it
* for using in the OneToMany direction.
* </p>
*/
private void checkMappedByOneToMany(DeployBeanInfo<?> info, DeployBeanPropertyAssocMany<?> prop) {
if (prop.isElementCollection()) {
// skip mapping check
return;
@@ -1197,7 +1110,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* For mappedBy copy the joins from the other side.
*/
private void checkMappedByManyToMany(DeployBeanPropertyAssocMany<?> prop) {
// get the bean descriptor that holds the mappedBy property
String mappedBy = prop.getMappedBy();
if (mappedBy == null) {
@@ -1258,50 +1170,40 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
private <T> void setBeanControllerFinderListener(DeployBeanDescriptor<T> descriptor) {
persistControllerManager.addPersistControllers(descriptor);
postLoadManager.addPostLoad(descriptor);
postConstructManager.addPostConstructListeners(descriptor);
persistListenerManager.addPersistListeners(descriptor);
beanQueryAdapterManager.addQueryAdapter(descriptor);
beanFinderManager.addFindControllers(descriptor);
if (changeLogRegister != null) {
ChangeLogFilter changeFilter = changeLogRegister.getChangeFilter(descriptor.getBeanType());
if (changeFilter != null) {
descriptor.setChangeLogFilter(changeFilter);
}
}
}
/**
* Read the initial deployment information for a given bean type.
*/
private <T> DeployBeanInfo<T> createDeployBeanInfo(Class<T> beanClass) {
DeployBeanDescriptor<T> desc = new DeployBeanDescriptor<>(this, beanClass, config);
beanLifecycleAdapterFactory.addLifecycleMethods(desc);
// set bean controller, finder and listener
setBeanControllerFinderListener(desc);
deplyInherit.process(desc);
desc.checkInheritanceMapping();
createProperties.createProperties(desc);
DeployBeanInfo<T> info = new DeployBeanInfo<>(deployUtil, desc);
readAnnotations.readInitial(info);
return info;
}
private <T> void readDeployAssociations(DeployBeanInfo<T> info) {
DeployBeanDescriptor<T> desc = info.getDescriptor();
readAnnotations.readAssociations(info, this);
if (EntityType.SQL == desc.getEntityType()) {
desc.setBaseTable(null, null, null);
}
@@ -1309,15 +1211,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
// mark transient properties
transientProperties.process(desc);
setScalarType(desc);
if (!desc.isEmbedded()) {
// Set IdGenerator or use DB Identity
setIdGeneration(desc);
// find the appropriate default concurrency mode
setConcurrencyMode(desc);
}
// generate the byte code
createByteCode(desc);
}
@@ -1326,7 +1225,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* Set the Identity generation mechanism.
*/
private <T> void setIdGeneration(DeployBeanDescriptor<T> desc) {
if (desc.getIdGenerator() != null) {
// already assigned (So custom or UUID)
return;
@@ -1334,7 +1232,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
if (desc.idProperty() == null) {
return;
}
final DeployIdentityMode identityMode = desc.getIdentityMode();
if (identityMode.isSequence() && !dbIdentity.isSupportsSequence()) {
// explicit sequence but not supported by the DatabasePlatform
@@ -1391,11 +1288,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
private void createByteCode(DeployBeanDescriptor<?> deploy) {
// check to see if the bean supports EntityBean interface
// generate a subclass if required
setEntityBeanClass(deploy);
// use Code generation or Standard reflection to support
// getter and setter methods
setBeanReflect(deploy);
@@ -1409,10 +1304,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* <p>
* Enums are treated a bit differently in that they always have a ScalarType
* as one is built for them.
* </p>
*/
private void setScalarType(DeployBeanDescriptor<?> deployDesc) {
for (DeployBeanProperty prop : deployDesc.propertiesAll()) {
if (!(prop instanceof DeployBeanPropertyAssoc<?>)) {
deployUtil.setScalarType(prop);
@@ -1426,17 +1319,13 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* This sets the implementation of constructing entity beans and the setting
* and getting of properties. It is generally faster to use code generation
* rather than reflection to do this.
* </p>
*/
private void setBeanReflect(DeployBeanDescriptor<?> desc) {
// Set the BeanReflectGetter and BeanReflectSetter that typically
// use generated code. NB: Due to Bug 166 so now doing this for
// abstract classes as well.
BeanPropertiesReader reflectProps = new BeanPropertiesReader(desc.getBeanType());
desc.setProperties(reflectProps.getProperties());
for (DeployBeanProperty prop : desc.propertiesAll()) {
String propName = prop.getName();
Integer pos = reflectProps.getPropertyIndex(propName);
@@ -1446,7 +1335,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
"If you are running in an IDE with enhancement plugin try a Build -> Rebuild Project to recompile and enhance all entity beans. " +
"Error - property " + propName + " not found in " + reflectProps + " for type " + desc.getBeanType());
}
} else {
final int propertyIndex = pos;
prop.setPropertyIndex(propertyIndex);
@@ -1463,7 +1351,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* Return true if this is a persistent field (not transient or static).
*/
private boolean isPersistentField(DeployBeanProperty prop) {
Field field = prop.getField();
if (field == null) {
return false;
@@ -1478,12 +1365,10 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* which contain version properties.
*/
private void setConcurrencyMode(DeployBeanDescriptor<?> desc) {
if (desc.getConcurrencyMode() != null) {
// concurrency mode explicitly set during deployment
return;
}
if (checkForVersionProperties(desc)) {
desc.setConcurrencyMode(ConcurrencyMode.VERSION);
} else {
@@ -1495,23 +1380,16 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* Search for version properties also including embedded beans.
*/
private boolean checkForVersionProperties(DeployBeanDescriptor<?> desc) {
boolean hasVersionProperty = false;
List<DeployBeanProperty> props = desc.propertiesBase();
for (DeployBeanProperty prop : props) {
for (DeployBeanProperty prop : desc.propertiesBase()) {
if (prop.isVersionColumn()) {
hasVersionProperty = true;
return true;
}
}
return hasVersionProperty;
return false;
}
private boolean hasEntityBeanInterface(Class<?> beanClass) {
Class<?>[] interfaces = beanClass.getInterfaces();
for (Class<?> anInterface : interfaces) {
for (Class<?> anInterface : beanClass.getInterfaces()) {
if (anInterface.equals(EntityBean.class)) {
return true;
}
@@ -1523,18 +1401,14 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* Test the bean type to see if it implements EntityBean interface already.
*/
private void setEntityBeanClass(DeployBeanDescriptor<?> desc) {
Class<?> beanClass = desc.getBeanType();
if (!hasEntityBeanInterface(beanClass)) {
String msg = "Bean " + beanClass + " is not enhanced? Check packages specified in ebean.mf. If you are running in IDEA or " +
"Eclipse check that the enhancement plugin is installed. See https://ebean.io/docs/trouble-shooting#not-enhanced";
throw new BeanNotEnhancedException(msg);
}
// the bean already implements EntityBean
checkInheritedClasses(beanClass);
entityBeanCount++;
}
@@ -1543,7 +1417,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* enhanced or all dynamically subclassed).
*/
private void checkInheritedClasses(Class<?> beanClass) {
Class<?> superclass = beanClass.getSuperclass();
if (Object.class.equals(superclass)) {
// we got to the top of the inheritance
@@ -1602,10 +1475,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
private void addPrimaryKeyJoin(DeployBeanPropertyAssocOne<?> prop) {
String baseTable = prop.getDesc().getBaseTable();
DeployTableJoin inverse = prop.getTableJoin().createInverse(baseTable);
TableJoin inverseJoin = new TableJoin(inverse, prop.getForeignKey());
DeployBeanInfo<?> target = deployInfoMap.get(prop.getTargetType());
target.setPrimaryKeyJoin(inverseJoin);
@@ -1622,7 +1493,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* Create a BeanDescriptor for an ElementCollection target.
*/
public <A> BeanDescriptor<A> createElementDescriptor(DeployBeanDescriptor<A> elementDescriptor, ManyType manyType, boolean scalar) {
ElementHelp elementHelp = elementHelper(manyType);
if (manyType.isMap()) {
if (scalar) {
@@ -1655,6 +1525,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
for (BeanDescriptor<?> desc : immutableDescriptorList) {
desc.visitMetrics(visitor);
}
for (BeanDescriptor<?> desc : elementDescriptors) {
desc.visitMetrics(visitor);
}
}
public List<MetaQueryPlan> queryPlanInit(QueryPlanInit request) {
@@ -3,10 +3,10 @@ package io.ebeaninternal.server.deploy;
import io.ebean.config.DatabaseConfig;
import io.ebean.config.EncryptKey;
import io.ebean.config.NamingConvention;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.server.cache.SpiCacheManager;
import io.ebeaninternal.server.deploy.id.IdBinder;
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeanservice.docstore.api.DocStoreBeanAdapter;
/**
@@ -71,4 +71,9 @@ public interface BeanDescriptorMap {
* Return the scalarType for the given logical type.
*/
ScalarType<?> getScalarType(String cast);
/**
* Return true if Jackson core is present on the classpath.
*/
boolean isJacksonCorePresent();
}
@@ -8,6 +8,9 @@ import io.ebean.bean.PersistenceContext;
import io.ebean.config.EncryptKey;
import io.ebean.config.dbplatform.DbEncryptFunction;
import io.ebean.config.dbplatform.DbPlatformType;
import io.ebean.core.type.DataReader;
import io.ebean.core.type.DocPropertyType;
import io.ebean.core.type.ScalarType;
import io.ebean.plugin.Property;
import io.ebean.text.StringParser;
import io.ebean.util.SplitName;
@@ -28,9 +31,7 @@ import io.ebeaninternal.server.query.STreeProperty;
import io.ebeaninternal.server.query.SqlBeanLoad;
import io.ebeaninternal.server.query.SqlJoinType;
import io.ebeaninternal.server.type.DataBind;
import io.ebeaninternal.server.type.DataReader;
import io.ebeaninternal.server.type.LocalEncryptedType;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeaninternal.server.type.ScalarTypeBoolean;
import io.ebeaninternal.server.type.ScalarTypeEnum;
import io.ebeaninternal.server.type.ScalarTypeLogicalType;
@@ -38,7 +39,6 @@ import io.ebeaninternal.util.ValueUtil;
import io.ebeanservice.docstore.api.mapping.DocMappingBuilder;
import io.ebeanservice.docstore.api.mapping.DocPropertyMapping;
import io.ebeanservice.docstore.api.mapping.DocPropertyOptions;
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
import io.ebeanservice.docstore.api.support.DocStructure;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.deploy;
import io.ebean.Query;
import io.ebean.bean.EntityBean;
import io.ebean.core.type.DocPropertyType;
import io.ebean.text.PathProperties;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.SpiEbeanServer;
@@ -22,7 +23,6 @@ import io.ebeaninternal.server.query.SqlJoinType;
import io.ebeaninternal.server.querydefn.DefaultOrmQuery;
import io.ebeanservice.docstore.api.mapping.DocMappingBuilder;
import io.ebeanservice.docstore.api.mapping.DocPropertyMapping;
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
import io.ebeanservice.docstore.api.support.DocStructure;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -144,7 +144,7 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
}
this.inverseJoin = deploy.createInverseTableJoin();
this.modifyListenMode = deploy.getModifyListenMode();
this.jsonHelp = new BeanPropertyAssocManyJsonHelp(this);
this.jsonHelp = descriptor.isJacksonCorePresent() ? new BeanPropertyAssocManyJsonHelp(this) : null;
}
@Override
@@ -569,6 +569,13 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
return elementCollection;
}
/**
* Return the element bean descriptor (for an element collection only).
*/
public BeanDescriptor<T> getElementDescriptor() {
return elementDescriptor;
}
/**
* ManyToMany only, join from local table to intersection table.
*/
@@ -7,6 +7,9 @@ import io.ebean.ValuePair;
import io.ebean.bean.EntityBean;
import io.ebean.bean.EntityBeanIntercept;
import io.ebean.bean.PersistenceContext;
import io.ebean.core.type.DataReader;
import io.ebean.core.type.ScalarDataReader;
import io.ebean.core.type.ScalarType;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiQuery;
@@ -23,9 +26,6 @@ import io.ebeaninternal.server.el.ElPropertyValue;
import io.ebeaninternal.server.query.STreePropertyAssocOne;
import io.ebeaninternal.server.query.SqlBeanLoad;
import io.ebeaninternal.server.query.SqlJoinType;
import io.ebeaninternal.server.type.DataReader;
import io.ebeaninternal.server.type.ScalarDataReader;
import io.ebeaninternal.server.type.ScalarType;
import javax.persistence.PersistenceException;
import java.io.IOException;
@@ -4,9 +4,9 @@ import io.ebean.bean.BeanCollection;
import io.ebean.bean.EntityBean;
import io.ebean.bean.EntityBeanIntercept;
import io.ebean.bean.PersistenceContext;
import io.ebean.core.type.DataReader;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.query.STreePropertyAssocMany;
import io.ebeaninternal.server.type.DataReader;
import java.util.Map;
@@ -1,8 +1,8 @@
package io.ebeaninternal.server.deploy;
import io.ebean.core.type.DataReader;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.server.query.SqlBeanLoad;
import io.ebeaninternal.server.type.DataReader;
import io.ebeaninternal.server.type.ScalarType;
import javax.persistence.PersistenceException;
@@ -1,8 +1,8 @@
package io.ebeaninternal.server.deploy;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.server.query.STreeProperty;
import io.ebeaninternal.server.query.SqlJoinType;
import io.ebeaninternal.server.type.ScalarType;
import java.util.List;

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