Compare commits

...
Author SHA1 Message Date
rob bygrave d432854b82 [maven-release-plugin] prepare release ebean-10.3.2 2017-06-25 16:01:37 +12:00
rob bygrave 93582c8ea3 Downgrade postgres jdbc driver for commit and continue test 2017-06-25 15:54:14 +12:00
rob bygrave 520d35b1d6 #963 - NullPointerException on no version provided (when setVersion(null) is used) 2017-06-25 14:44:13 +12:00
rob bygrave 8ca3599cbf #1046 Bump DB migration to 10.1.9 - fix for Checksum mismatch does not stop migration 2017-06-25 14:29:46 +12:00
rob bygrave 283ae74219 Update javadoc on ScalarTypeConverter. Should look to officially deprecate this in favor of AttributeConverter. 2017-06-24 11:35:58 +12:00
rob bygrave cebd3f92a4 #1045 - MySql - DbMigration generate wrong comment syntax - should be alter table comment = syntax 2017-06-24 11:23:21 +12:00
rob bygrave 4b2481d3ea #1039 Fix for - reset of dirty flag on L2 cached entities after lazy load 2017-06-23 23:20:17 +12:00
rob bygrave f1f2a416d3 No effective change - reformat only 2017-06-23 23:19:22 +12:00
rob bygrave 74dd97a55f No effective change 2017-06-23 23:18:57 +12:00
rob bygrave 3f04f7f363 Merge branch 'master' of https://github.com/SamhammerAG/ebean into SamhammerAG-master 2017-06-23 19:52:55 +12:00
rob bygrave 800f854a12 #1043 Additional test for RawSql with upper case SQL 2017-06-23 19:46:47 +12:00
rob bygrave bef9e6d54f Merge branch 'master' of github.com:ebean-orm/ebean 2017-06-23 19:43:45 +12:00
Tigran_DadaiantsandRob Bygrave 0e4c0ae6c3 #1043 RawSql should automatically map upper-case column alias to lower-case bean property (#1044) 2017-06-23 19:43:15 +12:00
rob bygrave a0ea9887df No effective change - remove unused imports 2017-06-23 19:37:24 +12:00
Roland PramlandRob Bygrave 0413c22e6e no effective code change - fixed warnings about serialization, override, raw-types (#1032) 2017-06-23 19:33:03 +12:00
rob bygrave 989ae44a6d Merge branch 'pr/id-in-as-collection' of https://github.com/FOCONIS/ebean into FOCONIS-pr/id-in-as-collection 2017-06-23 19:28:25 +12:00
rob bygrave 100d314e63 #1035 Update for - FIX: deleting and adding same bean in beanCollection leads to deletion in DB
If use Modify mode we need to listen for both adds and removes to support sorting (can't rely on undoDelete() due to ordering)
2017-06-19 23:34:44 +12:00
rob bygrave dbf4e99187 #1035 tests for - FIX: deleting and adding same bean in beanCollection leads to deletion in DB 2017-06-19 23:32:58 +12:00
Roland PramlandRob Bygrave 7b8a85106c FIX: deleting and adding same bean in beanCollection leads to deletion in DB (#1035) 2017-06-19 22:50:20 +12:00
rob bygrave 58c5f01e2b #1042 - JtaTransaction is TenantMode.DB aware 2017-06-19 22:28:15 +12:00
Roland PramlandRob Bygrave bc74d35651 FIX: correct behavior of "startsWith, "contains" etc (#1031)
* FIX: correct behavior of "startsWith" if string contains "like"-wildcards

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

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

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

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

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

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

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

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

Not doing this one.

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

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

* suggested fix for "select distinct id"

* add test case for distinct with fetch

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

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

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

* fine tuned the test case

* added test cases for findSingleAttributeList without distinct

* improved fix to support also findSingleAttribute without distinct

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

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

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

* no effective code change: removed obsolete imports

* no effective code change: removed obsolete @SuppressWarnings

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

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

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

Signed-off-by: Thibault Meyer <meyer.thibault@gmail.com>
2017-01-01 19:55:56 +13:00
Thibault MeyerandRob Bygrave 33d66ea9d1 Upgrade antlr4-runtime to prior version 4.6 (#934)
Signed-off-by: Thibault Meyer <meyer.thibault@gmail.com>
2017-01-01 19:54:25 +13:00
Nagy VilmosandRob Bygrave 073ea9c550 SQL Server boolean mapping fix (#932) 2017-01-01 19:52:57 +13:00
Rob Bygrave 8467934021 [maven-release-plugin] prepare for next development iteration 2016-12-23 16:14:19 +13:00
657 changed files with 8628 additions and 3690 deletions
+22 -27
View File
@@ -4,24 +4,20 @@
<parent>
<groupId>org.avaje</groupId>
<artifactId>java8-parent</artifactId>
<version>1.1</version>
<version>1.3</version>
</parent>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>10.1.3</version>
<version>10.3.2</version>
<packaging>jar</packaging>
<name>ebean</name>
<url>http://ebean-orm.github.io/</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-10.1.3</tag>
<tag>ebean-10.3.2</tag>
</scm>
<dependencies>
@@ -41,7 +37,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-annotation</artifactId>
<version>2.1</version>
<version>2.3</version>
</dependency>
<dependency>
@@ -53,7 +49,7 @@
<dependency>
<groupId>org.avaje</groupId>
<artifactId>avaje-datasource</artifactId>
<version>1.1.4</version>
<version>2.1.1</version>
</dependency>
<dependency>
@@ -71,7 +67,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-dbmigration</artifactId>
<version>10.1.2</version>
<version>10.1.9</version>
</dependency>
<dependency>
@@ -83,7 +79,7 @@
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4-runtime</artifactId>
<version>4.5.3</version>
<version>4.6</version>
</dependency>
<!-- Jackson core used internally by Ebean -->
@@ -112,21 +108,21 @@
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.0.0.GA</version>
<version>1.1.0.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.4</version>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>1.6</version>
<version>2.9.7</version>
<scope>provided</scope>
</dependency>
@@ -134,7 +130,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4-1202-jdbc41</version>
<version>9.4.1212</version>
<scope>provided</scope>
</dependency>
@@ -157,14 +153,14 @@
<dependency>
<groupId>org.avaje</groupId>
<artifactId>avaje-agentloader</artifactId>
<version>2.1.1</version>
<version>2.1.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-agent</artifactId>
<version>10.1.2</version>
<version>10.3.1</version>
<scope>test</scope>
</dependency>
@@ -173,28 +169,28 @@
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.192</version>
<version>1.4.193</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.8.11.2</version>
<version>3.15.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.0.0</version>
<version>2.3.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.36</version>
<version>6.0.5</version>
<scope>test</scope>
</dependency>
@@ -209,14 +205,14 @@
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
<version>2.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.avaje.moduuid</groupId>
<artifactId>avaje-moduuid</artifactId>
<version>1.2</version>
<version>2.1</version>
<scope>test</scope>
</dependency>
@@ -229,17 +225,16 @@
<plugin>
<groupId>io.ebean</groupId>
<artifactId>ebean-maven-plugin</artifactId>
<version>10.1.2</version>
<version>10.3.1</version>
<executions>
<execution>
<id>test</id>
<phase>process-test-classes</phase>
<configuration>
<classSource>target/test-classes</classSource>
<transformArgs>debug=1</transformArgs>
</configuration>
<goals>
<goal>enhance</goal>
<goal>testEnhance</goal>
</goals>
</execution>
</executions>
@@ -0,0 +1,21 @@
package io.ebean;
import javax.persistence.PessimisticLockException;
/**
* Thrown when failing to acquire a pessimistic lock.
* <p>
* Typically when "select for update nowait" or "select for update" is being used and
* the lock can not be obtained (as it is held by another transaction).
* </p>
*/
public class AcquireLockException extends PessimisticLockException {
private static final long serialVersionUID = -8585962352965876691L;
/**
* Create with a message and cause.
*/
public AcquireLockException(String message, Throwable cause) {
super(message, cause);
}
}
@@ -0,0 +1,17 @@
package io.ebean;
import javax.persistence.PersistenceException;
/**
* Thrown when a foreign key constraint is enforced.
*/
public class DataIntegrityException extends PersistenceException {
private static final long serialVersionUID = -6740171949170180970L;
/**
* Create with a message and cause.
*/
public DataIntegrityException(String message, Throwable cause) {
super(message, cause);
}
}
+19
View File
@@ -1,6 +1,7 @@
package io.ebean;
import io.ebeanservice.docstore.api.DocQueryRequest;
import io.ebeanservice.docstore.api.RawDoc;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
@@ -165,6 +166,24 @@ public interface DocumentStore {
*/
<T> void findEachWhile(DocQueryRequest<T> query, Predicate<T> consumer);
/**
* Find each processing raw documents.
*
* @param indexNameType The full index name and type
* @param rawQuery The query to execute
* @param consumer Consumer to process each document
*/
void findEach(String indexNameType, String rawQuery, Consumer<RawDoc> consumer);
/**
* Find each processing raw documents stopping when the predicate returns false.
*
* @param indexNameType The full index name and type
* @param rawQuery The query to execute
* @param consumer Consumer to process each document until false is returned
*/
void findEachWhile(String indexNameType, String rawQuery, Predicate<RawDoc> consumer);
/**
* Process the queue entries sending updates to the document store or queuing them for later processing.
*/
@@ -0,0 +1,15 @@
package io.ebean;
/**
* Thrown when a duplicate is attempted on a unique constraint.
*/
public class DuplicateKeyException extends DataIntegrityException {
private static final long serialVersionUID = -4771932723285724817L;
/**
* Create with a message and cause.
*/
public DuplicateKeyException(String message, Throwable cause) {
super(message, cause);
}
}
+19 -1
View File
@@ -154,7 +154,7 @@ public final class Ebean {
} else {
// look to see if there is a default server defined
String defaultName = PrimaryServer.getDefaultServerName();
logger.debug("defaultName:" + defaultName);
logger.debug("defaultName:{}", defaultName);
if (defaultName != null && !defaultName.trim().isEmpty()) {
defaultServer = getWithCreate(defaultName.trim());
}
@@ -428,6 +428,24 @@ public final class Ebean {
return serverMgr.getDefaultServer().currentTransaction();
}
/**
* The batch will be flushing automatically but you can use this to explicitly
* flush the batch if you like.
* <p>
* Flushing occurs automatically when:
* </p>
* <ul>
* <li>the batch size is reached</li>
* <li>A query is executed on the same transaction</li>
* <li>UpdateSql or CallableSql are mixed with bean save and delete</li>
* <li>Transaction commit occurs</li>
* <li>A getter method is called on a batched bean</li>
* </ul>
*/
public static void flush() {
currentTransaction().flush();
}
/**
* Register a TransactionCallback on the currently active transaction.
* <p/>
+45 -6
View File
@@ -14,6 +14,7 @@ import javax.persistence.PersistenceException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -232,9 +233,9 @@ public interface EbeanServer {
*
* // Find order additionally fetching the customer, details and details.product name.
*
* String eql = "fetch customer fetch details fetch details.product (name) where id = :orderId ";
* String ormQuery = "fetch customer fetch details fetch details.product (name) where id = :orderId ";
*
* Query<Order> query = Ebean.createQuery(Order.class, eql);
* Query<Order> query = Ebean.createQuery(Order.class, ormQuery);
* query.setParameter("orderId", 2);
*
* Order order = query.findUnique();
@@ -251,11 +252,11 @@ public interface EbeanServer {
* }</pre>
*
* @param beanType The type of bean to fetch
* @param eql The Ebean query
* @param ormQuery The Ebean ORM query
* @param <T> The type of the entity bean
* @return The query with expressions defined as per the parsed query statement
*/
<T> Query<T> createQuery(Class<T> beanType, String eql);
<T> Query<T> createQuery(Class<T> beanType, String ormQuery);
/**
* Create a query for a type of entity bean.
@@ -613,6 +614,19 @@ public interface EbeanServer {
*/
Transaction currentTransaction();
/**
* Flush the JDBC batch on the current transaction.
* <p>
* This only is useful when JDBC batch is used. Flush occurs automatically when the
* transaction commits or batch size is reached. This manually flushes the JDBC batch
* buffer.
* </p>
* <p>
* This is the same as <code>currentTransaction().flush()</code>.
* </p>
*/
void flush();
/**
* Commit the current transaction.
*/
@@ -1053,7 +1067,7 @@ public interface EbeanServer {
* This will throw a NonUniqueResultException if the query finds more than one result.
* </p>
* <p>
* Generally you are able to use {@link Query#findUnique()} rather than
* Generally you are able to use {@link Query#findOne()} rather than
* explicitly calling this method. You could use this method if you wish to
* explicitly control the transaction used for the query.
* </p>
@@ -1063,7 +1077,22 @@ public interface EbeanServer {
* @param transaction the transaction to use (can be null).
* @return the list of fetched beans.
* @throws NonUniqueResultException if more than one result was found
* @see Query#findUnique()
* @see Query#findOne()
*/
@Nullable
<T> T findOne(Query<T> query, Transaction transaction);
/**
* Similar to findOne() but returns an Optional (rather than nullable).
*/
<T> Optional<T> findOneOrEmpty(Query<T> query, Transaction transaction);
/**
* Synonym for findOne().
* <p>
* This proceeded findOne which was introduced to better match spring data.
* This will be deprecated at some future point.
* </p>
*/
@Nullable
<T> T findUnique(Query<T> query, Transaction transaction);
@@ -1148,6 +1177,16 @@ public interface EbeanServer {
* @see SqlQuery#findUnique()
*/
@Nullable
SqlRow findOne(SqlQuery query, Transaction transaction);
/**
* Synonym for findOne().
* <p>
* This proceeded findOne which was introduced to better match spring data.
* This will be deprecated at some future point.
* </p>
*/
@Nullable
SqlRow findUnique(SqlQuery query, Transaction transaction);
/**
@@ -7,7 +7,6 @@ import io.ebean.search.TextQueryString;
import io.ebean.search.TextSimple;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
@@ -308,9 +307,9 @@ public interface ExpressionFactory {
Expression idIn(Object... idValues);
/**
* Id IN a list of Id values.
* Id IN a collection of Id values.
*/
Expression idIn(List<?> idList);
Expression idIn(Collection<?> idCollection);
/**
* All Equal - Map containing property names and their values.
+39 -2
View File
@@ -12,6 +12,7 @@ import java.sql.Timestamp;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -118,6 +119,27 @@ public interface ExpressionList<T> {
*/
Query<T> asDraft();
/**
* Execute using "for update" clause which results in the DB locking the record.
*/
Query<T> forUpdate();
/**
* Execute using "for update" clause with No Wait option.
* <p>
* This is typically a Postgres and Oracle only option at this stage.
* </p>
*/
Query<T> forUpdateNoWait();
/**
* Execute using "for update" clause with Skip Locked option.
* <p>
* This is typically a Postgres and Oracle only option at this stage.
* </p>
*/
Query<T> forUpdateSkipLocked();
/**
* Execute the query including soft deleted rows.
*/
@@ -245,6 +267,21 @@ public interface ExpressionList<T> {
* @see Query#findUnique()
*/
@Nullable
T findOne();
/**
* Execute the query returning an optional bean.
*/
Optional<T> findOneOrEmpty();
/**
* Synonym for findOne().
* <p>
* This proceeded findOne which was introduced to better match spring data.
* This will be deprecated at some future point.
* </p>
*/
@Nullable
T findUnique();
/**
@@ -799,9 +836,9 @@ public interface ExpressionList<T> {
ExpressionList<T> idIn(Object... idValues);
/**
* Id IN a list of id values.
* Id IN a collection of id values.
*/
ExpressionList<T> idIn(List<?> idValues);
ExpressionList<T> idIn(Collection<?> idValues);
/**
* Id Equal to - ID property is equal to the value.
+9 -2
View File
@@ -18,7 +18,7 @@ import java.util.List;
* </p>
* <pre>{@code
*
* public class CustomerFinder extends Finder<Customer> {
* public class CustomerFinder extends Finder<Long,Customer> {
*
* public CustomerFinder() {
* super(Customer.class);
@@ -31,7 +31,7 @@ import java.util.List;
* }
*
* public List<Customer> findNew() {
* return query()
* return query().where()
* .eq("status", Customer.Status.NEW)
* .orderBy("name")
* .findList()
@@ -163,4 +163,11 @@ public class Finder<I, T> {
public Query<T> nativeSql(String nativeSql) {
return db().findNative(type, nativeSql);
}
/**
* Creates a query using the ORM query language.
*/
public Query<T> query(String ormQuery) {
return db().createQuery(type, ormQuery);
}
}
+4 -4
View File
@@ -6,22 +6,22 @@ package io.ebean;
public enum LikeType {
/**
* You need to put in your own wildcards.
* You need to put in your own wildcards - no escaping is performed.
*/
RAW,
/**
* The % wildcard is added to the end of the search word.
* The % wildcard is added to the end of the search word and search word is escaped.
*/
STARTS_WITH,
/**
* The % wildcard is added to the beginning of the search word.
* The % wildcard is added to the beginning of the search word and search word is escaped.
*/
ENDS_WITH,
/**
* The % wildcard is added to the beginning and end of the search word.
* The % wildcard is added to the beginning and end of the search word and search word is escaped.
*/
CONTAINS,
+11
View File
@@ -190,6 +190,17 @@ public abstract class Model {
db().save(this);
}
/**
* Flush any batched changes to the database.
* <p>
* When using JDBC batch flushing occurs automatically at commit() time or when the batch size
* is reached. This provides the ability to manually flush the batch.
* </p>
*/
public void flush() {
db().flush();
}
/**
* Update this entity.
*
+3
View File
@@ -162,6 +162,7 @@ public final class OrderBy<T> implements Serializable {
list.add(p);
}
@Override
public String toString() {
return list.toString();
}
@@ -201,6 +202,7 @@ public final class OrderBy<T> implements Serializable {
* Return a hash value for this OrderBy. This can be to determine logical
* equality for OrderBy clauses.
*/
@Override
public int hashCode() {
return list.hashCode();
}
@@ -276,6 +278,7 @@ public final class OrderBy<T> implements Serializable {
return highLow != null ? highLow.equals(e.highLow) : e.highLow == null;
}
@Override
public String toString() {
return toStringFormat();
}
+62
View File
@@ -6,6 +6,7 @@ import javax.persistence.NonUniqueResultException;
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -194,6 +195,26 @@ import java.util.function.Predicate;
*/
public interface Query<T> {
/**
* For update mode.
*/
enum ForUpdate {
/**
* Standard For update clause.
*/
BASE,
/**
* For update with No Wait option.
*/
NOWAIT,
/**
* For update with Skip Locked option.
*/
SKIPLOCKED
}
/**
* Return the RawSql that was set to use for this query.
*/
@@ -834,6 +855,21 @@ public interface Query<T> {
* @throws NonUniqueResultException if more than one result was found
*/
@Nullable
T findOne();
/**
* Execute the query returning an optional bean.
*/
Optional<T> findOneOrEmpty();
/**
* Synonym for findOne().
* <p>
* This proceeded findOne which was introduced to better match spring data.
* This will be deprecated at some future point.
* </p>
*/
@Nullable
T findUnique();
/**
@@ -1355,11 +1391,37 @@ public interface Query<T> {
*/
Query<T> setForUpdate(boolean forUpdate);
/**
* Execute using "for update" clause which results in the DB locking the record.
*/
Query<T> forUpdate();
/**
* Execute using "for update" clause with "no wait" option.
* <p>
* This is typically a Postgres and Oracle only option at this stage.
* </p>
*/
Query<T> forUpdateNoWait();
/**
* Execute using "for update" clause with "skip locked" option.
* <p>
* This is typically a Postgres and Oracle only option at this stage.
* </p>
*/
Query<T> forUpdateSkipLocked();
/**
* Return true if this query has forUpdate set.
*/
boolean isForUpdate();
/**
* Return the "for update" mode to use.
*/
ForUpdate getForUpdateMode();
/**
* Set root table alias.
*/
@@ -61,20 +61,24 @@ public interface QueryIterator<T> extends Iterator<T>, java.io.Closeable {
/**
* Returns <tt>true</tt> if the iteration has more elements.
*/
@Override
boolean hasNext();
/**
* Returns the next element in the iteration.
*/
@Override
T next();
/**
* Remove is not allowed.
*/
@Override
void remove();
/**
* Close the underlying resources held by this iterator.
*/
@Override
void close();
}
+2
View File
@@ -292,6 +292,7 @@ public final class RawSql implements Serializable {
this.distinct = distinct;
}
@Override
public String toString() {
if (!parsed) {
return "unparsed[" + unparsedSql + "]";
@@ -642,6 +643,7 @@ public final class RawSql implements Serializable {
return result;
}
@Override
public String toString() {
return dbColumn + "->" + propertyName;
}
+11
View File
@@ -2,6 +2,7 @@ package io.ebean;
import java.io.Serializable;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -70,6 +71,16 @@ public interface SqlQuery extends Serializable {
* PersistenceException.
* </p>
*/
SqlRow findOne();
/**
* Execute the query returning an optional row.
*/
Optional<SqlRow> findOneOrEmpty();
/**
* Synonym for findOne().
*/
SqlRow findUnique();
/**
+13
View File
@@ -39,16 +39,19 @@ public interface SqlRow extends Serializable, Map<String, Object> {
/**
* Remove a property from the map. Returns the value of the removed property.
*/
@Override
Object remove(Object name);
/**
* Return a property value by its name.
*/
@Override
Object get(Object name);
/**
* Set a value to a property.
*/
@Override
Object put(String name, Object value);
/**
@@ -118,51 +121,61 @@ public interface SqlRow extends Serializable, Map<String, Object> {
/**
* String description of the underlying map.
*/
@Override
String toString();
/**
* Clear the map.
*/
@Override
void clear();
/**
* Returns true if the map contains the property.
*/
@Override
boolean containsKey(Object key);
/**
* Returns true if the map contains the value.
*/
@Override
boolean containsValue(Object value);
/**
* Returns the entrySet of the map.
*/
@Override
Set<Map.Entry<String, Object>> entrySet();
/**
* Returns true if the map is empty.
*/
@Override
boolean isEmpty();
/**
* Returns the key set of the map.
*/
@Override
Set<String> keySet();
/**
* Put all the values from t into this map.
*/
@Override
void putAll(Map<? extends String, ?> t);
/**
* Return the size of the map.
*/
@Override
int size();
/**
* Return the values from this map.
*/
@Override
Collection<Object> values();
}
+20 -6
View File
@@ -5,14 +5,12 @@ import io.ebean.config.DocStoreConfig;
import io.ebean.config.ServerConfig;
import javax.persistence.PersistenceException;
import javax.persistence.RollbackException;
import java.io.Closeable;
import java.sql.Connection;
/**
* The Transaction object. Typically representing a JDBC or JTA transaction.
*/
public interface Transaction extends Closeable {
public interface Transaction extends AutoCloseable {
/**
* Read Committed transaction isolation. Same as
@@ -67,7 +65,7 @@ public interface Transaction extends Closeable {
* <li>Perform post-commit processing updating L2 cache, ElasticSearch etc</li>
* </ul>
*/
void commitAndContinue() throws RollbackException;
void commitAndContinue();
/**
* Commit the transaction.
@@ -85,7 +83,7 @@ public interface Transaction extends Closeable {
* <li>Mark the transaction as "Inactive"</li>
* </ul>
*/
void commit() throws RollbackException;
void commit();
/**
* Rollback the transaction.
@@ -125,7 +123,14 @@ public interface Transaction extends Closeable {
/**
* If the transaction is active then perform rollback. Otherwise do nothing.
*/
void end() throws PersistenceException;
void end();
/**
* Synonym for end() to support AutoClosable.
*/
@Override
void close();
/**
* Return true if the transaction is active.
@@ -423,8 +428,17 @@ public interface Transaction extends Closeable {
* <li>A query is executed on the same transaction</li>
* <li>UpdateSql or CallableSql are mixed with bean save and delete</li>
* <li>Transaction commit occurs</li>
* <li>A getter method is called on a batched bean</li>
* </ul>
*/
void flush() throws PersistenceException;
/**
* This is a synonym for flush() and will be deprecated.
* <p>
* flush() is preferred as it matches the JPA flush() method.
* </p>
*/
void flushBatch() throws PersistenceException;
/**
+1
View File
@@ -101,6 +101,7 @@ public final class TxScope {
/**
* Describes this TxScope instance.
*/
@Override
public String toString() {
return "TxScope[" + type + "] readOnly[" + readOnly + "] isolation[" + isolation
+ "] serverName[" + serverName + "] rollbackFor[" + rollbackFor + "] noRollbackFor[" + noRollbackFor + "]";
+1
View File
@@ -51,6 +51,7 @@ public class ValuePair {
this.oldValue = oldValue;
}
@Override
public String toString() {
return newValue + "," + oldValue;
}
@@ -1,138 +0,0 @@
package io.ebean.annotation;
import io.ebean.TxIsolation;
import io.ebean.TxType;
import io.ebean.PersistBatch;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specify transaction scoping for a method.
* <p>
* <b><i> This is only supported if "Enhancement" is used via javaagent, ANT
* task or IDE enhancement plugin etc. </i></b>
* </p>
* <p>
* Note: Currently there are 3 known annotations that perform this role.
* <ul>
* <li>EJB's javax.ejb.TransactionAttribute</li>
* <li>Spring's org.springframework.transaction.annotation.Transactional</li>
* <li>and this one, Ebean's own Transactional</li>
* </ul>
* Spring created their one because the EJB annotation does not support features
* such as isolation level and specifying rollbackOn, noRollbackOn exceptions.
* This one exists for Ebean because I agree that the standard one is
* insufficient and don't want to include a dependency on Spring.
* </p>
* <p>
* The default behaviour of EJB (and hence Spring) is to NOT ROLLBACK on checked
* exceptions. I find this very counter-intuitive. Ebean will provide a property
* to set the default behaviour to rollback on any exception and optionally
* change the setting to be consistent with EJB/Spring if people wish to do so.
* </p>
* <p>
* <pre>{@code
*
* // a normal class
* public class MySimpleUserService {
*
* // this method is transactional automatically handling
* // transaction begin, commit and rollback etc
* @Transactional
* public void runInTrans() throws IOException {
*
* // tasks performed within the transaction
* ...
* // find some objects
* Customer cust = ebeanServer.find(Customer.class, 42);
*
* Order order = ...;
* ...
* // save some objects
* ebeanServer.save(customer);
* ebeanServer.save(order);
* }
*
* }</pre>
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Transactional {
/**
* The type of transaction scoping. Defaults to REQUIRED.
*/
TxType type() default TxType.REQUIRED;
/**
* Persist batch mode for the transaction.
*/
PersistBatch batch() default PersistBatch.INHERIT;
/**
* Persist batch mode for the request if not set on the transaction.
* <p>
* If batch is set to NONE then batchOnCascade can be set to INSERT or ALL
* and then each save(), delete(), insert(), update() request that cascades
* to child beans can use JDBC batch.
* </p>
*/
PersistBatch batchOnCascade() default PersistBatch.INHERIT;
/**
* The batch size to use when using JDBC batch mode.
* <p>
* If unset this defaults to the value set in ServerConfig.
* </p>
*/
int batchSize() default 0;
/**
* Set to false when we want to skip getting generatedKeys.
* <p>
* This is typically used in the case of large batch inserts where we get a
* performance benefit from not calling getGeneratedKeys (as we are going to
* insert a lot of rows and have no need for the Id values after the insert).
* </p>
*/
boolean getGeneratedKeys() default true;
/**
* The transaction isolation level this transaction should have.
* <p>
* This will only be used if this scope creates the transaction. If the
* transaction has already started then this will currently be ignored (you
* could argue that it should throw an exception).
* </p>
*/
TxIsolation isolation() default TxIsolation.DEFAULT;
/**
* Set this to true if the transaction should be only contain queries.
*/
boolean readOnly() default false;
/**
* The name of the server that you want the transaction to be created from.
* <p>
* If left blank the 'default' server is used.
* </p>
*/
String serverName() default "";
// int timeout() default 0;
/**
* The Throwable's that will explicitly cause a rollback to occur.
*/
Class<? extends Throwable>[] rollbackFor() default {};
/**
* The Throwable's that will explicitly NOT cause a rollback to occur.
*/
Class<? extends Throwable>[] noRollbackFor() default {};
}
@@ -32,6 +32,7 @@ public final class CallStack implements Serializable {
this.pathHash = enc(pathHash);
}
@Override
public int hashCode() {
int hc = 0;
for (StackTraceElement aCallStack : callStack) {
@@ -40,6 +41,7 @@ public final class CallStack implements Serializable {
return hc;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
@@ -79,6 +81,7 @@ public final class CallStack implements Serializable {
return pathHash;
}
@Override
public String toString() {
return zeroHash + ":" + pathHash + ":" + callStack[0];
}
@@ -3,6 +3,7 @@ package io.ebean.bean;
import io.ebean.Ebean;
import io.ebean.ValuePair;
import java.util.Arrays;
import javax.persistence.EntityNotFoundException;
import javax.persistence.PersistenceException;
import java.beans.PropertyChangeEvent;
@@ -859,7 +860,7 @@ public final class EntityBeanIntercept implements Serializable {
loadedProps[propertyIndex] = true;
}
private final void preGetterCallback() {
private void preGetterCallback() {
if (preGetterCallback != null) {
preGetterCallback.preGetterTrigger();
}
@@ -1101,7 +1102,7 @@ public final class EntityBeanIntercept implements Serializable {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (!areEqualChars(oldValue, newValue)) {
} else if (!Arrays.equals(oldValue, newValue)) {
setChangedPropertyValue(propertyIndex, intercept, oldValue);
} else {
return null;
@@ -1116,53 +1117,11 @@ public final class EntityBeanIntercept implements Serializable {
if (state == STATE_NEW) {
setLoadedProperty(propertyIndex);
} else if (!areEqualBytes(oldValue, newValue)) {
} else if (!Arrays.equals(oldValue, newValue)) {
setChangedPropertyValue(propertyIndex, intercept, oldValue);
} else {
return null;
}
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
}
private static boolean areEqualBytes(byte[] b1, byte[] b2) {
if (b1 == null) {
return (b2 == null);
} else if (b2 == null) {
return false;
} else if (b1 == b2) {
return true;
} else if (b1.length != b2.length) {
return false;
}
for (int i = 0; i < b1.length; i++) {
if (b1[i] != b2[i]) {
return false;
}
}
return true;
}
private static boolean areEqualChars(char[] b1, char[] b2) {
if (b1 == null) {
return (b2 == null);
} else if (b2 == null) {
return false;
} else if (b1 == b2) {
return true;
} else if (b1.length != b2.length) {
return false;
}
for (int i = 0; i < b1.length; i++) {
if (b1[i] != b2[i]) {
return false;
}
}
return true;
}
}
@@ -120,6 +120,7 @@ public final class NodeUsageCollector {
return loadProperty;
}
@Override
public String toString() {
return node + " read:" + used + " modified:" + modified;
}
@@ -63,16 +63,19 @@ public final class ObjectGraphNode implements Serializable {
return path;
}
@Override
public String toString() {
return "origin:" + originQueryPoint + " path[" + path + "]";
}
@Override
public int hashCode() {
int hc = 92821 * originQueryPoint.hashCode();
hc = 92821 * hc + (path == null ? 0 : path.hashCode());
return hc;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
@@ -57,10 +57,12 @@ public final class ObjectGraphOrigin implements Serializable {
return callStack.getFirstStackTraceElement().toString();
}
@Override
public String toString() {
return "key[" + key + "] type[" + beanType + "] " + callStack.getFirstStackTraceElement() + " ";
}
@Override
public int hashCode() {
int hc = 92821 * callStack.hashCode();
hc = 92821 * hc + beanType.hashCode();
@@ -68,6 +70,7 @@ public final class ObjectGraphOrigin implements Serializable {
return hc;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
+3 -1
View File
@@ -1,5 +1,7 @@
package io.ebean.cache;
import io.ebean.config.CurrentTenantProvider;
/**
* Defines method for constructing caches for beans and queries.
*/
@@ -8,6 +10,6 @@ public interface ServerCacheFactory {
/**
* Create the cache for the given type with options.
*/
ServerCache createCache(ServerCacheType type, String cacheKey, ServerCacheOptions cacheOptions);
ServerCache createCache(ServerCacheType type, String cacheKey, CurrentTenantProvider tenantProvider, ServerCacheOptions cacheOptions);
}
@@ -39,6 +39,7 @@ public class ServerCacheStatistics {
protected long evictByLRU;
@Override
public String toString() {
//noinspection StringBufferReplaceableByString
StringBuilder sb = new StringBuilder(80);
+77
View File
@@ -0,0 +1,77 @@
package io.ebean.cache;
import io.ebean.config.CurrentTenantProvider;
import java.io.Serializable;
import java.util.Objects;
/**
* Tenant aware handling for caching.
*/
public class TenantAwareKey {
private final CurrentTenantProvider tenantProvider;
/**
* Construct with a tenant provider than can be null.
*/
public TenantAwareKey(CurrentTenantProvider tenantProvider) {
this.tenantProvider = tenantProvider;
}
/**
* Return a tenant aware key.
*/
public Object key(Object key) {
if (tenantProvider != null) {
return new CacheKey(key, tenantProvider.currentId());
} else {
return key;
}
}
/**
* We use a combined key, if this serverCache is per tenant.
*/
public static final class CacheKey implements Serializable {
private static final long serialVersionUID = 1L;
final Object key;
final Object tenantId;
/**
* Create with optional tenantId.
*/
public CacheKey(Object key, Object tenantId) {
this.key = key;
this.tenantId = tenantId;
}
@Override
public int hashCode() {
int result = key.hashCode();
result = 92821 * result + Objects.hashCode(tenantId);
return result;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof CacheKey) {
CacheKey that = (CacheKey) obj;
return Objects.equals(that.key, this.key)
&& Objects.equals(that.tenantId, this.tenantId);
}
return false;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(key.toString());
if (tenantId != null) {
sb.append(":").append(tenantId);
}
return sb.toString();
}
}
}
@@ -47,8 +47,7 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
protected ModifyHolder<E> modifyHolder;
protected ModifyListenMode modifyListenMode;
protected boolean modifyAddListening;
protected boolean modifyRemoveListening;
protected boolean modifyListening;
/**
@@ -68,18 +67,22 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
this.readOnly = ownerBean._ebean_getIntercept().isReadOnly();
}
@Override
public EntityBean getOwnerBean() {
return ownerBean;
}
@Override
public String getPropertyName() {
return propertyName;
}
@Override
public ExpressionList<?> getFilterMany() {
return filterMany;
}
@Override
public void setFilterMany(ExpressionList<?> filterMany) {
this.filterMany = filterMany;
}
@@ -104,20 +107,24 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
checkEmptyLazyLoad();
}
@Override
public boolean isRegisteredWithLoadContext() {
return registeredWithLoadContext;
}
@Override
public void setLoader(BeanCollectionLoader loader) {
this.registeredWithLoadContext = true;
this.loader = loader;
this.ebeanServerName = loader.getName();
}
@Override
public boolean isReadOnly() {
return readOnly;
}
@Override
public void setReadOnly(boolean readOnly) {
this.readOnly = readOnly;
}
@@ -136,12 +143,11 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
/**
* set modifyListening to be on or off.
*/
@Override
public void setModifyListening(ModifyListenMode mode) {
this.modifyListenMode = mode;
this.modifyAddListening = ModifyListenMode.ALL.equals(mode);
this.modifyRemoveListening = modifyAddListening || ModifyListenMode.REMOVALS.equals(mode);
this.modifyListening = modifyRemoveListening || modifyAddListening;
this.modifyListening = mode != null && ModifyListenMode.NONE != mode;
if (modifyListening) {
// lose any existing modifications
modifyHolder = null;
@@ -162,24 +168,28 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
return modifyHolder;
}
@Override
public void modifyAddition(E bean) {
if (modifyAddListening) {
if (modifyListening) {
getModifyHolder().modifyAddition(bean);
}
}
@Override
public void modifyRemoval(Object bean) {
if (modifyRemoveListening) {
if (modifyListening) {
getModifyHolder().modifyRemoval(bean);
}
}
@Override
public void modifyReset() {
if (modifyHolder != null) {
modifyHolder.reset();
}
}
@Override
public Set<E> getModifyAdditions() {
if (modifyHolder == null) {
return null;
@@ -188,6 +198,7 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
}
}
@Override
public Set<E> getModifyRemovals() {
if (modifyHolder == null) {
return null;
+50 -9
View File
@@ -59,6 +59,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return list == null || (list.isEmpty() && !holdsModifications());
}
@Override
@SuppressWarnings("unchecked")
public void addEntityBean(EntityBean bean) {
list.add((E) bean);
@@ -73,6 +74,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
list.addAll((Collection<? extends E>) other.getActualDetails());
}
@Override
@SuppressWarnings("unchecked")
public void internalAdd(Object bean) {
if (list == null) {
@@ -102,6 +104,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return false;
}
@Override
public boolean checkEmptyLazyLoad() {
if (list == null) {
list = new ArrayList<>();
@@ -153,6 +156,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return list;
}
@Override
public Collection<E> getActualDetails() {
return list;
}
@@ -165,6 +169,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
/**
* Return true if the underlying list is populated.
*/
@Override
public boolean isPopulated() {
return list != null;
}
@@ -173,10 +178,12 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
* Return true if this is a reference (lazy loading) bean collection. This is
* the same as !isPopulated();
*/
@Override
public boolean isReference() {
return list == null;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(50);
sb.append("BeanList ");
@@ -201,11 +208,13 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
* test.
* </p>
*/
@Override
public boolean equals(Object obj) {
init();
return list.equals(obj);
}
@Override
public int hashCode() {
init();
return list.hashCode();
@@ -219,10 +228,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
// proxy method for List
// -----------------------------------------------------//
@Override
public void add(int index, E element) {
checkReadOnly();
init();
if (modifyAddListening) {
if (modifyListening) {
modifyAddition(element);
}
list.add(index, element);
@@ -233,10 +243,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
add(bean);
}
@Override
public boolean add(E o) {
checkReadOnly();
init();
if (modifyAddListening) {
if (modifyListening) {
if (list.add(o)) {
modifyAddition(o);
return true;
@@ -247,32 +258,35 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return list.add(o);
}
@Override
public boolean addAll(Collection<? extends E> c) {
checkReadOnly();
init();
if (modifyAddListening) {
if (modifyListening) {
// all elements in c are added (no contains checking)
getModifyHolder().modifyAdditionAll(c);
}
return list.addAll(c);
}
@Override
public boolean addAll(int index, Collection<? extends E> c) {
checkReadOnly();
init();
if (modifyAddListening) {
if (modifyListening) {
// all elements in c are added (no contains checking)
getModifyHolder().modifyAdditionAll(c);
}
return list.addAll(index, c);
}
@Override
public void clear() {
checkReadOnly();
// TODO: when clear() and not initialised could be more clever
// and fetch just the Id's
initClear();
if (modifyRemoveListening) {
if (modifyListening) {
for (E aList : list) {
getModifyHolder().modifyRemoval(aList);
}
@@ -280,31 +294,37 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
list.clear();
}
@Override
public boolean contains(Object o) {
init();
return list.contains(o);
}
@Override
public boolean containsAll(Collection<?> c) {
init();
return list.containsAll(c);
}
@Override
public E get(int index) {
init();
return list.get(index);
}
@Override
public int indexOf(Object o) {
init();
return list.indexOf(o);
}
@Override
public boolean isEmpty() {
init();
return list.isEmpty();
}
@Override
public Iterator<E> iterator() {
init();
if (isReadOnly()) {
@@ -317,11 +337,13 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return list.iterator();
}
@Override
public int lastIndexOf(Object o) {
init();
return list.lastIndexOf(o);
}
@Override
public ListIterator<E> listIterator() {
init();
if (isReadOnly()) {
@@ -334,6 +356,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return list.listIterator();
}
@Override
public ListIterator<E> listIterator(int index) {
init();
if (isReadOnly()) {
@@ -353,10 +376,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
}
}
@Override
public E remove(int index) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
E o = list.remove(index);
modifyRemoval(o);
return o;
@@ -364,10 +388,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return list.remove(index);
}
@Override
public boolean remove(Object o) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
boolean isRemove = list.remove(o);
if (isRemove) {
modifyRemoval(o);
@@ -377,10 +402,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return list.remove(o);
}
@Override
public boolean removeAll(Collection<?> beans) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
boolean changed = false;
for (Object bean : beans) {
if (list.remove(bean)) {
@@ -394,10 +420,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return list.removeAll(beans);
}
@Override
public boolean retainAll(Collection<?> retainBeans) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
boolean changed = false;
Iterator<E> it = list.iterator();
while (it.hasNext()) {
@@ -414,6 +441,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return list.retainAll(retainBeans);
}
@Override
public E set(int index, E element) {
checkReadOnly();
init();
@@ -426,11 +454,13 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return list.set(index, element);
}
@Override
public int size() {
init();
return list.size();
}
@Override
public List<E> subList(int fromIndex, int toIndex) {
init();
if (isReadOnly()) {
@@ -442,11 +472,13 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
return list.subList(fromIndex, toIndex);
}
@Override
public Object[] toArray() {
init();
return list.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
init();
//noinspection SuspiciousToArrayCall
@@ -463,38 +495,47 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
this.i = i;
}
@Override
public void add(E o) {
throw new IllegalStateException("This collection is in ReadOnly mode");
}
@Override
public void remove() {
throw new IllegalStateException("This collection is in ReadOnly mode");
}
@Override
public void set(E o) {
throw new IllegalStateException("This collection is in ReadOnly mode");
}
@Override
public boolean hasNext() {
return i.hasNext();
}
@Override
public boolean hasPrevious() {
return i.hasPrevious();
}
@Override
public E next() {
return i.next();
}
@Override
public int nextIndex() {
return i.nextIndex();
}
@Override
public E previous() {
return i.previous();
}
@Override
public int previousIndex() {
return i.previousIndex();
}
+24 -2
View File
@@ -47,6 +47,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
this.map = null;
}
@Override
public boolean isSkipSave() {
return map == null || (map.isEmpty() && !holdsModifications());
}
@@ -86,6 +87,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
throw new RuntimeException("Not allowed for map");
}
@Override
public void internalAdd(Object bean) {
throw new RuntimeException("Not allowed for map");
}
@@ -94,6 +96,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
* Return true if the underlying map has been populated. Returns false if it
* has a deferred fetch pending.
*/
@Override
public boolean isPopulated() {
return map != null;
}
@@ -102,10 +105,12 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
* Return true if this is a reference (lazy loading) bean collection. This is
* the same as !isPopulated();
*/
@Override
public boolean isReference() {
return map == null;
}
@Override
public boolean checkEmptyLazyLoad() {
if (map == null) {
map = new LinkedHashMap<>();
@@ -153,6 +158,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
/**
* Returns the collection of beans (map values).
*/
@Override
public Collection<E> getActualDetails() {
return map.values();
}
@@ -164,10 +170,12 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
* they don't need to be set twice).
* </p>
*/
@Override
public Collection<?> getActualEntries() {
return map.entrySet();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(50);
sb.append("BeanMap ");
@@ -187,20 +195,23 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
/**
* Equal if obj is a Map and equal in a Map sense.
*/
@Override
public boolean equals(Object obj) {
init();
return map.equals(obj);
}
@Override
public int hashCode() {
init();
return map.hashCode();
}
@Override
public void clear() {
checkReadOnly();
initClear();
if (modifyRemoveListening) {
if (modifyListening) {
// add all beans to the removal list
for (E bean : map.values()) {
modifyRemoval(bean);
@@ -209,16 +220,19 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
map.clear();
}
@Override
public boolean containsKey(Object key) {
init();
return map.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
init();
return map.containsValue(value);
}
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public Set<Entry<K, E>> entrySet() {
init();
@@ -232,16 +246,19 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
return map.entrySet();
}
@Override
public E get(Object key) {
init();
return map.get(key);
}
@Override
public boolean isEmpty() {
init();
return map.isEmpty();
}
@Override
public Set<K> keySet() {
init();
if (isReadOnly()) {
@@ -251,6 +268,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
return map.keySet();
}
@Override
public E put(K key, E value) {
checkReadOnly();
init();
@@ -265,6 +283,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
return map.put(key, value);
}
@Override
public void putAll(Map<? extends K, ? extends E> puts) {
checkReadOnly();
init();
@@ -290,10 +309,11 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
throw new IllegalStateException("Method not allowed on Map. Please use List instead.");
}
@Override
public E remove(Object key) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
E o = map.remove(key);
modifyRemoval(o);
return o;
@@ -301,11 +321,13 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
return map.remove(key);
}
@Override
public int size() {
init();
return map.size();
}
@Override
public Collection<E> values() {
init();
if (isReadOnly()) {
+32 -6
View File
@@ -48,10 +48,12 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
this.set = null;
}
@Override
public boolean isSkipSave() {
return set == null || (set.isEmpty() && !holdsModifications());
}
@Override
@SuppressWarnings("unchecked")
public void addEntityBean(EntityBean bean) {
set.add((E) bean);
@@ -73,6 +75,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
}
}
@Override
@SuppressWarnings("unchecked")
public void internalAdd(Object bean) {
if (set == null) {
@@ -86,6 +89,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
/**
* Returns true if the underlying set has its data.
*/
@Override
public boolean isPopulated() {
return set != null;
}
@@ -94,10 +98,12 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
* Return true if this is a reference (lazy loading) bean collection. This is
* the same as !isPopulated();
*/
@Override
public boolean isReference() {
return set == null;
}
@Override
public boolean checkEmptyLazyLoad() {
if (set == null) {
set = new LinkedHashSet<>();
@@ -142,6 +148,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
return set;
}
@Override
public Collection<E> getActualDetails() {
return set;
}
@@ -151,6 +158,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
return set;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(50);
sb.append("BeanSet ");
@@ -170,11 +178,13 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
/**
* Equal if obj is a Set and equal in a Set sense.
*/
@Override
public boolean equals(Object obj) {
init();
return set.equals(obj);
}
@Override
public int hashCode() {
init();
return set.hashCode();
@@ -196,10 +206,11 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
// proxy method for map
// -----------------------------------------------------//
@Override
public boolean add(E o) {
checkReadOnly();
init();
if (modifyAddListening) {
if (modifyListening) {
if (set.add(o)) {
modifyAddition(o);
return true;
@@ -210,10 +221,11 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
return set.add(o);
}
@Override
public boolean addAll(Collection<? extends E> addCollection) {
checkReadOnly();
init();
if (modifyAddListening) {
if (modifyListening) {
boolean changed = false;
for (E bean : addCollection) {
if (set.add(bean)) {
@@ -227,10 +239,11 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
return set.addAll(addCollection);
}
@Override
public void clear() {
checkReadOnly();
initClear();
if (modifyRemoveListening) {
if (modifyListening) {
for (E bean : set) {
modifyRemoval(bean);
}
@@ -238,21 +251,25 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
set.clear();
}
@Override
public boolean contains(Object o) {
init();
return set.contains(o);
}
@Override
public boolean containsAll(Collection<?> c) {
init();
return set.containsAll(c);
}
@Override
public boolean isEmpty() {
init();
return set.isEmpty();
}
@Override
public Iterator<E> iterator() {
init();
if (isReadOnly()) {
@@ -264,10 +281,11 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
return set.iterator();
}
@Override
public boolean remove(Object o) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
if (set.remove(o)) {
modifyRemoval(o);
return true;
@@ -277,10 +295,11 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
return set.remove(o);
}
@Override
public boolean removeAll(Collection<?> beans) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
boolean changed = false;
for (Object bean : beans) {
if (set.remove(bean)) {
@@ -293,10 +312,11 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
return set.removeAll(beans);
}
@Override
public boolean retainAll(Collection<?> beans) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (modifyListening) {
boolean changed = false;
Iterator<?> it = set.iterator();
while (it.hasNext()) {
@@ -313,16 +333,19 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
return set.retainAll(beans);
}
@Override
public int size() {
init();
return set.size();
}
@Override
public Object[] toArray() {
init();
return set.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
init();
//noinspection SuspiciousToArrayCall
@@ -339,14 +362,17 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
this.it = it;
}
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
public E next() {
return it.next();
}
@Override
public void remove() {
throw new IllegalStateException("This collection is in ReadOnly mode");
}
@@ -30,6 +30,7 @@ class ModifyCollection<E> implements Collection<E> {
this.c = c;
}
@Override
public boolean add(E o) {
if (c.add(o)) {
owner.modifyAddition(o);
@@ -38,6 +39,7 @@ class ModifyCollection<E> implements Collection<E> {
return false;
}
@Override
public boolean addAll(Collection<? extends E> collection) {
boolean changed = false;
for (E o : collection) {
@@ -44,21 +44,29 @@ class ModifyHolder<E> implements Serializable {
}
}
private boolean undoDeletion(E bean) {
return (bean != null) && modifyDeletions.remove(bean);
}
void modifyAddition(E bean) {
if (bean != null) {
// If it is to delete then just remove the deletion
if (!modifyDeletions.remove(bean)) {
if (!undoDeletion(bean)) {
// Insert
modifyAdditions.add(bean);
}
}
}
private boolean undoAddition(Object bean) {
return (bean != null) && modifyAdditions.remove(bean);
}
@SuppressWarnings("unchecked")
void modifyRemoval(Object bean) {
if (bean != null) {
// If it is to be added then just remove the addition
if (!modifyAdditions.remove(bean)) {
if (!undoAddition(bean)) {
modifyDeletions.add((E) bean);
}
}
@@ -31,15 +31,18 @@ class ModifyIterator<E> implements Iterator<E> {
this.it = it;
}
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
public E next() {
last = it.next();
return last;
}
@Override
public void remove() {
owner.modifyRemoval(last);
it.remove();
@@ -33,11 +33,13 @@ class ModifyList<E> extends ModifyCollection<E> implements List<E> {
this.list = list;
}
@Override
public void add(int index, E element) {
list.add(index, element);
owner.modifyAddition(element);
}
@Override
public boolean addAll(int index, Collection<? extends E> addCollection) {
if (list.addAll(index, addCollection)) {
for (E bean : addCollection) {
@@ -48,32 +50,39 @@ class ModifyList<E> extends ModifyCollection<E> implements List<E> {
return false;
}
@Override
public E get(int index) {
return list.get(index);
}
@Override
public int indexOf(Object o) {
return list.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
@Override
public ListIterator<E> listIterator() {
return new ModifyListIterator<>(owner, list.listIterator());
}
@Override
public ListIterator<E> listIterator(int index) {
return new ModifyListIterator<>(owner, list.listIterator(index));
}
@Override
public E remove(int index) {
E o = list.remove(index);
owner.modifyRemoval(o);
return o;
}
@Override
public E set(int index, E element) {
E o = list.set(index, element);
owner.modifyAddition(element);
@@ -81,6 +90,7 @@ class ModifyList<E> extends ModifyCollection<E> implements List<E> {
return o;
}
@Override
public List<E> subList(int fromIndex, int toIndex) {
return new ModifyList<>(owner, list.subList(fromIndex, toIndex));
}
@@ -28,44 +28,53 @@ class ModifyListIterator<E> implements ListIterator<E> {
this.it = it;
}
@Override
public void add(E bean) {
owner.modifyAddition(bean);
last = null;
it.add(bean);
}
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
public boolean hasPrevious() {
return it.hasPrevious();
}
@Override
public E next() {
last = it.next();
return last;
}
@Override
public int nextIndex() {
return it.nextIndex();
}
@Override
public E previous() {
last = it.previous();
return last;
}
@Override
public int previousIndex() {
return it.previousIndex();
}
@Override
public void remove() {
owner.modifyRemoval(last);
last = null;
it.remove();
}
@Override
public void set(E o) {
if (last != null) {
owner.modifyRemoval(last);
@@ -76,10 +76,12 @@ public abstract class AbstractNamingConvention implements NamingConvention {
this(DEFAULT_SEQ_FORMAT);
}
@Override
public void setDatabasePlatform(DatabasePlatform databasePlatform) {
this.databasePlatform = databasePlatform;
}
@Override
public String getSequenceName(String tableName, String pkColumn) {
String s = sequenceFormat.replace("{table}", tableName);
if (pkColumn == null) {
@@ -152,6 +154,7 @@ public abstract class AbstractNamingConvention implements NamingConvention {
* column names.
* </p>
*/
@Override
public boolean isUseForeignKeyPrefix() {
return useForeignKeyPrefix;
}
@@ -180,31 +183,35 @@ public abstract class AbstractNamingConvention implements NamingConvention {
* @see #getTableNameFromAnnotation(Class)
* @see #getTableNameByConvention(Class)
*/
@Override
public TableName getTableName(Class<?> beanClass) {
while (true) {
TableName tableName = getTableNameFromAnnotation(beanClass);
if (tableName == null) {
Class<?> supCls = beanClass.getSuperclass();
if (hasInheritance(supCls)) {
// get the table as per inherited class in case there
// is not a table annotation in the inheritance hierarchy
return getTableName(supCls);
TableName tableName = getTableNameFromAnnotation(beanClass);
if (tableName == null) {
Class<?> supCls = beanClass.getSuperclass();
if (hasInheritance(supCls)) {
// get the table as per inherited class in case there
// is not a table annotation in the inheritance hierarchy
beanClass = supCls;
continue;
}
tableName = getTableNameByConvention(beanClass);
}
tableName = getTableNameByConvention(beanClass);
// Use naming convention for catalog or schema,
// if not set in the annotation.
String catalog = tableName.getCatalog();
if (isEmpty(catalog)) {
catalog = getCatalog();
}
String schema = tableName.getSchema();
if (isEmpty(schema)) {
schema = getSchema();
}
return new TableName(catalog, schema, tableName.getName());
}
// Use naming convention for catalog or schema,
// if not set in the annotation.
String catalog = tableName.getCatalog();
if (isEmpty(catalog)) {
catalog = getCatalog();
}
String schema = tableName.getSchema();
if (isEmpty(schema)) {
schema = getSchema();
}
return new TableName(catalog, schema, tableName.getName());
}
/**
@@ -221,6 +228,7 @@ public abstract class AbstractNamingConvention implements NamingConvention {
return supCls.getAnnotation(annotation) != null;
}
@Override
public TableName getM2MJoinTableName(TableName lhsTable, TableName rhsTable) {
StringBuilder buffer = new StringBuilder();
@@ -266,14 +274,16 @@ public abstract class AbstractNamingConvention implements NamingConvention {
* Search recursively for an @Table in the class hierarchy.
*/
protected Table findTableAnnotation(Class<?> cls) {
if (cls.equals(Object.class)) {
return null;
while (true) {
if (cls.equals(Object.class)) {
return null;
}
Table table = cls.getAnnotation(Table.class);
if (table != null) {
return table;
}
cls = cls.getSuperclass();
}
Table table = cls.getAnnotation(Table.class);
if (table != null) {
return table;
}
return findTableAnnotation(cls.getSuperclass());
}
/**
@@ -118,7 +118,7 @@ public class ClassLoadConfig {
/**
* Wraps the preferred, caller and context class loaders.
*/
protected class ClassLoaderContext {
protected static class ClassLoaderContext {
/**
* Optional - if set only use this classLoader (no fallback).
@@ -3,6 +3,7 @@ package io.ebean.config;
/**
* Provides the Tenant Id for the current request based on the current user.
*/
@FunctionalInterface
public interface CurrentTenantProvider {
/**
@@ -3,6 +3,7 @@ package io.ebean.config;
/**
* Provides the current user in order to support 'Who created', 'Who modified' and other audit features.
*/
@FunctionalInterface
public interface CurrentUserProvider {
/**
@@ -7,6 +7,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.Properties;
/**
* Configuration for the DB migration processing.
@@ -443,7 +444,7 @@ public class DbMigrationConfig {
/**
* Create the MigrationRunner to run migrations if necessary.
*/
public MigrationRunner createRunner(ClassLoader classLoader) {
public MigrationRunner createRunner(ClassLoader classLoader, Properties properties) {
MigrationConfig runnerConfig = new MigrationConfig();
runnerConfig.setMetaTable(metaTable);
@@ -454,6 +455,9 @@ public class DbMigrationConfig {
runnerConfig.setDbUsername(getDbUsername());
runnerConfig.setDbPassword(getDbPassword());
runnerConfig.setClassLoader(classLoader);
if (properties != null) {
runnerConfig.load(properties);
}
return new MigrationRunner(runnerConfig);
}
}
@@ -33,6 +33,21 @@ public class DocStoreConfig {
*/
protected String url;
/**
* Credential that be used for authentication to document store.
*/
protected String username;
/**
* Password credential that be used for authentication to document store.
*/
protected String password;
/**
* Set to true such that the client allows connections to invalid/self signed SSL certificates.
*/
protected boolean allowAllCertificates;
/**
* The default mode used by indexes.
*/
@@ -87,6 +102,34 @@ public class DocStoreConfig {
return url;
}
/**
* Return the user credential for connecting to the document store.
*/
public String getUsername() {
return username;
}
/**
* Set the user credential for connecting to the document store.
*/
public void setUsername(String username) {
this.username = username;
}
/**
* Return the password credential for connecting to the document store.
*/
public String getPassword() {
return password;
}
/**
* Set the password credential for connecting to the document store.
*/
public void setPassword(String password) {
this.password = password;
}
/**
* Set the URL to the Document store server.
* <p>
@@ -152,6 +195,20 @@ public class DocStoreConfig {
this.create = create;
}
/**
* Return true if the client allows connections to invalid/self signed SSL certificates.
*/
public boolean isAllowAllCertificates() {
return allowAllCertificates;
}
/**
* Set to true such that the client allows connections to invalid/self signed SSL certificates.
*/
public void setAllowAllCertificates(boolean allowAllCertificates) {
this.allowAllCertificates = allowAllCertificates;
}
/**
* Return the default batch size to use for calls to the Bulk API.
*/
@@ -248,11 +305,14 @@ public class DocStoreConfig {
active = properties.getBoolean("docstore.active", active);
url = properties.get("docstore.url", url);
username = properties.get("docstore.username", url);
password = properties.get("docstore.password", url);
persist = properties.getEnum(DocStoreMode.class, "docstore.persist", persist);
bulkBatchSize = properties.getInt("docstore.bulkBatchSize", bulkBatchSize);
generateMapping = properties.getBoolean("docstore.generateMapping", generateMapping);
dropCreate = properties.getBoolean("docstore.dropCreate", dropCreate);
create = properties.getBoolean("docstore.create", create);
allowAllCertificates = properties.getBoolean("docstore.allowAllCertificates", allowAllCertificates);
mappingPath = properties.get("docstore.mappingPath", mappingPath);
mappingSuffix = properties.get("docstore.mappingSuffix", mappingSuffix);
pathToResources = properties.get("docstore.pathToResources", pathToResources);
@@ -3,6 +3,7 @@ package io.ebean.config;
/**
* Programmatically define which database columns are encrypted.
*/
@FunctionalInterface
public interface EncryptDeployManager {
/**
@@ -6,6 +6,7 @@ package io.ebean.config;
* For simple cases this often represent a simple String key but depending on
* the encryption method this could contain other details.
*/
@FunctionalInterface
public interface EncryptKey {
/**
@@ -3,6 +3,7 @@ package io.ebean.config;
/**
* Determine keys used for encryption and decryption.
*/
@FunctionalInterface
public interface EncryptKeyManager {
/**
@@ -11,7 +12,7 @@ public interface EncryptKeyManager {
* This gives the EncryptKeyManager the opportunity to get keys etc.
* </p>
*/
void initialise();
default void initialise() {};
/**
* Return the key used to encrypt and decrypt a property mapping to the given
@@ -29,15 +29,18 @@ public class MatchingNamingConvention extends AbstractNamingConvention {
super(sequenceFormat);
}
@Override
public String getColumnFromProperty(Class<?> beanClass, String propertyName) {
return propertyName;
}
@Override
public TableName getTableNameByConvention(Class<?> beanClass) {
return new TableName(getCatalog(), getSchema(), beanClass.getSimpleName());
}
@Override
public String getPropertyFromColumn(Class<?> beanClass, String dbColumnName) {
return dbColumnName;
}
@@ -91,7 +91,7 @@ final class PropertyExpression {
// in which properties are being set/loaded. You can use
// GlobalProperties.evaluateExpressions() to get any unresolved
// expressions to be evaluated
logger.debug("Unable to evaluate expression [" + exp + "]");
logger.debug("Unable to evaluate expression [{}]", exp);
return null;
}
}
@@ -36,6 +36,7 @@ public final class PropertyMap implements Serializable {
return (disable == null || !disable.equalsIgnoreCase("true"));
}
@Override
public String toString() {
return map.toString();
}
@@ -112,7 +112,7 @@ final class PropertyMapLoader {
otherProps = otherProps.replace("\\", "/");
InputStream is = findInputStream(otherProps);
if (is != null) {
logger.debug("loading properties from " + otherProps);
logger.debug("loading properties from {}", otherProps);
load(p, is);
} else {
logger.error("load.properties " + otherProps + " not found.");
@@ -135,12 +135,12 @@ final class PropertyMapLoader {
File f = new File(fileName);
if (f.exists()) {
logger.debug(fileName + " found in file system");
logger.debug("{} found in file system", fileName);
return new FileInputStream(f);
} else {
InputStream in = findInClassPath(fileName);
if (in != null) {
logger.debug(fileName + " found in classpath");
logger.debug("{} found in classpath", fileName);
}
return in;
}
@@ -1,37 +1,27 @@
package io.ebean.config;
/**
* Matches the functionality of javax.persistence.AttributeConverter
* <p>
* In general AttributeConverter should be used in preference to this
* ScalarTypeConverter as it is JPA standard and offers the same functionality.
* </p>
* <p>
* For Ebean we will look to deprecate this interface in preference to AttributeConverter.
* </p>
* <p>
* Used to convert between a value object and a known scalar type. The value
* object is the logical type used in your application and the scalar type is
* the value used to persist than to the DB.
* </p>
* <p>
* The Value object should be immutable and scalar (aka not compound) and
* converts to and from a known scalar type which Ebean will use to persist the
* value.
* </p>
* <p>
* This is an easier alternative to implementing the
* io.ebean.server.type.ScalarType interface.
* </p>
* <p>
* Note that Ebean will automatically try to detect Immutable Scalar Value
* Objects and automatically support them via reflection. This however would not
* be appropriate when the logical type is different from the type you wish to
* use for persistence - for example, if the logical type was long and you
* wanted to use java.sql.Timestamp for persistence. In this case you would want
* to implement this interface rather than let Ebean automatically support that
* type via reflection.
* </p>
* <p>
* If you want to support a Compound Type rather than a Scalar Type refer to
* {@link CompoundType}.
* </p>
*
* @param <B> The value object type.
* @param <S> The scalar object type that is used to persist the value object.
* @author rbygrave
* @see CompoundType
* @see CompoundTypeProperty
*/
public interface ScalarTypeConverter<B, S> {
@@ -129,6 +129,8 @@ public class ServerConfig {
private TenantSchemaProvider tenantSchemaProvider;
private TenantCatalogProvider tenantCatalogProvider;
/**
* List of interesting classes such as entities, embedded, ScalarTypes,
* Listeners, Finders, Controllers etc.
@@ -378,6 +380,8 @@ public class ServerConfig {
private Encryptor encryptor;
private boolean dbOffline;
private DbEncrypt dbEncrypt;
private ServerCachePlugin serverCachePlugin;
@@ -694,6 +698,20 @@ public class ServerConfig {
this.tenantSchemaProvider = tenantSchemaProvider;
}
/**
* Return the tenancy catalog provider.
*/
public TenantCatalogProvider getTenantCatalogProvider() {
return tenantCatalogProvider;
}
/**
* Set the tenancy catalog provider.
*/
public void setTenantCatalogProvider(TenantCatalogProvider tenantCatalogProvider) {
this.tenantCatalogProvider = tenantCatalogProvider;
}
/**
* Return the PersistBatch mode to use by default at the transaction level.
* <p>
@@ -1623,6 +1641,24 @@ public class ServerConfig {
this.encryptor = encryptor;
}
/**
* Return true if the EbeanServer instance should be created in offline mode.
*/
public boolean isDbOffline() {
return dbOffline;
}
/**
* Set to true if the EbeanServer instance should be created in offline mode.
* <p>
* Typically used to create an EbeanServer instance for DDL Migration generation
* without requiring a real DataSource / Database to connect to.
* </p>
*/
public void setDbOffline(boolean dbOffline) {
this.dbOffline = dbOffline;
}
/**
* Return the DbEncrypt used to encrypt and decrypt properties.
* <p>
@@ -2507,6 +2543,7 @@ public class ServerConfig {
encryptDeployManager = createInstance(p, EncryptDeployManager.class, "encryptDeployManager", encryptDeployManager);
encryptor = createInstance(p, Encryptor.class, "encryptor", encryptor);
dbEncrypt = createInstance(p, DbEncrypt.class, "dbEncrypt", dbEncrypt);
dbOffline = p.getBoolean("dbOffline", dbOffline);
serverCachePlugin = createInstance(p, ServerCachePlugin.class, "serverCachePlugin", serverCachePlugin);
if (packages != null) {
@@ -2718,7 +2755,7 @@ public class ServerConfig {
*/
public DataSource runDbMigration(DataSource dataSource) {
if (migrationConfig.isRunMigration()) {
MigrationRunner runner = migrationConfig.createRunner(getClassLoadConfig().getClassLoader());
MigrationRunner runner = migrationConfig.createRunner(getClassLoadConfig().getClassLoader(), properties);
runner.run(dataSource);
}
return dataSource;
@@ -69,6 +69,7 @@ public final class TableName {
return new TableName(qualifiedTableName).getName();
}
@Override
public String toString() {
return getQualifiedName();
}
@@ -0,0 +1,16 @@
package io.ebean.config;
/**
* For multi-tenancy via DB CATALOG supply the catalog given the tenantId.
*/
@FunctionalInterface
public interface TenantCatalogProvider {
/**
* Return the DB catalog for the given tenantId.
*
* @param tenantId The current tenant id.
* @return The DB catalog to use for the given tenant
*/
String catalog(Object tenantId);
}
@@ -5,6 +5,7 @@ import javax.sql.DataSource;
/**
* For multi-tenancy via DB supply the DataSource given the tenantId.
*/
@FunctionalInterface
public interface TenantDataSourceProvider {
/**
@@ -15,5 +16,5 @@ public interface TenantDataSourceProvider {
/**
* Shutdown all the DataSources.
*/
void shutdown(boolean deregisterDriver);
default void shutdown(boolean deregisterDriver) {};
}
@@ -20,6 +20,11 @@ public enum TenantMode {
*/
SCHEMA(true),
/**
* Each Tenant has their own Database but with in connection pool
*/
CATALOG(true),
/**
* Tenants share tables but have a discriminator/partition column that partitions the data.
*/
@@ -3,6 +3,7 @@ package io.ebean.config;
/**
* For multi-tenancy via DB SCHEMA supply the schema given the tenantId.
*/
@FunctionalInterface
public interface TenantSchemaProvider {
/**
@@ -43,6 +43,7 @@ public class UnderscoreNamingConvention extends AbstractNamingConvention {
* @param beanClass the bean class
* @return the table name from class
*/
@Override
public TableName getTableNameByConvention(Class<?> beanClass) {
return new TableName(getCatalog(), getSchema(), toUnderscoreFromCamel(beanClass.getSimpleName()));
@@ -53,6 +54,7 @@ public class UnderscoreNamingConvention extends AbstractNamingConvention {
*
* @return the column from property
*/
@Override
public String getColumnFromProperty(Class<?> beanClass, String propertyName) {
return toUnderscoreFromCamel(propertyName);
@@ -65,6 +67,7 @@ public class UnderscoreNamingConvention extends AbstractNamingConvention {
* @param dbColumnName the db column name
* @return the property from column
*/
@Override
public String getPropertyFromColumn(Class<?> beanClass, String dbColumnName) {
return toCamelFromUnderscore(dbColumnName);
}
@@ -39,6 +39,7 @@ public abstract class AbstractDbEncrypt implements DbEncrypt {
* Null is returned if DB encryption of the type is not supported.
* </p>
*/
@Override
public DbEncryptFunction getDbEncryptFunction(int jdbcType) {
switch (jdbcType) {
case Types.VARCHAR:
@@ -64,6 +65,7 @@ public abstract class AbstractDbEncrypt implements DbEncrypt {
/**
* Return the DB stored type for encrypted properties.
*/
@Override
public int getEncryptDbType() {
return Types.VARBINARY;
}
@@ -71,6 +73,7 @@ public abstract class AbstractDbEncrypt implements DbEncrypt {
/**
* Generally encrypt function binding the data before the key (except h2).
*/
@Override
public boolean isBindEncryptDataFirst() {
return true;
}
@@ -0,0 +1,22 @@
package io.ebean.config.dbplatform;
/**
* Specific persistence error types we wish to map.
*/
public enum DataErrorType {
/**
* Error trying to acquire lock (e.g. failure executing select for update nowait)
*/
AcquireLock,
/**
* Error with a duplicate primary or unique key.
*/
DuplicateKey,
/**
* Data integrity error like an invalid foreign key.
*/
DataIntegrity
}
@@ -12,6 +12,7 @@ import io.ebean.dbmigration.ddlgeneration.platform.PlatformDdl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.PersistenceException;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
@@ -172,12 +173,23 @@ public class DatabasePlatform {
protected boolean supportsNativeIlike;
protected SqlExceptionTranslator exceptionTranslator = new SqlCodeTranslator();
protected char[] specialLikeCharacters = { '%', '_' };
/**
* Instantiates a new database platform.
*/
public DatabasePlatform() {
}
/**
* Translate the SQLException into a specific persistence exception if possible.
*/
public PersistenceException translate(String message, SQLException e) {
return exceptionTranslator.translate(message, e);
}
/**
* Configure UUID Storage etc based on ServerConfig settings.
*/
@@ -554,17 +566,16 @@ public class DatabasePlatform {
}
public String completeSql(String sql, Query<?> query) {
if (Boolean.TRUE.equals(query.isForUpdate())) {
sql = withForUpdate(sql);
if (query.isForUpdate()) {
sql = withForUpdate(sql, query.getForUpdateMode());
}
return sql;
}
protected String withForUpdate(String sql) {
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
// 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;
}
@@ -608,4 +619,37 @@ public class DatabasePlatform {
logger.error("Error closing resultSet", e);
}
}
/**
* Escapes the like string for this DB-Platform
*/
public String escapeLikeString(String value) {
StringBuilder sb = null;
for (int i = 0; i < value.length(); i++) {
char ch = value.charAt(i);
boolean escaped = false;
for (char escapeChar: specialLikeCharacters) {
if (ch == escapeChar) {
if (sb == null) {
sb = new StringBuilder(value.substring(0, i));
}
escapeLikeCharacter(escapeChar, sb);
escaped = true;
break;
}
}
if (!escaped && sb != null) {
sb.append(ch);
}
}
if (sb == null) {
return value;
} else {
return sb.toString();
}
}
protected void escapeLikeCharacter(char ch, StringBuilder sb) {
sb.append('\\').append(ch);
}
}
@@ -2,7 +2,7 @@ package io.ebean.config.dbplatform;
import io.ebean.config.ServerConfig;
import java.util.HashMap;
import java.util.EnumMap;
import java.util.Map;
/**
@@ -13,6 +13,7 @@ public class DbPlatformTypeMapping {
private static DbPlatformTypeLookup lookup = new DbPlatformTypeLookup();
private static final DbPlatformType UUID_NATIVE = new DbPlatformType("uuid", false);
@SuppressWarnings("unused")
private static final DbPlatformType UUID_PLACEHOLDER = new DbPlatformType("uuidPlaceholder");
private static final DbPlatformType JSON_CLOB_PLACEHOLDER = new DbPlatformType("jsonClobPlaceholder");
private static final DbPlatformType JSON_BLOB_PLACEHOLDER = new DbPlatformType("jsonBlobPlaceholder");
@@ -25,7 +26,7 @@ public class DbPlatformTypeMapping {
private static final DbPlatformType MULTILINESTRING = new DbPlatformType("multilinestring");
private static final DbPlatformType MULTIPOLYGON = new DbPlatformType("multipolygon");
private final Map<DbType, DbPlatformType> typeMap = new HashMap<>();
private final Map<DbType, DbPlatformType> typeMap = new EnumMap<>(DbType.class);
/**
* Return the DbTypeMap with standard (not platform specific) types.
@@ -15,6 +15,7 @@ public class LimitOffsetSqlLimiter implements SqlLimiter {
*/
private static final String OFFSET = "offset";
@Override
public SqlLimitResponse limit(SqlLimitRequest request) {
String dbSql = request.getDbSql();
@@ -28,6 +28,7 @@ public class RowNumberSqlLimiter implements SqlLimiter {
this("as limitresult");
}
@Override
public SqlLimitResponse limit(SqlLimitRequest request) {
String dbSql = request.getDbSql();
@@ -38,7 +39,7 @@ public class RowNumberSqlLimiter implements SqlLimiter {
int lastRow = request.getMaxRows();
if (lastRow > 0) {
lastRow = lastRow + firstRow;
lastRow += firstRow;
}
sb.append("select * from ( ");
@@ -25,6 +25,7 @@ public class RownumSqlLimiter implements SqlLimiter {
this.useFirstRowsHint = useFirstRowsHint;
}
@Override
public SqlLimitResponse limit(SqlLimitRequest request) {
// select *
@@ -43,7 +44,7 @@ public class RownumSqlLimiter implements SqlLimiter {
int lastRow = request.getMaxRows();
if (lastRow > 0) {
lastRow = lastRow + firstRow;
lastRow += firstRow;
}
sb.append("select * from ( ");
@@ -60,6 +60,7 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
/**
* Returns the sequence name.
*/
@Override
public String getName() {
return seqName;
}
@@ -67,6 +68,7 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
/**
* Returns true.
*/
@Override
public boolean isDbSequence() {
return true;
}
@@ -78,6 +80,7 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
* beans Ebean can call this to ensure .
* </p>
*/
@Override
public void preAllocateIds(int allocateSize) {
if (batchSize > 1 && allocateSize > batchSize) {
// only bother if allocateSize is bigger than
@@ -106,6 +109,7 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
* If a Transaction has been passed in use the Connection from it.
* </p>
*/
@Override
public Object nextId(Transaction t) {
synchronized (monitor) {
@@ -158,9 +162,7 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
}
synchronized (monitor) {
for (Long newId : newIds) {
idList.add(newId);
}
idList.addAll(newIds);
}
}
@@ -36,18 +36,22 @@ public class SimpleSequenceIdGenerator implements PlatformIdGenerator {
this.seqName = seqName;
}
@Override
public String getName() {
return seqName;
}
@Override
public boolean isDbSequence() {
return true;
}
@Override
public void preAllocateIds(int batchSize) {
// just ignore this
}
@Override
public Object nextId(Transaction t) {
boolean useTxnConnection = t != null;
@@ -0,0 +1,50 @@
package io.ebean.config.dbplatform;
import io.ebean.AcquireLockException;
import io.ebean.DataIntegrityException;
import io.ebean.DuplicateKeyException;
import javax.persistence.PersistenceException;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Map;
/**
* Translate SQLException based on SQLState codes.
*/
public class SqlCodeTranslator implements SqlExceptionTranslator {
private final Map<String,DataErrorType> map;
/**
* Create given the map of SQLState codes to error types.
*/
public SqlCodeTranslator(Map<String,DataErrorType> map) {
this.map = map;
}
/**
* Create "No-op" implementation.
*/
public SqlCodeTranslator() {
this.map = Collections.emptyMap();
}
@Override
public PersistenceException translate(String message, SQLException e) {
DataErrorType errorType = map.get(e.getSQLState());
if (errorType != null) {
switch (errorType) {
case AcquireLock:
return new AcquireLockException(message, e);
case DuplicateKey:
return new DuplicateKeyException(message, e);
case DataIntegrity:
return new DataIntegrityException(message, e);
}
}
// return a generic exception
return new PersistenceException(message, e);
}
}
@@ -0,0 +1,47 @@
package io.ebean.config.dbplatform;
import java.util.HashMap;
import java.util.Map;
/**
* Used to build a SQLCodeTranslator given DB platform specific codes.
*/
public class SqlErrorCodes {
private Map<String,DataErrorType> map = new HashMap<>();
/**
* Map the codes to AcquireLockException.
*/
public SqlErrorCodes addAcquireLock(String... codes) {
return add(DataErrorType.AcquireLock, codes);
}
/**
* Map the codes to DataIntegrityException.
*/
public SqlErrorCodes addDataIntegrity(String... codes) {
return add(DataErrorType.DataIntegrity, codes);
}
/**
* Map the codes to DuplicateKeyException.
*/
public SqlErrorCodes addDuplicateKey(String... codes) {
return add(DataErrorType.DuplicateKey, codes);
}
private SqlErrorCodes add(DataErrorType type, String... codes) {
for (String code : codes) {
map.put(code, type);
}
return this;
}
/**
* Build and return the SQLCodeTranslator with the mapped codes.
*/
public SqlCodeTranslator build() {
return new SqlCodeTranslator(map);
}
}
@@ -0,0 +1,15 @@
package io.ebean.config.dbplatform;
import javax.persistence.PersistenceException;
import java.sql.SQLException;
/**
* Used to translate SQLExceptions to specific persistence exceptions.
*/
public interface SqlExceptionTranslator {
/**
* Translate the given exception.
*/
PersistenceException translate(String message, SQLException e);
}
@@ -6,6 +6,7 @@ import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.DbPlatformType;
import io.ebean.config.dbplatform.DbType;
import io.ebean.config.dbplatform.PlatformIdGenerator;
import io.ebean.config.dbplatform.SqlErrorCodes;
import io.ebean.dbmigration.ddlgeneration.platform.DB2Ddl;
import javax.sql.DataSource;
@@ -27,6 +28,13 @@ public class DB2Platform extends DatabasePlatform {
this.dbIdentity.setSupportsGetGeneratedKeys(true);
this.dbIdentity.setSupportsSequence(true);
this.exceptionTranslator =
new SqlErrorCodes()
//.addAcquireLock("")
.addDuplicateKey("-803")
.addDataIntegrity("-407","-530","-531","-532","-543","-544","-545","-603","-667")
.build();
booleanDbType = Types.BOOLEAN;
dbTypeMap.put(DbType.REAL, new DbPlatformType("real"));
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint"));
@@ -22,6 +22,7 @@ public class DB2SequenceIdGenerator extends SequenceIdGenerator {
this.unionBaseSql = " union " + baseSql;
}
@Override
public String getSql(int batchSize) {
StringBuilder sb = new StringBuilder();
@@ -0,0 +1,4 @@
/**
* DB2 specific support.
*/
package io.ebean.config.dbplatform.db2;
@@ -18,17 +18,20 @@ public class H2DbEncrypt extends AbstractDbEncrypt {
/**
* For H2 encrypt function returns false binding the key before the data.
*/
@Override
public boolean isBindEncryptDataFirst() {
return false;
}
private static class H2VarcharFunction implements DbEncryptFunction {
@Override
public String getDecryptSql(String columnWithTableAlias) {
// Hmmm, this looks ugly - checking with H2 Database folks.
return "TRIM(CHAR(0) FROM UTF8TOSTRING(DECRYPT('AES', STRINGTOUTF8(?), " + columnWithTableAlias + ")))";
}
@Override
public String getEncryptBindSql() {
return "ENCRYPT('AES', STRINGTOUTF8(?), STRINGTOUTF8(?))";
}
@@ -37,10 +40,12 @@ public class H2DbEncrypt extends AbstractDbEncrypt {
private static class H2DateFunction implements DbEncryptFunction {
@Override
public String getDecryptSql(String columnWithTableAlias) {
return "PARSEDATETIME(TRIM(CHAR(0) FROM UTF8TOSTRING(DECRYPT('AES', STRINGTOUTF8(?), " + columnWithTableAlias + "))),'yyyyMMdd')";
}
@Override
public String getEncryptBindSql() {
return "ENCRYPT('AES', STRINGTOUTF8(?), STRINGTOUTF8(FORMATDATETIME(?,'yyyyMMdd')))";
}
@@ -100,14 +100,11 @@ public class H2HistoryTrigger implements Trigger {
*/
private void insertIntoHistory(Connection connection, Object[] oldRow) throws SQLException {
PreparedStatement stmt = connection.prepareStatement(insertHistorySql);
try {
try (PreparedStatement stmt = connection.prepareStatement(insertHistorySql)) {
for (int i = 0; i < oldRow.length; i++) {
stmt.setObject(i + 1, oldRow[i]);
}
stmt.executeUpdate();
} finally {
stmt.close();
}
}
@@ -2,11 +2,13 @@ package io.ebean.config.dbplatform.h2;
import io.ebean.BackgroundExecutor;
import io.ebean.Platform;
import io.ebean.Query;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.DbPlatformType;
import io.ebean.config.dbplatform.DbType;
import io.ebean.config.dbplatform.IdType;
import io.ebean.config.dbplatform.PlatformIdGenerator;
import io.ebean.config.dbplatform.SqlErrorCodes;
import io.ebean.dbmigration.ddlgeneration.platform.H2Ddl;
import javax.sql.DataSource;
@@ -26,15 +28,18 @@ public class H2Platform extends DatabasePlatform {
this.dbDefaultValue.setNow("now()");
this.columnAliasPrefix = null;
this.exceptionTranslator =
new SqlErrorCodes()
.addAcquireLock("50200")
.addDuplicateKey("23001","23505")
.addDataIntegrity("22001","22003","22012","22018","22025","23000","23002","23003","23502","23503","23506","23507","23513")
.build();
this.dbIdentity.setIdType(IdType.IDENTITY);
this.dbIdentity.setSupportsGetGeneratedKeys(true);
this.dbIdentity.setSupportsSequence(true);
this.dbIdentity.setSupportsIdentity(true);
// like ? escape'' not working in the latest version H2 so just using no
// escape clause for now noting that backslash is an escape char for like in H2
this.likeClause = "like ?";
dbTypeMap.put(DbType.UUID, new DbPlatformType("uuid", false));
}
@@ -50,7 +55,8 @@ public class H2Platform extends DatabasePlatform {
}
@Override
protected String withForUpdate(String sql) {
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
// NOWAIT and SKIP LOCKED currently not supported with H2
return sql + " for update";
}
}
@@ -22,6 +22,7 @@ public class H2SequenceIdGenerator extends SequenceIdGenerator {
this.unionBaseSql = " union " + baseSql;
}
@Override
public String getSql(int batchSize) {
StringBuilder sb = new StringBuilder();
@@ -0,0 +1,4 @@
/**
* H2 specific support.
*/
package io.ebean.config.dbplatform.h2;
@@ -0,0 +1,4 @@
/**
* Hsqldb specific support.
*/
package io.ebean.config.dbplatform.hsqldb;
@@ -17,10 +17,12 @@ public class MySqlDbEncrypt extends AbstractDbEncrypt {
private static class MyVarcharFunction implements DbEncryptFunction {
@Override
public String getDecryptSql(String columnWithTableAlias) {
return "CONVERT(AES_DECRYPT(" + columnWithTableAlias + ",?) USING UTF8)";
}
@Override
public String getEncryptBindSql() {
return "AES_ENCRYPT(?,?)";
}
@@ -28,10 +30,12 @@ public class MySqlDbEncrypt extends AbstractDbEncrypt {
private static class MyDateFunction implements DbEncryptFunction {
@Override
public String getDecryptSql(String columnWithTableAlias) {
return "STR_TO_DATE(AES_DECRYPT(" + columnWithTableAlias + ",?),'%Y%d%m')";
}
@Override
public String getEncryptBindSql() {
return "AES_ENCRYPT(DATE_FORMAT(?,'%Y%d%m'),?)";
}
@@ -2,11 +2,13 @@ package io.ebean.config.dbplatform.mysql;
import io.ebean.BackgroundExecutor;
import io.ebean.Platform;
import io.ebean.Query;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.DbPlatformType;
import io.ebean.config.dbplatform.DbType;
import io.ebean.config.dbplatform.IdType;
import io.ebean.config.dbplatform.PlatformIdGenerator;
import io.ebean.config.dbplatform.SqlErrorCodes;
import io.ebean.dbmigration.ddlgeneration.platform.MySqlDdl;
import javax.sql.DataSource;
@@ -28,7 +30,6 @@ public class MySqlPlatform extends DatabasePlatform {
super();
this.platform = Platform.MYSQL;
this.useExtraTransactionOnIterateSecondaryQueries = true;
this.likeClause = "like ? escape''";
this.selectCountWithAlias = true;
this.dbEncrypt = new MySqlDbEncrypt();
this.platformDdl = new MySqlDdl(this);
@@ -40,6 +41,13 @@ public class MySqlPlatform extends DatabasePlatform {
this.dbIdentity.setSupportsIdentity(true);
this.dbIdentity.setSupportsSequence(false);
this.exceptionTranslator =
new SqlErrorCodes()
.addAcquireLock("1205")
.addDuplicateKey("1062")
.addDataIntegrity("630","839","840","893","1169","1215","1216","1217","1364","1451","1452","1557")
.build();
this.openQuote = "`";
this.closeQuote = "`";
@@ -66,7 +74,8 @@ public class MySqlPlatform extends DatabasePlatform {
}
@Override
protected String withForUpdate(String sql) {
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
// NOWAIT and SKIP LOCKED currently not supported with MySQL
return sql + " for update";
}
}
@@ -0,0 +1,4 @@
/**
* MySql specific support.
*/
package io.ebean.config.dbplatform.mysql;
@@ -78,10 +78,12 @@ public class OracleDbEncrypt extends AbstractDbEncrypt {
this.decryptfunction = decryptfunction;
}
@Override
public String getDecryptSql(String columnWithTableAlias) {
return decryptfunction + "(" + columnWithTableAlias + ",?)";
}
@Override
public String getEncryptBindSql() {
return encryptfunction + "(?,?)";
}
@@ -101,10 +103,12 @@ public class OracleDbEncrypt extends AbstractDbEncrypt {
this.decryptfunction = decryptfunction;
}
@Override
public String getDecryptSql(String columnWithTableAlias) {
return "to_date(" + decryptfunction + "(" + columnWithTableAlias + ",?),'YYYYMMDD')";
}
@Override
public String getEncryptBindSql() {
return encryptfunction + "(to_char(?,'YYYYMMDD'),?)";
}
@@ -2,6 +2,7 @@ package io.ebean.config.dbplatform.oracle;
import io.ebean.BackgroundExecutor;
import io.ebean.Platform;
import io.ebean.Query;
import io.ebean.config.dbplatform.BasicSqlAnsiLimiter;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.DbPlatformType;
@@ -69,7 +70,14 @@ public class OraclePlatform extends DatabasePlatform {
}
@Override
protected String withForUpdate(String sql) {
return sql + " for update";
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
switch (forUpdateMode) {
case SKIPLOCKED:
return sql + " for update skip locked";
case NOWAIT:
return sql + " for update nowait";
default:
return sql + " for update";
}
}
}
@@ -20,6 +20,7 @@ public class OracleSequenceIdGenerator extends SequenceIdGenerator {
this.baseSql = "select " + seqName + ".nextval, a from (select level as a FROM dual CONNECT BY level <= ";
}
@Override
public String getSql(int batchSize) {
return baseSql + batchSize + ")";
}
@@ -0,0 +1,4 @@
/**
* Oracle specific support.
*/
package io.ebean.config.dbplatform.oracle;
@@ -15,10 +15,12 @@ public class PostgresDbEncrypt extends AbstractDbEncrypt {
private static class PgVarcharFunction implements DbEncryptFunction {
@Override
public String getDecryptSql(String columnWithTableAlias) {
return "pgp_sym_decrypt(" + columnWithTableAlias + ",?)";
}
@Override
public String getEncryptBindSql() {
return "pgp_sym_encrypt(?,?)";
}
@@ -26,10 +28,12 @@ public class PostgresDbEncrypt extends AbstractDbEncrypt {
private static class PgDateFunction implements DbEncryptFunction {
@Override
public String getDecryptSql(String columnWithTableAlias) {
return "to_date(pgp_sym_decrypt(" + columnWithTableAlias + ",?),'YYYYMMDD')";
}
@Override
public String getEncryptBindSql() {
return "pgp_sym_encrypt(to_char(?::date,'YYYYMMDD'),?)";
}
@@ -2,12 +2,14 @@ package io.ebean.config.dbplatform.postgres;
import io.ebean.BackgroundExecutor;
import io.ebean.Platform;
import io.ebean.Query;
import io.ebean.config.ServerConfig;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.DbPlatformType;
import io.ebean.config.dbplatform.DbType;
import io.ebean.config.dbplatform.IdType;
import io.ebean.config.dbplatform.PlatformIdGenerator;
import io.ebean.config.dbplatform.SqlErrorCodes;
import io.ebean.dbmigration.ddlgeneration.DdlHandler;
import io.ebean.dbmigration.ddlgeneration.platform.PostgresDdl;
@@ -26,7 +28,6 @@ public class PostgresPlatform extends DatabasePlatform {
super();
this.platform = Platform.POSTGRES;
this.supportsNativeIlike = true;
this.likeClause = "like ? escape''";
this.selectCountWithAlias = true;
this.blobDbType = Types.LONGVARBINARY;
this.clobDbType = Types.VARCHAR;
@@ -42,7 +43,12 @@ public class PostgresPlatform extends DatabasePlatform {
this.dbIdentity.setSupportsGetGeneratedKeys(true);
this.dbIdentity.setSupportsSequence(true);
//this.columnAliasPrefix = "as c";
this.exceptionTranslator =
new SqlErrorCodes()
.addAcquireLock("55P03")
.addDuplicateKey("23505")
.addDataIntegrity("23000","23502","23503","23514")
.build();
this.openQuote = "\"";
this.closeQuote = "\"";
@@ -70,6 +76,7 @@ public class PostgresPlatform extends DatabasePlatform {
dbTypeMap.put(DbType.LONGVARCHAR, dbTypeText);
}
@Override
protected void addGeoTypes(int srid) {
dbTypeMap.put(DbType.POINT, geoType("point", srid));
dbTypeMap.put(DbType.POLYGON, geoType("polygon", srid));
@@ -86,6 +93,7 @@ public class PostgresPlatform extends DatabasePlatform {
/**
* Return a DdlHandler instance for generating DDL for the specific platform.
*/
@Override
public DdlHandler createDdlHandler(ServerConfig serverConfig) {
return this.platformDdl.createDdlHandler(serverConfig);
}
@@ -100,7 +108,14 @@ public class PostgresPlatform extends DatabasePlatform {
}
@Override
protected String withForUpdate(String sql) {
return sql + " for update";
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
switch (forUpdateMode) {
case SKIPLOCKED:
return sql + " for update skip locked";
case NOWAIT:
return sql + " for update nowait";
default:
return sql + " for update";
}
}
}
@@ -20,6 +20,7 @@ public class PostgresSequenceIdGenerator extends SequenceIdGenerator {
this.baseSql = "select nextval('" + seqName + "'), s.generate_series from (select generate_series from generate_series(1,";
}
@Override
public String getSql(int batchSize) {
return baseSql + batchSize + ") ) as s";
}
@@ -0,0 +1,4 @@
/**
* Postgres specific support.
*/
package io.ebean.config.dbplatform.postgres;
@@ -9,6 +9,7 @@ import io.ebean.config.dbplatform.SqlLimiter;
*/
public class SqlAnywhereLimiter implements SqlLimiter {
@Override
public SqlLimitResponse limit(SqlLimitRequest request) {
String dbSql = request.getDbSql();
@@ -0,0 +1,4 @@
/**
* SqlAnywhere specific support.
*/
package io.ebean.config.dbplatform.sqlanywhere;
@@ -0,0 +1,4 @@
/**
* Sqlite specific support.
*/
package io.ebean.config.dbplatform.sqlite;
@@ -22,6 +22,7 @@ public class SqlServer2005SqlLimiter implements SqlLimiter {
this("as limitresult");
}
@Override
public SqlLimitResponse limit(SqlLimitRequest request) {
StringBuilder sb = new StringBuilder(500);
@@ -30,7 +31,7 @@ public class SqlServer2005SqlLimiter implements SqlLimiter {
int lastRow = request.getMaxRows();
if (lastRow > 0) {
lastRow = lastRow + firstRow;
lastRow += firstRow;
}
if (firstRow < 1) {
@@ -6,8 +6,11 @@ import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.DbPlatformType;
import io.ebean.config.dbplatform.DbType;
import io.ebean.config.dbplatform.IdType;
import io.ebean.config.dbplatform.SqlErrorCodes;
import io.ebean.dbmigration.ddlgeneration.platform.SqlServerDdl;
import java.sql.Types;
/**
* Microsoft SQL Server platform.
*/
@@ -29,9 +32,19 @@ public class SqlServerPlatform extends DatabasePlatform {
this.dbIdentity.setSupportsGetGeneratedKeys(true);
this.dbIdentity.setSupportsIdentity(true);
this.exceptionTranslator =
new SqlErrorCodes()
.addAcquireLock("1222")
.addDuplicateKey("2601","2627")
.addDataIntegrity("544","8114","8115")
.build();
this.openQuote = "[";
this.closeQuote = "]";
this.specialLikeCharacters = new char[] { '%', '_', '[' };
this.likeClause = "like ? COLLATE Latin1_General_BIN";
booleanDbType = Types.INTEGER;
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("bit default 0"));
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("integer", false));
@@ -52,4 +65,9 @@ public class SqlServerPlatform extends DatabasePlatform {
}
@Override
protected void escapeLikeCharacter(char ch, StringBuilder sb) {
sb.append('[').append(ch).append(']');
}
}
@@ -12,6 +12,7 @@ public class SqlServerSqlLimiter implements SqlLimiter {
public SqlServerSqlLimiter() {
}
@Override
public SqlLimitResponse limit(SqlLimitRequest request) {
String dbSql = request.getDbSql();
@@ -0,0 +1,4 @@
/**
* SqlServer specific support.
*/
package io.ebean.config.dbplatform.sqlserver;
@@ -263,10 +263,10 @@ public class DbMigration {
logger.info("writing repeatable script {}", fullName);
File file = new File(migrationDir, fullName);
FileWriter writer = new FileWriter(file);
writer.write(script.getValue());
writer.flush();
writer.close();
try (FileWriter writer = new FileWriter(file)) {
writer.write(script.getValue());
writer.flush();
}
}
private String repeatableMigrationName(String scriptName) {

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