Compare commits

...
Author SHA1 Message Date
Robin Bygrave 21b04c244b [maven-release-plugin] prepare release avaje-ebeanorm-4.8.1 2015-07-14 23:28:32 +12:00
Robin Bygrave 957c2def43 bump pom to 4.8.1-SNAPSHOT 2015-07-14 23:24:34 +12:00
Robin Bygrave 35f9cd3821 Bump pom to 4.8.1-SNAPSHOT 2015-07-14 23:18:51 +12:00
Robin Bygrave e95d3304bf #322 - RawSql fetch object with inheritance 2015-07-14 23:09:38 +12:00
rbygrave 0f7c9da5d2 #319 - Beans loaded without an @Id value ... return in NEW state rather than LOADED state (also refer to #317) 2015-07-09 22:18:03 +12:00
rbygrave b4008da70c #317 - RawSql getting error - Caused by: java.sql.SQLException: Column Index out of range, 0 < 1. 2015-07-09 21:44:45 +12:00
rbygrave 34a0f16c74 No effective change - bump mysql-connector-java test dependency version 2015-07-07 23:07:10 +12:00
Rob Bygrave a880109201 Merge pull request #316 from castovoid/master
Resolve NullPointerException on JtaTransacionManager constructor
2015-06-30 21:17:27 +12:00
Rob Bygrave 0607151ac8 Merge pull request #315 from ossd/patch-1
Update ScalarTypeEnumStandard.java
2015-06-30 21:15:47 +12:00
Leone Parise 5c4ad4c01c Resolve NullPointerException on JtaTransacionManager 2015-06-30 01:01:35 -03:00
ossd 3564504e00 Update ScalarTypeEnumStandard.java
Using toString() to calculate the Enum length is wrong. If you overwrite the Enum's toString() the length may be shorter. In this situation, the ddl script will create a to small varchar field for the value and you get an exception on save
2015-06-29 22:36:24 +02:00
rbygrave 49babef495 #314 - ServerCache API - change from int to long for ServerCacheStatistics (hitCount, missCount) and ServerCache remove putIfAbsent() method 2015-06-30 00:56:11 +12:00
rbygrave 9e3362d004 No effective change - tidy 2015-06-26 23:05:40 +12:00
Rob Bygrave 3f0dcdb6d1 Update README.md 2015-06-25 00:12:16 +12:00
rbygrave 481116251d [maven-release-plugin] prepare for next development iteration 2015-06-24 23:50:22 +12:00
rbygrave d490966025 [maven-release-plugin] prepare release avaje-ebeanorm-4.7.3 2015-06-24 23:50:02 +12:00
rbygrave 5bc0b01a6c #308 - Deprecate BeanFinder ... preference now to use BeanFindController 2015-06-24 23:42:35 +12:00
rbygrave 2bd14db8f7 #308 - Add BeanFindController 2015-06-24 23:36:34 +12:00
rbygrave 17a0933860 #308 - Add BeanFindController 2015-06-24 23:12:34 +12:00
rbygrave 5bb8384567 No effective change - format only 2015-06-24 22:44:08 +12:00
rbygrave 29a6bbb6e6 #312 - Ability to remove deregister BeanPersistListeners removed 2015-06-24 22:32:12 +12:00
rbygrave 46a1324f58 [maven-release-plugin] prepare for next development iteration 2015-06-22 00:22:45 +12:00
rbygrave 8f7199b586 [maven-release-plugin] prepare release avaje-ebeanorm-4.7.2 2015-06-22 00:22:23 +12:00
rbygrave d2c3142de4 WIP on Finder 2015-06-22 00:20:01 +12:00
rbygrave 721a50219d #307 - Add back support for JsonValueAdapter and JsonReadOptions into 4.x 2015-06-21 01:46:23 +12:00
Rob Bygrave f0b8270e5e Update README.md 2015-06-18 00:11:04 +12:00
rbygrave 92232c2afb [maven-release-plugin] prepare for next development iteration 2015-06-17 23:18:58 +12:00
rbygrave 5e68b1a25e [maven-release-plugin] prepare release avaje-ebeanorm-4.7.1 2015-06-17 23:18:36 +12:00
rbygrave 041324d177 #310 - Child bean with @Id long id = 0 ... when cascade saved from parent ... tries to update instead of insert resulting in OptimisticLockingException 2015-06-17 23:16:02 +12:00
rbygrave 7d02a42276 #309 - ScalarTypeConverters for Java8 time datatypes not working 2015-06-17 21:13:48 +12:00
rbygrave 2a900165f0 #305 - ENH: Add EbeanServerFactory.createWithContextClassLoader() to support OSGi 2015-06-03 20:47:58 +12:00
rbygrave e7c40e9552 No effective change - update javadoc on annotations 2015-06-01 12:26:59 +12:00
rbygrave 0d92807308 No effective change - change test code to use Long as @Version on BasicDomain 2015-06-01 12:14:20 +12:00
rbygrave 16f7de30c6 No effective change - format code 2015-06-01 12:11:53 +12:00
rbygrave 3d250b0eca No effective change - format code, tidy 2015-05-30 21:42:50 +12:00
rbygrave 8403adac90 #298 - JndiDataSourceLookup assumes java: prefix 2015-05-30 20:54:51 +12:00
rbygrave c006aa3f48 No effective change - inline String messages 2015-05-30 20:54:12 +12:00
rbygrave dcb7054248 #303 - Change beginTransaction() to use REQUIRED scope by default 2015-05-30 20:10:56 +12:00
rbygrave 12833bc918 Bump pom version to 4.7.1-SNAPSHOT 2015-05-30 19:43:15 +12:00
rbygrave 71d805bc17 #302 - Postgres specific - Rename @ColumnHstore to @DbHstore (deprecate @ColumnHstore ) 2015-05-30 19:41:54 +12:00
rbygrave ab8704e2c9 Bump version in README 2015-05-29 21:52:43 +12:00
rbygrave 327e2baae7 No effective change - format only 2015-05-29 21:52:00 +12:00
rbygrave 6e89c551d5 [maven-release-plugin] prepare for next development iteration 2015-05-29 21:17:29 +12:00
rbygrave 0a3941227f [maven-release-plugin] prepare release avaje-ebeanorm-4.6.3 2015-05-29 21:17:08 +12:00
rbygrave 0013cb1a76 #301 - MySQL specific issue - java.sql.SQLException: Streaming result set com.mysql.jdbc.RowDataDynamic@3ef4415f is still active. No statements may be issued when any streaming result sets a re open and in use on a given connection. Ensure that you have called .close() on any active streaming result sets before attempting more queries 2015-05-29 21:13:30 +12:00
rbygrave 8fe91f66c0 #300 - Stateless update with deleteMissingChildren and JDBC batched inserts on those children ... can delete newly inserted child 2015-05-29 20:51:23 +12:00
rbygrave 053fdf4abb No effective change - format and tidy 2015-05-29 20:49:55 +12:00
rbygrave 24be907dc5 No effective change - improved logging when PooledConnection.close() throws exception 2015-05-29 20:39:54 +12:00
rbygrave 6aa915b420 Fix test for cross database use 2015-05-29 20:38:38 +12:00
rbygrave 40d87af5b1 Fix test for cross database use 2015-05-29 20:38:07 +12:00
rbygrave 75082fe0c0 Fix test for cross database use 2015-05-29 20:37:12 +12:00
rbygrave 7d43f5a3d7 Fix test for cross database use 2015-05-29 20:36:51 +12:00
rbygrave 99203a35a2 No effective change - reformat and tidy 2015-05-29 00:40:47 +12:00
rbygrave 67f427b83e #299 - ENH: Add support for mapping Jackson JsonNode as JSON content to DB including Postgres JSON and JSON types 2015-05-28 22:54:32 +12:00
rbygrave f5a2cf8ff9 #297 - ENH: Add support for mapping Map<String,Object> as JSON content to DB including Postgres JSON and JSON types. 2015-05-28 00:02:57 +12:00
rbygrave 4e1cda691f No effective change - reformat and tidy 2015-05-19 01:35:27 +12:00
rbygrave 64b01324d1 No effective change - reformat and tidy 2015-05-19 01:25:51 +12:00
rbygrave 3cba238073 No effective change - reformat and tidy 2015-05-18 23:23:11 +12:00
rbygrave b5b4a4639f No effective change - reformat and tidy 2015-05-18 22:17:28 +12:00
rbygrave 2d0a179c3b No effective change - reformat and tidy 2015-05-15 00:09:19 +12:00
rbygrave 40f7a0088d No effective change - add tests for ConvertInetAddressesTest and DefaultTypeFactoryTest 2015-05-14 23:22:19 +12:00
rbygrave 6a02a8d69f No effective change - code format and tidy 2015-05-14 22:42:37 +12:00
rbygrave ed18cbcabf No effective change - add test for ConvertInetAddresses 2015-05-14 21:57:38 +12:00
Rob Bygrave 3ce4f2fb35 Merge pull request #294 from andersha/add_distinct_db2
add distinct to db2
2015-05-14 21:35:59 +12:00
Anders H. Abrahamsen 962a27f838 add distinct to db2 2015-05-13 15:52:50 +02:00
rbygrave 2b583cf707 Update README.md 2015-05-13 23:09:49 +12:00
rbygrave ef9ade4f5c [maven-release-plugin] prepare for next development iteration 2015-05-13 22:56:09 +12:00
rbygrave b1b7774a23 [maven-release-plugin] prepare release avaje-ebeanorm-4.6.2 2015-05-13 22:55:48 +12:00
rbygrave c6632bbc25 No effective change - code tidy, remove unused 2015-05-13 22:51:28 +12:00
rbygrave 8c12fc762c No effective change - code tidy, remove unused 2015-05-13 22:30:40 +12:00
rbygrave 8cb0b13ccb No effective change - code tidy, remove unused 2015-05-13 22:01:10 +12:00
rbygrave c2faffb6f4 No effective change - code tidy 2015-05-13 21:58:19 +12:00
rbygrave e17d823c17 No effective change - code tidy 2015-05-13 21:41:23 +12:00
rbygrave 9bf9338ba9 Fix for #293 - Invalid result rows when ManyToMany "fetch joined" with additional child OneToMany or ManyToMany child relationship fetched 2015-05-13 21:01:00 +12:00
rbygrave 0da764ed0c Test for #293 - Invalid result rows when ManyToMany "fetch joined" with additional child OneToMany or ManyToMany child relationship fetched 2015-05-13 21:00:10 +12:00
rbygrave 43003f4a3a No effective change - adjust test to miss cache 2015-05-13 20:54:54 +12:00
rbygrave 7081d3f54a No effective change - remove unused writer Method (left over from dynamic proxy support) 2015-05-13 20:53:51 +12:00
rbygrave cce2c2e28f No effective change - remove unused writer Method (left over from dynamic proxy support) 2015-05-13 20:52:58 +12:00
rbygrave 61ecf16978 No effective change - reformat 2015-05-11 23:59:41 +12:00
rbygrave 9ff4e63c32 #290 - Tries to register abstract class that implements custom ScalarType interface 2015-05-11 23:51:23 +12:00
rbygrave a13fd55f64 [maven-release-plugin] prepare for next development iteration 2015-05-09 08:58:08 +12:00
rbygrave a90d413e01 [maven-release-plugin] prepare release avaje-ebeanorm-4.6.1 2015-05-09 08:55:41 +12:00
rbygrave f2559f80ef #285 - ENH: support disable search classes config via ServerConfig.setDisableClasspathSearch(true) 2015-05-09 01:30:38 +12:00
rbygrave 23da6f3de8 No effective change - change newline char 2015-05-09 01:12:21 +12:00
rbygrave bdf35646a6 No effective change - change newline char 2015-05-09 01:12:09 +12:00
rbygrave f947a76fce No effective change - change newline char 2015-05-09 01:11:56 +12:00
rbygrave 88f144ec33 No effective change - change newline char 2015-05-09 01:11:44 +12:00
rbygrave 21c8dd524a No effective change - change newline char 2015-05-09 01:11:26 +12:00
rbygrave 624da4a34a No effective change - change newline char 2015-05-09 01:11:09 +12:00
rbygrave e3cccfa9a3 No effective change - change newline char 2015-05-09 01:10:56 +12:00
rbygrave 3358ab16a7 No effective change - change newline char 2015-05-09 01:10:42 +12:00
rbygrave 4eaa6adf08 No effective change - change newline char 2015-05-09 01:09:57 +12:00
rbygrave 4143c0de26 No effective change - change newline char 2015-05-09 01:09:32 +12:00
rbygrave 726d3a0c38 No effective change - change newline char 2015-05-09 01:09:16 +12:00
rbygrave 8f12bbb6c4 No effective change - change newline char 2015-05-09 01:08:53 +12:00
rbygrave 89db75e8c5 No effective change - change newline char 2015-05-09 01:08:33 +12:00
rbygrave dfb69e3cde No effective change - change newline char 2015-05-09 01:08:05 +12:00
rbygrave 39520e367d No effective change - change newline char 2015-05-09 01:07:41 +12:00
rbygrave 30d697d490 No effective change - change newline char 2015-05-09 01:06:00 +12:00
rbygrave 241a1236b8 No effective change - change newline char 2015-05-09 01:05:11 +12:00
rbygrave ccada72323 No effective change - change newline char 2015-05-09 01:03:40 +12:00
rbygrave c2ddab2ba0 No effective change - change newline char 2015-05-09 01:02:55 +12:00
rbygrave 27a0e93fda No effective change - change newline char 2015-05-09 01:01:45 +12:00
rbygrave f306672c6c No effective change - change newline char 2015-05-09 00:59:59 +12:00
rbygrave dc86b8b447 No effective change - change newline char and remove extraneous public modifiers on interfaces 2015-05-09 00:55:12 +12:00
rbygrave d63eb7abe1 No effective change - change newline char and remove extraneous public modifiers on interfaces 2015-05-09 00:51:49 +12:00
rbygrave cc200e8607 No effective change - change newline char and remove extraneous public modifiers on interfaces 2015-05-09 00:28:43 +12:00
rbygrave fffc684edd Add test for beginTransaction() with existing active transaction 2015-05-08 23:51:55 +12:00
rbygrave 82471c2573 #288 - Exclude MaxRows FirstRow in findRowCount 2015-05-08 23:49:11 +12:00
rbygrave f7fa778e99 #287 - ENH: Support nested transactions with the Ebean.beginTransaction() API 2015-05-08 21:55:49 +12:00
rbygrave fc3e1083d7 #283 - SPI change: Rename BootupEbeanManager to SpiContainer ... with a view to future exposing cluster specific methods 2015-05-01 22:06:55 +12:00
rbygrave 819edb20e8 #282 - API: Add Model.Find as alternative to Model.Finder ... which uses reflection to determine entity bean type literal 2015-05-01 21:03:38 +12:00
rbygrave e669a86135 Bump pom to 4.6.1-SNAPSHOT 2015-05-01 21:02:45 +12:00
rbygrave 4f67d2be4e Attempt to create test case for #281 - test case not failing 2015-04-30 20:30:12 +12:00
rbygrave 0356067d86 [maven-release-plugin] prepare for next development iteration 2015-04-24 23:50:25 +12:00
rbygrave 74c9c14838 [maven-release-plugin] prepare release avaje-ebeanorm-4.5.6 2015-04-24 23:50:02 +12:00
rbygrave fc53e281e8 #276 - WriteJson not write Transient properties (without using PathProperties) 2015-04-24 23:16:10 +12:00
rbygrave 0c5e092d16 Fix for #277 - please check fetchPaths not null - NPE on OrmQueryDetail.convertManyFetchJoinsToQueryJoins(OrmQueryDetail.java:331) 2015-04-24 22:18:22 +12:00
rbygrave 1260edc8ed Tweak to PrimaryServer to handle empty string defaultServerName values 2015-04-12 18:13:26 +12:00
Rob Bygrave de372bfb89 Merge pull request #270 from Ryszard-Trojnacki/master
Ability to run maven tests with diffrent databases.
2015-04-12 17:46:22 +12:00
rbygrave 2ed5e026e0 #275 - ENH: Add support for @SequenceGenerator initialValue and allocationSize 2015-04-12 12:10:57 +12:00
rbygrave 6c37dc494b Fix for #265 - java.lang.NoClassDefFoundError: Could not initialize class com.avaje.ebean.Ebean 2015-04-11 19:40:39 +12:00
rbygrave 6807499d01 Tweak test for #261 2015-04-11 19:30:05 +12:00
rbygrave cb6faa022b Fix for #260 - Trying to insert() or save() an entity with no @Id results in NPE 2015-04-11 19:16:36 +12:00
rbygrave 3b30388b35 Fix for #258 - Missing Inserts for Large Batches - Ebean 3.2.2 2015-04-11 18:55:08 +12:00
rbygrave db57404e18 #274 - Predicate using a foreign key column sometimes adds an extra join 2015-04-11 18:53:17 +12:00
rbygrave bede89fe13 Test for #269 - ENH: Add support for wildcard / startsWith jar searching 2015-04-11 11:14:48 +12:00
Ryszard-Trojnacki c9fb28b288 Added parameter datasource.default to jUnit (surefire plugin) for
changing default database in maven tests.
2015-04-02 08:29:53 +02:00
Ryszard-Trojnacki a192b0cdbf Ability to override default datasource with java parameter. 2015-04-02 08:23:33 +02:00
Rob Bygrave 0a15cdd7b2 Merge pull request #262 from ForNeVeR/issue-259
Fix issue #259
2015-04-02 11:57:57 +13:00
Rob Bygrave 14c5a1328b Merge pull request #264 from mrock42/master
Add link to Ebean ORM project website
2015-04-02 11:55:54 +13:00
Micah Schehl cac6333c5e Add Link to Ebean ORM project website 2015-03-30 00:28:47 -04:00
Micah Schehl f7d1291a41 Add Link to Ebean ORM Website 2015-03-30 00:25:20 -04:00
Friedrich von Never 151e44ff67 Add test for issue #259. 2015-03-26 23:27:21 +06:00
Friedrich von Never 4f24944ec4 Do not use getPreWhere in case of unparsed SQL.
Fixes #259.
2015-03-26 22:28:29 +06:00
rbygrave c3ccb1afb5 No effective change - reformat code whitespace etc 2015-03-22 22:05:15 +13:00
Rob Bygrave ca8f529629 Merge pull request #257 from Ryszard-Trojnacki/master
Added ability to set alias for root table of sql query and sql command exists and not exists.
2015-03-22 21:48:31 +13:00
Ryszard-Trojnacki 2e03452e2e Added SQL command "EXISTS" and "NOT EXISTS" to Ebean (ExpressionFactory,
ExpressionList).
2015-03-19 10:43:12 +01:00
Ryszard-Trojnacki f78f4ea64a Added ability to set alias for root table of sql query. 2015-03-18 10:28:54 +01:00
rbygrave 81aeca5475 [maven-release-plugin] prepare for next development iteration 2015-02-09 22:08:23 +13:00
rbygrave 36b5b3b817 [maven-release-plugin] prepare release avaje-ebeanorm-4.5.5 2015-02-09 22:08:01 +13:00
Rob Bygrave d83a70a155 Merge pull request #245 from megazord/master
Adds support to multiple methods as event listeners
2015-02-08 07:58:01 +13:00
Megazord c140574eba Adds support to multiple methods as event listeners
Fixes #244
2015-02-07 01:26:03 -02:00
rbygrave 4ab2f0df3c #238 - update to test, still not reproducing yet 2015-02-05 00:09:43 +13:00
rbygrave a447361ea0 #238 - Potential fix for stackOverflow error / recursion issue 2015-02-05 00:06:03 +13:00
rbygrave 8fc3f2da15 #238 - unsuccessful attempt to reproduce issue 238 2015-02-04 23:13:53 +13:00
rbygrave a838bc38c5 No effective change - format code 2015-02-04 21:09:12 +13:00
Rob Bygrave 84e853bcfa Merge pull request #241 from tbee/EventListenerIssue
Exceptions in events are swallowed
2015-02-04 21:06:41 +13:00
Rob Bygrave e2a508aa5e Merge pull request #242 from tbee/ClasspathreaderConfig
ebean.classpathreader is not initialized from ebean.properties
2015-02-04 21:05:42 +13:00
Tom Eugelink e9c66abfe6 ebean.classpathreader is not initialized from ebean.properties 2015-02-03 15:52:23 +01:00
Tom Eugelink 050aad717d Exceptions in events are swallowed 2015-02-03 15:47:58 +01:00
rbygrave 30e02de6f3 Fix for #236 - OptimisticLockException when saving a model the second time with joda DateTime and mysql 5.6 2015-02-03 00:57:58 +13:00
rbygrave b8a7017ffd update README with version 4.5.4 2015-02-03 00:22:57 +13:00
rbygrave da61136465 [maven-release-plugin] prepare for next development iteration 2015-02-03 00:12:19 +13:00
rbygrave 90ec7bafb3 [maven-release-plugin] prepare release avaje-ebeanorm-4.5.4 2015-02-03 00:11:56 +13:00
rbygrave c638ad8d56 Fix for #235: Stored procedures not commited 2015-02-03 00:01:18 +13:00
rbygrave 6a582c0eef No effective change - code format 2015-02-03 00:00:49 +13:00
rbygrave 0551b3066f Fix for #237: find method is returning old entity rather than updated entity in some situations 2015-02-02 23:12:37 +13:00
rbygrave af36c9ec7d No effective change - update TestQueryFindPagedList with better test case error message 2015-02-02 22:03:42 +13:00
rbygrave bd99badb28 No effective change - code cleanup of BindableProperty to remove unused parameter (property name) 2015-02-02 21:43:08 +13:00
rbygrave f7e07633a1 No effective change - format code 2015-02-02 21:30:31 +13:00
rbygrave ace45a038e Fix for #240 - Add support for using Joda LocalDateTime and DateTime with @CreatedTimestamp, @UpdatedTimestamp 2015-02-02 20:39:06 +13:00
rbygrave 36dd2bbee7 Add test for #234 - Not-trimmed values in configuration properties 2015-01-29 22:29:02 +13:00
rbygrave 71e7baff01 #232 - no effective change, format of TransactionManager only 2015-01-17 13:32:13 +13:00
rbygrave ef093b2c6c Fix for #232 - New ebean leaves connections with active transactions 2015-01-17 13:28:34 +13:00
rbygrave 14de498955 bump version in README to 4.5.3 2015-01-13 00:59:42 +13:00
rbygrave bcda8576bc [maven-release-plugin] prepare for next development iteration 2015-01-13 00:48:20 +13:00
rbygrave 0d35c8cb1b [maven-release-plugin] prepare release avaje-ebeanorm-4.5.3 2015-01-13 00:48:00 +13:00
rbygrave 6362634924 Fix for #230 - Delete with OneToOne fails with foreign key constraint violation 2015-01-13 00:43:27 +13:00
rbygrave 676a9c8d6c Fix for #229 - EbeanCacheWarmer timer not canceled 2015-01-12 20:59:32 +13:00
rbygrave b1b9f68b7e Fix for #228 - LazyLoad bug with QueryIterator. Getting EntityNotFoundException("Bean has been deleted - lazy loading failed") 2015-01-12 20:41:37 +13:00
rbygrave 961b219e3e Fix for #227 - Many2Many cache bug, incorrect query plan hash calculation 2015-01-11 20:45:07 +13:00
rbygrave a998c0be55 Fix for #226 - Json - support parsing json with unknown bean properties 2014-12-19 00:01:02 +13:00
rbygrave e0159ccb4f Modify JsonContext added support for toBean() toList() and toObject() using JsonParser 2014-12-18 22:07:47 +13:00
rbygrave 423066ada7 Update README with version 4.5.2 2014-12-18 01:14:05 +13:00
rbygrave c9d968b4b0 [maven-release-plugin] prepare for next development iteration 2014-12-18 00:46:55 +13:00
770 changed files with 92682 additions and 85930 deletions
+15 -4
View File
@@ -1,12 +1,23 @@
[![Stories in Ready](https://badge.waffle.io/ebean-orm/avaje-ebeanorm.png?label=ready&title=Ready)](https://waffle.io/ebean-orm/avaje-ebeanorm)
avaje-ebeanorm
* [![Maven Central : avaje-ebeanorm](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm) - avaje-ebeanorm
* [![Maven Central : avaje-ebeanorm-agent](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-agent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-agent) - avaje-ebeanorm-agent
* [![Maven Central : avaje-ebeanorm-agent](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-mavenenhancer/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-mavenenhancer) - avaje-ebeanorm-mavenenhancer
Ebean ORM
==============
[http://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Website")
Maven Dependency
----------------
<dependency>
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm</artifactId>
<version>4.4.1</version>
<version>4.7.3</version>
</dependency>
[Maven central - avaje-ebeanorm](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.avaje.ebeanorm%22%20AND%20a%3A%22avaje-ebeanorm%22 "maven central ebeanorm")
[Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cavaje-ebeanorm "maven central ebeanorm")
+29 -13
View File
@@ -9,7 +9,7 @@
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm</artifactId>
<version>4.5.2</version>
<version>4.8.1</version>
<packaging>jar</packaging>
<name>avaje-ebeanorm</name>
@@ -55,12 +55,21 @@
<version>1.7.7</version>
</dependency>
<!-- provided scope for JsonNode support -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.3</version>
<scope>provided</scope>
</dependency>
<!-- Jackson core used internally by Ebean -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.4.3</version>
<version>2.5.3</version>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
@@ -68,6 +77,7 @@
<scope>provided</scope>
</dependency>
<!-- provided scope to read validation annotations Size etc -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
@@ -89,6 +99,14 @@
<scope>provided</scope>
</dependency>
<!-- Provided scope for Postgres JSON/JSONB support -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4-1201-jdbc41</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp</groupId>
<artifactId>okhttp</artifactId>
@@ -124,13 +142,6 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>8.4-701.jdbc4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
@@ -141,7 +152,7 @@
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.27</version>
<version>5.1.36</version>
<scope>test</scope>
</dependency>
@@ -228,6 +239,13 @@
<include>**/*Test.java</include>
<include>**/*Tests.java</include>
</includes>
<systemProperties>
<property>
<!-- transfer datasource.default parameter -->
<name>datasource.default</name>
<value>${datasource.default}</value>
</property>
</systemProperties>
</configuration>
</plugin>
<plugin>
@@ -247,8 +265,6 @@
<configuration>
<doctitle>Ebean 4</doctitle>
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
<!-- <excludePackageNames>com.avaje.ebeaninternal.*:com.avaje.ebean.util</excludePackageNames> -->
<!--<additionalparam>-Xdoclint:none</additionalparam>-->
<source>1.8</source>
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
<excludePackageNames>com.avaje.ebeaninternal.*:com.avaje.ebean.util</excludePackageNames>
@@ -8,28 +8,28 @@ public interface AdminAutofetch {
/**
* Return true if profiling is enabled.
*/
public boolean isProfiling();
boolean isProfiling();
/**
* Set to true to enable profiling.
*/
public void setProfiling(boolean enable);
void setProfiling(boolean enable);
/**
* Return true if autoFetch automatic query tuning is enabled.
*/
public boolean isQueryTuning();
boolean isQueryTuning();
/**
* Set to true to enable autoFetch automatic query tuning.
*/
public void setQueryTuning(boolean enable);
void setQueryTuning(boolean enable);
/**
* Returns the rate which profiling is collected. This is an int between 0 and
* 100.
*/
public double getProfilingRate();
double getProfilingRate();
/**
* Set the rate at which profiling is collected after the base.
@@ -37,13 +37,13 @@ public interface AdminAutofetch {
* @param rate
* a int between 0 and 100.
*/
public void setProfilingRate(double rate);
void setProfilingRate(double rate);
/**
* Return the number of queries profiled after which profiling is collected at
* a percentage rate.
*/
public int getProfilingBase();
int getProfilingBase();
/**
* Set a base number of queries to profile per query point.
@@ -52,7 +52,7 @@ public interface AdminAutofetch {
* the Profiling Percentage rate.
* </p>
*/
public void setProfilingBase(int profilingBase);
void setProfilingBase(int profilingBase);
/**
* Return the minimum number of queries profiled before autoFetch will start
@@ -62,7 +62,7 @@ public interface AdminAutofetch {
* profiling information is collected.
* </p>
*/
public int getProfilingMin();
int getProfilingMin();
/**
* Set the minimum number of queries profiled per query point before autoFetch
@@ -72,13 +72,13 @@ public interface AdminAutofetch {
* autoFetch starts tuning the query.
* </p>
*/
public void setProfilingMin(int autoFetchMinThreshold);
void setProfilingMin(int autoFetchMinThreshold);
/**
* Fire a garbage collection (hint to the JVM). Assuming garbage collection
* fires this will gather the usage profiling information.
*/
public String collectUsageViaGC();
String collectUsageViaGC();
/**
* This will take the current profiling information and update the "tuned
@@ -89,7 +89,7 @@ public interface AdminAutofetch {
*
* @return a summary of the updates that occurred
*/
public String updateTunedQueryInfo();
String updateTunedQueryInfo();
/**
* Clear all the tuned query info.
@@ -99,7 +99,7 @@ public interface AdminAutofetch {
*
* @return the amount of tuned query information cleared.
*/
public int clearTunedQueryInfo();
int clearTunedQueryInfo();
/**
* Clear all the profiling information.
@@ -112,26 +112,26 @@ public interface AdminAutofetch {
*
* @return the amount of profiled information cleared.
*/
public int clearProfilingInfo();
int clearProfilingInfo();
/**
* Clear the query execution statistics.
*/
public void clearQueryStatistics();
void clearQueryStatistics();
/**
* Return the number of queries tuned by AutoFetch.
*/
public int getTotalTunedQueryCount();
int getTotalTunedQueryCount();
/**
* Return the size of the TuneQuery map.
*/
public int getTotalTunedQuerySize();
int getTotalTunedQuerySize();
/**
* Return the size of the profile map.
*/
public int getTotalProfileSize();
int getTotalProfileSize();
}
@@ -1,40 +1,40 @@
package com.avaje.ebean;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* Background thread pool service for executing of tasks asynchronously.
* <p>
* This service is used internally by Ebean for executing background tasks such
* as the {@link Query#findFutureList()} and also for executing background tasks
* periodically.
* </p>
* <p>
* This service has been made available so you can use it for your application
* code if you want. It can be useful for some server caching implementations
* (background population and trimming of the cache etc).
* </p>
*
* @author rbygrave
*/
public interface BackgroundExecutor {
/**
* Execute a task in the background.
*/
public void execute(Runnable r);
/**
* Execute a task periodically with a fixed delay between each execution.
* <p>
* For example, execute a runnable every minute.
* </p>
* <p>
* The delay is the time between executions no matter how long the task took.
* That is, this method has the same behaviour characteristics as
* {@link ScheduledExecutorService#scheduleWithFixedDelay(Runnable, long, long, TimeUnit)}
* </p>
*/
public void executePeriodically(Runnable r, long delay, TimeUnit unit);
}
package com.avaje.ebean;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* Background thread pool service for executing of tasks asynchronously.
* <p>
* This service is used internally by Ebean for executing background tasks such
* as the {@link Query#findFutureList()} and also for executing background tasks
* periodically.
* </p>
* <p>
* This service has been made available so you can use it for your application
* code if you want. It can be useful for some server caching implementations
* (background population and trimming of the cache etc).
* </p>
*
* @author rbygrave
*/
public interface BackgroundExecutor {
/**
* Execute a task in the background.
*/
void execute(Runnable r);
/**
* Execute a task periodically with a fixed delay between each execution.
* <p>
* For example, execute a runnable every minute.
* </p>
* <p>
* The delay is the time between executions no matter how long the task took.
* That is, this method has the same behaviour characteristics as
* {@link ScheduledExecutorService#scheduleWithFixedDelay(Runnable, long, long, TimeUnit)}
* </p>
*/
void executePeriodically(Runnable r, long delay, TimeUnit unit);
}
+85 -85
View File
@@ -1,86 +1,86 @@
package com.avaje.ebean;
import java.beans.PropertyChangeListener;
import java.util.Map;
import java.util.Set;
/**
* Provides access to the internal state of an entity bean.
*/
public interface BeanState {
/**
* Return true if this is a lazy loading reference bean.
* <p>
* If so the this bean only holds the Id property and will invoke lazy loading
* if any other property is get or set.
* </p>
*/
public boolean isReference();
/**
* Return true if the bean is new (and not yet saved).
*/
public boolean isNew();
/**
* Return true if the bean is new or dirty (and probably needs to be saved).
*/
public boolean isNewOrDirty();
/**
* Return true if the bean has been changed but not yet saved.
*/
public boolean isDirty();
/**
* For partially populated beans returns the properties that are loaded on the
* bean.
* <p>
* Accessing another property will cause lazy loading to occur.
* </p>
*/
public Set<String> getLoadedProps();
/**
* Return the set of changed properties.
*/
public Set<String> getChangedProps();
/**
* Return a map of the updated properties and their new and old values.
*/
public Map<String,ValuePair> getDirtyValues();
/**
* Return true if the bean is readOnly.
* <p>
* If a setter is called on a readOnly bean it will throw an exception.
* </p>
*/
public boolean isReadOnly();
/**
* Set the readOnly status for the bean.
*/
public void setReadOnly(boolean readOnly);
/**
* Add a propertyChangeListener.
*/
public void addPropertyChangeListener(PropertyChangeListener listener);
/**
* Remove a propertyChangeListener.
*/
public void removePropertyChangeListener(PropertyChangeListener listener);
/**
* Advanced - Used to programmatically build a partially or fully loaded
* entity bean. First create an entity bean via
* {@link EbeanServer#createEntityBean(Class)}, then populate its properties
* and then call this method specifying which properties where loaded or null
* for a fully loaded entity bean.
*/
public void setLoaded();
package com.avaje.ebean;
import java.beans.PropertyChangeListener;
import java.util.Map;
import java.util.Set;
/**
* Provides access to the internal state of an entity bean.
*/
public interface BeanState {
/**
* Return true if this is a lazy loading reference bean.
* <p>
* If so the this bean only holds the Id property and will invoke lazy loading
* if any other property is get or set.
* </p>
*/
boolean isReference();
/**
* Return true if the bean is new (and not yet saved).
*/
boolean isNew();
/**
* Return true if the bean is new or dirty (and probably needs to be saved).
*/
boolean isNewOrDirty();
/**
* Return true if the bean has been changed but not yet saved.
*/
boolean isDirty();
/**
* For partially populated beans returns the properties that are loaded on the
* bean.
* <p>
* Accessing another property will cause lazy loading to occur.
* </p>
*/
Set<String> getLoadedProps();
/**
* Return the set of changed properties.
*/
Set<String> getChangedProps();
/**
* Return a map of the updated properties and their new and old values.
*/
Map<String,ValuePair> getDirtyValues();
/**
* Return true if the bean is readOnly.
* <p>
* If a setter is called on a readOnly bean it will throw an exception.
* </p>
*/
boolean isReadOnly();
/**
* Set the readOnly status for the bean.
*/
void setReadOnly(boolean readOnly);
/**
* Add a propertyChangeListener.
*/
void addPropertyChangeListener(PropertyChangeListener listener);
/**
* Remove a propertyChangeListener.
*/
void removePropertyChangeListener(PropertyChangeListener listener);
/**
* Advanced - Used to programmatically build a partially or fully loaded
* entity bean. First create an entity bean via
* {@link EbeanServer#createEntityBean(Class)}, then populate its properties
* and then call this method specifying which properties where loaded or null
* for a fully loaded entity bean.
*/
void setLoaded();
}
+11 -12
View File
@@ -85,17 +85,17 @@ public interface CallableSql {
/**
* Set the label that is put in the transaction log.
*/
public CallableSql setLabel(String label);
CallableSql setLabel(String label);
/**
* Return the statement execution timeout.
*/
public int getTimeout();
int getTimeout();
/**
* Return the callable sql.
*/
public String getSql();
String getSql();
/**
* Set the statement execution timeout. Zero implies unlimited time.
@@ -103,12 +103,12 @@ public interface CallableSql {
* This is set to the underlying CallableStatement.
* </p>
*/
public CallableSql setTimeout(int secs);
CallableSql setTimeout(int secs);
/**
* Set the callable sql.
*/
public CallableSql setSql(String sql);
CallableSql setSql(String sql);
/**
* Bind a parameter that is bound as a IN parameter.
@@ -125,7 +125,7 @@ public interface CallableSql {
* @param value
* the value of the parameter.
*/
public CallableSql bind(int position, Object value);
CallableSql bind(int position, Object value);
/**
* Bind a positioned parameter (same as bind method).
@@ -135,7 +135,7 @@ public interface CallableSql {
* @param value
* the value of the parameter.
*/
public CallableSql setParameter(int position, Object value);
CallableSql setParameter(int position, Object value);
/**
* Register an OUT parameter.
@@ -153,7 +153,7 @@ public interface CallableSql {
* @param type
* the jdbc type of the OUT parameter that will be read.
*/
public CallableSql registerOut(int position, int type);
CallableSql registerOut(int position, int type);
/**
* Return an OUT parameter value.
@@ -165,7 +165,7 @@ public interface CallableSql {
* in batch mode you effectively can't use this method.
* </p>
*/
public Object getObject(int position);
Object getObject(int position);
/**
*
@@ -173,7 +173,7 @@ public interface CallableSql {
* stored procedure calls. This would be the case when ResultSets are returned
* etc.
*/
public boolean executeOverride(CallableStatement cstmt) throws SQLException;
boolean executeOverride(CallableStatement cstmt) throws SQLException;
/**
* Add table modification information to the TransactionEvent.
@@ -188,7 +188,6 @@ public interface CallableSql {
* delete.
* </p>
*/
public CallableSql addModification(String tableName, boolean inserts, boolean updates,
boolean deletes);
CallableSql addModification(String tableName, boolean inserts, boolean updates, boolean deletes);
}
File diff suppressed because it is too large Load Diff
+162 -106
View File
@@ -103,30 +103,30 @@ public interface EbeanServer {
* if true then deregister the JDBC driver if it is the EbeanORM
* DataSource implementation.
*/
public void shutdown(boolean shutdownDataSource, boolean deregisterDriver);
void shutdown(boolean shutdownDataSource, boolean deregisterDriver);
/**
* Return the AdminAutofetch which is used to control and configure the
* Autofetch service at runtime.
*/
public AdminAutofetch getAdminAutofetch();
AdminAutofetch getAdminAutofetch();
/**
* Return the name. This is used with {@link Ebean#getServer(String)} to get a
* EbeanServer that was registered with the Ebean singleton.
*/
public String getName();
String getName();
/**
* Return the ExpressionFactory for this server.
*/
public ExpressionFactory getExpressionFactory();
ExpressionFactory getExpressionFactory();
/**
* Return the MetaInfoManager which is used to get meta data from the EbeanServer
* such as query execution statistics.
*/
public MetaInfoManager getMetaInfoManager();
MetaInfoManager getMetaInfoManager();
/**
* Return the BeanState for a given entity bean.
@@ -134,12 +134,12 @@ public interface EbeanServer {
* This will return null if the bean is not an enhanced entity bean.
* </p>
*/
public BeanState getBeanState(Object bean);
BeanState getBeanState(Object bean);
/**
* Return the value of the Id property for a given bean.
*/
public Object getBeanId(Object bean);
Object getBeanId(Object bean);
/**
* Return a map of the differences between two objects of the same type.
@@ -148,7 +148,7 @@ public interface EbeanServer {
* difference comparison.
* </p>
*/
public Map<String, ValuePair> diff(Object a, Object b);
Map<String, ValuePair> diff(Object a, Object b);
/**
* Create a new instance of T that is an EntityBean.
@@ -157,12 +157,12 @@ public interface EbeanServer {
* favour of always using enhancement).
* </p>
*/
public <T> T createEntityBean(Class<T> type);
<T> T createEntityBean(Class<T> type);
/**
* Create a CsvReader for a given beanType.
*/
public <T> CsvReader<T> createCsvReader(Class<T> beanType);
<T> CsvReader<T> createCsvReader(Class<T> beanType);
/**
* Return a named Query that will have defined fetch paths, predicates etc.
@@ -182,7 +182,7 @@ public interface EbeanServer {
*
* }</pre>
*/
public <T> Query<T> createNamedQuery(Class<T> beanType, String namedQuery);
<T> Query<T> createNamedQuery(Class<T> beanType, String namedQuery);
/**
* Create a query using the query language.
@@ -208,14 +208,14 @@ public interface EbeanServer {
* @param query
* the object query
*/
public <T> Query<T> createQuery(Class<T> beanType, String query);
<T> Query<T> createQuery(Class<T> beanType, String query);
/**
* Create a query for an entity bean and synonym for {@link #find(Class)}.
*
* @see #find(Class)
*/
public <T> Query<T> createQuery(Class<T> beanType);
<T> Query<T> createQuery(Class<T> beanType);
/**
* Create a query for a type of entity bean.
@@ -257,7 +257,7 @@ public interface EbeanServer {
* }</pre>
*
*/
public <T> Query<T> find(Class<T> beanType);
<T> Query<T> find(Class<T> beanType);
/**
* Return the next unique identity value for a given bean type.
@@ -271,7 +271,7 @@ public interface EbeanServer {
* complex cases where it is useful to get an ID prior to some processing.
* </p>
*/
public Object nextId(Class<?> beanType);
Object nextId(Class<?> beanType);
/**
* Create a filter for sorting and filtering lists of entities locally without
@@ -283,7 +283,7 @@ public interface EbeanServer {
* Refer to {@link Filter} for an example of its use.
* </p>
*/
public <T> Filter<T> filter(Class<T> beanType);
<T> Filter<T> filter(Class<T> beanType);
/**
* Sort the list in memory using the sortByClause which can contain a comma delimited
@@ -327,7 +327,7 @@ public interface EbeanServer {
* @param sortByClause
* the properties to sort the list by
*/
public <T> void sort(List<T> list, String sortByClause);
<T> void sort(List<T> list, String sortByClause);
/**
* Create a named orm update. The update statement is specified via the
@@ -383,7 +383,7 @@ public interface EbeanServer {
*
* }</pre>
*/
public <T> Update<T> createNamedUpdate(Class<T> beanType, String namedUpdate);
<T> Update<T> createNamedUpdate(Class<T> beanType, String namedUpdate);
/**
* Create a orm update where you will supply the insert/update or delete
@@ -414,7 +414,7 @@ public interface EbeanServer {
*
* }</pre>
*/
public <T> Update<T> createUpdate(Class<T> beanType, String ormUpdate);
<T> Update<T> createUpdate(Class<T> beanType, String ormUpdate);
/**
* Create a SqlQuery for executing native sql
@@ -424,7 +424,7 @@ public interface EbeanServer {
* annotation for examples.
* </p>
*/
public SqlQuery createSqlQuery(String sql);
SqlQuery createSqlQuery(String sql);
/**
* Create a named sql query.
@@ -435,7 +435,7 @@ public interface EbeanServer {
* @param namedQuery
* the name of the query
*/
public SqlQuery createNamedSqlQuery(String namedQuery);
SqlQuery createNamedSqlQuery(String namedQuery);
/**
* Create a sql update for executing native dml statements.
@@ -451,12 +451,12 @@ public interface EbeanServer {
* xml file (named update) and use {@link #createNamedSqlUpdate(String)} .
* </p>
*/
public SqlUpdate createSqlUpdate(String sql);
SqlUpdate createSqlUpdate(String sql);
/**
* Create a CallableSql to execute a given stored procedure.
*/
public CallableSql createCallableSql(String callableSql);
CallableSql createCallableSql(String callableSql);
/**
* Create a named sql update.
@@ -477,7 +477,7 @@ public interface EbeanServer {
*
* }</pre>
*/
public SqlUpdate createNamedSqlUpdate(String namedQuery);
SqlUpdate createNamedSqlUpdate(String namedQuery);
/**
* Register a TransactionCallback on the currently active transaction.
@@ -488,7 +488,7 @@ public interface EbeanServer {
*
* @throws PersistenceException If there is no currently active transaction
*/
public void register(TransactionCallback transactionCallback) throws PersistenceException;
void register(TransactionCallback transactionCallback) throws PersistenceException;
/**
* Create a new transaction that is not held in TransactionThreadLocal.
@@ -498,7 +498,7 @@ public interface EbeanServer {
* management.
* </p>
*/
public Transaction createTransaction();
Transaction createTransaction();
/**
* Create a new transaction additionally specifying the isolation level.
@@ -506,10 +506,13 @@ public interface EbeanServer {
* Note that this transaction is NOT stored in a thread local.
* </p>
*/
public Transaction createTransaction(TxIsolation isolation);
Transaction createTransaction(TxIsolation isolation);
/**
* Start a new explicit transaction putting it into a ThreadLocal.
* Start a transaction with 'REQUIRED' semantics.
* <p>
* With REQUIRED semantics if an active transaction already exists that transaction will be used.
* </p>
* <p>
* The transaction is stored in a ThreadLocal variable and typically you only
* need to use the returned Transaction <em>IF</em> you wish to do things like
@@ -579,27 +582,80 @@ public interface EbeanServer {
* EbeanServer yourself.
* </p>
*/
public Transaction beginTransaction();
Transaction beginTransaction();
/**
* Start a transaction additionally specifying the isolation level.
*/
public Transaction beginTransaction(TxIsolation isolation);
Transaction beginTransaction(TxIsolation isolation);
/**
* Start a transaction typically specifying REQUIRES_NEW or REQUIRED semantics.
*
* <p>
* Note that this provides an try finally alternative to using {@link #execute(TxScope, TxCallable)} or
* {@link #execute(TxScope, TxRunnable)}.
* </p>
*
* <h3>REQUIRES_NEW example:</h3>
* <pre>{@code
* // Start a new transaction. If there is a current transaction
* // suspend it until this transaction ends
* Transaction txn = server.beginTransaction(TxScope.requiresNew());
* try {
*
* ...
*
* // commit the transaction
* txn.commit();
*
* } finally {
* // end this transaction which:
* // A) will rollback transaction if it has not been committed already
* // B) will restore a previously suspended transaction
* txn.end();
* }
*
* }</pre>
*
* <h3>REQUIRED example:</h3>
* <pre>{@code
*
* // start a new transaction if there is not a current transaction
* Transaction txn = server.beginTransaction(TxScope.required());
* try {
*
* ...
*
* // commit the transaction if it was created or
* // do nothing if there was already a current transaction
* txn.commit();
*
* } finally {
* // end this transaction which will rollback the transaction
* // if it was created for this try finally scope and has not
* // already been committed
* txn.end();
* }
*
* }</pre>
*/
Transaction beginTransaction(TxScope scope);
/**
* Returns the current transaction or null if there is no current transaction in scope.
*/
public Transaction currentTransaction();
Transaction currentTransaction();
/**
* Commit the current transaction.
*/
public void commitTransaction();
void commitTransaction();
/**
* Rollback the current transaction.
*/
public void rollbackTransaction();
void rollbackTransaction();
/**
* If the current transaction has already been committed do nothing otherwise
@@ -630,7 +686,7 @@ public interface EbeanServer {
* </p>
*
*/
public void endTransaction();
void endTransaction();
/**
* Refresh the values of a bean.
@@ -639,7 +695,7 @@ public interface EbeanServer {
* are accessed a lazy load will refresh the many property.
* </p>
*/
public void refresh(Object bean);
void refresh(Object bean);
/**
* Refresh a many property of an entity bean.
@@ -650,7 +706,7 @@ public interface EbeanServer {
* the 'many' property to be refreshed
*
*/
public void refreshMany(Object bean, String propertyName);
void refreshMany(Object bean, String propertyName);
/**
* Find a bean using its unique id.
@@ -700,7 +756,7 @@ public interface EbeanServer {
* @param id
* the id value
*/
public <T> T find(Class<T> beanType, Object id);
<T> T find(Class<T> beanType, Object id);
/**
* Get a reference object.
@@ -745,7 +801,7 @@ public interface EbeanServer {
* @param id
* the id value
*/
public <T> T getReference(Class<T> beanType, Object id);
<T> T getReference(Class<T> beanType, Object id);
/**
* Return the number of 'top level' or 'root' entities this query should
@@ -754,14 +810,14 @@ public interface EbeanServer {
* @see Query#findRowCount()
* @see com.avaje.ebean.Query#findFutureRowCount()
*/
public <T> int findRowCount(Query<T> query, Transaction transaction);
<T> int findRowCount(Query<T> query, Transaction transaction);
/**
* Return the Id values of the query as a List.
*
* @see com.avaje.ebean.Query#findIds()
*/
public <T> List<Object> findIds(Query<T> query, Transaction transaction);
<T> List<Object> findIds(Query<T> query, Transaction transaction);
/**
* Return a QueryIterator for the query.
@@ -779,7 +835,7 @@ public interface EbeanServer {
* @see Query#findEach(QueryEachConsumer)
* @see Query#findEachWhile(QueryEachWhileConsumer)
*/
public <T> QueryIterator<T> findIterate(Query<T> query, Transaction transaction);
<T> QueryIterator<T> findIterate(Query<T> query, Transaction transaction);
/**
* Execute the query visiting the each bean one at a time.
@@ -809,7 +865,7 @@ public interface EbeanServer {
* @see Query#findEach(QueryEachConsumer)
* @see Query#findEachWhile(QueryEachWhileConsumer)
*/
public <T> void findEach(Query<T> query, QueryEachConsumer<T> consumer, Transaction transaction);
<T> void findEach(Query<T> query, QueryEachConsumer<T> consumer, Transaction transaction);
/**
* Execute the query visiting the each bean one at a time.
@@ -846,7 +902,7 @@ public interface EbeanServer {
* @see Query#findEach(QueryEachConsumer)
* @see Query#findEachWhile(QueryEachWhileConsumer)
*/
public <T> void findEachWhile(Query<T> query, QueryEachWhileConsumer<T> consumer, Transaction transaction);
<T> void findEachWhile(Query<T> query, QueryEachWhileConsumer<T> consumer, Transaction transaction);
/**
* Deprecated in favor of #findEachWhile which is functionally exactly the same
@@ -859,7 +915,7 @@ public interface EbeanServer {
*
* @deprecated
*/
public <T> void findVisit(Query<T> query, QueryResultVisitor<T> visitor, Transaction transaction);
<T> void findVisit(Query<T> query, QueryResultVisitor<T> visitor, Transaction transaction);
/**
* Execute a query returning a list of beans.
@@ -888,7 +944,7 @@ public interface EbeanServer {
*
* @see Query#findList()
*/
public <T> List<T> findList(Query<T> query, Transaction transaction);
<T> List<T> findList(Query<T> query, Transaction transaction);
/**
* Execute find row count query in a background thread.
@@ -906,7 +962,7 @@ public interface EbeanServer {
*
* @see com.avaje.ebean.Query#findFutureRowCount()
*/
public <T> FutureRowCount<T> findFutureRowCount(Query<T> query, Transaction transaction);
<T> FutureRowCount<T> findFutureRowCount(Query<T> query, Transaction transaction);
/**
* Execute find Id's query in a background thread.
@@ -924,7 +980,7 @@ public interface EbeanServer {
*
* @see com.avaje.ebean.Query#findFutureIds()
*/
public <T> FutureIds<T> findFutureIds(Query<T> query, Transaction transaction);
<T> FutureIds<T> findFutureIds(Query<T> query, Transaction transaction);
/**
* Execute find list query in a background thread returning a FutureList object.
@@ -944,7 +1000,7 @@ public interface EbeanServer {
*
* @see Query#findFutureList()
*/
public <T> FutureList<T> findFutureList(Query<T> query, Transaction transaction);
<T> FutureList<T> findFutureList(Query<T> query, Transaction transaction);
/**
* Execute find list SQL query in a background thread.
@@ -960,7 +1016,7 @@ public interface EbeanServer {
* the transaction (can be null).
* @return a Future object for the list result of the query
*/
public SqlFutureList findFutureList(SqlQuery query, Transaction transaction);
SqlFutureList findFutureList(SqlQuery query, Transaction transaction);
/**
* Return a PagedList for this query.
@@ -983,7 +1039,7 @@ public interface EbeanServer {
*
* @see Query#findPagedList(int, int)
*/
public <T> PagedList<T> findPagedList(Query<T> query, Transaction transaction, int pageIndex, int pageSize);
<T> PagedList<T> findPagedList(Query<T> query, Transaction transaction, int pageIndex, int pageSize);
/**
* Execute the query returning a set of entity beans.
@@ -1012,7 +1068,7 @@ public interface EbeanServer {
*
* @see Query#findSet()
*/
public <T> Set<T> findSet(Query<T> query, Transaction transaction);
<T> Set<T> findSet(Query<T> query, Transaction transaction);
/**
* Execute the query returning the entity beans in a Map.
@@ -1032,7 +1088,7 @@ public interface EbeanServer {
*
* @see Query#findMap()
*/
public <T> Map<?, T> findMap(Query<T> query, Transaction transaction);
<T> Map<?, T> findMap(Query<T> query, Transaction transaction);
/**
* Execute the query returning at most one entity bean. This will throw a
@@ -1053,7 +1109,7 @@ public interface EbeanServer {
*
* @see Query#findUnique()
*/
public <T> T findUnique(Query<T> query, Transaction transaction);
<T> T findUnique(Query<T> query, Transaction transaction);
/**
* Execute the sql query returning a list of MapBean.
@@ -1071,7 +1127,7 @@ public interface EbeanServer {
*
* @see SqlQuery#findList()
*/
public List<SqlRow> findList(SqlQuery query, Transaction transaction);
List<SqlRow> findList(SqlQuery query, Transaction transaction);
/**
* Execute the sql query returning a set of MapBean.
@@ -1089,7 +1145,7 @@ public interface EbeanServer {
*
* @see SqlQuery#findSet()
*/
public Set<SqlRow> findSet(SqlQuery query, Transaction transaction);
Set<SqlRow> findSet(SqlQuery query, Transaction transaction);
/**
* Execute the sql query returning a map of MapBean.
@@ -1107,7 +1163,7 @@ public interface EbeanServer {
*
* @see SqlQuery#findMap()
*/
public Map<?, SqlRow> findMap(SqlQuery query, Transaction transaction);
Map<?, SqlRow> findMap(SqlQuery query, Transaction transaction);
/**
* Execute the sql query returning a single MapBean or null.
@@ -1129,7 +1185,7 @@ public interface EbeanServer {
*
* @see SqlQuery#findUnique()
*/
public SqlRow findUnique(SqlQuery query, Transaction transaction);
SqlRow findUnique(SqlQuery query, Transaction transaction);
/**
* Either Insert or Update the bean depending on its state.
@@ -1164,17 +1220,17 @@ public interface EbeanServer {
* will be set against each order detail when it is saved.
* </p>
*/
public void save(Object bean) throws OptimisticLockException;
void save(Object bean) throws OptimisticLockException;
/**
* Save all the beans in the iterator.
*/
public int save(Iterator<?> it) throws OptimisticLockException;
int save(Iterator<?> it) throws OptimisticLockException;
/**
* Save all the beans in the collection.
*/
public int save(Collection<?> beans) throws OptimisticLockException;
int save(Collection<?> beans) throws OptimisticLockException;
/**
* Delete the bean.
@@ -1183,38 +1239,38 @@ public interface EbeanServer {
* you automatically.
* </p>
*/
public void delete(Object bean) throws OptimisticLockException;
void delete(Object bean) throws OptimisticLockException;
/**
* Delete all the beans from an Iterator.
*/
public int delete(Iterator<?> it) throws OptimisticLockException;
int delete(Iterator<?> it) throws OptimisticLockException;
/**
* Delete all the beans in the collection.
*/
public int delete(Collection<?> c) throws OptimisticLockException;
int delete(Collection<?> c) throws OptimisticLockException;
/**
* Delete the bean given its type and id.
*/
public int delete(Class<?> beanType, Object id);
int delete(Class<?> beanType, Object id);
/**
* Delete the bean given its type and id with an explicit transaction.
*/
public int delete(Class<?> beanType, Object id, Transaction transaction);
int delete(Class<?> beanType, Object id, Transaction transaction);
/**
* Delete several beans given their type and id values.
*/
public void delete(Class<?> beanType, Collection<?> ids);
void delete(Class<?> beanType, Collection<?> ids);
/**
* Delete several beans given their type and id values with an explicit
* transaction.
*/
public void delete(Class<?> beanType, Collection<?> ids, Transaction transaction);
void delete(Class<?> beanType, Collection<?> ids, Transaction transaction);
/**
* Execute a Sql Update Delete or Insert statement. This returns the number of
@@ -1257,7 +1313,7 @@ public interface EbeanServer {
*
* @see CallableSql
*/
public int execute(SqlUpdate sqlUpdate);
int execute(SqlUpdate sqlUpdate);
/**
* Execute a ORM insert update or delete statement using the current
@@ -1266,13 +1322,13 @@ public interface EbeanServer {
* This returns the number of rows that where inserted, updated or deleted.
* </p>
*/
public int execute(Update<?> update);
int execute(Update<?> update);
/**
* Execute a ORM insert update or delete statement with an explicit
* transaction.
*/
public int execute(Update<?> update, Transaction t);
int execute(Update<?> update, Transaction t);
/**
* For making calls to stored procedures.
@@ -1299,7 +1355,7 @@ public interface EbeanServer {
* @see CallableSql
* @see Ebean#execute(SqlUpdate)
*/
public int execute(CallableSql callableSql);
int execute(CallableSql callableSql);
/**
* Inform Ebean that tables have been modified externally. These could be the
@@ -1335,7 +1391,7 @@ public interface EbeanServer {
* @param deleted
* true if rows on the table where deleted
*/
public void externalModification(String tableName, boolean inserted, boolean updated, boolean deleted);
void externalModification(String tableName, boolean inserted, boolean updated, boolean deleted);
/**
* Find a entity bean with an explicit transaction.
@@ -1349,22 +1405,22 @@ public interface EbeanServer {
* @param transaction
* the transaction to use (can be null)
*/
public <T> T find(Class<T> beanType, Object uid, Transaction transaction);
<T> T find(Class<T> beanType, Object uid, Transaction transaction);
/**
* Insert or update a bean with an explicit transaction.
*/
public void save(Object bean, Transaction transaction) throws OptimisticLockException;
void save(Object bean, Transaction transaction) throws OptimisticLockException;
/**
* Save all the beans in the iterator with an explicit transaction.
*/
public int save(Iterator<?> it, Transaction transaction) throws OptimisticLockException;
int save(Iterator<?> it, Transaction transaction) throws OptimisticLockException;
/**
* Save all the beans in the collection with an explicit transaction.
*/
public int save(Collection<?> beans, Transaction transaction) throws OptimisticLockException;
int save(Collection<?> beans, Transaction transaction) throws OptimisticLockException;
/**
* Marks the entity bean as dirty.
@@ -1386,7 +1442,7 @@ public interface EbeanServer {
*
* }</pre>
*/
public void markAsDirty(Object bean);
void markAsDirty(Object bean);
/**
* Saves the bean using an update. If you know you are updating a bean then it is preferrable to
@@ -1424,12 +1480,12 @@ public interface EbeanServer {
* @see ServerConfig#setUpdatesDeleteMissingChildren(boolean)
* @see ServerConfig#setUpdateChangesOnly(boolean)
*/
public void update(Object bean) throws OptimisticLockException;
void update(Object bean) throws OptimisticLockException;
/**
* Update a bean additionally specifying a transaction.
*/
public void update(Object bean, Transaction t) throws OptimisticLockException;
void update(Object bean, Transaction t) throws OptimisticLockException;
/**
* Update a bean additionally specifying a transaction and the deleteMissingChildren setting.
@@ -1443,18 +1499,18 @@ public interface EbeanServer {
* or ManyToMany to be automatically deleted.
*/
public void update(Object bean, Transaction transaction, boolean deleteMissingChildren) throws OptimisticLockException;
void update(Object bean, Transaction transaction, boolean deleteMissingChildren) throws OptimisticLockException;
/**
* Update a collection of beans. If there is no current transaction one is created and used to
* update all the beans in the collection.
*/
public void update(Collection<?> beans) throws OptimisticLockException;
void update(Collection<?> beans) throws OptimisticLockException;
/**
* Update a collection of beans with an explicit transaction.
*/
public void update(Collection<?> beans, Transaction transaction) throws OptimisticLockException;
void update(Collection<?> beans, Transaction transaction) throws OptimisticLockException;
/**
* Insert the bean.
@@ -1464,23 +1520,23 @@ public interface EbeanServer {
* and want to insert them into another database (and you want to explicitly insert them).
* </p>
*/
public void insert(Object bean);
void insert(Object bean);
/**
* Insert the bean with a transaction.
*/
public void insert(Object bean, Transaction t);
void insert(Object bean, Transaction t);
/**
* Insert a collection of beans. If there is no current transaction one is created and used to
* insert all the beans in the collection.
*/
public void insert(Collection<?> beans);
void insert(Collection<?> beans);
/**
* Insert a collection of beans with an explicit transaction.
*/
public void insert(Collection<?> beans, Transaction t);
void insert(Collection<?> beans, Transaction t);
/**
* Delete the associations (from the intersection table) of a ManyToMany given
@@ -1492,7 +1548,7 @@ public interface EbeanServer {
*
* @return the number of associations deleted (from the intersection table).
*/
public int deleteManyToManyAssociations(Object ownerBean, String propertyName);
int deleteManyToManyAssociations(Object ownerBean, String propertyName);
/**
* Delete the associations (from the intersection table) of a ManyToMany given
@@ -1507,7 +1563,7 @@ public interface EbeanServer {
*
* @return the number of associations deleted (from the intersection table).
*/
public int deleteManyToManyAssociations(Object ownerBean, String propertyName, Transaction t);
int deleteManyToManyAssociations(Object ownerBean, String propertyName, Transaction t);
/**
* Save the associations of a ManyToMany given the owner bean and the
@@ -1518,7 +1574,7 @@ public interface EbeanServer {
* way to invoke those insertions directly.
* </p>
*/
public void saveManyToManyAssociations(Object ownerBean, String propertyName);
void saveManyToManyAssociations(Object ownerBean, String propertyName);
/**
* Save the associations of a ManyToMany given the owner bean and the
@@ -1529,7 +1585,7 @@ public interface EbeanServer {
* way to invoke those insertions directly.
* </p>
*/
public void saveManyToManyAssociations(Object ownerBean, String propertyName, Transaction t);
void saveManyToManyAssociations(Object ownerBean, String propertyName, Transaction t);
/**
* Save the associated collection or bean given the property name.
@@ -1547,7 +1603,7 @@ public interface EbeanServer {
* @param propertyName
* the property we want to save
*/
public void saveAssociation(Object ownerBean, String propertyName);
void saveAssociation(Object ownerBean, String propertyName);
/**
* Save the associated collection or bean given the property name with a
@@ -1566,27 +1622,27 @@ public interface EbeanServer {
* @param propertyName
* the property we want to save
*/
public void saveAssociation(Object ownerBean, String propertyName, Transaction t);
void saveAssociation(Object ownerBean, String propertyName, Transaction t);
/**
* Delete the bean with an explicit transaction.
*/
public void delete(Object bean, Transaction t) throws OptimisticLockException;
void delete(Object bean, Transaction t) throws OptimisticLockException;
/**
* Delete all the beans from an iterator.
*/
public int delete(Iterator<?> it, Transaction t) throws OptimisticLockException;
int delete(Iterator<?> it, Transaction t) throws OptimisticLockException;
/**
* Execute explicitly passing a transaction.
*/
public int execute(SqlUpdate updSql, Transaction t);
int execute(SqlUpdate updSql, Transaction t);
/**
* Execute explicitly passing a transaction.
*/
public int execute(CallableSql callableSql, Transaction t);
int execute(CallableSql callableSql, Transaction t);
/**
* Execute a TxRunnable in a Transaction with an explicit scope.
@@ -1609,7 +1665,7 @@ public interface EbeanServer {
*
* }</pre>
*/
public void execute(TxScope scope, TxRunnable r);
void execute(TxScope scope, TxRunnable r);
/**
* Execute a TxRunnable in a Transaction with the default scope.
@@ -1635,7 +1691,7 @@ public interface EbeanServer {
*
* }</pre>
*/
public void execute(TxRunnable r);
void execute(TxRunnable r);
/**
* Execute a TxCallable in a Transaction with an explicit scope.
@@ -1659,7 +1715,7 @@ public interface EbeanServer {
*
* }</pre>
*/
public <T> T execute(TxScope scope, TxCallable<T> c);
<T> T execute(TxScope scope, TxCallable<T> c);
/**
* Execute a TxCallable in a Transaction with the default scope.
@@ -1691,19 +1747,19 @@ public interface EbeanServer {
*
* }</pre>
*/
public <T> T execute(TxCallable<T> c);
<T> T execute(TxCallable<T> c);
/**
* Return the manager of the server cache ("L2" cache).
*
*/
public ServerCacheManager getServerCacheManager();
ServerCacheManager getServerCacheManager();
/**
* Return the BackgroundExecutor service for asynchronous processing of
* queries.
*/
public BackgroundExecutor getBackgroundExecutor();
BackgroundExecutor getBackgroundExecutor();
/**
* Run the cache warming queries on all bean types that have one defined.
@@ -1711,7 +1767,7 @@ public interface EbeanServer {
* A cache warming query can be defined via {@link CacheStrategy}.
* </p>
*/
public void runCacheWarming();
void runCacheWarming();
/**
* Run the cache warming query for a specific bean type.
@@ -1719,13 +1775,13 @@ public interface EbeanServer {
* A cache warming query can be defined via {@link CacheStrategy}.
* </p>
*/
public void runCacheWarming(Class<?> beanType);
void runCacheWarming(Class<?> beanType);
/**
* Return the JsonContext for reading/writing JSON.
* @deprecated Please use #json instead.
*/
public JsonContext createJsonContext();
JsonContext createJsonContext();
/**
* Return the JsonContext for reading/writing JSON.
@@ -1765,6 +1821,6 @@ public interface EbeanServer {
* @see com.avaje.ebean.text.PathProperties
* @see Query#apply(com.avaje.ebean.text.PathProperties)
*/
public JsonContext json();
JsonContext json();
}
@@ -1,119 +1,148 @@
package com.avaje.ebean;
import com.avaje.ebean.common.BootupEbeanManager;
import com.avaje.ebean.config.ContainerConfig;
import com.avaje.ebean.config.ServerConfig;
import javax.persistence.PersistenceException;
import java.lang.reflect.Constructor;
import java.util.Properties;
/**
* Creates EbeanServer instances.
* <p>
* This uses either a ServerConfig or properties in the ebean.properties file to
* configure and create a EbeanServer instance.
* </p>
* <p>
* The EbeanServer instance can either be registered with the Ebean singleton or
* not. The Ebean singleton effectively holds a map of EbeanServers by a name.
* If the EbeanServer is registered with the Ebean singleton you can retrieve it
* later via {@link Ebean#getServer(String)}.
* </p>
* <p>
* One EbeanServer can be nominated as the 'default/primary' EbeanServer. Many
* methods on the Ebean singleton such as {@link Ebean#find(Class)} are just a
* convenient way of using the 'default/primary' EbeanServer.
* </p>
*/
public class EbeanServerFactory {
private static BootupEbeanManager bootupEbeanManager;
/**
* Initialise the container with clustering configuration.
*
* Call this prior to creating any EbeanServer instances or alternatively set the
* ContainerConfig on the ServerConfig when creating the first EbeanServer instance.
*/
public static synchronized void initialiseContainer(ContainerConfig containerConfig) {
getServerFactory(containerConfig);
}
/**
* Create using ebean.properties to configure the server.
*/
public static synchronized EbeanServer create(String name) {
// construct based on loading properties files
// and if invoked by Ebean then it handles registration
BootupEbeanManager serverFactory = getServerFactory(null);
return serverFactory.createServer(name);
}
/**
* Create using the ServerConfig object to configure the server.
*/
public static synchronized EbeanServer create(ServerConfig config) {
if (config.getName() == null) {
throw new PersistenceException("The name is null (it is required)");
}
EbeanServer server = createInternal(config);
if (config.isDefaultServer()) {
PrimaryServer.setSkip(true);
}
if (config.isRegister()) {
Ebean.register(server, config.isDefaultServer());
}
return server;
}
private static EbeanServer createInternal(ServerConfig config) {
return getServerFactory(config.getContainerConfig()).createServer(config);
}
/**
* Get the BootupEbeanManager initialising it if necessary.
*
* @param containerConfig the configuration controlling clustering communication
*/
private static BootupEbeanManager getServerFactory(ContainerConfig containerConfig) {
if (bootupEbeanManager != null) {
return bootupEbeanManager;
}
if (containerConfig == null) {
// effectively load configuration from ebean.properties
Properties properties = PrimaryServer.getProperties();
containerConfig = new ContainerConfig();
containerConfig.loadFromProperties(properties);
}
bootupEbeanManager = createServerFactory(containerConfig);
return bootupEbeanManager;
}
/**
* Create the container instance using the configuration.
*/
private static BootupEbeanManager createServerFactory(ContainerConfig containerConfig) {
String dflt = "com.avaje.ebeaninternal.server.core.DefaultServerFactory";
String implClassName = System.getProperty("ebean.serverfactory", dflt);
try {
Class<?> cls = Class.forName(implClassName);
Constructor<?> constructor = cls.getConstructor(ContainerConfig.class);
return (BootupEbeanManager) constructor.newInstance(containerConfig);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
package com.avaje.ebean;
import com.avaje.ebean.common.SpiContainer;
import com.avaje.ebean.config.ContainerConfig;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebeaninternal.server.lib.ShutdownManager;
import javax.persistence.PersistenceException;
import java.lang.reflect.Constructor;
import java.util.Properties;
/**
* Creates EbeanServer instances.
* <p>
* This uses either a ServerConfig or properties in the ebean.properties file to
* configure and create a EbeanServer instance.
* </p>
* <p>
* The EbeanServer instance can either be registered with the Ebean singleton or
* not. The Ebean singleton effectively holds a map of EbeanServers by a name.
* If the EbeanServer is registered with the Ebean singleton you can retrieve it
* later via {@link Ebean#getServer(String)}.
* </p>
* <p>
* One EbeanServer can be nominated as the 'default/primary' EbeanServer. Many
* methods on the Ebean singleton such as {@link Ebean#find(Class)} are just a
* convenient way of using the 'default/primary' EbeanServer.
* </p>
*/
public class EbeanServerFactory {
private static final String DEFAULT_CONTAINER = "com.avaje.ebeaninternal.server.core.DefaultContainer";
private static SpiContainer container;
/**
* Initialise the container with clustering configuration.
*
* Call this prior to creating any EbeanServer instances or alternatively set the
* ContainerConfig on the ServerConfig when creating the first EbeanServer instance.
*/
public static synchronized void initialiseContainer(ContainerConfig containerConfig) {
getContainer(containerConfig);
}
/**
* Create using ebean.properties to configure the server.
*/
public static synchronized EbeanServer create(String name) {
// construct based on loading properties files
// and if invoked by Ebean then it handles registration
SpiContainer serverFactory = getContainer(null);
return serverFactory.createServer(name);
}
/**
* Create using the ServerConfig object to configure the server.
*/
public static synchronized EbeanServer create(ServerConfig config) {
if (config.getName() == null) {
throw new PersistenceException("The name is null (it is required)");
}
EbeanServer server = createInternal(config);
if (config.isDefaultServer()) {
PrimaryServer.setSkip(true);
}
if (config.isRegister()) {
Ebean.register(server, config.isDefaultServer());
}
return server;
}
/**
* Create using the ServerConfig additionally specifying a classLoader to use as the context class loader.
*/
public static synchronized EbeanServer createWithContextClassLoader(ServerConfig config, ClassLoader classLoader) {
ClassLoader currentContextLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);
try {
return EbeanServerFactory.create(config);
} finally {
// set the currentContextLoader back
Thread.currentThread().setContextClassLoader(currentContextLoader);
}
}
/**
* Shutdown gracefully all EbeanServers cleaning up any resources as required.
* <p>
* This is typically invoked via JVM shutdown hook and not explicitly called.
* </p>
*/
public static synchronized void shutdown() {
ShutdownManager.shutdown();
}
private static EbeanServer createInternal(ServerConfig config) {
return getContainer(config.getContainerConfig()).createServer(config);
}
/**
* Get the EbeanContainer initialising it if necessary.
*
* @param containerConfig the configuration controlling clustering communication
*/
private static SpiContainer getContainer(ContainerConfig containerConfig) {
// thread safe in that all calling methods are synchronized
if (container != null) {
return container;
}
if (containerConfig == null) {
// effectively load configuration from ebean.properties
Properties properties = PrimaryServer.getProperties();
containerConfig = new ContainerConfig();
containerConfig.loadFromProperties(properties);
}
container = createContainer(containerConfig);
return container;
}
/**
* Create the container instance using the configuration.
*/
private static SpiContainer createContainer(ContainerConfig containerConfig) {
String implClassName = System.getProperty("ebean.container", DEFAULT_CONTAINER);
try {
Class<?> cls = Class.forName(implClassName);
Constructor<?> constructor = cls.getConstructor(ContainerConfig.class);
return (SpiContainer) constructor.newInstance(containerConfig);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
@@ -1,93 +1,93 @@
package com.avaje.ebean;
/**
* Query by Example expression.
* <p>
* Pass in an example entity and for each non-null scalar properties an
* expression is added.
* </p>
* <p>
* By Default this case sensitive, will ignore numeric zero values and will use
* a Like for string values (you must put in your own wildcards).
* </p>
* <p>
* To get control over the options you can create an ExampleExpression and set
* those options such as case insensitive etc.
* </p>
*
* <pre class="code">
* // create an example bean and set the properties
* // with the query parameters you want
* Customer example = new Customer();
* example.setName(&quot;Rob%&quot;);
* example.setNotes(&quot;%something%&quot;);
*
* List&lt;Customer&gt; list =
* Ebean.find(Customer.class)
* .where()
* // pass the bean into the where() clause
* .exampleLike(example)
* // you can add other expressions to the same query
* .gt(&quot;id&quot;, 2)
* .findList();
*
* </pre>
*
* Similarly you can create an ExampleExpression
*
* <pre>
* Customer example = new Customer();
* example.setName(&quot;Rob%&quot;);
* example.setNotes(&quot;%something%&quot;);
*
* // create a ExampleExpression with more control
* ExampleExpression qbe = new ExampleExpression(example, true, LikeType.EQUAL_TO)
* .includeZeros();
*
* List&lt;Customer&gt; list =
* Ebean.find(Customer.class)
* .where()
* .add(qbe)
* .findList();
* </pre>
*
* @author Rob Bygrave
*/
public interface ExampleExpression extends Expression {
/**
* By calling this method zero value properties are going to be included in
* the expression.
* <p>
* By default numeric zero values are excluded as they can result from
* primitive int and long types.
* </p>
*/
public ExampleExpression includeZeros();
/**
* Set case insensitive to true.
*/
public ExampleExpression caseInsensitive();
/**
* Use startsWith expression for string properties.
*/
public ExampleExpression useStartsWith();
/**
* Use contains expression for string properties.
*/
public ExampleExpression useContains();
/**
* Use endsWith expression for string properties.
*/
public ExampleExpression useEndsWith();
/**
* Use equal to expression for string properties.
*/
public ExampleExpression useEqualTo();
package com.avaje.ebean;
/**
* Query by Example expression.
* <p>
* Pass in an example entity and for each non-null scalar properties an
* expression is added.
* </p>
* <p>
* By Default this case sensitive, will ignore numeric zero values and will use
* a Like for string values (you must put in your own wildcards).
* </p>
* <p>
* To get control over the options you can create an ExampleExpression and set
* those options such as case insensitive etc.
* </p>
*
* <pre class="code">
* // create an example bean and set the properties
* // with the query parameters you want
* Customer example = new Customer();
* example.setName(&quot;Rob%&quot;);
* example.setNotes(&quot;%something%&quot;);
*
* List&lt;Customer&gt; list =
* Ebean.find(Customer.class)
* .where()
* // pass the bean into the where() clause
* .exampleLike(example)
* // you can add other expressions to the same query
* .gt(&quot;id&quot;, 2)
* .findList();
*
* </pre>
*
* Similarly you can create an ExampleExpression
*
* <pre>
* Customer example = new Customer();
* example.setName(&quot;Rob%&quot;);
* example.setNotes(&quot;%something%&quot;);
*
* // create a ExampleExpression with more control
* ExampleExpression qbe = new ExampleExpression(example, true, LikeType.EQUAL_TO)
* .includeZeros();
*
* List&lt;Customer&gt; list =
* Ebean.find(Customer.class)
* .where()
* .add(qbe)
* .findList();
* </pre>
*
* @author Rob Bygrave
*/
public interface ExampleExpression extends Expression {
/**
* By calling this method zero value properties are going to be included in
* the expression.
* <p>
* By default numeric zero values are excluded as they can result from
* primitive int and long types.
* </p>
*/
ExampleExpression includeZeros();
/**
* Set case insensitive to true.
*/
ExampleExpression caseInsensitive();
/**
* Use startsWith expression for string properties.
*/
ExampleExpression useStartsWith();
/**
* Use contains expression for string properties.
*/
ExampleExpression useContains();
/**
* Use endsWith expression for string properties.
*/
ExampleExpression useEndsWith();
/**
* Use equal to expression for string properties.
*/
ExampleExpression useEqualTo();
}
+322 -322
View File
@@ -1,322 +1,322 @@
package com.avaje.ebean;
import java.util.Collection;
import java.util.Map;
/**
* Expression factory for creating standard expressions for WHERE and HAVING
* clauses.
* <p>
* Generally you will only need to use this object for creating OR, JUNCTION or
* CONJUNCTION expressions. To create simple expressions you will most likely
* just use the methods on the ExpressionList object that is returned via
* {@link Query#where()}.
* </p>
* <p>
* This provides a convenient way to create expressions for the 'Default'
* server. It is actually a short cut for using the ExpressionFactory of the
* 'default' EbeanServer.
* <p>
* See also {@link Ebean#getExpressionFactory()}
* </p>
* <p>
* Creates standard common expressions for using in a Query Where or Having
* clause.
* </p>
*
* <pre class="code">
* // Example: Using an Expr.or() method
* Query&lt;Order&gt; query = Ebean.createQuery(Order.class);
* query.where(
* Expr.or(Expr.eq(&quot;status&quot;, Order.NEW),
* Expr.gt(&quot;orderDate&quot;, lastWeek));
*
* List&lt;Order&gt; list = query.findList();
* ...
* </pre>
*
* @see Query#where()
* @author Rob Bygrave
*/
public class Expr {
private Expr() {
}
/**
* Equal To - property equal to the given value.
*/
public static Expression eq(String propertyName, Object value) {
return Ebean.getExpressionFactory().eq(propertyName, value);
}
/**
* Not Equal To - property not equal to the given value.
*/
public static Expression ne(String propertyName, Object value) {
return Ebean.getExpressionFactory().ne(propertyName, value);
}
/**
* Case Insensitive Equal To - property equal to the given value (typically
* using a lower() function to make it case insensitive).
*/
public static Expression ieq(String propertyName, String value) {
return Ebean.getExpressionFactory().ieq(propertyName, value);
}
/**
* Between - property between the two given values.
*/
public static Expression between(String propertyName, Object value1, Object value2) {
return Ebean.getExpressionFactory().between(propertyName, value1, value2);
}
/**
* Between - value between two given properties.
*/
public static Expression between(String lowProperty, String highProperty, Object value) {
return Ebean.getExpressionFactory().betweenProperties(lowProperty, highProperty, value);
}
/**
* Greater Than - property greater than the given value.
*/
public static Expression gt(String propertyName, Object value) {
return Ebean.getExpressionFactory().gt(propertyName, value);
}
/**
* Greater Than or Equal to - property greater than or equal to the given
* value.
*/
public static Expression ge(String propertyName, Object value) {
return Ebean.getExpressionFactory().ge(propertyName, value);
}
/**
* Less Than - property less than the given value.
*/
public static Expression lt(String propertyName, Object value) {
return Ebean.getExpressionFactory().lt(propertyName, value);
}
/**
* Less Than or Equal to - property less than or equal to the given value.
*/
public static Expression le(String propertyName, Object value) {
return Ebean.getExpressionFactory().le(propertyName, value);
}
/**
* Is Null - property is null.
*/
public static Expression isNull(String propertyName) {
return Ebean.getExpressionFactory().isNull(propertyName);
}
/**
* Is Not Null - property is not null.
*/
public static Expression isNotNull(String propertyName) {
return Ebean.getExpressionFactory().isNotNull(propertyName);
}
/**
* Case insensitive {@link #exampleLike(Object)}
*/
public static ExampleExpression iexampleLike(Object example) {
return Ebean.getExpressionFactory().iexampleLike(example);
}
/**
* Create the query by Example expression which is case sensitive and using
* LikeType.RAW (you need to add you own wildcards % and _).
*/
public static ExampleExpression exampleLike(Object example) {
return Ebean.getExpressionFactory().exampleLike(example);
}
/**
* Create the query by Example expression specifying more options.
*/
public static ExampleExpression exampleLike(Object example, boolean caseInsensitive,
LikeType likeType) {
return Ebean.getExpressionFactory().exampleLike(example, caseInsensitive, likeType);
}
/**
* Like - property like value where the value contains the SQL wild card
* characters % (percentage) and _ (underscore).
*/
public static Expression like(String propertyName, String value) {
return Ebean.getExpressionFactory().like(propertyName, value);
}
/**
* Case insensitive Like - property like value where the value contains the
* SQL wild card characters % (percentage) and _ (underscore). Typically uses
* a lower() function to make the expression case insensitive.
*/
public static Expression ilike(String propertyName, String value) {
return Ebean.getExpressionFactory().ilike(propertyName, value);
}
/**
* Starts With - property like value%.
*/
public static Expression startsWith(String propertyName, String value) {
return Ebean.getExpressionFactory().startsWith(propertyName, value);
}
/**
* Case insensitive Starts With - property like value%. Typically uses a
* lower() function to make the expression case insensitive.
*/
public static Expression istartsWith(String propertyName, String value) {
return Ebean.getExpressionFactory().istartsWith(propertyName, value);
}
/**
* Ends With - property like %value.
*/
public static Expression endsWith(String propertyName, String value) {
return Ebean.getExpressionFactory().endsWith(propertyName, value);
}
/**
* Case insensitive Ends With - property like %value. Typically uses a lower()
* function to make the expression case insensitive.
*/
public static Expression iendsWith(String propertyName, String value) {
return Ebean.getExpressionFactory().iendsWith(propertyName, value);
}
/**
* Contains - property like %value%.
*/
public static Expression contains(String propertyName, String value) {
return Ebean.getExpressionFactory().contains(propertyName, value);
}
/**
* Case insensitive Contains - property like %value%. Typically uses a lower()
* function to make the expression case insensitive.
*/
public static Expression icontains(String propertyName, String value) {
return Ebean.getExpressionFactory().icontains(propertyName, value);
}
/**
* In - property has a value in the array of values.
*/
public static Expression in(String propertyName, Object[] values) {
return Ebean.getExpressionFactory().in(propertyName, values);
}
/**
* In - using a subQuery.
*/
public static Expression in(String propertyName, Query<?> subQuery) {
return Ebean.getExpressionFactory().in(propertyName, subQuery);
}
/**
* In - property has a value in the collection of values.
*/
public static Expression in(String propertyName, Collection<?> values) {
return Ebean.getExpressionFactory().in(propertyName, values);
}
/**
* Id Equal to - ID property is equal to the value.
*/
public static Expression idEq(Object value) {
return Ebean.getExpressionFactory().idEq(value);
}
/**
* All Equal - Map containing property names and their values.
* <p>
* Expression where all the property names in the map are equal to the
* corresponding value.
* </p>
*
* @param propertyMap
* a map keyed by property names.
*/
public static Expression allEq(Map<String, Object> propertyMap) {
return Ebean.getExpressionFactory().allEq(propertyMap);
}
/**
* Add raw expression with a single parameter.
* <p>
* The raw expression should contain a single ? at the location of the
* parameter.
* </p>
*/
public static Expression raw(String raw, Object value) {
return Ebean.getExpressionFactory().raw(raw, value);
}
/**
* Add raw expression with an array of parameters.
* <p>
* The raw expression should contain the same number of ? as there are
* parameters.
* </p>
*/
public static Expression raw(String raw, Object[] values) {
return Ebean.getExpressionFactory().raw(raw, values);
}
/**
* Add raw expression with no parameters.
*/
public static Expression raw(String raw) {
return Ebean.getExpressionFactory().raw(raw);
}
/**
* And - join two expressions with a logical and.
*/
public static Expression and(Expression expOne, Expression expTwo) {
return Ebean.getExpressionFactory().and(expOne, expTwo);
}
/**
* Or - join two expressions with a logical or.
*/
public static Expression or(Expression expOne, Expression expTwo) {
return Ebean.getExpressionFactory().or(expOne, expTwo);
}
/**
* Negate the expression (prefix it with NOT).
*/
public static Expression not(Expression exp) {
return Ebean.getExpressionFactory().not(exp);
}
/**
* Return a list of expressions that will be joined by AND's.
*/
public static <T> Junction<T> conjunction(Query<T> query) {
return Ebean.getExpressionFactory().conjunction(query);
}
/**
* Return a list of expressions that will be joined by OR's.
*/
public static <T> Junction<T> disjunction(Query<T> query) {
return Ebean.getExpressionFactory().disjunction(query);
}
}
package com.avaje.ebean;
import java.util.Collection;
import java.util.Map;
/**
* Expression factory for creating standard expressions for WHERE and HAVING
* clauses.
* <p>
* Generally you will only need to use this object for creating OR, JUNCTION or
* CONJUNCTION expressions. To create simple expressions you will most likely
* just use the methods on the ExpressionList object that is returned via
* {@link Query#where()}.
* </p>
* <p>
* This provides a convenient way to create expressions for the 'Default'
* server. It is actually a short cut for using the ExpressionFactory of the
* 'default' EbeanServer.
* <p>
* See also {@link Ebean#getExpressionFactory()}
* </p>
* <p>
* Creates standard common expressions for using in a Query Where or Having
* clause.
* </p>
*
* <pre class="code">
* // Example: Using an Expr.or() method
* Query&lt;Order&gt; query = Ebean.createQuery(Order.class);
* query.where(
* Expr.or(Expr.eq(&quot;status&quot;, Order.NEW),
* Expr.gt(&quot;orderDate&quot;, lastWeek));
*
* List&lt;Order&gt; list = query.findList();
* ...
* </pre>
*
* @see Query#where()
* @author Rob Bygrave
*/
public class Expr {
private Expr() {
}
/**
* Equal To - property equal to the given value.
*/
public static Expression eq(String propertyName, Object value) {
return Ebean.getExpressionFactory().eq(propertyName, value);
}
/**
* Not Equal To - property not equal to the given value.
*/
public static Expression ne(String propertyName, Object value) {
return Ebean.getExpressionFactory().ne(propertyName, value);
}
/**
* Case Insensitive Equal To - property equal to the given value (typically
* using a lower() function to make it case insensitive).
*/
public static Expression ieq(String propertyName, String value) {
return Ebean.getExpressionFactory().ieq(propertyName, value);
}
/**
* Between - property between the two given values.
*/
public static Expression between(String propertyName, Object value1, Object value2) {
return Ebean.getExpressionFactory().between(propertyName, value1, value2);
}
/**
* Between - value between two given properties.
*/
public static Expression between(String lowProperty, String highProperty, Object value) {
return Ebean.getExpressionFactory().betweenProperties(lowProperty, highProperty, value);
}
/**
* Greater Than - property greater than the given value.
*/
public static Expression gt(String propertyName, Object value) {
return Ebean.getExpressionFactory().gt(propertyName, value);
}
/**
* Greater Than or Equal to - property greater than or equal to the given
* value.
*/
public static Expression ge(String propertyName, Object value) {
return Ebean.getExpressionFactory().ge(propertyName, value);
}
/**
* Less Than - property less than the given value.
*/
public static Expression lt(String propertyName, Object value) {
return Ebean.getExpressionFactory().lt(propertyName, value);
}
/**
* Less Than or Equal to - property less than or equal to the given value.
*/
public static Expression le(String propertyName, Object value) {
return Ebean.getExpressionFactory().le(propertyName, value);
}
/**
* Is Null - property is null.
*/
public static Expression isNull(String propertyName) {
return Ebean.getExpressionFactory().isNull(propertyName);
}
/**
* Is Not Null - property is not null.
*/
public static Expression isNotNull(String propertyName) {
return Ebean.getExpressionFactory().isNotNull(propertyName);
}
/**
* Case insensitive {@link #exampleLike(Object)}
*/
public static ExampleExpression iexampleLike(Object example) {
return Ebean.getExpressionFactory().iexampleLike(example);
}
/**
* Create the query by Example expression which is case sensitive and using
* LikeType.RAW (you need to add you own wildcards % and _).
*/
public static ExampleExpression exampleLike(Object example) {
return Ebean.getExpressionFactory().exampleLike(example);
}
/**
* Create the query by Example expression specifying more options.
*/
public static ExampleExpression exampleLike(Object example, boolean caseInsensitive,
LikeType likeType) {
return Ebean.getExpressionFactory().exampleLike(example, caseInsensitive, likeType);
}
/**
* Like - property like value where the value contains the SQL wild card
* characters % (percentage) and _ (underscore).
*/
public static Expression like(String propertyName, String value) {
return Ebean.getExpressionFactory().like(propertyName, value);
}
/**
* Case insensitive Like - property like value where the value contains the
* SQL wild card characters % (percentage) and _ (underscore). Typically uses
* a lower() function to make the expression case insensitive.
*/
public static Expression ilike(String propertyName, String value) {
return Ebean.getExpressionFactory().ilike(propertyName, value);
}
/**
* Starts With - property like value%.
*/
public static Expression startsWith(String propertyName, String value) {
return Ebean.getExpressionFactory().startsWith(propertyName, value);
}
/**
* Case insensitive Starts With - property like value%. Typically uses a
* lower() function to make the expression case insensitive.
*/
public static Expression istartsWith(String propertyName, String value) {
return Ebean.getExpressionFactory().istartsWith(propertyName, value);
}
/**
* Ends With - property like %value.
*/
public static Expression endsWith(String propertyName, String value) {
return Ebean.getExpressionFactory().endsWith(propertyName, value);
}
/**
* Case insensitive Ends With - property like %value. Typically uses a lower()
* function to make the expression case insensitive.
*/
public static Expression iendsWith(String propertyName, String value) {
return Ebean.getExpressionFactory().iendsWith(propertyName, value);
}
/**
* Contains - property like %value%.
*/
public static Expression contains(String propertyName, String value) {
return Ebean.getExpressionFactory().contains(propertyName, value);
}
/**
* Case insensitive Contains - property like %value%. Typically uses a lower()
* function to make the expression case insensitive.
*/
public static Expression icontains(String propertyName, String value) {
return Ebean.getExpressionFactory().icontains(propertyName, value);
}
/**
* In - property has a value in the array of values.
*/
public static Expression in(String propertyName, Object[] values) {
return Ebean.getExpressionFactory().in(propertyName, values);
}
/**
* In - using a subQuery.
*/
public static Expression in(String propertyName, Query<?> subQuery) {
return Ebean.getExpressionFactory().in(propertyName, subQuery);
}
/**
* In - property has a value in the collection of values.
*/
public static Expression in(String propertyName, Collection<?> values) {
return Ebean.getExpressionFactory().in(propertyName, values);
}
/**
* Id Equal to - ID property is equal to the value.
*/
public static Expression idEq(Object value) {
return Ebean.getExpressionFactory().idEq(value);
}
/**
* All Equal - Map containing property names and their values.
* <p>
* Expression where all the property names in the map are equal to the
* corresponding value.
* </p>
*
* @param propertyMap
* a map keyed by property names.
*/
public static Expression allEq(Map<String, Object> propertyMap) {
return Ebean.getExpressionFactory().allEq(propertyMap);
}
/**
* Add raw expression with a single parameter.
* <p>
* The raw expression should contain a single ? at the location of the
* parameter.
* </p>
*/
public static Expression raw(String raw, Object value) {
return Ebean.getExpressionFactory().raw(raw, value);
}
/**
* Add raw expression with an array of parameters.
* <p>
* The raw expression should contain the same number of ? as there are
* parameters.
* </p>
*/
public static Expression raw(String raw, Object[] values) {
return Ebean.getExpressionFactory().raw(raw, values);
}
/**
* Add raw expression with no parameters.
*/
public static Expression raw(String raw) {
return Ebean.getExpressionFactory().raw(raw);
}
/**
* And - join two expressions with a logical and.
*/
public static Expression and(Expression expOne, Expression expTwo) {
return Ebean.getExpressionFactory().and(expOne, expTwo);
}
/**
* Or - join two expressions with a logical or.
*/
public static Expression or(Expression expOne, Expression expTwo) {
return Ebean.getExpressionFactory().or(expOne, expTwo);
}
/**
* Negate the expression (prefix it with NOT).
*/
public static Expression not(Expression exp) {
return Ebean.getExpressionFactory().not(exp);
}
/**
* Return a list of expressions that will be joined by AND's.
*/
public static <T> Junction<T> conjunction(Query<T> query) {
return Ebean.getExpressionFactory().conjunction(query);
}
/**
* Return a list of expressions that will be joined by OR's.
*/
public static <T> Junction<T> disjunction(Query<T> query) {
return Ebean.getExpressionFactory().disjunction(query);
}
}
+10 -10
View File
@@ -1,10 +1,10 @@
package com.avaje.ebean;
import java.io.Serializable;
/**
* An expression that is part of a WHERE or HAVING clause.
*/
public interface Expression extends Serializable {
}
package com.avaje.ebean;
import java.io.Serializable;
/**
* An expression that is part of a WHERE or HAVING clause.
*/
public interface Expression extends Serializable {
}
@@ -1,252 +1,262 @@
package com.avaje.ebean;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* Expression factory for creating standard expressions.
* <p>
* Creates standard common expressions for using in a Query Where or Having
* clause.
* </p>
* <p>
* You will often not use this class directly but instead just add expressions
* via the methods on ExpressionList such as
* {@link ExpressionList#gt(String, Object)}.
* </p>
* <p>
* The ExpressionList is returned from {@link Query#where()}.
* </p>
*
* <pre class="code">
* // Example: fetch orders where status equals new or orderDate > lastWeek.
*
* Expression newOrLastWeek =
* Expr.or(Expr.eq(&quot;status&quot;, Order.Status.NEW),
* Expr.gt(&quot;orderDate&quot;, lastWeek));
*
* Query&lt;Order&gt; query = Ebean.createQuery(Order.class);
* query.where().add(newOrLastWeek);
* List&lt;Order&gt; list = query.findList();
* ...
* </pre>
*
* @see Query#where()
*/
public interface ExpressionFactory {
/**
* Equal To - property equal to the given value.
*/
public Expression eq(String propertyName, Object value);
/**
* Not Equal To - property not equal to the given value.
*/
public Expression ne(String propertyName, Object value);
/**
* Case Insensitive Equal To - property equal to the given value (typically
* using a lower() function to make it case insensitive).
*/
public Expression ieq(String propertyName, String value);
/**
* Between - property between the two given values.
*/
public Expression between(String propertyName, Object value1, Object value2);
/**
* Between - value between two given properties.
*/
public Expression betweenProperties(String lowProperty, String highProperty, Object value);
/**
* Greater Than - property greater than the given value.
*/
public Expression gt(String propertyName, Object value);
/**
* Greater Than or Equal to - property greater than or equal to the given
* value.
*/
public Expression ge(String propertyName, Object value);
/**
* Less Than - property less than the given value.
*/
public Expression lt(String propertyName, Object value);
/**
* Less Than or Equal to - property less than or equal to the given value.
*/
public Expression le(String propertyName, Object value);
/**
* Is Null - property is null.
*/
public Expression isNull(String propertyName);
/**
* Is Not Null - property is not null.
*/
public Expression isNotNull(String propertyName);
/**
* Case insensitive {@link #exampleLike(Object)}
*/
public ExampleExpression iexampleLike(Object example);
/**
* Create the query by Example expression which is case sensitive and using
* LikeType.RAW (you need to add you own wildcards % and _).
*/
public ExampleExpression exampleLike(Object example);
/**
* Create the query by Example expression specifying more options.
*/
public ExampleExpression exampleLike(Object example, boolean caseInsensitive, LikeType likeType);
/**
* Like - property like value where the value contains the SQL wild card
* characters % (percentage) and _ (underscore).
*/
public Expression like(String propertyName, String value);
/**
* Case insensitive Like - property like value where the value contains the
* SQL wild card characters % (percentage) and _ (underscore). Typically uses
* a lower() function to make the expression case insensitive.
*/
public Expression ilike(String propertyName, String value);
/**
* Starts With - property like value%.
*/
public Expression startsWith(String propertyName, String value);
/**
* Case insensitive Starts With - property like value%. Typically uses a
* lower() function to make the expression case insensitive.
*/
public Expression istartsWith(String propertyName, String value);
/**
* Ends With - property like %value.
*/
public Expression endsWith(String propertyName, String value);
/**
* Case insensitive Ends With - property like %value. Typically uses a lower()
* function to make the expression case insensitive.
*/
public Expression iendsWith(String propertyName, String value);
/**
* Contains - property like %value%.
*/
public Expression contains(String propertyName, String value);
/**
* Case insensitive Contains - property like %value%. Typically uses a lower()
* function to make the expression case insensitive.
*/
public Expression icontains(String propertyName, String value);
/**
* In - property has a value in the array of values.
*/
public Expression in(String propertyName, Object[] values);
/**
* In - using a subQuery.
*/
public Expression in(String propertyName, Query<?> subQuery);
/**
* In - property has a value in the collection of values.
*/
public Expression in(String propertyName, Collection<?> values);
/**
* Id Equal to - ID property is equal to the value.
*/
public Expression idEq(Object value);
/**
* Id IN a list of Id values.
*/
public Expression idIn(List<?> idList);
/**
* All Equal - Map containing property names and their values.
* <p>
* Expression where all the property names in the map are equal to the
* corresponding value.
* </p>
*
* @param propertyMap
* a map keyed by property names.
*/
public Expression allEq(Map<String, Object> propertyMap);
/**
* Add raw expression with a single parameter.
* <p>
* The raw expression should contain a single ? at the location of the
* parameter.
* </p>
*/
public Expression raw(String raw, Object value);
/**
* Add raw expression with an array of parameters.
* <p>
* The raw expression should contain the same number of ? as there are
* parameters.
* </p>
*/
public Expression raw(String raw, Object[] values);
/**
* Add raw expression with no parameters.
*/
public Expression raw(String raw);
/**
* And - join two expressions with a logical and.
*/
public Expression and(Expression expOne, Expression expTwo);
/**
* Or - join two expressions with a logical or.
*/
public Expression or(Expression expOne, Expression expTwo);
/**
* Negate the expression (prefix it with NOT).
*/
public Expression not(Expression exp);
/**
* Return a list of expressions that will be joined by AND's.
*/
public <T> Junction<T> conjunction(Query<T> query);
/**
* Return a list of expressions that will be joined by OR's.
*/
public <T> Junction<T> disjunction(Query<T> query);
/**
* Return a list of expressions that will be joined by AND's.
*/
public <T> Junction<T> conjunction(Query<T> query, ExpressionList<T> parent);
/**
* Return a list of expressions that will be joined by OR's.
*/
public <T> Junction<T> disjunction(Query<T> query, ExpressionList<T> parent);
}
package com.avaje.ebean;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* Expression factory for creating standard expressions.
* <p>
* Creates standard common expressions for using in a Query Where or Having
* clause.
* </p>
* <p>
* You will often not use this class directly but instead just add expressions
* via the methods on ExpressionList such as
* {@link ExpressionList#gt(String, Object)}.
* </p>
* <p>
* The ExpressionList is returned from {@link Query#where()}.
* </p>
*
* <pre class="code">
* // Example: fetch orders where status equals new or orderDate > lastWeek.
*
* Expression newOrLastWeek =
* Expr.or(Expr.eq(&quot;status&quot;, Order.Status.NEW),
* Expr.gt(&quot;orderDate&quot;, lastWeek));
*
* Query&lt;Order&gt; query = Ebean.createQuery(Order.class);
* query.where().add(newOrLastWeek);
* List&lt;Order&gt; list = query.findList();
* ...
* </pre>
*
* @see Query#where()
*/
public interface ExpressionFactory {
/**
* Equal To - property equal to the given value.
*/
Expression eq(String propertyName, Object value);
/**
* Not Equal To - property not equal to the given value.
*/
Expression ne(String propertyName, Object value);
/**
* Case Insensitive Equal To - property equal to the given value (typically
* using a lower() function to make it case insensitive).
*/
Expression ieq(String propertyName, String value);
/**
* Between - property between the two given values.
*/
Expression between(String propertyName, Object value1, Object value2);
/**
* Between - value between two given properties.
*/
Expression betweenProperties(String lowProperty, String highProperty, Object value);
/**
* Greater Than - property greater than the given value.
*/
Expression gt(String propertyName, Object value);
/**
* Greater Than or Equal to - property greater than or equal to the given
* value.
*/
Expression ge(String propertyName, Object value);
/**
* Less Than - property less than the given value.
*/
Expression lt(String propertyName, Object value);
/**
* Less Than or Equal to - property less than or equal to the given value.
*/
Expression le(String propertyName, Object value);
/**
* Is Null - property is null.
*/
Expression isNull(String propertyName);
/**
* Is Not Null - property is not null.
*/
Expression isNotNull(String propertyName);
/**
* Case insensitive {@link #exampleLike(Object)}
*/
ExampleExpression iexampleLike(Object example);
/**
* Create the query by Example expression which is case sensitive and using
* LikeType.RAW (you need to add you own wildcards % and _).
*/
ExampleExpression exampleLike(Object example);
/**
* Create the query by Example expression specifying more options.
*/
ExampleExpression exampleLike(Object example, boolean caseInsensitive, LikeType likeType);
/**
* Like - property like value where the value contains the SQL wild card
* characters % (percentage) and _ (underscore).
*/
Expression like(String propertyName, String value);
/**
* Case insensitive Like - property like value where the value contains the
* SQL wild card characters % (percentage) and _ (underscore). Typically uses
* a lower() function to make the expression case insensitive.
*/
Expression ilike(String propertyName, String value);
/**
* Starts With - property like value%.
*/
Expression startsWith(String propertyName, String value);
/**
* Case insensitive Starts With - property like value%. Typically uses a
* lower() function to make the expression case insensitive.
*/
Expression istartsWith(String propertyName, String value);
/**
* Ends With - property like %value.
*/
Expression endsWith(String propertyName, String value);
/**
* Case insensitive Ends With - property like %value. Typically uses a lower()
* function to make the expression case insensitive.
*/
Expression iendsWith(String propertyName, String value);
/**
* Contains - property like %value%.
*/
Expression contains(String propertyName, String value);
/**
* Case insensitive Contains - property like %value%. Typically uses a lower()
* function to make the expression case insensitive.
*/
Expression icontains(String propertyName, String value);
/**
* In - property has a value in the array of values.
*/
Expression in(String propertyName, Object[] values);
/**
* In - using a subQuery.
*/
Expression in(String propertyName, Query<?> subQuery);
/**
* In - property has a value in the collection of values.
*/
Expression in(String propertyName, Collection<?> values);
/**
* Exists expression
*/
Expression exists(Query<?> subQuery);
/**
* Not exists expression
*/
Expression notExists(Query<?> subQuery);
/**
* Id Equal to - ID property is equal to the value.
*/
Expression idEq(Object value);
/**
* Id IN a list of Id values.
*/
Expression idIn(List<?> idList);
/**
* All Equal - Map containing property names and their values.
* <p>
* Expression where all the property names in the map are equal to the
* corresponding value.
* </p>
*
* @param propertyMap
* a map keyed by property names.
*/
Expression allEq(Map<String, Object> propertyMap);
/**
* Add raw expression with a single parameter.
* <p>
* The raw expression should contain a single ? at the location of the
* parameter.
* </p>
*/
Expression raw(String raw, Object value);
/**
* Add raw expression with an array of parameters.
* <p>
* The raw expression should contain the same number of ? as there are
* parameters.
* </p>
*/
Expression raw(String raw, Object[] values);
/**
* Add raw expression with no parameters.
*/
Expression raw(String raw);
/**
* And - join two expressions with a logical and.
*/
Expression and(Expression expOne, Expression expTwo);
/**
* Or - join two expressions with a logical or.
*/
Expression or(Expression expOne, Expression expTwo);
/**
* Negate the expression (prefix it with NOT).
*/
Expression not(Expression exp);
/**
* Return a list of expressions that will be joined by AND's.
*/
<T> Junction<T> conjunction(Query<T> query);
/**
* Return a list of expressions that will be joined by OR's.
*/
<T> Junction<T> disjunction(Query<T> query);
/**
* Return a list of expressions that will be joined by AND's.
*/
<T> Junction<T> conjunction(Query<T> query, ExpressionList<T> parent);
/**
* Return a list of expressions that will be joined by OR's.
*/
<T> Junction<T> disjunction(Query<T> query, ExpressionList<T> parent);
}
File diff suppressed because it is too large Load Diff
+252 -252
View File
@@ -1,252 +1,252 @@
package com.avaje.ebean;
import java.io.Serializable;
/**
* Defines the configuration options for a "query fetch" or a
* "lazy loading fetch". This gives you the ability to use multiple smaller
* queries to populate an object graph as opposed to a single large query.
* <p>
* The primary goal is to provide efficient ways of loading complex object
* graphs avoiding SQL Cartesian product and issues around populating object
* graphs that have multiple *ToMany relationships.
* </p>
* <p>
* It also provides the ability to control the lazy loading queries (batch size,
* selected properties and fetches) to avoid N+1 queries etc.
* <p>
* There can also be cases loading across a single OneToMany where 2 SQL queries
* using Ebean FetchConfig.query() can be more efficient than one SQL query.
* When the "One" side is wide (lots of columns) and the cardinality difference
* is high (a lot of "Many" beans per "One" bean) then this can be more
* efficient loaded as 2 SQL queries.
* </p>
*
* <pre class="code">
* // Normal fetch join results in a single SQL query
* List&lt;Order&gt; list = Ebean.find(Order.class).fetch(&quot;details&quot;).findList();
*
* // Find Orders join details using a single SQL query
* </pre>
* <p>
* Example: Using a "query join" instead of a "fetch join" we instead use 2 SQL
* queries
* </p>
*
* <pre class="code">
* // This will use 2 SQL queries to build this object graph
* List&lt;Order&gt; list =
* Ebean.find(Order.class)
* .fetch(&quot;details&quot;, new FetchConfig().query())
* .findList();
*
* // query 1) find order
* // query 2) find orderDetails where order.id in (?,?...) // first 100 order id's
* </pre>
* <p>
* Example: Using 2 "query joins"
* </p>
*
* <pre class="code">
* // This will use 3 SQL queries to build this object graph
* List&lt;Order&gt; list =
* Ebean.find(Order.class)
* .fetch(&quot;details&quot;, new FetchConfig().query())
* .fetch(&quot;customer&quot;, new FetchConfig().queryFirst(5))
* .findList();
*
* // query 1) find order
* // query 2) find orderDetails where order.id in (?,?...) // first 100 order id's
* // query 3) find customer where id in (?,?,?,?,?) // first 5 customers
* </pre>
* <p>
* Example: Using "query joins" and partial objects
* </p>
*
* <pre class="code">
* // This will use 3 SQL queries to build this object graph
* List&lt;Order&gt; list =
* Ebean.find(Order.class)
* .select(&quot;status, shipDate&quot;)
* .fetch(&quot;details&quot;, &quot;quantity, price&quot;, new FetchConfig().query())
* .fetch(&quot;details.product&quot;, &quot;sku, name&quot;)
* .fetch(&quot;customer&quot;, &quot;name&quot;, new FetchConfig().queryFirst(5))
* .fetch(&quot;customer.contacts&quot;)
* .fetch(&quot;customer.shippingAddress&quot;)
* .findList();
*
* // query 1) find order (status, shipDate)
* // query 2) find orderDetail (quantity, price) fetch product (sku, name) where
* // order.id in (?,? ...)
* // query 3) find customer (name) fetch contacts (*) fetch shippingAddress (*)
* // where id in (?,?,?,?,?)
*
* // Note: the fetch of &quot;details.product&quot; is automatically included into the
* // fetch of &quot;details&quot;
* //
* // Note: the fetch of &quot;customer.contacts&quot; and &quot;customer.shippingAddress&quot;
* // are automatically included in the fetch of &quot;customer&quot;
* </pre>
* <p>
* You can use query() and lazy together on a single join. The query is executed
* immediately and the lazy defines the batch size to use for further lazy
* loading (if lazy loading is invoked).
* </p>
*
* <pre class="code">
* List&lt;Order&gt; list =
* Ebean.find(Order.class)
* .fetch(&quot;customer&quot;, new FetchConfig().query(10).lazy(5))
* .findList();
*
* // query 1) find order
* // query 2) find customer where id in (?,?,?,?,?,?,?,?,?,?) // first 10 customers
* // .. then if lazy loading of customers is invoked
* // .. use a batch size of 5 to load the customers
*
* </pre>
*
* <p>
* Example of controlling the lazy loading query:
* </p>
* <p>
* This gives us the ability to optimise the lazy loading query for a given use
* case.
* </p>
*
* <pre class="code">
* List&lt;Order&gt; list = Ebean.find(Order.class)
* .fetch(&quot;customer&quot;,&quot;name&quot;, new FetchConfig().lazy(5))
* .fetch(&quot;customer.contacts&quot;,&quotcontactName, phone, email&quot)
* .fetch(&quot;customer.shippingAddress&quot;)
* .where().eq(&quot;status&quot;,Order.Status.NEW)
* .findList();
*
* // query 1) find order where status = Order.Status.NEW
* //
* // .. if lazy loading of customers is invoked
* // .. use a batch size of 5 to load the customers
*
* find customer (name)
* fetch customer.contacts (contactName, phone, email)
* fetch customer.shippingAddress (*)
* where id in (?,?,?,?,?)
*
* </pre>
*
* @author mario
* @author rbygrave
*/
public class FetchConfig implements Serializable {
private static final long serialVersionUID = 1L;
private int lazyBatchSize = -1;
private int queryBatchSize = -1;
private boolean queryAll;
/**
* Construct the fetch configuration object.
*/
public FetchConfig() {
}
/**
* Specify that this path should be lazy loaded using the default batch load
* size.
*/
public FetchConfig lazy() {
this.lazyBatchSize = 0;
this.queryAll = false;
return this;
}
/**
* Specify that this path should be lazy loaded with a specified batch size.
*
* @param lazyBatchSize
* the batch size for lazy loading
*/
public FetchConfig lazy(int lazyBatchSize) {
this.lazyBatchSize = lazyBatchSize;
this.queryAll = false;
return this;
}
/**
* Eagerly fetch the beans in this path as a separate query (rather than as
* part of the main query).
* <p>
* This will use the default batch size for separate query which is 100.
* </p>
*/
public FetchConfig query() {
this.queryBatchSize = 0;
this.queryAll = true;
return this;
}
/**
* Eagerly fetch the beans in this path as a separate query (rather than as
* part of the main query).
* <p>
* The queryBatchSize is the number of parent id's that this separate query
* will load per batch.
* </p>
* <p>
* This will load all beans on this path eagerly unless a {@link #lazy(int)}
* is also used.
* </p>
*
* @param queryBatchSize
* the batch size used to load beans on this path
*/
public FetchConfig query(int queryBatchSize) {
this.queryBatchSize = queryBatchSize;
// queryAll true as long as a lazy batch size has not already been set
this.queryAll = (lazyBatchSize == -1);
return this;
}
/**
* Eagerly fetch the first batch of beans on this path.
* This is similar to {@link #query(int)} but only fetches the first batch.
* <p>
* If there are more parent beans than the batch size then they will not be
* loaded eagerly but instead use lazy loading.
* </p>
*
* @param queryBatchSize
* the number of parent beans this path is populated for
*/
public FetchConfig queryFirst(int queryBatchSize) {
this.queryBatchSize = queryBatchSize;
this.queryAll = false;
return this;
}
/**
* Return the batch size for lazy loading.
*/
public int getLazyBatchSize() {
return lazyBatchSize;
}
/**
* Return the batch size for separate query load.
*/
public int getQueryBatchSize() {
return queryBatchSize;
}
/**
* Return true if the query fetch should fetch 'all' rather than just the
* 'first' batch.
*/
public boolean isQueryAll() {
return queryAll;
}
}
package com.avaje.ebean;
import java.io.Serializable;
/**
* Defines the configuration options for a "query fetch" or a
* "lazy loading fetch". This gives you the ability to use multiple smaller
* queries to populate an object graph as opposed to a single large query.
* <p>
* The primary goal is to provide efficient ways of loading complex object
* graphs avoiding SQL Cartesian product and issues around populating object
* graphs that have multiple *ToMany relationships.
* </p>
* <p>
* It also provides the ability to control the lazy loading queries (batch size,
* selected properties and fetches) to avoid N+1 queries etc.
* <p>
* There can also be cases loading across a single OneToMany where 2 SQL queries
* using Ebean FetchConfig.query() can be more efficient than one SQL query.
* When the "One" side is wide (lots of columns) and the cardinality difference
* is high (a lot of "Many" beans per "One" bean) then this can be more
* efficient loaded as 2 SQL queries.
* </p>
*
* <pre class="code">
* // Normal fetch join results in a single SQL query
* List&lt;Order&gt; list = Ebean.find(Order.class).fetch(&quot;details&quot;).findList();
*
* // Find Orders join details using a single SQL query
* </pre>
* <p>
* Example: Using a "query join" instead of a "fetch join" we instead use 2 SQL
* queries
* </p>
*
* <pre class="code">
* // This will use 2 SQL queries to build this object graph
* List&lt;Order&gt; list =
* Ebean.find(Order.class)
* .fetch(&quot;details&quot;, new FetchConfig().query())
* .findList();
*
* // query 1) find order
* // query 2) find orderDetails where order.id in (?,?...) // first 100 order id's
* </pre>
* <p>
* Example: Using 2 "query joins"
* </p>
*
* <pre class="code">
* // This will use 3 SQL queries to build this object graph
* List&lt;Order&gt; list =
* Ebean.find(Order.class)
* .fetch(&quot;details&quot;, new FetchConfig().query())
* .fetch(&quot;customer&quot;, new FetchConfig().queryFirst(5))
* .findList();
*
* // query 1) find order
* // query 2) find orderDetails where order.id in (?,?...) // first 100 order id's
* // query 3) find customer where id in (?,?,?,?,?) // first 5 customers
* </pre>
* <p>
* Example: Using "query joins" and partial objects
* </p>
*
* <pre class="code">
* // This will use 3 SQL queries to build this object graph
* List&lt;Order&gt; list =
* Ebean.find(Order.class)
* .select(&quot;status, shipDate&quot;)
* .fetch(&quot;details&quot;, &quot;quantity, price&quot;, new FetchConfig().query())
* .fetch(&quot;details.product&quot;, &quot;sku, name&quot;)
* .fetch(&quot;customer&quot;, &quot;name&quot;, new FetchConfig().queryFirst(5))
* .fetch(&quot;customer.contacts&quot;)
* .fetch(&quot;customer.shippingAddress&quot;)
* .findList();
*
* // query 1) find order (status, shipDate)
* // query 2) find orderDetail (quantity, price) fetch product (sku, name) where
* // order.id in (?,? ...)
* // query 3) find customer (name) fetch contacts (*) fetch shippingAddress (*)
* // where id in (?,?,?,?,?)
*
* // Note: the fetch of &quot;details.product&quot; is automatically included into the
* // fetch of &quot;details&quot;
* //
* // Note: the fetch of &quot;customer.contacts&quot; and &quot;customer.shippingAddress&quot;
* // are automatically included in the fetch of &quot;customer&quot;
* </pre>
* <p>
* You can use query() and lazy together on a single join. The query is executed
* immediately and the lazy defines the batch size to use for further lazy
* loading (if lazy loading is invoked).
* </p>
*
* <pre class="code">
* List&lt;Order&gt; list =
* Ebean.find(Order.class)
* .fetch(&quot;customer&quot;, new FetchConfig().query(10).lazy(5))
* .findList();
*
* // query 1) find order
* // query 2) find customer where id in (?,?,?,?,?,?,?,?,?,?) // first 10 customers
* // .. then if lazy loading of customers is invoked
* // .. use a batch size of 5 to load the customers
*
* </pre>
*
* <p>
* Example of controlling the lazy loading query:
* </p>
* <p>
* This gives us the ability to optimise the lazy loading query for a given use
* case.
* </p>
*
* <pre class="code">
* List&lt;Order&gt; list = Ebean.find(Order.class)
* .fetch(&quot;customer&quot;,&quot;name&quot;, new FetchConfig().lazy(5))
* .fetch(&quot;customer.contacts&quot;,&quotcontactName, phone, email&quot)
* .fetch(&quot;customer.shippingAddress&quot;)
* .where().eq(&quot;status&quot;,Order.Status.NEW)
* .findList();
*
* // query 1) find order where status = Order.Status.NEW
* //
* // .. if lazy loading of customers is invoked
* // .. use a batch size of 5 to load the customers
*
* find customer (name)
* fetch customer.contacts (contactName, phone, email)
* fetch customer.shippingAddress (*)
* where id in (?,?,?,?,?)
*
* </pre>
*
* @author mario
* @author rbygrave
*/
public class FetchConfig implements Serializable {
private static final long serialVersionUID = 1L;
private int lazyBatchSize = -1;
private int queryBatchSize = -1;
private boolean queryAll;
/**
* Construct the fetch configuration object.
*/
public FetchConfig() {
}
/**
* Specify that this path should be lazy loaded using the default batch load
* size.
*/
public FetchConfig lazy() {
this.lazyBatchSize = 0;
this.queryAll = false;
return this;
}
/**
* Specify that this path should be lazy loaded with a specified batch size.
*
* @param lazyBatchSize
* the batch size for lazy loading
*/
public FetchConfig lazy(int lazyBatchSize) {
this.lazyBatchSize = lazyBatchSize;
this.queryAll = false;
return this;
}
/**
* Eagerly fetch the beans in this path as a separate query (rather than as
* part of the main query).
* <p>
* This will use the default batch size for separate query which is 100.
* </p>
*/
public FetchConfig query() {
this.queryBatchSize = 0;
this.queryAll = true;
return this;
}
/**
* Eagerly fetch the beans in this path as a separate query (rather than as
* part of the main query).
* <p>
* The queryBatchSize is the number of parent id's that this separate query
* will load per batch.
* </p>
* <p>
* This will load all beans on this path eagerly unless a {@link #lazy(int)}
* is also used.
* </p>
*
* @param queryBatchSize
* the batch size used to load beans on this path
*/
public FetchConfig query(int queryBatchSize) {
this.queryBatchSize = queryBatchSize;
// queryAll true as long as a lazy batch size has not already been set
this.queryAll = (lazyBatchSize == -1);
return this;
}
/**
* Eagerly fetch the first batch of beans on this path.
* This is similar to {@link #query(int)} but only fetches the first batch.
* <p>
* If there are more parent beans than the batch size then they will not be
* loaded eagerly but instead use lazy loading.
* </p>
*
* @param queryBatchSize
* the number of parent beans this path is populated for
*/
public FetchConfig queryFirst(int queryBatchSize) {
this.queryBatchSize = queryBatchSize;
this.queryAll = false;
return this;
}
/**
* Return the batch size for lazy loading.
*/
public int getLazyBatchSize() {
return lazyBatchSize;
}
/**
* Return the batch size for separate query load.
*/
public int getQueryBatchSize() {
return queryBatchSize;
}
/**
* Return true if the query fetch should fetch 'all' rather than just the
* 'first' batch.
*/
public boolean isQueryAll() {
return queryAll;
}
}
+20 -20
View File
@@ -90,98 +90,98 @@ public interface Filter<T> {
* Refer to {@link Ebean#sort(List, String)} for more detail.
* </p>
*/
public Filter<T> sort(String sortByClause);
Filter<T> sort(String sortByClause);
/**
* Specify the maximum number of rows/elements to return.
*/
public Filter<T> maxRows(int maxRows);
Filter<T> maxRows(int maxRows);
/**
* Equal To - property equal to the given value.
*/
public Filter<T> eq(String prop, Object value);
Filter<T> eq(String prop, Object value);
/**
* Not Equal To - property not equal to the given value.
*/
public Filter<T> ne(String propertyName, Object value);
Filter<T> ne(String propertyName, Object value);
/**
* Case Insensitive Equal To.
*/
public Filter<T> ieq(String propertyName, String value);
Filter<T> ieq(String propertyName, String value);
/**
* Between - property between the two given values.
*/
public Filter<T> between(String propertyName, Object value1, Object value2);
Filter<T> between(String propertyName, Object value1, Object value2);
/**
* Greater Than - property greater than the given value.
*/
public Filter<T> gt(String propertyName, Object value);
Filter<T> gt(String propertyName, Object value);
/**
* Greater Than or Equal to - property greater than or equal to the given
* value.
*/
public Filter<T> ge(String propertyName, Object value);
Filter<T> ge(String propertyName, Object value);
/**
* Less Than - property less than the given value.
*/
public Filter<T> lt(String propertyName, Object value);
Filter<T> lt(String propertyName, Object value);
/**
* Less Than or Equal to - property less than or equal to the given value.
*/
public Filter<T> le(String propertyName, Object value);
Filter<T> le(String propertyName, Object value);
/**
* Is Null - property is null.
*/
public Filter<T> isNull(String propertyName);
Filter<T> isNull(String propertyName);
/**
* Is Not Null - property is not null.
*/
public Filter<T> isNotNull(String propertyName);
Filter<T> isNotNull(String propertyName);
/**
* Starts With.
*/
public Filter<T> startsWith(String propertyName, String value);
Filter<T> startsWith(String propertyName, String value);
/**
* Case insensitive Starts With.
*/
public Filter<T> istartsWith(String propertyName, String value);
Filter<T> istartsWith(String propertyName, String value);
/**
* Ends With.
*/
public Filter<T> endsWith(String propertyName, String value);
Filter<T> endsWith(String propertyName, String value);
/**
* Case insensitive Ends With.
*/
public Filter<T> iendsWith(String propertyName, String value);
Filter<T> iendsWith(String propertyName, String value);
/**
* Contains - property contains the string "value".
*/
public Filter<T> contains(String propertyName, String value);
Filter<T> contains(String propertyName, String value);
/**
* Case insensitive Contains.
*/
public Filter<T> icontains(String propertyName, String value);
Filter<T> icontains(String propertyName, String value);
/**
* In - property has a value contained in the set of values.
*/
public Filter<T> in(String propertyName, Set<?> values);
Filter<T> in(String propertyName, Set<?> values);
/**
* Apply the filter to the list returning a new list of the matching elements
@@ -192,6 +192,6 @@ public interface Filter<T> {
*
* @return Returns a new list with the sorting and filters applied.
*/
public List<T> filter(List<T> sourceList);
List<T> filter(List<T> sourceList);
}
+34 -34
View File
@@ -1,34 +1,34 @@
package com.avaje.ebean;
import java.util.List;
import java.util.concurrent.Future;
/**
* FutureIds represents the result of a background query execution for the Id's.
* <p>
* It extends the java.util.concurrent.Future with the ability to get the Id's
* while the query is still executing in the background.
* </p>
*
* @author rbygrave
*/
public interface FutureIds<T> extends Future<List<Object>> {
/**
* Returns the original query used to fetch the Id's.
*/
public Query<T> getQuery();
/**
* Return the list of Id's which could be partially populated.
* <p>
* That is the query getting the id's could still be running and adding id's
* to this list.
* </p>
* <p>
* To get the list of Id's ensuring the query has finished use the
* {@link Future#get()} method instead of this one.
* </p>
*/
public List<Object> getPartialIds();
}
package com.avaje.ebean;
import java.util.List;
import java.util.concurrent.Future;
/**
* FutureIds represents the result of a background query execution for the Id's.
* <p>
* It extends the java.util.concurrent.Future with the ability to get the Id's
* while the query is still executing in the background.
* </p>
*
* @author rbygrave
*/
public interface FutureIds<T> extends Future<List<Object>> {
/**
* Returns the original query used to fetch the Id's.
*/
Query<T> getQuery();
/**
* Return the list of Id's which could be partially populated.
* <p>
* That is the query getting the id's could still be running and adding id's
* to this list.
* </p>
* <p>
* To get the list of Id's ensuring the query has finished use the
* {@link Future#get()} method instead of this one.
* </p>
*/
List<Object> getPartialIds();
}
+76 -76
View File
@@ -1,76 +1,76 @@
package com.avaje.ebean;
import javax.persistence.PersistenceException;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* FutureList represents the result of a background query execution that will
* return a list of entities.
* <p>
* It extends the java.util.concurrent.Future with the ability to cancel the
* query, check if it is finished and get the resulting list waiting for the
* query to finish (ie. the standard features of java.util.concurrent.Future).
* </p>
* <p>
* A simple example:
* </p>
*
* <pre>{@code
* // create a query to find all orders
* Query<Order> query = Ebean.find(Order.class);
*
* // execute the query in a background thread
* // immediately returning the futureList
* FutureList<Order> futureList = query.findFutureList();
*
* // do something else ...
*
* if (!futureList.isDone()){
* // we can cancel the query execution. This will cancel
* // the underlying query if that is supported by the JDBC
* // driver and database
* futureList.cancel(true);
* }
*
*
* if (!futureList.isCancelled()){
* // wait for the query to finish and return the list
* List<Order> list = futureList.get();
* ...
* }
*
* }</pre>
*/
public interface FutureList<T> extends Future<List<T>> {
/**
* Return the query that is being executed by a background thread.
*/
public Query<T> getQuery();
/**
* Same as {@link #get()} but wraps InterruptedException and ExecutionException in the
* unchecked PersistenceException.
*
* @return The query list result
*
* @throws PersistenceException when a InterruptedException or ExecutionException occurs.
*/
public List<T> getUnchecked();
/**
* Same as {@link #get(long, java.util.concurrent.TimeUnit)} but wraps InterruptedException
* and ExecutionException in the unchecked PersistenceException.
*
* @return The query list result
*
* @throws TimeoutException if the wait timed out
* @throws PersistenceException if a InterruptedException or ExecutionException occurs.
*/
public List<T> getUnchecked(long timeout, TimeUnit unit) throws TimeoutException;
}
package com.avaje.ebean;
import javax.persistence.PersistenceException;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* FutureList represents the result of a background query execution that will
* return a list of entities.
* <p>
* It extends the java.util.concurrent.Future with the ability to cancel the
* query, check if it is finished and get the resulting list waiting for the
* query to finish (ie. the standard features of java.util.concurrent.Future).
* </p>
* <p>
* A simple example:
* </p>
*
* <pre>{@code
* // create a query to find all orders
* Query<Order> query = Ebean.find(Order.class);
*
* // execute the query in a background thread
* // immediately returning the futureList
* FutureList<Order> futureList = query.findFutureList();
*
* // do something else ...
*
* if (!futureList.isDone()){
* // we can cancel the query execution. This will cancel
* // the underlying query if that is supported by the JDBC
* // driver and database
* futureList.cancel(true);
* }
*
*
* if (!futureList.isCancelled()){
* // wait for the query to finish and return the list
* List<Order> list = futureList.get();
* ...
* }
*
* }</pre>
*/
public interface FutureList<T> extends Future<List<T>> {
/**
* Return the query that is being executed by a background thread.
*/
Query<T> getQuery();
/**
* Same as {@link #get()} but wraps InterruptedException and ExecutionException in the
* unchecked PersistenceException.
*
* @return The query list result
*
* @throws PersistenceException when a InterruptedException or ExecutionException occurs.
*/
List<T> getUnchecked();
/**
* Same as {@link #get(long, java.util.concurrent.TimeUnit)} but wraps InterruptedException
* and ExecutionException in the unchecked PersistenceException.
*
* @return The query list result
*
* @throws TimeoutException if the wait timed out
* @throws PersistenceException if a InterruptedException or ExecutionException occurs.
*/
List<T> getUnchecked(long timeout, TimeUnit unit) throws TimeoutException;
}
@@ -1,15 +1,15 @@
package com.avaje.ebean;
import java.util.concurrent.Future;
/**
* Represents the result of a background query execution for the total row count
* for a query.
* <p>
* It extends the java.util.concurrent.Future.
* </p>
*
* @author rbygrave
*/
public interface FutureRowCount<T> extends Future<Integer> {
}
package com.avaje.ebean;
import java.util.concurrent.Future;
/**
* Represents the result of a background query execution for the total row count
* for a query.
* <p>
* It extends the java.util.concurrent.Future.
* </p>
*
* @author rbygrave
*/
public interface FutureRowCount<T> extends Future<Integer> {
}
+192 -46
View File
@@ -1,11 +1,13 @@
package com.avaje.ebean;
import com.avaje.ebean.text.PathProperties;
import com.avaje.ebean.util.ClassUtil;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import javax.persistence.MappedSuperclass;
@@ -34,7 +36,7 @@ import javax.persistence.MappedSuperclass;
*
* <p>
* If you choose to use the Model mapped superclass you will probably also chose to additionally add
* a {@link Finder} as a public static field to complete the active record pattern and provide a
* a {@link Find} as a public static field to complete the active record pattern and provide a
* relatively nice clean way to write queries.
*
* <h3>Typical common @MappedSuperclass</h3>
@@ -64,19 +66,15 @@ import javax.persistence.MappedSuperclass;
* // Extend the mappedSuperclass
*
* @Entity @Table(name="oto_account")
* public class Account extends BaseModel {
* public class Customer extends BaseModel {
*
* // add a static Finder
* // ... with Long being the type of our ID property ...
* // Add a static Find
* // ... with Long being the type of our @Id property.
* // ... Note the {} at the end as Find is an abstract class.
*
* public static final Finder<Long,Account> find =
* new Finder<Long,Account>(Long.class, Account.class);
* public static final Find<Long,Account> find = new Find<Long,Account>(){};
*
* String name;
*
* @OneToOne(mappedBy = "account",optional = true)
* User user;
*
* ...
* }
*
@@ -86,28 +84,28 @@ import javax.persistence.MappedSuperclass;
* <pre>{@code
*
* // Active record style ... save(), delete() etc
* Account account = new Account();
* account.setName("AC234");
* Customer customer = new Customer();
* customer.setName("AC234");
*
* // save() method inherited from Model
* account.save();
* customer.save();
*
* }</pre>
*
* <h3>Finder: find byId</h3>
* <h3>Find byId</h3>
* <pre>{@code
*
* // find byId
* Account account = Account.find.byId(42);
* Customer customer = Customer.find.byId(42);
*
* }</pre>
*
* <h3>Finder: find where</h3>
* <h3>Find where</h3>
* <pre>{@code
*
* // find where ...
* List<Account> accounts =
* Account.find
* List<Customer> customers =
* Customer.find
* .where().gt("startDate", lastMonth)
* .findList();
*
@@ -124,7 +122,8 @@ public abstract class Model {
*
* <p>
* Example:
* <pre class="code">
* <pre>{@code
*
* Transaction transaction = Customer.db().beginTransaction();
* try {
*
@@ -141,7 +140,7 @@ public abstract class Model {
* customer.save();
*
* Customer otherCustomer = new Customer();
* otherCustomer.setName(&quot;Franko&quot;);
* otherCustomer.setName("Franko");
* otherCustomer.save();
*
* transaction.commit();
@@ -150,7 +149,7 @@ public abstract class Model {
* transaction.end();
* }
*
* </pre>
* }</pre>
*/
public static EbeanServer db() {
return Ebean.getServer(null);
@@ -179,7 +178,7 @@ public abstract class Model {
* An unmodified bean that is saved or updated is normally skipped and this marks the bean as
* dirty so that it is not skipped.
*
* <pre class="code">
* <pre>{@code
*
* Customer customer = Customer.find.byId(id);
*
@@ -188,7 +187,7 @@ public abstract class Model {
* customer.markAsDirty();
* customer.save();
*
* </pre>
* }</pre>
*
* @see EbeanServer#markAsDirty(Object)
*/
@@ -266,46 +265,193 @@ public abstract class Model {
db().refresh(this);
}
/**
* A concrete implementation of Find.
* <p>
* It should be preferred to use {@link Find} instead of Finder as that can use reflection to determine the class
* literal type of the entity bean.
* </p>
* @param <I> type of the Id property
* @param <T> type of the entity bean
*/
public static class Finder<I, T> extends Find<I, T> {
/**
* Create with the type of the entity bean.
*
* <pre>{@code
*
* @Entity
* public class Customer extends BaseModel {
*
* public static final Finder<Long,Customer> find = new Finder<Long,Customer>(Customer.class);
* ...
*
* }</pre>
*
* <p/>
* The preferred approach is to instead use <code>Find</code> as below. This approach is more DRY in that it does
* not require the class literal Customer.class to be passed into the constructor.
*
* <pre>{@code
*
* @Entity
* public class Customer extends BaseModel {
*
* public static final Find<Long,Customer> find = new Find<Long,Customer>(){};
* ...
*
* }</pre>
*/
public Finder(Class<T> type) {
super(null, type);
}
/**
* Create with the type of the entity bean and specific server name.
*/
public Finder(String serverName, Class<T> type) {
super(serverName, type);
}
/**
* Please migrate to use {@link Find} or constructor <code>Finder(Class)</code> that
* does not have the idType parameter.
* <p/>
* Create with the type of the ID property and entity bean and specific server name.
*
* @deprecated
*/
public Finder(Class<I> idType, Class<T> type) {
super(null, type);
}
/**
* Please migrate to use the constructor <code>Finder(String, Class)</code> that
* does not have the idType parameter.
* <p/>
* Create with the type of the ID property and entity bean and specific server name.
*
* @deprecated
*/
public Finder(String serverName, Class<I> idType, Class<T> type) {
super(serverName, type);
}
}
/**
* Helper object for performing queries.
*
* <p>
* Typically a Finder is defined as a public static field on an entity bean class to provide a
* Typically a Find instance is defined as a public static field on an entity bean class to provide a
* nice way to write queries.
*
*
* <h3>Example use:</h3>
*
* <pre>{@code
*
* @Entity
* public class Customer extends BaseModel {
*
* public static final Find<Long,Customer> find = new Find<Long,Customer>(){};
*
* ...
*
* }</pre>
* <p/>
* This enables you to write code like:
* <pre>{@code
*
* Customer customer = Customer.find.byId(42L);
*
* List<Customer> customers =
* Customer.find
* .select("name, dateOfBirth")
* .findList();
*
* }</pre>
*
* <h3>Kotlin</h3>
* In Kotlin you would typically create Find as a companion object.
* <pre>{@code
*
* // kotlin
* companion object : Model.Find<Long, Product>() {}
*
* }</pre>
* @param <I>
* The Id type. This is most often a {@link Long} but is also often a {@link UUID} or
* {@link String}.
*
* @param <T>
* The bean type
* The entity bean type
*/
public static class Finder<I, T> {
public static abstract class Find<I, T> {
private final Class<I> idType;
/**
* The entity bean type.
*/
private final Class<T> type;
/**
* The name of the EbeanServer, null for the default server.
*/
private final String serverName;
/**
* Creates a finder for entity of type <code>T</code> with ID of type <code>I</code>.
*
* <p>
* Typically you use this constructor to have a static "find" field on each entity bean.
* <p/>
* Typically you create Find as a public static field on each entity bean as the example below.
*
* <p/>
* Note that Find is an abstract class and hence <code>{}</code> is required. This is done so
* that the type (class literal) of the entity bean can be derived from the generics parameter.
*
* <pre>{@code
*
* @Entity
* public class Customer extends BaseModel {
*
* // Note the trailing {} as Find is an abstract class.
* // We do this so that we can derive the type literal Customer.class
* // via reflection
* public static final Find<Long,Customer> find = new Find<Long,Customer>(){};
* ...
*
* }</pre>
* <p/>
* This enables you to write code like:
* <pre>{@code
*
* Customer customer = Customer.find.byId(42L);
*
* List<Customer> customers =
* Customer.find
* .select("name, email, dateOfBirth")
* .findList();
*
* }</pre>
*
* <h3>Kotlin</h3>
* In Kotlin you would typically create it as a companion object.
*
* <pre>{@code
*
* // kotlin
* companion object : Model.Find<Long, Product>() {}
*
* }</pre>
*/
public Finder(Class<I> idType, Class<T> type) {
this(null, idType, type);
public Find() {
this.serverName = null;
this.type = (Class<T>)ClassUtil.getSecondArgumentType(getClass());
}
/**
* Creates a finder for entity of type <code>T</code> with ID of type <code>I</code>, using a
* specific EbeanServer.
*
* <p>
* Typically you don't need to use this method.
* Construct passing the class literal type of the entity type.
*/
public Finder(String serverName, Class<I> idType, Class<T> type) {
protected Find(String serverName, Class<T> type) {
this.type = type;
this.idType = idType;
this.serverName = serverName;
}
@@ -335,12 +481,12 @@ public abstract class Model {
/**
* Creates a Finder for the named EbeanServer.
*
*
* <p>
* Create and return a new Finder for a different server.
*/
public Finder<I, T> on(String server) {
return new Finder<I, T>(server, idType, type);
return new Finder<I, T>(server, type);
}
/**
+351 -351
View File
@@ -1,351 +1,351 @@
package com.avaje.ebean;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Represents an Order By for a Query.
* <p>
* Is a ordered list of OrderBy.Property objects each specifying a property and
* whether it is ascending or descending order.
* </p>
* <p>
* Typically you will not construct an OrderBy yourself but use one that exists
* on the Query object.
* </p>
*/
public final class OrderBy<T> implements Serializable {
private static final long serialVersionUID = 9157089257745730539L;
private transient Query<T> query;
private final List<Property> list;
/**
* Create an empty OrderBy with no associated query.
*/
public OrderBy() {
this.list = new ArrayList<Property>(2);
}
private OrderBy(List<Property> list) {
this.list = list;
}
/**
* Create an orderBy parsing the order by clause.
* <p>
* The order by clause follows SQL order by clause with comma's between each
* property and optionally "asc" or "desc" to represent ascending or
* descending order respectively.
* </p>
*/
public OrderBy(String orderByClause) {
this(null, orderByClause);
}
/**
* Construct with a given query and order by clause.
*/
public OrderBy(Query<T> query, String orderByClause) {
this.query = query;
this.list = new ArrayList<Property>(2);
parse(orderByClause);
}
/**
* Reverse the ascending/descending order on all the properties.
*/
public void reverse() {
for (int i = 0; i < list.size(); i++) {
list.get(i).reverse();
}
}
/**
* Add a property with ascending order to this OrderBy.
*/
public Query<T> asc(String propertyName) {
list.add(new Property(propertyName, true));
return query;
}
/**
* Add a property with descending order to this OrderBy.
*/
public Query<T> desc(String propertyName) {
list.add(new Property(propertyName, false));
return query;
}
/**
* Return a copy of this OrderBy with the path trimmed.
*/
public OrderBy<T> copyWithTrim(String path) {
List<Property> newList = new ArrayList<Property>(list.size());
for (int i = 0; i < list.size(); i++) {
newList.add(list.get(i).copyWithTrim(path));
}
return new OrderBy<T>(newList);
}
/**
* Return the properties for this OrderBy.
*/
public List<Property> getProperties() {
// not returning an Immutable list at this point
return list;
}
/**
* Return true if this OrderBy does not have any properties.
*/
public boolean isEmpty() {
return list.isEmpty();
}
/**
* Return the associated query if there is one.
*/
public Query<T> getQuery() {
return query;
}
/**
* Associate this OrderBy with a query.
*/
public void setQuery(Query<T> query) {
this.query = query;
}
/**
* Return a copy of the OrderBy.
*/
public OrderBy<T> copy() {
OrderBy<T> copy = new OrderBy<T>();
for (int i = 0; i < list.size(); i++) {
copy.add(list.get(i).copy());
}
return copy;
}
/**
* Add a property to the order by.
*/
public void add(Property p) {
list.add(p);
}
public String toString() {
return list.toString();
}
/**
* Returns the OrderBy in string format.
*/
public String toStringFormat() {
if (list.isEmpty()) {
return null;
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < list.size(); i++) {
Property property = list.get(i);
if (i > 0) {
sb.append(", ");
}
sb.append(property.toStringFormat());
}
return sb.toString();
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof OrderBy<?>)) {
return false;
}
OrderBy<?> e = (OrderBy<?>) obj;
return e.list.equals(list);
}
/**
* Return a hash value for this OrderBy. This can be to determine logical
* equality for OrderBy clauses.
*/
public int hashCode() {
return list.hashCode();
}
/**
* A property and its ascending descending order.
*/
public static final class Property implements Serializable {
private static final long serialVersionUID = 1546009780322478077L;
private String property;
private boolean ascending;
public Property(String property, boolean ascending) {
this.property = property;
this.ascending = ascending;
}
/**
* Return a copy of this Property with the path trimmed.
*/
public Property copyWithTrim(String path) {
return new Property(property.substring(path.length() + 1), ascending);
}
public int hashCode() {
int hc = property.hashCode();
hc = hc * 31 + (ascending ? 0 : 1);
return hc;
}
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof Property)) {
return false;
}
Property e = (Property) obj;
return e.ascending == ascending
&& e.property.equals(property);
}
public String toString() {
return toStringFormat();
}
public String toStringFormat() {
if (ascending) {
return property;
} else {
return property + " desc";
}
}
/**
* Reverse the ascending/descending order for this property.
*/
public void reverse() {
this.ascending = !ascending;
}
/**
* Trim off the pathPrefix.
*/
public void trim(String pathPrefix) {
property = property.substring(pathPrefix.length() + 1);
}
/**
* Return a copy of this property.
*/
public Property copy() {
return new Property(property, ascending);
}
/**
* Return the property name.
*/
public String getProperty() {
return property;
}
/**
* Set the property name.
*/
public void setProperty(String property) {
this.property = property;
}
/**
* Return true if the order is ascending.
*/
public boolean isAscending() {
return ascending;
}
/**
* Set to true if the order is ascending.
*/
public void setAscending(boolean ascending) {
this.ascending = ascending;
}
}
private void parse(String orderByClause) {
if (orderByClause == null) {
return;
}
String[] chunks = orderByClause.split(",");
for (int i = 0; i < chunks.length; i++) {
String[] pairs = chunks[i].split(" ");
Property p = parseProperty(pairs);
if (p != null) {
list.add(p);
}
}
}
private Property parseProperty(String[] pairs) {
if (pairs.length == 0) {
return null;
}
ArrayList<String> wordList = new ArrayList<String>(pairs.length);
for (int i = 0; i < pairs.length; i++) {
if (!isEmptyString(pairs[i])) {
wordList.add(pairs[i]);
}
}
if (wordList.isEmpty()) {
return null;
}
if (wordList.size() == 1) {
return new Property(wordList.get(0), true);
}
if (wordList.size() == 2) {
boolean asc = isAscending(wordList.get(1));
return new Property(wordList.get(0), asc);
}
String m = "Expecting a max of 2 words in [" + Arrays.toString(pairs)
+ "] but got " + wordList.size();
throw new RuntimeException(m);
}
private boolean isAscending(String s) {
s = s.toLowerCase();
if (s.startsWith("asc")) {
return true;
}
if (s.startsWith("desc")) {
return false;
}
String m = "Expecting [" + s + "] to be asc or desc?";
throw new RuntimeException(m);
}
private boolean isEmptyString(String s) {
return s == null || s.length() == 0;
}
}
package com.avaje.ebean;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Represents an Order By for a Query.
* <p>
* Is a ordered list of OrderBy.Property objects each specifying a property and
* whether it is ascending or descending order.
* </p>
* <p>
* Typically you will not construct an OrderBy yourself but use one that exists
* on the Query object.
* </p>
*/
public final class OrderBy<T> implements Serializable {
private static final long serialVersionUID = 9157089257745730539L;
private transient Query<T> query;
private final List<Property> list;
/**
* Create an empty OrderBy with no associated query.
*/
public OrderBy() {
this.list = new ArrayList<Property>(2);
}
private OrderBy(List<Property> list) {
this.list = list;
}
/**
* Create an orderBy parsing the order by clause.
* <p>
* The order by clause follows SQL order by clause with comma's between each
* property and optionally "asc" or "desc" to represent ascending or
* descending order respectively.
* </p>
*/
public OrderBy(String orderByClause) {
this(null, orderByClause);
}
/**
* Construct with a given query and order by clause.
*/
public OrderBy(Query<T> query, String orderByClause) {
this.query = query;
this.list = new ArrayList<Property>(2);
parse(orderByClause);
}
/**
* Reverse the ascending/descending order on all the properties.
*/
public void reverse() {
for (int i = 0; i < list.size(); i++) {
list.get(i).reverse();
}
}
/**
* Add a property with ascending order to this OrderBy.
*/
public Query<T> asc(String propertyName) {
list.add(new Property(propertyName, true));
return query;
}
/**
* Add a property with descending order to this OrderBy.
*/
public Query<T> desc(String propertyName) {
list.add(new Property(propertyName, false));
return query;
}
/**
* Return a copy of this OrderBy with the path trimmed.
*/
public OrderBy<T> copyWithTrim(String path) {
List<Property> newList = new ArrayList<Property>(list.size());
for (int i = 0; i < list.size(); i++) {
newList.add(list.get(i).copyWithTrim(path));
}
return new OrderBy<T>(newList);
}
/**
* Return the properties for this OrderBy.
*/
public List<Property> getProperties() {
// not returning an Immutable list at this point
return list;
}
/**
* Return true if this OrderBy does not have any properties.
*/
public boolean isEmpty() {
return list.isEmpty();
}
/**
* Return the associated query if there is one.
*/
public Query<T> getQuery() {
return query;
}
/**
* Associate this OrderBy with a query.
*/
public void setQuery(Query<T> query) {
this.query = query;
}
/**
* Return a copy of the OrderBy.
*/
public OrderBy<T> copy() {
OrderBy<T> copy = new OrderBy<T>();
for (int i = 0; i < list.size(); i++) {
copy.add(list.get(i).copy());
}
return copy;
}
/**
* Add a property to the order by.
*/
public void add(Property p) {
list.add(p);
}
public String toString() {
return list.toString();
}
/**
* Returns the OrderBy in string format.
*/
public String toStringFormat() {
if (list.isEmpty()) {
return null;
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < list.size(); i++) {
Property property = list.get(i);
if (i > 0) {
sb.append(", ");
}
sb.append(property.toStringFormat());
}
return sb.toString();
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof OrderBy<?>)) {
return false;
}
OrderBy<?> e = (OrderBy<?>) obj;
return e.list.equals(list);
}
/**
* Return a hash value for this OrderBy. This can be to determine logical
* equality for OrderBy clauses.
*/
public int hashCode() {
return list.hashCode();
}
/**
* A property and its ascending descending order.
*/
public static final class Property implements Serializable {
private static final long serialVersionUID = 1546009780322478077L;
private String property;
private boolean ascending;
public Property(String property, boolean ascending) {
this.property = property;
this.ascending = ascending;
}
/**
* Return a copy of this Property with the path trimmed.
*/
public Property copyWithTrim(String path) {
return new Property(property.substring(path.length() + 1), ascending);
}
public int hashCode() {
int hc = property.hashCode();
hc = hc * 31 + (ascending ? 0 : 1);
return hc;
}
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof Property)) {
return false;
}
Property e = (Property) obj;
return e.ascending == ascending
&& e.property.equals(property);
}
public String toString() {
return toStringFormat();
}
public String toStringFormat() {
if (ascending) {
return property;
} else {
return property + " desc";
}
}
/**
* Reverse the ascending/descending order for this property.
*/
public void reverse() {
this.ascending = !ascending;
}
/**
* Trim off the pathPrefix.
*/
public void trim(String pathPrefix) {
property = property.substring(pathPrefix.length() + 1);
}
/**
* Return a copy of this property.
*/
public Property copy() {
return new Property(property, ascending);
}
/**
* Return the property name.
*/
public String getProperty() {
return property;
}
/**
* Set the property name.
*/
public void setProperty(String property) {
this.property = property;
}
/**
* Return true if the order is ascending.
*/
public boolean isAscending() {
return ascending;
}
/**
* Set to true if the order is ascending.
*/
public void setAscending(boolean ascending) {
this.ascending = ascending;
}
}
private void parse(String orderByClause) {
if (orderByClause == null) {
return;
}
String[] chunks = orderByClause.split(",");
for (int i = 0; i < chunks.length; i++) {
String[] pairs = chunks[i].split(" ");
Property p = parseProperty(pairs);
if (p != null) {
list.add(p);
}
}
}
private Property parseProperty(String[] pairs) {
if (pairs.length == 0) {
return null;
}
ArrayList<String> wordList = new ArrayList<String>(pairs.length);
for (int i = 0; i < pairs.length; i++) {
if (!isEmptyString(pairs[i])) {
wordList.add(pairs[i]);
}
}
if (wordList.isEmpty()) {
return null;
}
if (wordList.size() == 1) {
return new Property(wordList.get(0), true);
}
if (wordList.size() == 2) {
boolean asc = isAscending(wordList.get(1));
return new Property(wordList.get(0), asc);
}
String m = "Expecting a max of 2 words in [" + Arrays.toString(pairs)
+ "] but got " + wordList.size();
throw new RuntimeException(m);
}
private boolean isAscending(String s) {
s = s.toLowerCase();
if (s.startsWith("asc")) {
return true;
}
if (s.startsWith("desc")) {
return false;
}
String m = "Expecting [" + s + "] to be asc or desc?";
throw new RuntimeException(m);
}
private boolean isEmptyString(String s) {
return s == null || s.length() == 0;
}
}
+192 -192
View File
@@ -1,192 +1,192 @@
package com.avaje.ebean;
import java.util.List;
import java.util.concurrent.Future;
/**
* Represents a page of results.
* <p>
* The benefit of using PagedList over just using the normal Query with
* {@link Query#setFirstRow(int)} and {@link Query#setMaxRows(int)} is that it additionally wraps
* functionality that can call {@link Query#findFutureRowCount()} to determine total row count,
* total page count etc.
* </p>
* <p>
* Internally this works using {@link Query#setFirstRow(int)} and {@link Query#setMaxRows(int)} on
* the query. This translates into SQL that uses limit offset, rownum or row_number function to
* limit the result set.
* </p>
*
* <h4>Example: typical use including total row count</h4>
* <pre>{@code
*
* // We want to find the first 100 new orders
* // ... 0 means first page
* // ... page size is 100
*
* PagedList<Order> pagedList
* = ebeanServer.find(Order.class)
* .where().eq("status", Order.Status.NEW)
* .order().asc("id")
* .findPagedList(0, 100);
*
* // Optional: initiate the loading of the total
* // row count in a background thread
* pagedList.loadRowCount();
*
* // fetch and return the list in the foreground thread
* List<Order> orders = pagedList.getList();
*
* // get the total row count (from the future)
* int totalRowCount = pagedList.getTotalRowCount();
*
* }</pre>
*
* <h4>Example: No total row count required</h4>
* <pre>{@code
*
* // If you are not getting the 'first page' often
* // you do not bother getting the total row count again
* // so instead just get the page list of data
*
* // fetch and return the list in the foreground thread
* List<Order> orders = pagedList.getList();
*
* }</pre>
*
* @param <T>
* the entity bean type
*
* @see Query#findPagedList(int, int)
*/
public interface PagedList<T> {
/**
* Initiate the loading of the total row count in the background.
* <pre>{@code
*
* // initiate the loading of the total row count
* // in a background thread
* pagedList.loadRowCount();
*
* // fetch and return the list in the foreground thread
* List<Order> orders = pagedList.getList();
*
* // get the total row count (from the future)
* int totalRowCount = pagedList.getTotalRowCount();
*
* }</pre>
*
* <p>
* Also note that using loadRowCount() and getTotalRowCount() rather than getFutureRowCount()
* means that exceptions ExecutionException, InterruptedException, TimeoutException are instead
* wrapped in the unchecked PersistenceException (which might be preferrable).
* </p>
*/
public void loadRowCount();
/**
* Return the Future row count. You might get this if you wish to cancel the total row count query
* or specify a timeout for the row count query.
* <p>
* The loadRowCount() & getTotalRowCount() methods internally make use of this getFutureRowCount() method.
* Generally I expect people to prefer loadRowCount() & getTotalRowCount() over getFutureRowCount().
* </p>
* <pre>{@code
*
* // initiate the row count query in the background thread
* Future<Integer> rowCount = pagedList.getFutureRowCount();
*
* // fetch and return the list in the foreground thread
* List<Order> orders = pagedList.getList();
*
* // now get the total count with a timeout
* Integer totalRowCount = rowCount.get(30, TimeUnit.SECONDS);
*
* // or ge the total count without a timeout
* Integer totalRowCountViaFuture = rowCount.get();
*
* // which is actually the same as ...
* int totalRowCount = pagedList.getTotalRowCount();
*
* }</pre>
*/
public Future<Integer> getFutureRowCount();
/**
* Return the list of entities for this page.
*/
public List<T> getList();
/**
* Return the total row count for all pages.
* <p>
* If loadRowCount() has already been called then the row count query is already executing in a background thread
* and this gets the associated Future and gets the value waiting for the future to finish.
* </p>
* <p>
* If loadRowCount() has not been called then this executes the find row count query and returns the result and this
* will just occur in the current thread and not use a background thread.
* </p>
* <pre>{@code
*
* // Optional: initiate the loading of the total
* // row count in a background thread
* pagedList.loadRowCount();
*
* // fetch and return the list in the foreground thread
* List<Order> orders = pagedList.getList();
*
* // get the total row count (which was being executed
* // in a background thread if loadRowCount() was used)
* int totalRowCount = pagedList.getTotalRowCount();
*
* }</pre>
*/
public int getTotalRowCount();
/**
* Return the total number of pages based on the page size and total row count.
* <p>
* This method requires that the total row count has been fetched and will invoke
* the total row count query if it has not already been invoked.
* </p>
*/
public int getTotalPageCount();
/**
* Return the index position of this page. Zero based.
*/
public int getPageIndex();
/**
* Return true if there is a next page.
* <p>
* This method requires that the total row count has been fetched and will invoke
* the total row count query if it has not already been invoked.
* </p>
*/
public boolean hasNext();
/**
* Return true if there is a previous page.
*/
public boolean hasPrev();
/**
* Helper method to return a "X to Y of Z" string for this page where X is the first row, Y the
* last row and Z the total row count.
* <p>
* This method requires that the total row count has been fetched and will invoke
* the total row count query if it has not already been invoked.
* </p>
*
* @param to
* String to put between the first and last row
* @param of
* String to put between the last row and the total row count
*
* @return String of the format XtoYofZ.
*/
public String getDisplayXtoYofZ(String to, String of);
}
package com.avaje.ebean;
import java.util.List;
import java.util.concurrent.Future;
/**
* Represents a page of results.
* <p>
* The benefit of using PagedList over just using the normal Query with
* {@link Query#setFirstRow(int)} and {@link Query#setMaxRows(int)} is that it additionally wraps
* functionality that can call {@link Query#findFutureRowCount()} to determine total row count,
* total page count etc.
* </p>
* <p>
* Internally this works using {@link Query#setFirstRow(int)} and {@link Query#setMaxRows(int)} on
* the query. This translates into SQL that uses limit offset, rownum or row_number function to
* limit the result set.
* </p>
*
* <h4>Example: typical use including total row count</h4>
* <pre>{@code
*
* // We want to find the first 100 new orders
* // ... 0 means first page
* // ... page size is 100
*
* PagedList<Order> pagedList
* = ebeanServer.find(Order.class)
* .where().eq("status", Order.Status.NEW)
* .order().asc("id")
* .findPagedList(0, 100);
*
* // Optional: initiate the loading of the total
* // row count in a background thread
* pagedList.loadRowCount();
*
* // fetch and return the list in the foreground thread
* List<Order> orders = pagedList.getList();
*
* // get the total row count (from the future)
* int totalRowCount = pagedList.getTotalRowCount();
*
* }</pre>
*
* <h4>Example: No total row count required</h4>
* <pre>{@code
*
* // If you are not getting the 'first page' often
* // you do not bother getting the total row count again
* // so instead just get the page list of data
*
* // fetch and return the list in the foreground thread
* List<Order> orders = pagedList.getList();
*
* }</pre>
*
* @param <T>
* the entity bean type
*
* @see Query#findPagedList(int, int)
*/
public interface PagedList<T> {
/**
* Initiate the loading of the total row count in the background.
* <pre>{@code
*
* // initiate the loading of the total row count
* // in a background thread
* pagedList.loadRowCount();
*
* // fetch and return the list in the foreground thread
* List<Order> orders = pagedList.getList();
*
* // get the total row count (from the future)
* int totalRowCount = pagedList.getTotalRowCount();
*
* }</pre>
*
* <p>
* Also note that using loadRowCount() and getTotalRowCount() rather than getFutureRowCount()
* means that exceptions ExecutionException, InterruptedException, TimeoutException are instead
* wrapped in the unchecked PersistenceException (which might be preferrable).
* </p>
*/
void loadRowCount();
/**
* Return the Future row count. You might get this if you wish to cancel the total row count query
* or specify a timeout for the row count query.
* <p>
* The loadRowCount() & getTotalRowCount() methods internally make use of this getFutureRowCount() method.
* Generally I expect people to prefer loadRowCount() & getTotalRowCount() over getFutureRowCount().
* </p>
* <pre>{@code
*
* // initiate the row count query in the background thread
* Future<Integer> rowCount = pagedList.getFutureRowCount();
*
* // fetch and return the list in the foreground thread
* List<Order> orders = pagedList.getList();
*
* // now get the total count with a timeout
* Integer totalRowCount = rowCount.get(30, TimeUnit.SECONDS);
*
* // or ge the total count without a timeout
* Integer totalRowCountViaFuture = rowCount.get();
*
* // which is actually the same as ...
* int totalRowCount = pagedList.getTotalRowCount();
*
* }</pre>
*/
Future<Integer> getFutureRowCount();
/**
* Return the list of entities for this page.
*/
List<T> getList();
/**
* Return the total row count for all pages.
* <p>
* If loadRowCount() has already been called then the row count query is already executing in a background thread
* and this gets the associated Future and gets the value waiting for the future to finish.
* </p>
* <p>
* If loadRowCount() has not been called then this executes the find row count query and returns the result and this
* will just occur in the current thread and not use a background thread.
* </p>
* <pre>{@code
*
* // Optional: initiate the loading of the total
* // row count in a background thread
* pagedList.loadRowCount();
*
* // fetch and return the list in the foreground thread
* List<Order> orders = pagedList.getList();
*
* // get the total row count (which was being executed
* // in a background thread if loadRowCount() was used)
* int totalRowCount = pagedList.getTotalRowCount();
*
* }</pre>
*/
int getTotalRowCount();
/**
* Return the total number of pages based on the page size and total row count.
* <p>
* This method requires that the total row count has been fetched and will invoke
* the total row count query if it has not already been invoked.
* </p>
*/
int getTotalPageCount();
/**
* Return the index position of this page. Zero based.
*/
int getPageIndex();
/**
* Return true if there is a next page.
* <p>
* This method requires that the total row count has been fetched and will invoke
* the total row count query if it has not already been invoked.
* </p>
*/
boolean hasNext();
/**
* Return true if there is a previous page.
*/
boolean hasPrev();
/**
* Helper method to return a "X to Y of Z" string for this page where X is the first row, Y the
* last row and Z the total row count.
* <p>
* This method requires that the total row count has been fetched and will invoke
* the total row count query if it has not already been invoked.
* </p>
*
* @param to
* String to put between the first and last row
* @param of
* String to put between the last row and the total row count
*
* @return String of the format XtoYofZ.
*/
String getDisplayXtoYofZ(String to, String of);
}
@@ -46,10 +46,35 @@ class PrimaryServer {
if (globalProperties == null) {
globalProperties = PropertyMap.defaultProperties();
}
defaultServerName = globalProperties.getProperty("datasource.default");
if (defaultServerName == null) {
defaultServerName = globalProperties.getProperty("ebean.default.datasource");
defaultServerName = determineDefaultServerName();
}
return globalProperties;
}
/**
* Determine and return the default server name checking system environment variables and then global properties.
*/
private static String determineDefaultServerName() {
String defaultServerName = System.getProperty("datasource.default");
if (isEmpty(defaultServerName)) {
defaultServerName = System.getProperty("ebean.default.datasource");
}
if (isEmpty(defaultServerName)) {
defaultServerName = globalProperties.getProperty("datasource.default");
}
if (isEmpty(defaultServerName)) {
defaultServerName = globalProperties.getProperty("ebean.default.datasource");
}
return defaultServerName;
}
/**
* Return true if the string is null or empty.
*/
private static boolean isEmpty(String value) {
return value == null || value.trim().length() == 0;
}
}
File diff suppressed because it is too large Load Diff
@@ -1,41 +1,41 @@
package com.avaje.ebean;
/**
* Used to process a query result one bean at a time via a callback to this
* visitor.
* <p>
* If you wish to stop further processing return false from the accept method.
* </p>
* <p>
* Unlike findList() and findSet() using a QueryResultVisitor does not require
* all the beans in the query result to be held in memory at once. This makes
* QueryResultVisitor useful for processing large queries.
* </p>
*
* <pre>{@code
*
* Query<Customer> query = server.find(Customer.class)
* .where().eq("status", Status.NEW)
* .order().asc("id");
*
* query.findEach((Customer customer) -> {
*
* // do something with customer
* System.out.println("-- visit " + customer);
* });
*
* }</pre>
*
* @param <T>
* the type of entity bean being queried.
*/
public interface QueryEachConsumer<T> {
/**
* Process the bean.
*
* @param bean
* the entity bean to process
*/
public void accept(T bean);
}
package com.avaje.ebean;
/**
* Used to process a query result one bean at a time via a callback to this
* visitor.
* <p>
* If you wish to stop further processing return false from the accept method.
* </p>
* <p>
* Unlike findList() and findSet() using a QueryResultVisitor does not require
* all the beans in the query result to be held in memory at once. This makes
* QueryResultVisitor useful for processing large queries.
* </p>
*
* <pre>{@code
*
* Query<Customer> query = server.find(Customer.class)
* .where().eq("status", Status.NEW)
* .order().asc("id");
*
* query.findEach((Customer customer) -> {
*
* // do something with customer
* System.out.println("-- visit " + customer);
* });
*
* }</pre>
*
* @param <T>
* the type of entity bean being queried.
*/
public interface QueryEachConsumer<T> {
/**
* Process the bean.
*
* @param bean
* the entity bean to process
*/
void accept(T bean);
}
@@ -1,45 +1,45 @@
package com.avaje.ebean;
/**
* Used to process a query result one bean at a time via a callback to this
* visitor.
* <p>
* If you wish to stop further processing return false from the accept method.
* </p>
* <p>
* Unlike findList() and findSet() using a QueryResultVisitor does not require
* all the beans in the query result to be held in memory at once. This makes
* QueryResultVisitor useful for processing large queries.
* </p>
* <p/>
* <pre class="code">
*
* Query&lt;Customer&gt; query = server.find(Customer.class)
* .fetch(&quot;contacts&quot;, new FetchConfig().query(2))
* .where().gt(&quot;id&quot;, 0)
* .orderBy(&quot;id&quot;)
* .setMaxRows(2);
*
* query.findEachWhile((Customer customer) -> {
*
* // do something with customer
* System.out.println(&quot;-- visit &quot; + customer);
*
* // return true to continue processing or false to stop
* return (customer.getId() < 40);
* });
* </pre>
*
* @param <T> the type of entity bean being queried.
*/
public interface QueryEachWhileConsumer<T> {
/**
* Process the bean and return true if you want to continue processing more
* beans. Return false if you want to stop processing further.
*
* @param bean the entity bean to process
* @return true to continue processing more beans or false to stop.
*/
public boolean accept(T bean);
}
package com.avaje.ebean;
/**
* Used to process a query result one bean at a time via a callback to this
* visitor.
* <p>
* If you wish to stop further processing return false from the accept method.
* </p>
* <p>
* Unlike findList() and findSet() using a QueryResultVisitor does not require
* all the beans in the query result to be held in memory at once. This makes
* QueryResultVisitor useful for processing large queries.
* </p>
* <p/>
* <pre class="code">
*
* Query&lt;Customer&gt; query = server.find(Customer.class)
* .fetch(&quot;contacts&quot;, new FetchConfig().query(2))
* .where().gt(&quot;id&quot;, 0)
* .orderBy(&quot;id&quot;)
* .setMaxRows(2);
*
* query.findEachWhile((Customer customer) -> {
*
* // do something with customer
* System.out.println(&quot;-- visit &quot; + customer);
*
* // return true to continue processing or false to stop
* return (customer.getId() < 40);
* });
* </pre>
*
* @param <T> the type of entity bean being queried.
*/
public interface QueryEachWhileConsumer<T> {
/**
* Process the bean and return true if you want to continue processing more
* beans. Return false if you want to stop processing further.
*
* @param bean the entity bean to process
* @return true to continue processing more beans or false to stop.
*/
boolean accept(T bean);
}
@@ -1,60 +1,60 @@
package com.avaje.ebean;
import java.util.Iterator;
/**
* Used to provide iteration over query results.
* <p>
* This can be used when you want to process a very large number of results and
* means that you don't have to hold all the results in memory at once (unlike
* findList(), findSet() etc where all the beans are held in the List or Set
* etc).
* </p>
*
* <pre class="code">
*
* Query&lt;Customer&gt; query = server.find(Customer.class)
* .fetch(&quot;contacts&quot;, new FetchConfig().query(2))
* .where().gt(&quot;id&quot;, 0)
* .orderBy(&quot;id&quot;)
* .setMaxRows(2);
*
* QueryIterator&lt;Customer&gt; it = query.findIterate();
* try {
* while (it.hasNext()) {
* Customer customer = it.next();
* // do something with customer...
* }
* } finally {
* // close the associated resources
* it.close();
* }
* </pre>
*
* @author rbygrave
*
* @param <T>
* the type of entity bean in the iteration
*/
public interface QueryIterator<T> extends Iterator<T>, java.io.Closeable {
/**
* Returns <tt>true</tt> if the iteration has more elements.
*/
public boolean hasNext();
/**
* Returns the next element in the iteration.
*/
public T next();
/**
* Remove is not allowed.
*/
public void remove();
/**
* Close the underlying resources held by this iterator.
*/
public void close();
}
package com.avaje.ebean;
import java.util.Iterator;
/**
* Used to provide iteration over query results.
* <p>
* This can be used when you want to process a very large number of results and
* means that you don't have to hold all the results in memory at once (unlike
* findList(), findSet() etc where all the beans are held in the List or Set
* etc).
* </p>
*
* <pre class="code">
*
* Query&lt;Customer&gt; query = server.find(Customer.class)
* .fetch(&quot;contacts&quot;, new FetchConfig().query(2))
* .where().gt(&quot;id&quot;, 0)
* .orderBy(&quot;id&quot;)
* .setMaxRows(2);
*
* QueryIterator&lt;Customer&gt; it = query.findIterate();
* try {
* while (it.hasNext()) {
* Customer customer = it.next();
* // do something with customer...
* }
* } finally {
* // close the associated resources
* it.close();
* }
* </pre>
*
* @author rbygrave
*
* @param <T>
* the type of entity bean in the iteration
*/
public interface QueryIterator<T> extends Iterator<T>, java.io.Closeable {
/**
* Returns <tt>true</tt> if the iteration has more elements.
*/
boolean hasNext();
/**
* Returns the next element in the iteration.
*/
T next();
/**
* Remove is not allowed.
*/
void remove();
/**
* Close the underlying resources held by this iterator.
*/
void close();
}
@@ -1,49 +1,49 @@
package com.avaje.ebean;
/**
* Used to process a query result one bean at a time via a callback to this
* visitor.
* <p>
* If you wish to stop further processing return false from the accept method.
* </p>
* <p>
* Unlike findList() and findSet() using a QueryResultVisitor does not require
* all the beans in the query result to be held in memory at once. This makes
* QueryResultVisitor useful for processing large queries.
* </p>
*
* <pre class="code">
*
* Query&lt;Customer&gt; query = server.find(Customer.class)
* .fetch(&quot;contacts&quot;, new FetchConfig().query(2))
* .where().gt(&quot;id&quot;, 0)
* .orderBy(&quot;id&quot;)
* .setMaxRows(2);
*
* query.findVisit(new QueryResultVisitor&lt;Customer&gt;() {
*
* public boolean accept(Customer customer) {
* // do something with customer
* System.out.println(&quot;-- visit &quot; + customer);
* return true;
* }
* });
* </pre>
*
* @author rbygrave
*
* @param <T>
* the type of entity bean being queried.
*/
public interface QueryResultVisitor<T> {
/**
* Process the bean and return true if you want to continue processing more
* beans. Return false if you want to stop processing further.
*
* @param bean
* the entity bean to process
* @return true to continue processing or false to stop.
*/
public boolean accept(T bean);
}
package com.avaje.ebean;
/**
* Used to process a query result one bean at a time via a callback to this
* visitor.
* <p>
* If you wish to stop further processing return false from the accept method.
* </p>
* <p>
* Unlike findList() and findSet() using a QueryResultVisitor does not require
* all the beans in the query result to be held in memory at once. This makes
* QueryResultVisitor useful for processing large queries.
* </p>
*
* <pre class="code">
*
* Query&lt;Customer&gt; query = server.find(Customer.class)
* .fetch(&quot;contacts&quot;, new FetchConfig().query(2))
* .where().gt(&quot;id&quot;, 0)
* .orderBy(&quot;id&quot;)
* .setMaxRows(2);
*
* query.findVisit(new QueryResultVisitor&lt;Customer&gt;() {
*
* public boolean accept(Customer customer) {
* // do something with customer
* System.out.println(&quot;-- visit &quot; + customer);
* return true;
* }
* });
* </pre>
*
* @author rbygrave
*
* @param <T>
* the type of entity bean being queried.
*/
public interface QueryResultVisitor<T> {
/**
* Process the bean and return true if you want to continue processing more
* beans. Return false if you want to stop processing further.
*
* @param bean
* the entity bean to process
* @return true to continue processing or false to stop.
*/
boolean accept(T bean);
}
File diff suppressed because it is too large Load Diff
+132 -132
View File
@@ -1,132 +1,132 @@
package com.avaje.ebean;
import java.sql.ResultSet;
import com.avaje.ebean.RawSql.ColumnMapping;
import com.avaje.ebean.RawSql.Sql;
/**
* Builds RawSql instances from a SQL string and column mappings.
* <p>
* Note that RawSql can also be defined in ebean-orm.xml files and be used as a
* named query.
* </p>
*
* @see RawSql
*/
public class RawSqlBuilder {
/**
* Special property name assigned to a DB column that should be ignored.
*/
public static final String IGNORE_COLUMN = "$$_IGNORE_COLUMN_$$";
private final ResultSet resultSet;
private final Sql sql;
private final ColumnMapping columnMapping;
/**
* Create and return a RawSql object based on the resultSet and list of properties the columns in
* the resultSet map to.
* <p>
* The properties listed in the propertyNames must be in the same order as the columns in the
* resultSet.
*/
public static RawSql resultSet(ResultSet resultSet, String... propertyNames) {
return new RawSql(resultSet, propertyNames);
}
/**
* Return an unparsed RawSqlBuilder. Unlike a parsed one this query can not be
* modified - so no additional WHERE or HAVING expressions can be added to
* this query.
*/
public static RawSqlBuilder unparsed(String sql) {
Sql s = new Sql(sql);
return new RawSqlBuilder(s, new ColumnMapping());
}
/**
* Return a RawSqlBuilder parsing the sql.
* <p>
* The sql statement will be parsed so that Ebean can determine where it can
* insert additional WHERE or HAVING expressions.
* </p>
* <p>
* Additionally the selected columns are parsed to determine the column
* ordering. This also means additional checks can be made with the column
* mapping - specifically we can check that all columns are mapped and that
* correct column names are entered into the mapping.
* </p>
*/
public static RawSqlBuilder parse(String sql) {
Sql sql2 = DRawSqlParser.parse(sql);
String select = sql2.getPreFrom();
ColumnMapping mapping = DRawSqlColumnsParser.parse(select);
return new RawSqlBuilder(sql2, mapping);
}
private RawSqlBuilder(Sql sql, ColumnMapping columnMapping) {
this.sql = sql;
this.columnMapping = columnMapping;
this.resultSet = null;
}
/**
* Set the mapping of a DB Column to a bean property.
* <p>
* For Unparsed SQL the columnMapping MUST be defined in the same order that
* the columns appear in the SQL statement.
* </p>
*
* @param dbColumn
* the DB column that we are mapping to a bean property
* @param propertyName
* the bean property that we are mapping the DB column to.
*/
public RawSqlBuilder columnMapping(String dbColumn, String propertyName) {
columnMapping.columnMapping(dbColumn, propertyName);
return this;
}
/**
* Ignore this DB column. It is not mapped to any bean property.
*/
public RawSqlBuilder columnMappingIgnore(String dbColumn) {
return columnMapping(dbColumn, IGNORE_COLUMN);
}
/**
* Modify any column mappings with the given table alias to have the path prefix.
* <p>
* For example modify all mappings with table alias "c" to have the path prefix "customer".
* </p>
*/
public RawSqlBuilder tableAliasMapping(String tableAlias, String path) {
columnMapping.tableAliasMapping(tableAlias, path);
return this;
}
/**
* Create the immutable RawSql object. Do this after all the column mapping
* has been defined.
*/
public RawSql create() {
return new RawSql(resultSet, sql, columnMapping.createImmutableCopy());
}
/**
* Return the internal parsed Sql object (for testing).
*/
protected Sql getSql() {
return sql;
}
}
package com.avaje.ebean;
import java.sql.ResultSet;
import com.avaje.ebean.RawSql.ColumnMapping;
import com.avaje.ebean.RawSql.Sql;
/**
* Builds RawSql instances from a SQL string and column mappings.
* <p>
* Note that RawSql can also be defined in ebean-orm.xml files and be used as a
* named query.
* </p>
*
* @see RawSql
*/
public class RawSqlBuilder {
/**
* Special property name assigned to a DB column that should be ignored.
*/
public static final String IGNORE_COLUMN = "$$_IGNORE_COLUMN_$$";
private final ResultSet resultSet;
private final Sql sql;
private final ColumnMapping columnMapping;
/**
* Create and return a RawSql object based on the resultSet and list of properties the columns in
* the resultSet map to.
* <p>
* The properties listed in the propertyNames must be in the same order as the columns in the
* resultSet.
*/
public static RawSql resultSet(ResultSet resultSet, String... propertyNames) {
return new RawSql(resultSet, propertyNames);
}
/**
* Return an unparsed RawSqlBuilder. Unlike a parsed one this query can not be
* modified - so no additional WHERE or HAVING expressions can be added to
* this query.
*/
public static RawSqlBuilder unparsed(String sql) {
Sql s = new Sql(sql);
return new RawSqlBuilder(s, new ColumnMapping());
}
/**
* Return a RawSqlBuilder parsing the sql.
* <p>
* The sql statement will be parsed so that Ebean can determine where it can
* insert additional WHERE or HAVING expressions.
* </p>
* <p>
* Additionally the selected columns are parsed to determine the column
* ordering. This also means additional checks can be made with the column
* mapping - specifically we can check that all columns are mapped and that
* correct column names are entered into the mapping.
* </p>
*/
public static RawSqlBuilder parse(String sql) {
Sql sql2 = DRawSqlParser.parse(sql);
String select = sql2.getPreFrom();
ColumnMapping mapping = DRawSqlColumnsParser.parse(select);
return new RawSqlBuilder(sql2, mapping);
}
private RawSqlBuilder(Sql sql, ColumnMapping columnMapping) {
this.sql = sql;
this.columnMapping = columnMapping;
this.resultSet = null;
}
/**
* Set the mapping of a DB Column to a bean property.
* <p>
* For Unparsed SQL the columnMapping MUST be defined in the same order that
* the columns appear in the SQL statement.
* </p>
*
* @param dbColumn
* the DB column that we are mapping to a bean property
* @param propertyName
* the bean property that we are mapping the DB column to.
*/
public RawSqlBuilder columnMapping(String dbColumn, String propertyName) {
columnMapping.columnMapping(dbColumn, propertyName);
return this;
}
/**
* Ignore this DB column. It is not mapped to any bean property.
*/
public RawSqlBuilder columnMappingIgnore(String dbColumn) {
return columnMapping(dbColumn, IGNORE_COLUMN);
}
/**
* Modify any column mappings with the given table alias to have the path prefix.
* <p>
* For example modify all mappings with table alias "c" to have the path prefix "customer".
* </p>
*/
public RawSqlBuilder tableAliasMapping(String tableAlias, String path) {
columnMapping.tableAliasMapping(tableAlias, path);
return this;
}
/**
* Create the immutable RawSql object. Do this after all the column mapping
* has been defined.
*/
public RawSql create() {
return new RawSql(resultSet, sql, columnMapping.createImmutableCopy());
}
/**
* Return the internal parsed Sql object (for testing).
*/
protected Sql getSql() {
return sql;
}
}
@@ -1,47 +1,47 @@
package com.avaje.ebean;
import java.util.List;
import java.util.concurrent.Future;
/**
* The SqlFutureList represents the result of a background SQL query execution.
*
* <p>
* It extends the java.util.concurrent.Future.
* </p>
*
* <pre class="code">
* // create a query
* String sql = ... ;
* SqlQuery sqlQuery = Ebean.createSqlQuery(sql);
*
* // execute the query in a background thread
* SqlFutureList sqlFuture = sqlQuery.findFutureList();
*
* // do something else ... we will sleep
* Thread.sleep(3000);
* System.out.println("end of sleep");
*
* if (!futureList.isDone()){
* // we can cancel the query execution
* futureList.cancel(true);
* }
*
* System.out.println("and... done:"+futureList.isDone());
*
* if (!futureList.isCancelled()){
* // wait for the query to finish and return the list
* List&lt;SqlRow&gt; list = futureList.get();
* System.out.println("list:"+list);
* }
*
* </pre>
*
* @author rob
*
*/
public interface SqlFutureList extends Future<List<SqlRow>> {
public SqlQuery getQuery();
}
package com.avaje.ebean;
import java.util.List;
import java.util.concurrent.Future;
/**
* The SqlFutureList represents the result of a background SQL query execution.
*
* <p>
* It extends the java.util.concurrent.Future.
* </p>
*
* <pre class="code">
* // create a query
* String sql = ... ;
* SqlQuery sqlQuery = Ebean.createSqlQuery(sql);
*
* // execute the query in a background thread
* SqlFutureList sqlFuture = sqlQuery.findFutureList();
*
* // do something else ... we will sleep
* Thread.sleep(3000);
* System.out.println("end of sleep");
*
* if (!futureList.isDone()){
* // we can cancel the query execution
* futureList.cancel(true);
* }
*
* System.out.println("and... done:"+futureList.isDone());
*
* if (!futureList.isCancelled()){
* // wait for the query to finish and return the list
* List&lt;SqlRow&gt; list = futureList.get();
* System.out.println("list:"+list);
* }
*
* </pre>
*
* @author rob
*
*/
public interface SqlFutureList extends Future<List<SqlRow>> {
SqlQuery getQuery();
}
+151 -151
View File
@@ -1,151 +1,151 @@
package com.avaje.ebean;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Query object for performing native SQL queries that return SqlRow's.
* <p>
* Firstly note that you can use your own sql queries with <em>entity beans</em>
* by using the SqlSelect annotation. This should be your first approach when
* wanting to use your own SQL queries.
* </p>
* <p>
* If ORM Mapping is too tight and constraining for your problem then SqlQuery
* could be a good approach.
* </p>
* <p>
* The returned SqlRow objects are similar to a LinkedHashMap with some type
* conversion support added.
* </p>
*
* <pre class="code">
* // its typically a good idea to use a named query
* // and put the sql in the orm.xml instead of in your code
*
* String sql = &quot;select id, name from customer where name like :name and status_code = :status&quot;;
*
* SqlQuery sqlQuery = Ebean.createSqlQuery(sql);
* sqlQuery.setParameter(&quot;name&quot;, &quot;Acme%&quot;);
* sqlQuery.setParameter(&quot;status&quot;, &quot;ACTIVE&quot;);
*
* // execute the query returning a List of MapBean objects
* List&lt;SqlRow&gt; list = sqlQuery.findList();
* </pre>
*
*/
public interface SqlQuery extends Serializable {
/**
* Cancel the query if support by the underlying database and driver.
* <p>
* This must be called from a different thread to the one executing the query.
* </p>
*/
public void cancel();
/**
* Execute the query returning a list.
*/
public List<SqlRow> findList();
/**
* Execute the query returning a set.
*/
public Set<SqlRow> findSet();
/**
* Execute the query returning a map.
*/
public Map<?, SqlRow> findMap();
/**
* Execute the query returning a single row or null.
* <p>
* If this query finds 2 or more rows then it will throw a
* PersistenceException.
* </p>
*/
public SqlRow findUnique();
/**
* Execute find list SQL query in a background thread.
* <p>
* This returns a Future object which can be used to cancel, check the
* execution status (isDone etc) and get the value (with or without a
* timeout).
* </p>
*
* @return a Future object for the list result of the query
* @deprecated
*/
public SqlFutureList findFutureList();
/**
* The same as bind for named parameters.
*/
public SqlQuery setParameter(String name, Object value);
/**
* The same as bind for positioned parameters.
*/
public SqlQuery setParameter(int position, Object value);
/**
* Set a listener to process the query on a row by row basis.
* <p>
* It this case the rows are not loaded into the persistence context and
* instead can be processed by the query listener.
* </p>
* <p>
* Use this when you want to process a large query and do not want to hold the
* entire query result in memory.
* </p>
*/
public SqlQuery setListener(SqlQueryListener queryListener);
/**
* Set the index of the first row of the results to return.
*/
public SqlQuery setFirstRow(int firstRow);
/**
* Set the maximum number of query results to return.
*/
public SqlQuery setMaxRows(int maxRows);
/**
* Set the index after which fetching continues in a background thread.
*/
public SqlQuery setBackgroundFetchAfter(int backgroundFetchAfter);
/**
* Set the column to use to determine the keys for a Map.
*/
public SqlQuery setMapKey(String mapKey);
/**
* Set a timeout on this query.
* <p>
* This will typically result in a call to setQueryTimeout() on a
* preparedStatement. If the timeout occurs an exception will be thrown - this
* will be a SQLException wrapped up in a PersistenceException.
* </p>
*
* @param secs
* the query timeout limit in seconds. Zero means there is no limit.
*/
public SqlQuery setTimeout(int secs);
/**
* A hint which for JDBC translates to the Statement.fetchSize().
* <p>
* Gives the JDBC driver a hint as to the number of rows that should be
* fetched from the database when more rows are needed for ResultSet.
* </p>
*/
public SqlQuery setBufferFetchSizeHint(int bufferFetchSizeHint);
}
package com.avaje.ebean;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Query object for performing native SQL queries that return SqlRow's.
* <p>
* Firstly note that you can use your own sql queries with <em>entity beans</em>
* by using the SqlSelect annotation. This should be your first approach when
* wanting to use your own SQL queries.
* </p>
* <p>
* If ORM Mapping is too tight and constraining for your problem then SqlQuery
* could be a good approach.
* </p>
* <p>
* The returned SqlRow objects are similar to a LinkedHashMap with some type
* conversion support added.
* </p>
*
* <pre class="code">
* // its typically a good idea to use a named query
* // and put the sql in the orm.xml instead of in your code
*
* String sql = &quot;select id, name from customer where name like :name and status_code = :status&quot;;
*
* SqlQuery sqlQuery = Ebean.createSqlQuery(sql);
* sqlQuery.setParameter(&quot;name&quot;, &quot;Acme%&quot;);
* sqlQuery.setParameter(&quot;status&quot;, &quot;ACTIVE&quot;);
*
* // execute the query returning a List of MapBean objects
* List&lt;SqlRow&gt; list = sqlQuery.findList();
* </pre>
*
*/
public interface SqlQuery extends Serializable {
/**
* Cancel the query if support by the underlying database and driver.
* <p>
* This must be called from a different thread to the one executing the query.
* </p>
*/
void cancel();
/**
* Execute the query returning a list.
*/
List<SqlRow> findList();
/**
* Execute the query returning a set.
*/
Set<SqlRow> findSet();
/**
* Execute the query returning a map.
*/
Map<?, SqlRow> findMap();
/**
* Execute the query returning a single row or null.
* <p>
* If this query finds 2 or more rows then it will throw a
* PersistenceException.
* </p>
*/
SqlRow findUnique();
/**
* Execute find list SQL query in a background thread.
* <p>
* This returns a Future object which can be used to cancel, check the
* execution status (isDone etc) and get the value (with or without a
* timeout).
* </p>
*
* @return a Future object for the list result of the query
* @deprecated
*/
SqlFutureList findFutureList();
/**
* The same as bind for named parameters.
*/
SqlQuery setParameter(String name, Object value);
/**
* The same as bind for positioned parameters.
*/
SqlQuery setParameter(int position, Object value);
/**
* Set a listener to process the query on a row by row basis.
* <p>
* It this case the rows are not loaded into the persistence context and
* instead can be processed by the query listener.
* </p>
* <p>
* Use this when you want to process a large query and do not want to hold the
* entire query result in memory.
* </p>
*/
SqlQuery setListener(SqlQueryListener queryListener);
/**
* Set the index of the first row of the results to return.
*/
SqlQuery setFirstRow(int firstRow);
/**
* Set the maximum number of query results to return.
*/
SqlQuery setMaxRows(int maxRows);
/**
* Set the index after which fetching continues in a background thread.
*/
SqlQuery setBackgroundFetchAfter(int backgroundFetchAfter);
/**
* Set the column to use to determine the keys for a Map.
*/
SqlQuery setMapKey(String mapKey);
/**
* Set a timeout on this query.
* <p>
* This will typically result in a call to setQueryTimeout() on a
* preparedStatement. If the timeout occurs an exception will be thrown - this
* will be a SQLException wrapped up in a PersistenceException.
* </p>
*
* @param secs
* the query timeout limit in seconds. Zero means there is no limit.
*/
SqlQuery setTimeout(int secs);
/**
* A hint which for JDBC translates to the Statement.fetchSize().
* <p>
* Gives the JDBC driver a hint as to the number of rows that should be
* fetched from the database when more rows are needed for ResultSet.
* </p>
*/
SqlQuery setBufferFetchSizeHint(int bufferFetchSizeHint);
}
@@ -1,33 +1,33 @@
package com.avaje.ebean;
/**
* Provides a mechanism for processing a SqlQuery one SqlRow at a time.
* <p>
* This is useful when the query will return a large number of results and you
* want to process the beans one at a time rather than have all of the beans in
* memory at once.
* </p>
*
* <pre class="code">
* SqlQueryListener listener = ...;
*
* SqlQuery query = Ebean.createSqlQuery(&quot;my.large.query&quot;);
*
* // set the listener that will process each row one at a time
* query.setListener(listener);
*
* // execute the query. Note that the returned
* // list will be empty ... so don't bother assigning it...
* query.findList();
* </pre>
*/
public interface SqlQueryListener {
/**
* Process the bean that has just been read.
* <p>
* Note this bean will not be added to the List Set or Map.
* </p>
*/
public void process(SqlRow bean);
}
package com.avaje.ebean;
/**
* Provides a mechanism for processing a SqlQuery one SqlRow at a time.
* <p>
* This is useful when the query will return a large number of results and you
* want to process the beans one at a time rather than have all of the beans in
* memory at once.
* </p>
*
* <pre class="code">
* SqlQueryListener listener = ...;
*
* SqlQuery query = Ebean.createSqlQuery(&quot;my.large.query&quot;);
*
* // set the listener that will process each row one at a time
* query.setListener(listener);
*
* // execute the query. Note that the returned
* // list will be empty ... so don't bother assigning it...
* query.findList();
* </pre>
*/
public interface SqlQueryListener {
/**
* Process the bean that has just been read.
* <p>
* Note this bean will not be added to the List Set or Map.
* </p>
*/
void process(SqlRow bean);
}
+167 -167
View File
@@ -1,168 +1,168 @@
package com.avaje.ebean;
import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.Date;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
/**
* Used to return raw SQL query results.
* <p>
* Refer to {@link SqlQuery} for examples.
* </p>
* <p>
* There are convenience methods such as getInteger(), getBigDecimal() etc. The
* reason for these methods is that the values put into this map often come
* straight from the JDBC resultSet. Depending on the JDBC driver it may put a
* different type into a given property. For example an Integer, BigDecimal,
* Double could all be put into a property depending on the JDBC driver used.
* These convenience methods automatically convert the value as required
* returning the type you expect.
* </p>
*/
public interface SqlRow extends Serializable, Map<String, Object> {
/**
* Return the property names (String).
* <p>
* Internally this uses LinkedHashMap and so the order of the property names
* should be predictable and ordered by the use of LinkedHashMap.
* </p>
*/
public Iterator<String> keys();
/**
* Remove a property from the map. Returns the value of the removed property.
*/
public Object remove(Object name);
/**
* Return a property value by its name.
*/
public Object get(Object name);
/**
* Set a value to a property.
*/
public Object put(String name, Object value);
/**
* Exactly the same as the put method.
* <p>
* I added this method because it seems more bean like to have get and set
* methods.
* </p>
*/
public Object set(String name, Object value);
/**
* Return a property as a Boolean.
*/
public Boolean getBoolean(String name);
/**
* Return a property as a UUID.
*/
public UUID getUUID(String name);
/**
* Return a property as an Integer.
*/
public Integer getInteger(String name);
/**
* Return a property value as a BigDecimal.
*/
public BigDecimal getBigDecimal(String name);
/**
* Return a property value as a Long.
*/
public Long getLong(String name);
/**
* Return the property value as a Double.
*/
public Double getDouble(String name);
/**
* Return the property value as a Float.
*/
public Float getFloat(String name);
/**
* Return a property as a String.
*/
public String getString(String name);
/**
* Return the property as a java.util.Date.
*/
public java.util.Date getUtilDate(String name);
/**
* Return the property as a sql date.
*/
public Date getDate(String name);
/**
* Return the property as a sql timestamp.
*/
public Timestamp getTimestamp(String name);
/**
* String description of the underlying map.
*/
public String toString();
/**
* Clear the map.
*/
public void clear();
/**
* Returns true if the map contains the property.
*/
public boolean containsKey(Object key);
/**
* Returns true if the map contains the value.
*/
public boolean containsValue(Object value);
/**
* Returns the entrySet of the map.
*/
public Set<Map.Entry<String, Object>> entrySet();
/**
* Returns true if the map is empty.
*/
public boolean isEmpty();
/**
* Returns the key set of the map.
*/
public Set<String> keySet();
/**
* Put all the values from t into this map.
*/
public void putAll(Map<? extends String, ? extends Object> t);
/**
* Return the size of the map.
*/
public int size();
/**
* Return the values from this map.
*/
public Collection<Object> values();
package com.avaje.ebean;
import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.Date;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
/**
* Used to return raw SQL query results.
* <p>
* Refer to {@link SqlQuery} for examples.
* </p>
* <p>
* There are convenience methods such as getInteger(), getBigDecimal() etc. The
* reason for these methods is that the values put into this map often come
* straight from the JDBC resultSet. Depending on the JDBC driver it may put a
* different type into a given property. For example an Integer, BigDecimal,
* Double could all be put into a property depending on the JDBC driver used.
* These convenience methods automatically convert the value as required
* returning the type you expect.
* </p>
*/
public interface SqlRow extends Serializable, Map<String, Object> {
/**
* Return the property names (String).
* <p>
* Internally this uses LinkedHashMap and so the order of the property names
* should be predictable and ordered by the use of LinkedHashMap.
* </p>
*/
Iterator<String> keys();
/**
* Remove a property from the map. Returns the value of the removed property.
*/
Object remove(Object name);
/**
* Return a property value by its name.
*/
Object get(Object name);
/**
* Set a value to a property.
*/
Object put(String name, Object value);
/**
* Exactly the same as the put method.
* <p>
* I added this method because it seems more bean like to have get and set
* methods.
* </p>
*/
Object set(String name, Object value);
/**
* Return a property as a Boolean.
*/
Boolean getBoolean(String name);
/**
* Return a property as a UUID.
*/
UUID getUUID(String name);
/**
* Return a property as an Integer.
*/
Integer getInteger(String name);
/**
* Return a property value as a BigDecimal.
*/
BigDecimal getBigDecimal(String name);
/**
* Return a property value as a Long.
*/
Long getLong(String name);
/**
* Return the property value as a Double.
*/
Double getDouble(String name);
/**
* Return the property value as a Float.
*/
Float getFloat(String name);
/**
* Return a property as a String.
*/
String getString(String name);
/**
* Return the property as a java.util.Date.
*/
java.util.Date getUtilDate(String name);
/**
* Return the property as a sql date.
*/
Date getDate(String name);
/**
* Return the property as a sql timestamp.
*/
Timestamp getTimestamp(String name);
/**
* String description of the underlying map.
*/
String toString();
/**
* Clear the map.
*/
void clear();
/**
* Returns true if the map contains the property.
*/
boolean containsKey(Object key);
/**
* Returns true if the map contains the value.
*/
boolean containsValue(Object value);
/**
* Returns the entrySet of the map.
*/
Set<Map.Entry<String, Object>> entrySet();
/**
* Returns true if the map is empty.
*/
boolean isEmpty();
/**
* Returns the key set of the map.
*/
Set<String> keySet();
/**
* Put all the values from t into this map.
*/
void putAll(Map<? extends String, ? extends Object> t);
/**
* Return the size of the map.
*/
int size();
/**
* Return the values from this map.
*/
Collection<Object> values();
}
+145 -145
View File
@@ -1,146 +1,146 @@
package com.avaje.ebean;
/**
* A SqlUpdate for executing insert update or delete statements.
* <p>
* Provides a simple way to execute raw SQL insert update or delete statements
* without having to resort to JDBC.
* </p>
* <p>
* Supports the use of positioned or named parameters and can automatically
* notify Ebean of the table modified so that Ebean can maintain its cache.
* </p>
* <p>
* Note that {@link #setAutoTableMod(boolean)} and
* Ebean#externalModification(String, boolean, boolean, boolean)} can be to
* notify Ebean of external changes and enable Ebean to maintain it's "L2"
* server cache.
* </p>
*
* <pre class="code">
* // example that uses 'named' parameters
* String s = &quot;UPDATE f_topic set post_count = :count where id = :id&quot;
* SqlUpdate update = Ebean.createSqlUpdate(s);
* update.setParameter(&quot;id&quot;, 1);
* update.setParameter(&quot;count&quot;, 50);
*
* int modifiedCount = Ebean.execute(update);
*
* String msg = &quot;There where &quot; + modifiedCount + &quot;rows updated&quot;
* </pre>
*
* @see Update
* @see SqlQuery
* @see CallableSql
*/
public interface SqlUpdate {
/**
* Execute the update returning the number of rows modified.
* <p>
* After you have executed the SqlUpdate you can bind new variables using
* {@link #setParameter(String, Object)} etc and then execute the SqlUpdate
* again.
* </p>
* <p>
* For JDBC batch processing refer to
* {@link Transaction#setBatchMode(boolean)} and
* {@link Transaction#setBatchSize(int)}.
* </p>
*
* @see com.avaje.ebean.Ebean#execute(SqlUpdate)
*/
public int execute();
/**
* Return true if eBean should automatically deduce the table modification
* information and process it.
* <p>
* If this is true then cache invalidation and text index management are aware
* of the modification.
* </p>
*/
public boolean isAutoTableMod();
/**
* Set this to false if you don't want eBean to automatically deduce the table
* modification information and process it.
* <p>
* Set this to false if you don't want any cache invalidation or text index
* management to occur. You may do this when say you update only one column
* and you know that it is not important for cached objects or text indexes.
* </p>
*/
public SqlUpdate setAutoTableMod(boolean isAutoTableMod);
/**
* Return the label that can be seen in the transaction logs.
*/
public String getLabel();
/**
* Set a descriptive text that can be put into the transaction log.
* <p>
* Useful when identifying the statement in the transaction log.
* </p>
*/
public SqlUpdate setLabel(String label);
/**
* Return the sql statement.
*/
public String getSql();
/**
* Return the generated sql that has named parameters converted to positioned parameters.
*/
public String getGeneratedSql();
/**
* Return the timeout used to execute this statement.
*/
public int getTimeout();
/**
* Set the timeout in seconds. Zero implies no limit.
* <p>
* This will set the query timeout on the underlying PreparedStatement. If the
* timeout expires a SQLException will be throw and wrapped in a
* PersistenceException.
* </p>
*/
public SqlUpdate setTimeout(int secs);
/**
* Set a parameter via its index position.
*/
public SqlUpdate setParameter(int position, Object value);
/**
* Set a null parameter via its index position. Exactly the same as
* {@link #setNull(int, int)}.
*/
public SqlUpdate setNull(int position, int jdbcType);
/**
* Set a null valued parameter using its index position.
*/
public SqlUpdate setNullParameter(int position, int jdbcType);
/**
* Set a named parameter value.
*/
public SqlUpdate setParameter(String name, Object param);
/**
* Set a named parameter that has a null value. Exactly the same as
* {@link #setNullParameter(String, int)}.
*/
public SqlUpdate setNull(String name, int jdbcType);
/**
* Set a named parameter that has a null value.
*/
public SqlUpdate setNullParameter(String name, int jdbcType);
package com.avaje.ebean;
/**
* A SqlUpdate for executing insert update or delete statements.
* <p>
* Provides a simple way to execute raw SQL insert update or delete statements
* without having to resort to JDBC.
* </p>
* <p>
* Supports the use of positioned or named parameters and can automatically
* notify Ebean of the table modified so that Ebean can maintain its cache.
* </p>
* <p>
* Note that {@link #setAutoTableMod(boolean)} and
* Ebean#externalModification(String, boolean, boolean, boolean)} can be to
* notify Ebean of external changes and enable Ebean to maintain it's "L2"
* server cache.
* </p>
*
* <pre class="code">
* // example that uses 'named' parameters
* String s = &quot;UPDATE f_topic set post_count = :count where id = :id&quot;
* SqlUpdate update = Ebean.createSqlUpdate(s);
* update.setParameter(&quot;id&quot;, 1);
* update.setParameter(&quot;count&quot;, 50);
*
* int modifiedCount = Ebean.execute(update);
*
* String msg = &quot;There where &quot; + modifiedCount + &quot;rows updated&quot;
* </pre>
*
* @see Update
* @see SqlQuery
* @see CallableSql
*/
public interface SqlUpdate {
/**
* Execute the update returning the number of rows modified.
* <p>
* After you have executed the SqlUpdate you can bind new variables using
* {@link #setParameter(String, Object)} etc and then execute the SqlUpdate
* again.
* </p>
* <p>
* For JDBC batch processing refer to
* {@link Transaction#setBatchMode(boolean)} and
* {@link Transaction#setBatchSize(int)}.
* </p>
*
* @see com.avaje.ebean.Ebean#execute(SqlUpdate)
*/
int execute();
/**
* Return true if eBean should automatically deduce the table modification
* information and process it.
* <p>
* If this is true then cache invalidation and text index management are aware
* of the modification.
* </p>
*/
boolean isAutoTableMod();
/**
* Set this to false if you don't want eBean to automatically deduce the table
* modification information and process it.
* <p>
* Set this to false if you don't want any cache invalidation or text index
* management to occur. You may do this when say you update only one column
* and you know that it is not important for cached objects or text indexes.
* </p>
*/
SqlUpdate setAutoTableMod(boolean isAutoTableMod);
/**
* Return the label that can be seen in the transaction logs.
*/
String getLabel();
/**
* Set a descriptive text that can be put into the transaction log.
* <p>
* Useful when identifying the statement in the transaction log.
* </p>
*/
SqlUpdate setLabel(String label);
/**
* Return the sql statement.
*/
String getSql();
/**
* Return the generated sql that has named parameters converted to positioned parameters.
*/
String getGeneratedSql();
/**
* Return the timeout used to execute this statement.
*/
int getTimeout();
/**
* Set the timeout in seconds. Zero implies no limit.
* <p>
* This will set the query timeout on the underlying PreparedStatement. If the
* timeout expires a SQLException will be throw and wrapped in a
* PersistenceException.
* </p>
*/
SqlUpdate setTimeout(int secs);
/**
* Set a parameter via its index position.
*/
SqlUpdate setParameter(int position, Object value);
/**
* Set a null parameter via its index position. Exactly the same as
* {@link #setNull(int, int)}.
*/
SqlUpdate setNull(int position, int jdbcType);
/**
* Set a null valued parameter using its index position.
*/
SqlUpdate setNullParameter(int position, int jdbcType);
/**
* Set a named parameter value.
*/
SqlUpdate setParameter(String name, Object param);
/**
* Set a named parameter that has a null value. Exactly the same as
* {@link #setNullParameter(String, int)}.
*/
SqlUpdate setNull(String name, int jdbcType);
/**
* Set a named parameter that has a null value.
*/
SqlUpdate setNullParameter(String name, int jdbcType);
}
+329 -329
View File
@@ -1,329 +1,329 @@
package com.avaje.ebean;
import com.avaje.ebean.config.PersistBatch;
import javax.persistence.OptimisticLockException;
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 {
/**
* Read Committed transaction isolation. Same as
* java.sql.Connection.TRANSACTION_READ_COMMITTED.
*/
public static final int READ_COMMITTED = java.sql.Connection.TRANSACTION_READ_COMMITTED;
/**
* Read Uncommitted transaction isolation. Same as
* java.sql.Connection.TRANSACTION_READ_UNCOMMITTED.
*/
public static final int READ_UNCOMMITTED = java.sql.Connection.TRANSACTION_READ_UNCOMMITTED;
/**
* Repeatable read transaction isolation. Same as
* java.sql.Connection.TRANSACTION_REPEATABLE_READ.
*/
public static final int REPEATABLE_READ = java.sql.Connection.TRANSACTION_REPEATABLE_READ;
/**
* Serializable transaction isolation. Same as
* java.sql.Connection.TRANSACTION_SERIALIZABLE.
*/
public static final int SERIALIZABLE = java.sql.Connection.TRANSACTION_SERIALIZABLE;
/**
* Register a TransactionCallback with this transaction.
*/
public void register(TransactionCallback callback);
/**
* Return true if this transaction is read only.
*/
public boolean isReadOnly();
/**
* Set whether this transaction should be readOnly.
*/
public void setReadOnly(boolean readOnly);
/**
* Commit the transaction.
*/
public void commit() throws RollbackException;
/**
* Rollback the transaction.
*/
public void rollback() throws PersistenceException;
/**
* Rollback the transaction specifying a throwable that caused the rollback to
* occur.
* <p>
* If you are using transaction logging this will log the throwable in the
* transaction logs.
* </p>
*/
public void rollback(Throwable e) throws PersistenceException;
/**
* If the transaction is active then perform rollback. Otherwise do nothing.
*/
public void end() throws PersistenceException;
/**
* Return true if the transaction is active.
*/
public boolean isActive();
/**
* Explicitly turn off or on the cascading nature of save() and delete(). This
* gives the developer exact control over what beans are saved and deleted
* rather than Ebean cascading detecting 'dirty/modified' beans etc.
* <p>
* This is useful if you can getting back entity beans from a layer of code
* (potentially remote) and you prefer to have exact control.
* </p>
* <p>
* This may also be useful if you are using jdbc batching with jdbc drivers
* that do not support getGeneratedKeys.
* </p>
*/
public void setPersistCascade(boolean persistCascade);
/**
* Turn on or off statement batching. Statement batching can be transparent
* for drivers and databases that support getGeneratedKeys. Otherwise you may
* wish to specifically control when batching is used via this method.
* <p>
* Refer to <code>java.sql.PreparedStatement.addBatch();</code>
* <p>
* Note that you may also wish to use the setPersistCascade method to stop
* save and delete cascade behaviour. You may do this to have full control
* over the order of execution rather than the normal cascading fashion.
* </p>
* <p>
* Note that the <em>execution order</em> in batch mode may be different from
* non batch mode execution order. Also note that <em>insert behaviour</em>
* may be different depending on the JDBC driver and its support for
* getGeneratedKeys. That is, for JDBC drivers that do not support
* getGeneratedKeys you may not get back the generated IDs (used for inserting
* associated detail beans etc).
* </p>
* <p>
* Calls to save(), delete(), insert() and execute() all support batch
* processing. This includes normal beans, MapBean, CallableSql and UpdateSql.
* </p>
* <p>
* The flushing of the batched statements is automatic but you can call
* batchFlush when you like. Note that flushing occurs when a query is
* executed or when you mix UpdateSql and CallableSql with save and delete of
* beans.
* </p>
* <p>
* Example: batch processing executing every 3 rows
* </p>
*
* <pre>{@code
*
* String data = "This is a simple test of the batch processing"
* + " mode and the transaction execute batch method";
*
* String[] da = data.split(" ");
*
* String sql = "{call sp_t3(?,?)}";
*
* CallableSql cs = new CallableSql(sql);
* cs.registerOut(2, Types.INTEGER);
*
* // (optional) inform eBean this stored procedure
* // inserts into a table called sp_test
* cs.addModification("sp_test", true, false, false);
*
* Transaction txn = ebeanServer.beginTransaction();
* txn.setBatchMode(true);
* txn.setBatchSize(3);
* try {
* for (int i = 0; i < da.length;) {
* cs.setParameter(1, da[i]);
* ebeanServer.execute(cs);
* }
*
* // NB: commit implicitly flushes
* txn.commit();
*
* } finally {
* txn.end();
* }
*
* }</pre>
*
*/
public void setBatchMode(boolean useBatch);
/**
* The JDBC batch mode to use for this transaction.
* <p>
* If this is NONE then JDBC batch can still be used for each request - save(), insert(), update() or delete()
* and this would be useful if the request cascades to detail beans.
* </p>
*
* @param persistBatchMode the batch mode to use for this transaction
*
* @see com.avaje.ebean.config.ServerConfig#setPersistBatch(com.avaje.ebean.config.PersistBatch)
*/
public void setBatch(PersistBatch persistBatchMode);
/**
* Return the batch mode at the transaction level.
*/
public PersistBatch getBatch();
/**
* Set the JDBC batch mode to use for a save() or delete() request.
* <p>
* This only takes effect when batch mode on the transaction has not already meant that
* JDBC batch mode is being used.
* </p>
* <p>
* This is useful when the single save() or delete() cascades. For example, inserting a 'master' cascades
* and inserts a collection of 'detail' beans. The detail beans can be inserted using JDBC batch.
* </p>
*
* @param batchOnCascadeMode the batch mode to use per save(), insert(), update() or delete()
*
* @see com.avaje.ebean.config.ServerConfig#setPersistBatchOnCascade(com.avaje.ebean.config.PersistBatch)
*/
public void setBatchOnCascade(PersistBatch batchOnCascadeMode);
/**
* Return the batch mode at the request level (for each save(), insert(), update() or delete()).
*/
public PersistBatch getBatchOnCascade();
/**
* Specify the number of statements before a batch is flushed automatically.
*/
public void setBatchSize(int batchSize);
/**
* Return the current batch size.
*/
public int getBatchSize();
/**
* Specify if you want batched inserts to use getGeneratedKeys.
* <p>
* By default batched inserts will try to use getGeneratedKeys if it is
* supported by the underlying jdbc driver and database.
* </p>
* <p>
* You may want to turn getGeneratedKeys off when you are inserting a large
* number of objects and you don't care about getting back the ids.
* </p>
*/
public void setBatchGetGeneratedKeys(boolean getGeneratedKeys);
/**
* By default when mixing UpdateSql (or CallableSql) with Beans the batch is
* automatically flushed when you change (between persisting beans and
* executing UpdateSql or CallableSql).
* <p>
* If you want to execute both WITHOUT having the batch automatically flush
* you need to call this with batchFlushOnMixed = false.
* </p>
* <p>
* Note that UpdateSql and CallableSql are ALWAYS executed first (before the
* beans are executed). This is because the UpdateSql and CallableSql have
* already been bound to their PreparedStatements. The beans on the other hand
* have a 2 step process (delayed binding).
* </p>
*/
public void setBatchFlushOnMixed(boolean batchFlushOnMixed);
/**
* By default executing a query will automatically flush any batched
* statements (persisted beans, executed UpdateSql etc).
* <p>
* Calling this method with batchFlushOnQuery = false means that you can
* execute a query and the batch will not be automatically flushed.
* </p>
*/
public void setBatchFlushOnQuery(boolean batchFlushOnQuery);
/**
* Return true if the batch (of persisted beans or executed UpdateSql etc)
* should be flushed prior to executing a query.
* <p>
* The default is for this to be true.
* </p>
*/
public boolean isBatchFlushOnQuery();
/**
* The batch will be flushing automatically but you can use this to explicitly
* flush the batch if you like.
* <p>
* Flushing occurs automatically when:
* </p>
* <ul>
* <li>the batch size is reached</li>
* <li>A query is executed on the same transaction</li>
* <li>UpdateSql or CallableSql are mixed with bean save and delete</li>
* <li>Transaction commit occurs</li>
* </ul>
*/
public void flushBatch() throws PersistenceException, OptimisticLockException;
/**
* Return the underlying Connection object.
* <p>
* Useful where a Developer wishes to use the JDBC API directly. Note that the
* commit() rollback() and end() methods on the Transaction should still be
* used. Calling these methods on the Connection would be a big no no unless
* you know what you are doing.
* </p>
* <p>
* Examples of when a developer may wish to use the connection directly are:
* Savepoints, advanced CLOB BLOB use and advanced stored procedure calls.
* </p>
*/
public Connection getConnection();
/**
* Add table modification information to the TransactionEvent.
* <p>
* Use this in conjunction with getConnection() and raw JDBC.
* </p>
* <p>
* This effectively informs Ebean of the data that has been changed by the
* transaction and this information is normally automatically handled by Ebean
* when you save entity beans or use UpdateSql etc.
* </p>
* <p>
* If you use raw JDBC then you can use this method to inform Ebean for the
* tables that have been modified. Ebean uses this information to keep its
* caches in synch and maintain text indexes.
* </p>
*/
public void addModification(String tableName, boolean inserts, boolean updates, boolean deletes);
/**
* Add an arbitrary user object to the transaction. The objects added have no
* impact on any internals of ebena and are solely meant as a convenient
* method push user information to e.g. the
* {@link com.avaje.ebean.event.TransactionEventListener}.
*/
public void putUserObject(String name, Object value);
/**
* Get an object added with {@link #putUserObject(String, Object)}.
*/
public Object getUserObject(String name);
}
package com.avaje.ebean;
import com.avaje.ebean.config.PersistBatch;
import javax.persistence.OptimisticLockException;
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 {
/**
* Read Committed transaction isolation. Same as
* java.sql.Connection.TRANSACTION_READ_COMMITTED.
*/
int READ_COMMITTED = java.sql.Connection.TRANSACTION_READ_COMMITTED;
/**
* Read Uncommitted transaction isolation. Same as
* java.sql.Connection.TRANSACTION_READ_UNCOMMITTED.
*/
int READ_UNCOMMITTED = java.sql.Connection.TRANSACTION_READ_UNCOMMITTED;
/**
* Repeatable read transaction isolation. Same as
* java.sql.Connection.TRANSACTION_REPEATABLE_READ.
*/
int REPEATABLE_READ = java.sql.Connection.TRANSACTION_REPEATABLE_READ;
/**
* Serializable transaction isolation. Same as
* java.sql.Connection.TRANSACTION_SERIALIZABLE.
*/
int SERIALIZABLE = java.sql.Connection.TRANSACTION_SERIALIZABLE;
/**
* Register a TransactionCallback with this transaction.
*/
void register(TransactionCallback callback);
/**
* Return true if this transaction is read only.
*/
boolean isReadOnly();
/**
* Set whether this transaction should be readOnly.
*/
void setReadOnly(boolean readOnly);
/**
* Commit the transaction.
*/
void commit() throws RollbackException;
/**
* Rollback the transaction.
*/
void rollback() throws PersistenceException;
/**
* Rollback the transaction specifying a throwable that caused the rollback to
* occur.
* <p>
* If you are using transaction logging this will log the throwable in the
* transaction logs.
* </p>
*/
void rollback(Throwable e) throws PersistenceException;
/**
* If the transaction is active then perform rollback. Otherwise do nothing.
*/
void end() throws PersistenceException;
/**
* Return true if the transaction is active.
*/
boolean isActive();
/**
* Explicitly turn off or on the cascading nature of save() and delete(). This
* gives the developer exact control over what beans are saved and deleted
* rather than Ebean cascading detecting 'dirty/modified' beans etc.
* <p>
* This is useful if you can getting back entity beans from a layer of code
* (potentially remote) and you prefer to have exact control.
* </p>
* <p>
* This may also be useful if you are using jdbc batching with jdbc drivers
* that do not support getGeneratedKeys.
* </p>
*/
void setPersistCascade(boolean persistCascade);
/**
* Turn on or off statement batching. Statement batching can be transparent
* for drivers and databases that support getGeneratedKeys. Otherwise you may
* wish to specifically control when batching is used via this method.
* <p>
* Refer to <code>java.sql.PreparedStatement.addBatch();</code>
* <p>
* Note that you may also wish to use the setPersistCascade method to stop
* save and delete cascade behaviour. You may do this to have full control
* over the order of execution rather than the normal cascading fashion.
* </p>
* <p>
* Note that the <em>execution order</em> in batch mode may be different from
* non batch mode execution order. Also note that <em>insert behaviour</em>
* may be different depending on the JDBC driver and its support for
* getGeneratedKeys. That is, for JDBC drivers that do not support
* getGeneratedKeys you may not get back the generated IDs (used for inserting
* associated detail beans etc).
* </p>
* <p>
* Calls to save(), delete(), insert() and execute() all support batch
* processing. This includes normal beans, MapBean, CallableSql and UpdateSql.
* </p>
* <p>
* The flushing of the batched statements is automatic but you can call
* batchFlush when you like. Note that flushing occurs when a query is
* executed or when you mix UpdateSql and CallableSql with save and delete of
* beans.
* </p>
* <p>
* Example: batch processing executing every 3 rows
* </p>
*
* <pre>{@code
*
* String data = "This is a simple test of the batch processing"
* + " mode and the transaction execute batch method";
*
* String[] da = data.split(" ");
*
* String sql = "{call sp_t3(?,?)}";
*
* CallableSql cs = new CallableSql(sql);
* cs.registerOut(2, Types.INTEGER);
*
* // (optional) inform eBean this stored procedure
* // inserts into a table called sp_test
* cs.addModification("sp_test", true, false, false);
*
* Transaction txn = ebeanServer.beginTransaction();
* txn.setBatchMode(true);
* txn.setBatchSize(3);
* try {
* for (int i = 0; i < da.length;) {
* cs.setParameter(1, da[i]);
* ebeanServer.execute(cs);
* }
*
* // NB: commit implicitly flushes
* txn.commit();
*
* } finally {
* txn.end();
* }
*
* }</pre>
*
*/
void setBatchMode(boolean useBatch);
/**
* The JDBC batch mode to use for this transaction.
* <p>
* If this is NONE then JDBC batch can still be used for each request - save(), insert(), update() or delete()
* and this would be useful if the request cascades to detail beans.
* </p>
*
* @param persistBatchMode the batch mode to use for this transaction
*
* @see com.avaje.ebean.config.ServerConfig#setPersistBatch(com.avaje.ebean.config.PersistBatch)
*/
void setBatch(PersistBatch persistBatchMode);
/**
* Return the batch mode at the transaction level.
*/
PersistBatch getBatch();
/**
* Set the JDBC batch mode to use for a save() or delete() request.
* <p>
* This only takes effect when batch mode on the transaction has not already meant that
* JDBC batch mode is being used.
* </p>
* <p>
* This is useful when the single save() or delete() cascades. For example, inserting a 'master' cascades
* and inserts a collection of 'detail' beans. The detail beans can be inserted using JDBC batch.
* </p>
*
* @param batchOnCascadeMode the batch mode to use per save(), insert(), update() or delete()
*
* @see com.avaje.ebean.config.ServerConfig#setPersistBatchOnCascade(com.avaje.ebean.config.PersistBatch)
*/
void setBatchOnCascade(PersistBatch batchOnCascadeMode);
/**
* Return the batch mode at the request level (for each save(), insert(), update() or delete()).
*/
PersistBatch getBatchOnCascade();
/**
* Specify the number of statements before a batch is flushed automatically.
*/
void setBatchSize(int batchSize);
/**
* Return the current batch size.
*/
int getBatchSize();
/**
* Specify if you want batched inserts to use getGeneratedKeys.
* <p>
* By default batched inserts will try to use getGeneratedKeys if it is
* supported by the underlying jdbc driver and database.
* </p>
* <p>
* You may want to turn getGeneratedKeys off when you are inserting a large
* number of objects and you don't care about getting back the ids.
* </p>
*/
void setBatchGetGeneratedKeys(boolean getGeneratedKeys);
/**
* By default when mixing UpdateSql (or CallableSql) with Beans the batch is
* automatically flushed when you change (between persisting beans and
* executing UpdateSql or CallableSql).
* <p>
* If you want to execute both WITHOUT having the batch automatically flush
* you need to call this with batchFlushOnMixed = false.
* </p>
* <p>
* Note that UpdateSql and CallableSql are ALWAYS executed first (before the
* beans are executed). This is because the UpdateSql and CallableSql have
* already been bound to their PreparedStatements. The beans on the other hand
* have a 2 step process (delayed binding).
* </p>
*/
void setBatchFlushOnMixed(boolean batchFlushOnMixed);
/**
* By default executing a query will automatically flush any batched
* statements (persisted beans, executed UpdateSql etc).
* <p>
* Calling this method with batchFlushOnQuery = false means that you can
* execute a query and the batch will not be automatically flushed.
* </p>
*/
void setBatchFlushOnQuery(boolean batchFlushOnQuery);
/**
* Return true if the batch (of persisted beans or executed UpdateSql etc)
* should be flushed prior to executing a query.
* <p>
* The default is for this to be true.
* </p>
*/
boolean isBatchFlushOnQuery();
/**
* The batch will be flushing automatically but you can use this to explicitly
* flush the batch if you like.
* <p>
* Flushing occurs automatically when:
* </p>
* <ul>
* <li>the batch size is reached</li>
* <li>A query is executed on the same transaction</li>
* <li>UpdateSql or CallableSql are mixed with bean save and delete</li>
* <li>Transaction commit occurs</li>
* </ul>
*/
void flushBatch() throws PersistenceException, OptimisticLockException;
/**
* Return the underlying Connection object.
* <p>
* Useful where a Developer wishes to use the JDBC API directly. Note that the
* commit() rollback() and end() methods on the Transaction should still be
* used. Calling these methods on the Connection would be a big no no unless
* you know what you are doing.
* </p>
* <p>
* Examples of when a developer may wish to use the connection directly are:
* Savepoints, advanced CLOB BLOB use and advanced stored procedure calls.
* </p>
*/
Connection getConnection();
/**
* Add table modification information to the TransactionEvent.
* <p>
* Use this in conjunction with getConnection() and raw JDBC.
* </p>
* <p>
* This effectively informs Ebean of the data that has been changed by the
* transaction and this information is normally automatically handled by Ebean
* when you save entity beans or use UpdateSql etc.
* </p>
* <p>
* If you use raw JDBC then you can use this method to inform Ebean for the
* tables that have been modified. Ebean uses this information to keep its
* caches in synch and maintain text indexes.
* </p>
*/
void addModification(String tableName, boolean inserts, boolean updates, boolean deletes);
/**
* Add an arbitrary user object to the transaction. The objects added have no
* impact on any internals of ebena and are solely meant as a convenient
* method push user information to e.g. the
* {@link com.avaje.ebean.event.TransactionEventListener}.
*/
void putUserObject(String name, Object value);
/**
* Get an object added with {@link #putUserObject(String, Object)}.
*/
Object getUserObject(String name);
}
+45 -45
View File
@@ -1,45 +1,45 @@
package com.avaje.ebean;
/**
* Execute a TxCallable in a Transaction scope.
* <p>
* Use this with the {@link Ebean#execute(TxCallable)} method.
* </p>
* <p>
* Note that this is basically the same as TxRunnable except that it returns an
* Object (and you specify the return type via generics).
* </p>
* <p>
* See also {@link TxRunnable}.
* </p>
*
* <pre class="code">
* Ebean.execute(new TxCallable&lt;String&gt;() {
* public String call() {
* User u1 = Ebean.find(User.class, 1);
* User u2 = Ebean.find(User.class, 2);
*
* u1.setName(&quot;u1 mod&quot;);
* u2.setName(&quot;u2 mod&quot;);
*
* Ebean.save(u1);
* Ebean.save(u2);
*
* return u1.getEmail();
* }
* });
* </pre>
*
* @see TxRunnable
*/
public interface TxCallable<T> {
/**
* Execute the method within a transaction scope returning the result.
* <p>
* If you do not want to return a result you should look to use TxRunnable
* instead.
* </p>
*/
public T call();
}
package com.avaje.ebean;
/**
* Execute a TxCallable in a Transaction scope.
* <p>
* Use this with the {@link Ebean#execute(TxCallable)} method.
* </p>
* <p>
* Note that this is basically the same as TxRunnable except that it returns an
* Object (and you specify the return type via generics).
* </p>
* <p>
* See also {@link TxRunnable}.
* </p>
*
* <pre class="code">
* Ebean.execute(new TxCallable&lt;String&gt;() {
* public String call() {
* User u1 = Ebean.find(User.class, 1);
* User u2 = Ebean.find(User.class, 2);
*
* u1.setName(&quot;u1 mod&quot;);
* u2.setName(&quot;u2 mod&quot;);
*
* Ebean.save(u1);
* Ebean.save(u2);
*
* return u1.getEmail();
* }
* });
* </pre>
*
* @see TxRunnable
*/
public interface TxCallable<T> {
/**
* Execute the method within a transaction scope returning the result.
* <p>
* If you do not want to return a result you should look to use TxRunnable
* instead.
* </p>
*/
T call();
}
+100 -100
View File
@@ -1,100 +1,100 @@
package com.avaje.ebean;
import java.sql.Connection;
/**
* The Transaction Isolation levels.
* <p>
* These match those of java.sql.Connection with the addition of DEFAULT which
* implies the configured default of the DataSource.
* </p>
* <p>
* This can be used with TxScope to define transactional scopes to execute
* method within.
* </p>
*
* @see TxScope
*/
public enum TxIsolation {
/**
* Read Committed Isolation level. This is typically the default for most
* configurations.
*/
READ_COMMITED(Connection.TRANSACTION_READ_COMMITTED),
/**
* Read uncommitted Isolation level.
*/
READ_UNCOMMITTED(Connection.TRANSACTION_READ_UNCOMMITTED),
/**
* Repeatable Read Isolation level.
*/
REPEATABLE_READ(Connection.TRANSACTION_REPEATABLE_READ),
/**
* Serializable Isolation level.
*/
SERIALIZABLE(Connection.TRANSACTION_SERIALIZABLE),
/**
* No Isolation level.
*/
NONE(Connection.TRANSACTION_NONE),
/**
* The default isolation level. This typically means the default that the
* DataSource is using or configured to use.
*/
DEFAULT(-1);
final int level;
private TxIsolation(int level) {
this.level = level;
}
/**
* Return the level as per java.sql.Connection.
* <p>
* Note that -1 denotes the default isolation level.
* </p>
*/
public int getLevel() {
return level;
}
/**
* Return the TxIsolation given the java.sql.Connection isolation level.
* <p>
* Note that -1 denotes the default isolation level.
* </p>
*/
public static TxIsolation fromLevel(int connectionIsolationLevel) {
switch (connectionIsolationLevel) {
case Connection.TRANSACTION_READ_UNCOMMITTED:
return TxIsolation.READ_UNCOMMITTED;
case Connection.TRANSACTION_READ_COMMITTED:
return TxIsolation.READ_COMMITED;
case Connection.TRANSACTION_REPEATABLE_READ:
return TxIsolation.REPEATABLE_READ;
case Connection.TRANSACTION_SERIALIZABLE:
return TxIsolation.SERIALIZABLE;
case Connection.TRANSACTION_NONE:
return TxIsolation.NONE;
case -1:
return TxIsolation.DEFAULT;
default:
throw new RuntimeException("Unknown isolation level " + connectionIsolationLevel);
}
}
}
package com.avaje.ebean;
import java.sql.Connection;
/**
* The Transaction Isolation levels.
* <p>
* These match those of java.sql.Connection with the addition of DEFAULT which
* implies the configured default of the DataSource.
* </p>
* <p>
* This can be used with TxScope to define transactional scopes to execute
* method within.
* </p>
*
* @see TxScope
*/
public enum TxIsolation {
/**
* Read Committed Isolation level. This is typically the default for most
* configurations.
*/
READ_COMMITED(Connection.TRANSACTION_READ_COMMITTED),
/**
* Read uncommitted Isolation level.
*/
READ_UNCOMMITTED(Connection.TRANSACTION_READ_UNCOMMITTED),
/**
* Repeatable Read Isolation level.
*/
REPEATABLE_READ(Connection.TRANSACTION_REPEATABLE_READ),
/**
* Serializable Isolation level.
*/
SERIALIZABLE(Connection.TRANSACTION_SERIALIZABLE),
/**
* No Isolation level.
*/
NONE(Connection.TRANSACTION_NONE),
/**
* The default isolation level. This typically means the default that the
* DataSource is using or configured to use.
*/
DEFAULT(-1);
final int level;
TxIsolation(int level) {
this.level = level;
}
/**
* Return the level as per java.sql.Connection.
* <p>
* Note that -1 denotes the default isolation level.
* </p>
*/
public int getLevel() {
return level;
}
/**
* Return the TxIsolation given the java.sql.Connection isolation level.
* <p>
* Note that -1 denotes the default isolation level.
* </p>
*/
public static TxIsolation fromLevel(int connectionIsolationLevel) {
switch (connectionIsolationLevel) {
case Connection.TRANSACTION_READ_UNCOMMITTED:
return TxIsolation.READ_UNCOMMITTED;
case Connection.TRANSACTION_READ_COMMITTED:
return TxIsolation.READ_COMMITED;
case Connection.TRANSACTION_REPEATABLE_READ:
return TxIsolation.REPEATABLE_READ;
case Connection.TRANSACTION_SERIALIZABLE:
return TxIsolation.SERIALIZABLE;
case Connection.TRANSACTION_NONE:
return TxIsolation.NONE;
case -1:
return TxIsolation.DEFAULT;
default:
throw new RuntimeException("Unknown isolation level " + connectionIsolationLevel);
}
}
}
+39 -39
View File
@@ -1,39 +1,39 @@
package com.avaje.ebean;
/**
* Execute a TxRunnable in a Transaction scope.
* <p>
* Use this with the {@link Ebean#execute(TxRunnable)} method.
* </p>
* <p>
* See also {@link TxCallable}.
* </p>
*
* <pre class="code">
*
* // this run method runs in a transaction scope
* // which by default is TxScope.REQUIRED
*
* Ebean.execute(new TxRunnable() {
* public void run() {
* User u1 = Ebean.find(User.class, 1);
* User u2 = Ebean.find(User.class, 2);
*
* u1.setName(&quot;u1 mod&quot;);
* u2.setName(&quot;u2 mod&quot;);
*
* Ebean.save(u1);
* Ebean.save(u2);
* }
* });
* </pre>
*
* @see TxCallable
*/
public interface TxRunnable {
/**
* Run the method in a transaction sope.
*/
public void run();
}
package com.avaje.ebean;
/**
* Execute a TxRunnable in a Transaction scope.
* <p>
* Use this with the {@link Ebean#execute(TxRunnable)} method.
* </p>
* <p>
* See also {@link TxCallable}.
* </p>
*
* <pre class="code">
*
* // this run method runs in a transaction scope
* // which by default is TxScope.REQUIRED
*
* Ebean.execute(new TxRunnable() {
* public void run() {
* User u1 = Ebean.find(User.class, 1);
* User u2 = Ebean.find(User.class, 2);
*
* u1.setName(&quot;u1 mod&quot;);
* u2.setName(&quot;u2 mod&quot;);
*
* Ebean.save(u1);
* Ebean.save(u2);
* }
* });
* </pre>
*
* @see TxCallable
*/
public interface TxRunnable {
/**
* Run the method in a transaction sope.
*/
void run();
}
+13 -13
View File
@@ -54,7 +54,7 @@ public interface Update<T> {
/**
* Return the name if it is a named update.
*/
public String getName();
String getName();
/**
* Set this to false if you do not want the cache to invalidate related
@@ -64,7 +64,7 @@ public interface Update<T> {
* parts of the "L2" server cache.
* </p>
*/
public Update<T> setNotifyCache(boolean notifyCache);
Update<T> setNotifyCache(boolean notifyCache);
/**
* Set a timeout for statement execution.
@@ -77,12 +77,12 @@ public interface Update<T> {
* @param secs
* the timeout in seconds. Zero implies unlimited.
*/
public Update<T> setTimeout(int secs);
Update<T> setTimeout(int secs);
/**
* Execute the statement returning the number of rows modified.
*/
public int execute();
int execute();
/**
* Set an ordered bind parameter.
@@ -98,7 +98,7 @@ public interface Update<T> {
* @param value
* the parameter value to bind.
*/
public Update<T> set(int position, Object value);
Update<T> set(int position, Object value);
/**
* Set and ordered bind parameter (same as bind).
@@ -108,7 +108,7 @@ public interface Update<T> {
* @param value
* the parameter value to bind.
*/
public Update<T> setParameter(int position, Object value);
Update<T> setParameter(int position, Object value);
/**
* Set an ordered parameter that is null. The JDBC type of the null must be
@@ -117,12 +117,12 @@ public interface Update<T> {
* position starts at value 1 (not 0) to be consistent with PreparedStatement.
* </p>
*/
public Update<T> setNull(int position, int jdbcType);
Update<T> setNull(int position, int jdbcType);
/**
* Set an ordered parameter that is null (same as bind).
*/
public Update<T> setNullParameter(int position, int jdbcType);
Update<T> setNullParameter(int position, int jdbcType);
/**
* Set a named parameter. Named parameters have a colon to prefix the name.
@@ -135,12 +135,12 @@ public interface Update<T> {
* @param value
* the parameter value.
*/
public Update<T> set(String name, Object value);
Update<T> set(String name, Object value);
/**
* Bind a named parameter (same as bind).
*/
public Update<T> setParameter(String name, Object param);
Update<T> setParameter(String name, Object param);
/**
* Set a named parameter that is null. The JDBC type of the null must be
@@ -154,16 +154,16 @@ public interface Update<T> {
* @param jdbcType
* the type of the property being bound.
*/
public Update<T> setNull(String name, int jdbcType);
Update<T> setNull(String name, int jdbcType);
/**
* Bind a named parameter that is null (same as bind).
*/
public Update<T> setNullParameter(String name, int jdbcType);
Update<T> setNullParameter(String name, int jdbcType);
/**
* Return the sql that is actually executed.
*/
public String getGeneratedSql();
String getGeneratedSql();
}
+50 -50
View File
@@ -1,50 +1,50 @@
package com.avaje.ebean;
/**
* Holds two values as the result of a difference comparison.
*/
public class ValuePair {
private final Object newValue;
private final Object oldValue;
public ValuePair(Object newValue, Object oldValue) {
this.newValue = newValue;
this.oldValue = oldValue;
}
/**
* Return the new value.
*/
public Object getNewValue() {
return newValue;
}
/**
* Return the old value.
*/
public Object getOldValue() {
return oldValue;
}
/**
* Return the new value.
*/
@Deprecated
public Object getValue1() {
return newValue;
}
/**
* Return the old value.
*/
@Deprecated
public Object getValue2() {
return oldValue;
}
public String toString() {
return newValue + "," + oldValue;
}
}
package com.avaje.ebean;
/**
* Holds two values as the result of a difference comparison.
*/
public class ValuePair {
private final Object newValue;
private final Object oldValue;
public ValuePair(Object newValue, Object oldValue) {
this.newValue = newValue;
this.oldValue = oldValue;
}
/**
* Return the new value.
*/
public Object getNewValue() {
return newValue;
}
/**
* Return the old value.
*/
public Object getOldValue() {
return oldValue;
}
/**
* Return the new value.
*/
@Deprecated
public Object getValue1() {
return newValue;
}
/**
* Return the old value.
*/
@Deprecated
public Object getValue2() {
return oldValue;
}
public String toString() {
return newValue + "," + oldValue;
}
}
@@ -1,58 +1,58 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.avaje.ebean.Query;
/**
* Specify the default cache use specific entity type.
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface CacheStrategy {
/**
* When set to true the bean cache will be used unless explicitly stated not
* to in a query via {@link Query#setUseCache(boolean)}.
*/
boolean useBeanCache() default true;
/**
* A single property that is a natural unique identifier for the bean.
* <p>
* When a findUnique query is used with this property as the sole expression
* then there will be a lookup into the L2 natural key cache.
* </p>
*/
String naturalKey() default "";
/**
* When set to true the beans returned from a query will default to be
* readOnly.
* <p>
* If the bean is readOnly and has no relationships then it may be sharable.
* </p>
* <p>
* If you try to modify a readOnly bean it will throw an
* IllegalStateException.
* </p>
*/
boolean readOnly() default false;
/**
* Specify a query that can be used to warm the cache.
* <p>
* All the beans fetched by this query will be loaded into the bean cache and
* the query itself will be loaded into the query cache.
* </p>
* <p>
* The warming query will typically be executed at startup time after a short
* delay (defaults to a 30 seconds delay).
* </p>
*/
String warmingQuery() default "";
};
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.avaje.ebean.Query;
/**
* Specify the default cache use specific entity type.
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface CacheStrategy {
/**
* When set to true the bean cache will be used unless explicitly stated not
* to in a query via {@link Query#setUseCache(boolean)}.
*/
boolean useBeanCache() default true;
/**
* A single property that is a natural unique identifier for the bean.
* <p>
* When a findUnique query is used with this property as the sole expression
* then there will be a lookup into the L2 natural key cache.
* </p>
*/
String naturalKey() default "";
/**
* When set to true the beans returned from a query will default to be
* readOnly.
* <p>
* If the bean is readOnly and has no relationships then it may be sharable.
* </p>
* <p>
* If you try to modify a readOnly bean it will throw an
* IllegalStateException.
* </p>
*/
boolean readOnly() default false;
/**
* Specify a query that can be used to warm the cache.
* <p>
* All the beans fetched by this query will be loaded into the bean cache and
* the query itself will be loaded into the query cache.
* </p>
* <p>
* The warming query will typically be executed at startup time after a short
* delay (defaults to a 30 seconds delay).
* </p>
*/
String warmingQuery() default "";
}
@@ -1,47 +1,55 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specify cache tuning for a specific entity type.
* <p>
* If this is not specified then the system default settings are used.
* </p>
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface CacheTuning {
/**
* The maximum size for the cache.
* <p>
* This defaults to 0 which means unlimited.
* </p>
*/
int maxSize() default 0;
/**
* The maximum time (in seconds) that a cache entry is allowed to stay in the
* cache when it has not been accessed.
* <p>
* This defaults to 0 which means unlimited.
* </p>
*/
int maxIdleSecs() default 0;
/**
* The maximum time (in seconds) a cache entry is allowed to stay in the
* cache.
* <p>
* This is not generally required as the cache entries are automatically
* evicted when related data changes are committed.
* </p>
* <p>
* This defaults to 0 which means unlimited.
* </p>
*/
int maxSecsToLive() default 0;
};
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specify cache tuning for a specific entity type.
* <p>
* If this is not specified then the system default settings are used.
* </p>
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface CacheTuning {
/**
* The maximum size for the cache.
* <p>
* This defaults to 0 which means unlimited.
* </p>
*/
int maxSize() default 0;
/**
* The maximum time (in seconds) that a cache entry is allowed to stay in the
* cache when it has not been accessed.
* <p>
* This defaults to 0 which means unlimited.
* </p>
*/
int maxIdleSecs() default 0;
/**
* The maximum time (in seconds) a cache entry is allowed to stay in the
* cache.
* <p>
* This is not generally required as the cache entries are automatically
* evicted when related data changes are committed.
* </p>
* <p>
* This defaults to 0 which means unlimited.
* </p>
*/
int maxSecsToLive() default 0;
/**
* The frequency (in seconds) that cache trimming should occur.
* <p>
* This is a hint for cache implementations that use background cache trimming.
* </p>
*/
int trimFrequency() default 0;
}
@@ -6,8 +6,10 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* Deprecated - please use @DbHstore instead.
* @see DbHstore
*/
@Deprecated
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ColumnHstore {
@@ -1,31 +1,34 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* For a timestamp property that is set to the datetime when the entity is
* created/inserted.
* <p>
* An alternative to using this annotation would be to use insertable=false,
* updateable=false with @Column and have the DB insert the current time
* (default value on the DB column is SYSTIME etc).
* </p>
* <p>
* The downside to this approach is that the inserted entity does not have the
* timestamp value after the insert has occurred. You need to fetch the entity
* back to get the inserted timestamp if you want to used it.
* </p>
*
* <pre class="code">
* &#064;Column(insertable = false, updateable = false)
* Timestamp cretimestamp;
* </pre>
*/
@Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface CreatedTimestamp {
};
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* For a timestamp property that is set to the datetime when the entity is
* created/inserted.
* <p>
* An alternative to using this annotation would be to use insertable=false,
* updateable=false with @Column and have the DB insert the current time
* (default value on the DB column is SYSTIME etc).
* </p>
* <p>
* The downside to this approach is that the inserted entity does not have the
* timestamp value after the insert has occurred. You need to fetch the entity
* back to get the inserted timestamp if you want to used it.
* </p>
*
* <h3>Example:</h3>
* <pre>{@code
*
* @CreatedTimestamp
* Timestamp whenCreated;
*
* }</pre>
*/
@Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface CreatedTimestamp {
}
@@ -0,0 +1,26 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Used for mapping a Map<String,String> type property to Postgres HSTORE data type.
* <p>
* The Map property should have keys and values of type String.
* </p>
*
* <h3>Example:</h3>
* <pre>{@code
*
* @DbHstore
* Map<String, String> tags;
*
* }</pre>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface DbHstore {
}
@@ -0,0 +1,44 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specify a property holding JSON content.
* <p>
* By default the content will be stored in a DB Clob except on Postgres where DB JSON type is used.
* </p>
* <h3>Example:</h3>
* <pre>{@code
*
* // Store as JSON on Postgres or Clob on other databases
* @DbJson
* Map<String,Object> content;
*
* }</pre>
*
* <h3>Example with JSONB storage</h3>
* <pre>{@code
*
* // Store as JSONB on Postgres or Clob on other databases
* @DbJson(storage = DbJsonType.JSONB)
* Map<String,Object> content;
*
* }</pre>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface DbJson {
/**
* Specify the database type used to store the JSON content.
*/
DbJsonType storage() default DbJsonType.JSON;
/**
* For VARCHAR storage specify the column length (defaults to 3000).
*/
int length() default 0;
}
@@ -0,0 +1,39 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specify a property holding JSON content.
* <p>
* The content will be stored on Postgres using it's JSONB type and as Clob for other databases.
* </p>
* <p>
* This is equivalent to using <code>@DbJson(storage = DbJsonType.JSONB)</code>
* </p>
*
* <h3>Example:</h3>
* <pre>{@code
*
* // Store as JSONB on Postgres or Clob on other databases
* @DbJsonB
* Map<String,Object> content;
*
* }</pre>
*
* <h3>Equivalent to:</h3>
* <pre>{@code
*
* // Store as JSONB on Postgres or Clob on other databases
* @DbJson(storage = DbJsonType.JSONB)
* Map<String,Object> content;
*
* }</pre>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface DbJsonB {
}
@@ -0,0 +1,32 @@
package com.avaje.ebean.annotation;
/**
* Specify the DB storage type used to store JSON content.
*/
public enum DbJsonType {
/**
* Store as JSON on Postgres and for other databases store as CLOB.
*/
JSON,
/**
* Store as JSONB on Postgres and for other databases store as CLOB.
*/
JSONB,
/**
* Store as database VARCHAR.
*/
VARCHAR,
/**
* Store as database CLOB.
*/
CLOB,
/**
* Store as database BLOB.
*/
BLOB
}
@@ -1,31 +1,31 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specify property name to db column mapping for Embedded beans.
* <p>
* This is designed to be easier to use than the AttributeOverride annotation in
* standard JPA.
* </p>
*/
@Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface EmbeddedColumns {
/**
* A list of property names mapped to DB columns.
* <p>
* For example <code>currency=IN_CURR, amount=IN_AMOUNT</code>
* </p>
* <p>
* Where currency and amount are properties and IN_CURR and IN_AMOUNT are the
* respective DB columns these properties will be mapped to.
* </p>
*/
String columns() default "";
};
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specify property name to db column mapping for Embedded beans.
* <p>
* This is designed to be easier to use than the AttributeOverride annotation in
* standard JPA.
* </p>
*/
@Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface EmbeddedColumns {
/**
* A list of property names mapped to DB columns.
* <p>
* For example <code>currency=IN_CURR, amount=IN_AMOUNT</code>
* </p>
* <p>
* Where currency and amount are properties and IN_CURR and IN_AMOUNT are the
* respective DB columns these properties will be mapped to.
* </p>
*/
String columns() default "";
}
@@ -1,24 +1,24 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specify that the property is stored in encrypted form.
*/
@Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Encrypted {
/**
* When true try to use DB encryption rather than local java encryption.
*/
boolean dbEncryption() default true;
/**
* Used to specify the DB column length.
*/
int dbLength() default 0;
};
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specify that the property is stored in encrypted form.
*/
@Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Encrypted {
/**
* When true try to use DB encryption rather than local java encryption.
*/
boolean dbEncryption() default true;
/**
* Used to specify the DB column length.
*/
int dbLength() default 0;
}
@@ -1,90 +1,90 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* For mapping the values of an Enum to and from Database values.
* <p>
* Also refer to the {@link EnumValue} approach which probably the preferred now
* (preferred over using this EnumMapping annotation).
* </p>
* <p>
* Both of the approaches defined in the JPA have significant problems!!!
* </p>
* <p>
* Using the ordinal value is VERY RISKY because that depends on the compile
* order of the enum values. Aka if you change the order of the enum values you
* have changed their ordinal values and now your DB values are WRONG - a HUGE
* disaster!!!.
* </p>
* <p>
* Using the String values of enums is fairly restrictive because in a Database
* these values are usually truncated into short codes (e.g. "A" short for
* "ACTIVE") so space used in the database is minimised. Making your enum names
* match the database values would give them very short less meaningful names -
* not a great solution.
* </p>
* <p>
* You can use this annotation to control the mapping of your enums to database
* values.
* </p>
* <p>
* The design of this using nameValuePairs is not optimal for safety or
* refactoring so if you have a better solution I'm all ears. The other
* solutions would probably involve modifying each enumeration with a method
* which may be ok.
* </p>
* <p>
* An example mapping the UserState enum.
* </p>
*
* <pre class="code">
* ...
* &#064;EnumMapping(nameValuePairs=&quot;NEW=N, ACTIVE=A, INACTIVE=I&quot;)
* public enum UserState {
* NEW,
* ACTIVE,
* INACTIVE;
* }
* </pre>
*
* @see EnumValue
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface EnumMapping {
/**
* A comma delimited list of name=value pairs.
* <p>
* e.g. "ACTIVE=A, INACTIVE=I, NEW=N".
* </p>
* <p>
* Where ACTIVE, INACTIVE and NEW are the enumeration values and "A", "I" and
* "N" are the database values.
* </p>
* <p>
* This is not really an optimal approach so if you have a better one I'm all
* ears - thanks.
* </p>
*/
String nameValuePairs();
/**
* Defaults to mapping values to database VARCHAR type. If this is set to true
* then the values will be converted to INTEGER and mapped to the database
* integer type.
* <p>
* e.g. "ACTIVE=1, INACTIVE=0, NEW=2".
* </p>
*/
boolean integerType() default false;
/**
* The length of DB column if mapping to string values.
*/
int length() default 0;
};
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* For mapping the values of an Enum to and from Database values.
* <p>
* Also refer to the {@link EnumValue} approach which probably the preferred now
* (preferred over using this EnumMapping annotation).
* </p>
* <p>
* Both of the approaches defined in the JPA have significant problems!!!
* </p>
* <p>
* Using the ordinal value is VERY RISKY because that depends on the compile
* order of the enum values. Aka if you change the order of the enum values you
* have changed their ordinal values and now your DB values are WRONG - a HUGE
* disaster!!!.
* </p>
* <p>
* Using the String values of enums is fairly restrictive because in a Database
* these values are usually truncated into short codes (e.g. "A" short for
* "ACTIVE") so space used in the database is minimised. Making your enum names
* match the database values would give them very short less meaningful names -
* not a great solution.
* </p>
* <p>
* You can use this annotation to control the mapping of your enums to database
* values.
* </p>
* <p>
* The design of this using nameValuePairs is not optimal for safety or
* refactoring so if you have a better solution I'm all ears. The other
* solutions would probably involve modifying each enumeration with a method
* which may be ok.
* </p>
* <p>
* An example mapping the UserState enum.
* </p>
*
* <pre class="code">
* ...
* &#064;EnumMapping(nameValuePairs=&quot;NEW=N, ACTIVE=A, INACTIVE=I&quot;)
* public enum UserState {
* NEW,
* ACTIVE,
* INACTIVE;
* }
* </pre>
*
* @see EnumValue
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface EnumMapping {
/**
* A comma delimited list of name=value pairs.
* <p>
* e.g. "ACTIVE=A, INACTIVE=I, NEW=N".
* </p>
* <p>
* Where ACTIVE, INACTIVE and NEW are the enumeration values and "A", "I" and
* "N" are the database values.
* </p>
* <p>
* This is not really an optimal approach so if you have a better one I'm all
* ears - thanks.
* </p>
*/
String nameValuePairs();
/**
* Defaults to mapping values to database VARCHAR type. If this is set to true
* then the values will be converted to INTEGER and mapped to the database
* integer type.
* <p>
* e.g. "ACTIVE=1, INACTIVE=0, NEW=2".
* </p>
*/
boolean integerType() default false;
/**
* The length of DB column if mapping to string values.
*/
int length() default 0;
}
@@ -1,46 +1,48 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Enables you to specify a value to use to persist for an enum value.
*
* <pre class="code">
* public enum Status {
* &#064;EnumValue(&quot;N&quot;)
* NEW,
*
* &#064;EnumValue(&quot;A&quot;)
* ACTIVE,
*
* &#064;EnumValue(&quot;I&quot;)
* INACTIVE,
* }
*
* </pre>
* <p>
* This is an alternative to using the JPA standard approach or Ebean's
* {@link EnumMapping} annotation.
* </p>
* <p>
* Note that if all the EnumValue values are parsable as Integers then Ebean
* will persist and fetch them as integers - otherwise they will be persisted
* and fetched as strings.
* </p>
*/
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface EnumValue {
/**
* Specify the value to persist for a specific enum value.
* <p>
* If all the values are parsable as Integers then Ebean will persist and
* fetch them as integers rather than strings.
* </p>
*/
String value();
};
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Enables you to specify a value to use to persist for an enum value.
*
* <pre>{@code
*
* public enum Status {
*
* @EnumValue("N")
* NEW,
*
* @EnumValue("A")
* ACTIVE,
*
* @EnumValue("I")
* INACTIVE,
* }
*
* }</pre>
* <p>
* This is an alternative to using the JPA standard approach or Ebean's
* {@link EnumMapping} annotation.
* </p>
* <p>
* Note that if all the EnumValue values are parsable as Integers then Ebean
* will persist and fetch them as integers - otherwise they will be persisted
* and fetched as strings.
* </p>
*/
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface EnumValue {
/**
* Specify the value to persist for a specific enum value.
* <p>
* If all the values are parsable as Integers then Ebean will persist and
* fetch them as integers rather than strings.
* </p>
*/
String value();
}
@@ -12,17 +12,17 @@ import java.lang.annotation.Target;
@Target(ElementType.FIELD)
public @interface Expose {
/**
* If {@code true}, the field marked with this annotation is written out in the JSON while
* serializing. If {@code false}, the field marked with this annotation is skipped from the
* serialized output. Defaults to {@code true}.
*/
public boolean serialize() default true;
/**
* If {@code true}, the field marked with this annotation is written out in the JSON while
* serializing. If {@code false}, the field marked with this annotation is skipped from the
* serialized output. Defaults to {@code true}.
*/
boolean serialize() default true;
/**
* If {@code true}, the field marked with this annotation is deserialized from the JSON.
* If {@code false}, the field marked with this annotation is skipped during deserialization.
* Defaults to {@code true}.
*/
public boolean deserialize() default true;
/**
* If {@code true}, the field marked with this annotation is deserialized from the JSON.
* If {@code false}, the field marked with this annotation is skipped during deserialization.
* Defaults to {@code true}.
*/
boolean deserialize() default true;
}
@@ -1,103 +1,106 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.avaje.ebean.Query;
/**
* Assign to a property to be based on a SQL formula.
* <p>
* This is typically a SQL Literal value, SQL case statement, SQL function or
* similar.
* </p>
* <p>
* Any property based on a formula becomes a read only property.
* </p>
* <p>
* You may also put use the Transient annotation with the Formula annotation.
* The effect of the Transient annotation in this case is that the formula will
* <b>NOT</b> be included in queries by default - you have to explicitly include
* it via {@link Query#select(String)} or {@link Query#fetch(String, String, com.avaje.ebean.FetchConfig)}.
* You may want to do this if the Formula is relatively expensive and only want
* it included in the query when you explicitly state it.
* </p>
*
* <pre class="code">
* // On the Order &quot;master&quot; bean
* // ... a formula using the Order details
* // ... sum(order_qty*unit_price)
* &#064;Transient
* &#064;Formula(select = &quot;_b${ta}.total_amount&quot;, join = &quot;join (select order_id, sum(order_qty*unit_price) as total_amount from o_order_detail group by order_id) as _b${ta} on _b${ta}.order_id = ${ta}.id&quot;)
* Double totalAmount;
*
* </pre>
* <p>
* As the totalAmount formula is also Transient it is not included by default in
* queries - it needs to be explicitly included.
* </p>
*
* <pre class="code">
* // find by Id
* Order o1 = Ebean.find(Order.class)
* .select(&quot;id, totalAmount&quot;)
* .setId(1).findUnique();
*
* // find list ... using totalAmount in the where clause
* List&lt;Order&gt; list = Ebean.find(Order.class)
* .select(&quot;id, totalAmount&quot;)
* .where()
* .eq(&quot;status&quot;, Order.Status.NEW)
* .gt(&quot;totalAmount&quot;, 10)
* .findList();
*
* // as a join from customer
* List&lt;Customer&gt; l0 = Ebean.find(Customer.class)
* .select(&quot;id, name&quot;)
* .join(&quot;orders&quot;, &quot;status, totalAmount&quot;)
* .where()
* .gt(&quot;id&quot;, 0)
* .gt(&quot;orders.totalAmount&quot;, 10)
* .findList();
*
* </pre>
*/
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Formula {
/**
* The SQL to be used in the SELECT part of the SQL to populate a property.
*/
String select();
/**
* OPTIONAL - the SQL to be used in the JOIN part of the SQL to support the
* formula.
* <p>
* This is commonly used to join a 'dynamic view' to support aggregation such
* as count, sum etc.
* </p>
* <p>
* The join string should start with either "left outer join" or "join".
* </p>
*
* <p>
* You will almost certainly use the "${ta}" as a place holder for the table
* alias of the table you are joining back to (the "base table" of the entity
* bean).
* </p>
* <p>
* The example below is used to support a total count of topics created by a
* user.
* </p>
*
* <pre class="code">
* join (select user_id, count(*) as topic_count from f_topic group by user_id) as _tc on _tc.user_id = ${ta}.id
* </pre>
*/
String join() default "";
};
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.avaje.ebean.Query;
/**
* Assign to a property to be based on a SQL formula.
* <p>
* This is typically a SQL Literal value, SQL case statement, SQL function or
* similar.
* </p>
* <p>
* Any property based on a formula becomes a read only property.
* </p>
* <p>
* You may also put use the Transient annotation with the Formula annotation.
* The effect of the Transient annotation in this case is that the formula will
* <b>NOT</b> be included in queries by default - you have to explicitly include
* it via {@link Query#select(String)} or {@link Query#fetch(String, String, com.avaje.ebean.FetchConfig)}.
* You may want to do this if the Formula is relatively expensive and only want
* it included in the query when you explicitly state it.
* </p>
*
* <pre class="code">
* // On the Order &quot;master&quot; bean
* // ... a formula using the Order details
* // ... sum(order_qty*unit_price)
* &#064;Transient
* &#064;Formula(select = &quot;_b${ta}.total_amount&quot;, join = &quot;join (select order_id, sum(order_qty*unit_price) as total_amount from o_order_detail group by order_id) as _b${ta} on _b${ta}.order_id = ${ta}.id&quot;)
* Double totalAmount;
*
* </pre>
* <p>
* As the totalAmount formula is also Transient it is not included by default in
* queries - it needs to be explicitly included.
* </p>
*
* <pre>{@code
*
* // find by Id
* Order o1 = Ebean.find(Order.class)
* .select("id, totalAmount")
* .setId(1).findUnique();
*
* // find list ... using totalAmount in the where clause
* List<Order> list = Ebean.find(Order.class)
* .select("id, totalAmount")
* .where()
* .eq("status", Order.Status.NEW)
* .gt("totalAmount", 10)
* .findList();
*
* // as a join from customer
* List<Customer> l0 = Ebean.find(Customer.class)
* .select("id, name")
* .fetch("orders", "status, totalAmount")
* .where()
* .gt("id", 0)
* .gt("orders.totalAmount", 10)
* .findList();
*
* }</pre>
*/
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Formula {
/**
* The SQL to be used in the SELECT part of the SQL to populate a property.
*/
String select();
/**
* OPTIONAL - the SQL to be used in the JOIN part of the SQL to support the
* formula.
* <p>
* This is commonly used to join a 'dynamic view' to support aggregation such
* as count, sum etc.
* </p>
* <p>
* The join string should start with either "left outer join" or "join".
* </p>
*
* <p>
* You will almost certainly use the "${ta}" as a place holder for the table
* alias of the table you are joining back to (the "base table" of the entity
* bean).
* </p>
* <p>
* The example below is used to support a total count of topics created by a
* user.
* </p>
*
* <pre>{@code
*
* join (select user_id, count(*) as topic_count from f_topic group by user_id) as _tc on _tc.user_id = ${ta}.id
*
* }</pre>
*/
String join() default "";
}
@@ -14,11 +14,11 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
public @interface Index {
/**
* Name of the index
*
* @return index name
*/
String value() default "";
/**
* Name of the index
*
* @return index name
*/
String value() default "";
}
@@ -1,37 +1,37 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* An Update statement for a particular entity bean type.
* <p>
* The update can either be a sql insert,update or delete statement with tables
* and columns etc or the equivalent statement but with table names and columns
* expressed as bean types and bean properties.
* </p>
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface NamedUpdate {
/**
* The name of the update.
*/
String name();
/**
* The insert, update or delete statement.
*/
String update();
/**
* Set this to false if you do not want the cache to be notified. If true the
* cache will invalidate appropriate objects from the cache (after a
* successful transaction commit).
*/
boolean notifyCache() default true;
};
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* An Update statement for a particular entity bean type.
* <p>
* The update can either be a sql insert,update or delete statement with tables
* and columns etc or the equivalent statement but with table names and columns
* expressed as bean types and bean properties.
* </p>
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface NamedUpdate {
/**
* The name of the update.
*/
String name();
/**
* The insert, update or delete statement.
*/
String update();
/**
* Set this to false if you do not want the cache to be notified. If true the
* cache will invalidate appropriate objects from the cache (after a
* successful transaction commit).
*/
boolean notifyCache() default true;
}
@@ -1,20 +1,20 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Holds an array of named Update statements for a particular entity bean type.
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface NamedUpdates {
/**
* An array of named updates.
*/
NamedUpdate[] value();
};
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Holds an array of named Update statements for a particular entity bean type.
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface NamedUpdates {
/**
* An array of named updates.
*/
NamedUpdate[] value();
}
@@ -1,34 +1,34 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specify that the elements of a OneToMany are private owned.
* <p>
* This means that if they are removed from the List/Set/Map they will be
* deleted when their parent object is saved.
* </p>
* <p>
* This could also be described as deleting orphans - in that beans removed from
* the List/Set/Map will be deleted automatically when the parent bean is saved.
* They are considered 'orphans' when they have been removed from the collection
* in that they are no longer associated/linked to their parent bean.
* </p>
*/
@Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface PrivateOwned {
/**
* Set this to false if you don't want cascade REMOVE on this relationship.
* <p>
* That is, by default PrivateOwned implicitly adds a cascade REMOVE to the
* relationship and if you don't want that you need to set this to false.
* </p>
*/
boolean cascadeRemove() default true;
};
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specify that the elements of a OneToMany are private owned.
* <p>
* This means that if they are removed from the List/Set/Map they will be
* deleted when their parent object is saved.
* </p>
* <p>
* This could also be described as deleting orphans - in that beans removed from
* the List/Set/Map will be deleted automatically when the parent bean is saved.
* They are considered 'orphans' when they have been removed from the collection
* in that they are no longer associated/linked to their parent bean.
* </p>
*/
@Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface PrivateOwned {
/**
* Set this to false if you don't want cascade REMOVE on this relationship.
* <p>
* That is, by default PrivateOwned implicitly adds a cascade REMOVE to the
* relationship and if you don't want that you need to set this to false.
* </p>
*/
boolean cascadeRemove() default true;
}
@@ -1,24 +1,24 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specify explicit sql for multiple select statements. Need to use this if you
* have more than one SqlSelect for a given bean.
* <p>
* FUTURE: Support explicit sql for SqlInsert, SqlUpdate and SqlDelete.
* </p>
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Sql {
/**
* The sql select statements.
*/
SqlSelect[] select() default { @SqlSelect };
};
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specify explicit sql for multiple select statements. Need to use this if you
* have more than one SqlSelect for a given bean.
* <p>
* FUTURE: Support explicit sql for SqlInsert, SqlUpdate and SqlDelete.
* </p>
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Sql {
/**
* The sql select statements.
*/
SqlSelect[] select() default { @SqlSelect };
}
@@ -1,298 +1,298 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.avaje.ebean.Query;
/**
* Specify an explicit sql select statement to use for querying an entity bean.
* <p>
* The reason for using explicit sql is that you want better control over the
* exact sql or sql that Ebean does not generate for you (such as group by,
* union, intersection, window functions, recursive queries).
* </p>
* <p>
* An example of two sql select queries deployed on the ReportTopic entity bean.
* The first one has no name specified so it becomes the default query. The
* second query extends the first adding a where clause with a named parameter.
* </p>
*
* <pre class="code">
* ...
* &#064;Entity
* &#064;Sql(select = {
* &#064;SqlSelect(query =
* &quot;select t.id, t.title, count(p.id) as score &quot;+
* &quot;from f_topic t &quot;+
* &quot;join f_topic_post p on p.topic_id = t.id &quot;+
* &quot;group by t.id, t.title&quot;),
* &#064;SqlSelect(
* name = &quot;with.title&quot;,
* extend = &quot;default&quot;,
* debug = true,
* where = &quot;title like :likeTitle&quot;)
* })
* public class ReportTopic
* &#064;Id Integer id;
* String title;
* Double score;
* ...
* </pre>
*
* <p>
* An example using the first "default" query.
* </p>
*
* <pre class="code">
*
* List&lt;ReportTopic&gt; list =
* Ebean.find(ReportTopic.class)
* .having().gt(&quot;score&quot;, 0)
* .findList();
*
* </pre>
*
* <p>
* The resulting sql, note the having clause has been added.
* </p>
*
* <pre class="code">
* select t.id, t.title, count(p.id) as score
* from f_topic t join f_topic_post p on p.topic_id = t.id
* group by t.id, t.title
* having count(p.id) &gt; ?
* </pre>
*
* <p>
* An example using the second query. Note the named parameter "likeTitle" must
* be set.
* </p>
*
* <pre class="code">
* List&lt;ReportTopic&gt; list =
* Ebean.find(ReportTopic.class, &quot;with.title&quot;)
* .set(&quot;likeTitle&quot;, &quot;a%&quot;)
* .findList();
* </pre>
*
* <p>
* Ebean tries to parse the sql in the query to determine 4 things
* <li>Location for inserting WHERE expressions (if required)</li>
* <li>Location for inserting HAVING expressions (if required)</li>
* <li>Mapping of columns to bean properties</li>
* <li>The order by clause</li>
* </p>
* <p>
* If Ebean is unable to parse out this information (perhaps because the sql
* contains multiple select from keywords etc) then you need to manually specify
* it.
* </p>
* <p>
* Insert ${where} or ${andWhere} into the location where Ebean can insert any
* expressions added to the where clause. Use ${andWhere} if the sql already has
* the WHERE keyword and Ebean will instead start with a AND keyword.
* </p>
* <p>
* Insert ${having} or ${andHaving} into the location where Ebean can insert any
* expressions added to the having clause. Use ${andHaving} if the sql already
* has a HAVING keyword and Ebean will instead start with a AND keyword.
* </p>
* <p>
* Use the columnMapping property if Ebean is unable to determine the columns
* and map them to bean properties.
* </p>
* <p>
* Example with ${andWhere} & ${having}.
* </p>
*
* <pre class="code">
* &#064;SqlSelect(
* name = &quot;explicit.where&quot;,
* query =
* &quot;select t.id, t.title, count(p.id) as score &quot;+
* &quot;from f_topic t, f_topic_post p &quot;+
* &quot;where p.topic_id = t.id ${andWhere} &quot;+
* &quot;group by t.id, t.title ${having}&quot;),
* </pre>
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Deprecated
public @interface SqlSelect {
/**
* The name of the query. If left blank this is assumed to be the default
* query for this bean type.
* <p>
* This will default to "default" and in that case becomes the default query
* used for the bean.
* </p>
*/
String name() default "default";
/**
* The tableAlias used when adding where expressions to the query.
*/
String tableAlias() default "";
/**
* The sql select statement.
* <p>
* If this query <em>extends</em> another then this string is appended to the
* parent query string. Often when using <em>extend</em> you will leave the
* query part blank and just specify a where and/or having clauses.
* </p>
* <p>
* This sql <em>CAN NOT</em> contain named parameters. You have to put these
* in the separate where and/or having sections.
* </p>
* <p>
* Ebean automatically tries to determine the location in the sql string for
* putting in additional where or having clauses. If Ebean is unable to
* successfully determine this then you have to explicitly specify these
* locations by including
* <em>${where} or ${andWhere} and ${having} or ${andHaving}</em> in the sql.
* </p>
* <p>
* <b>${where}</b> location of where clause (and will add WHERE ... ) <br/>
* Use this when there is no where clause in the sql. If expressions are added
* to the where clause Ebean will put them in at this location starting with
* the WHERE keyword.
* <p>
* <p>
* <b>${andWhere}</b> <br/>
* Use this instead of ${where} if there IS an existing where clause in the
* sql. Ebean will add the expressions starting with the AND keyword.
* <p>
* <b>${having}</b> location of having clause (and will add HAVING... ) <br/>
* </p>
* <p>
* <b>${andHaving}</b> <br/>
* Use this instead of ${having} when there IS an existing HAVING clause.
* Ebean will add the expressions starting with the AND keyword.
* </p>
* <p>
* You can include one of ${where} OR ${andWhere} but not both.
* </p>
* <p>
* You can include one of ${having} OR ${andHaving} but not both.
* </p>
*/
String query() default "";
/**
* Specify the name of a sql-select query that this one 'extends'.
* <p>
* When a query is extended the sql query contents are appended together. The
* where and having clauses are NOT appended but overridden.
* </p>
*/
String extend() default "";
/**
* Specify a where clause typically containing named parameters.
* <p>
* If a where clause is specified with named parameters then they will need to
* be set on the query via {@link Query#setParameter(String, Object)}.
* </p>
* <p>
* In the example below the query specifies a where clause that includes a
* named parameter "likeTitle".
* </p>
*
* <pre class="code">
* ...
* &#064;Entity
* &#064;Sql(select = {
* ...
* &#064;SqlSelect(
* name = &quot;with.title&quot;,
* extend = &quot;default&quot;,
* debug = true,
* where = &quot;title like :likeTitle&quot;)
* })
* public class ReportTopic
* ...
* </pre>
*
* <p>
* Example use of the above named query.
* </p>
*
* <pre class="code">
*
* Query&lt;ReportTopic&gt; query0 = Ebean.createQuery(ReportTopic.class, &quot;with.title&quot;);
*
* query0.set(&quot;likeTitle&quot;, &quot;Bana%&quot;);
*
* List&lt;ReportTopic&gt; list0 = query0.findList();
* </pre>
*
*/
String where() default "";
/**
* Specify a having clause typically containing named parameters.
* <p>
* If a having clause is specified with named parameters then they will need
* to be set on the query via {@link Query#setParameter(String, Object)}.
* </p>
*/
String having() default "";
/**
* (Optional) Explicitly specify column to property mapping.
* <p>
* This is required when Ebean is unable to parse the sql. This could occur if
* the sql contains multiple select keywords etc.
* </p>
* <p>
* Specify the columns and property names they map to in the format.
* </p>
*
* <pre class="code">
* column1 propertyName1, column2 propertyName2, ...
* </pre>
*
* <p>
* Optionally put a AS keyword between the column and property.
* </p>
*
* <pre class="code">
* // the AS keyword is optional
* column1 AS propertyName1, column2 propertyName2, ...
* </pre>
*
* <p>
* <b>column</b> should contain the table alias if there is one
* </p>
* <p>
* <b>propertyName</b> should match the property name.
* </p>
*
* <p>
* Example mapping 5 columns to properties.
* </p>
*
* <pre class="code">
* columnMapping=&quot;t.id, t.bug_body description, t.bug_title as title, count(p.id) as scoreValue&quot;,
* </pre>
*
* <p>
* Without this set Ebean will parse the sql looking for the select clause and
* try to map the columns to property names. It is expected that Ebean will
* not be able to successfully parse some sql and for those cases you should
* specify the column to property mapping explicitly.
* </p>
*
*/
String columnMapping() default "";
/**
* Set this to true to have debug output when Ebean parses the sql-select.
*/
boolean debug() default false;
};
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.avaje.ebean.Query;
/**
* Specify an explicit sql select statement to use for querying an entity bean.
* <p>
* The reason for using explicit sql is that you want better control over the
* exact sql or sql that Ebean does not generate for you (such as group by,
* union, intersection, window functions, recursive queries).
* </p>
* <p>
* An example of two sql select queries deployed on the ReportTopic entity bean.
* The first one has no name specified so it becomes the default query. The
* second query extends the first adding a where clause with a named parameter.
* </p>
*
* <pre class="code">
* ...
* &#064;Entity
* &#064;Sql(select = {
* &#064;SqlSelect(query =
* &quot;select t.id, t.title, count(p.id) as score &quot;+
* &quot;from f_topic t &quot;+
* &quot;join f_topic_post p on p.topic_id = t.id &quot;+
* &quot;group by t.id, t.title&quot;),
* &#064;SqlSelect(
* name = &quot;with.title&quot;,
* extend = &quot;default&quot;,
* debug = true,
* where = &quot;title like :likeTitle&quot;)
* })
* public class ReportTopic
* &#064;Id Integer id;
* String title;
* Double score;
* ...
* </pre>
*
* <p>
* An example using the first "default" query.
* </p>
*
* <pre class="code">
*
* List&lt;ReportTopic&gt; list =
* Ebean.find(ReportTopic.class)
* .having().gt(&quot;score&quot;, 0)
* .findList();
*
* </pre>
*
* <p>
* The resulting sql, note the having clause has been added.
* </p>
*
* <pre class="code">
* select t.id, t.title, count(p.id) as score
* from f_topic t join f_topic_post p on p.topic_id = t.id
* group by t.id, t.title
* having count(p.id) &gt; ?
* </pre>
*
* <p>
* An example using the second query. Note the named parameter "likeTitle" must
* be set.
* </p>
*
* <pre class="code">
* List&lt;ReportTopic&gt; list =
* Ebean.find(ReportTopic.class, &quot;with.title&quot;)
* .set(&quot;likeTitle&quot;, &quot;a%&quot;)
* .findList();
* </pre>
*
* <p>
* Ebean tries to parse the sql in the query to determine 4 things
* <li>Location for inserting WHERE expressions (if required)</li>
* <li>Location for inserting HAVING expressions (if required)</li>
* <li>Mapping of columns to bean properties</li>
* <li>The order by clause</li>
* </p>
* <p>
* If Ebean is unable to parse out this information (perhaps because the sql
* contains multiple select from keywords etc) then you need to manually specify
* it.
* </p>
* <p>
* Insert ${where} or ${andWhere} into the location where Ebean can insert any
* expressions added to the where clause. Use ${andWhere} if the sql already has
* the WHERE keyword and Ebean will instead start with a AND keyword.
* </p>
* <p>
* Insert ${having} or ${andHaving} into the location where Ebean can insert any
* expressions added to the having clause. Use ${andHaving} if the sql already
* has a HAVING keyword and Ebean will instead start with a AND keyword.
* </p>
* <p>
* Use the columnMapping property if Ebean is unable to determine the columns
* and map them to bean properties.
* </p>
* <p>
* Example with ${andWhere} & ${having}.
* </p>
*
* <pre class="code">
* &#064;SqlSelect(
* name = &quot;explicit.where&quot;,
* query =
* &quot;select t.id, t.title, count(p.id) as score &quot;+
* &quot;from f_topic t, f_topic_post p &quot;+
* &quot;where p.topic_id = t.id ${andWhere} &quot;+
* &quot;group by t.id, t.title ${having}&quot;),
* </pre>
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Deprecated
public @interface SqlSelect {
/**
* The name of the query. If left blank this is assumed to be the default
* query for this bean type.
* <p>
* This will default to "default" and in that case becomes the default query
* used for the bean.
* </p>
*/
String name() default "default";
/**
* The tableAlias used when adding where expressions to the query.
*/
String tableAlias() default "";
/**
* The sql select statement.
* <p>
* If this query <em>extends</em> another then this string is appended to the
* parent query string. Often when using <em>extend</em> you will leave the
* query part blank and just specify a where and/or having clauses.
* </p>
* <p>
* This sql <em>CAN NOT</em> contain named parameters. You have to put these
* in the separate where and/or having sections.
* </p>
* <p>
* Ebean automatically tries to determine the location in the sql string for
* putting in additional where or having clauses. If Ebean is unable to
* successfully determine this then you have to explicitly specify these
* locations by including
* <em>${where} or ${andWhere} and ${having} or ${andHaving}</em> in the sql.
* </p>
* <p>
* <b>${where}</b> location of where clause (and will add WHERE ... ) <br/>
* Use this when there is no where clause in the sql. If expressions are added
* to the where clause Ebean will put them in at this location starting with
* the WHERE keyword.
* <p>
* <p>
* <b>${andWhere}</b> <br/>
* Use this instead of ${where} if there IS an existing where clause in the
* sql. Ebean will add the expressions starting with the AND keyword.
* <p>
* <b>${having}</b> location of having clause (and will add HAVING... ) <br/>
* </p>
* <p>
* <b>${andHaving}</b> <br/>
* Use this instead of ${having} when there IS an existing HAVING clause.
* Ebean will add the expressions starting with the AND keyword.
* </p>
* <p>
* You can include one of ${where} OR ${andWhere} but not both.
* </p>
* <p>
* You can include one of ${having} OR ${andHaving} but not both.
* </p>
*/
String query() default "";
/**
* Specify the name of a sql-select query that this one 'extends'.
* <p>
* When a query is extended the sql query contents are appended together. The
* where and having clauses are NOT appended but overridden.
* </p>
*/
String extend() default "";
/**
* Specify a where clause typically containing named parameters.
* <p>
* If a where clause is specified with named parameters then they will need to
* be set on the query via {@link Query#setParameter(String, Object)}.
* </p>
* <p>
* In the example below the query specifies a where clause that includes a
* named parameter "likeTitle".
* </p>
*
* <pre class="code">
* ...
* &#064;Entity
* &#064;Sql(select = {
* ...
* &#064;SqlSelect(
* name = &quot;with.title&quot;,
* extend = &quot;default&quot;,
* debug = true,
* where = &quot;title like :likeTitle&quot;)
* })
* public class ReportTopic
* ...
* </pre>
*
* <p>
* Example use of the above named query.
* </p>
*
* <pre class="code">
*
* Query&lt;ReportTopic&gt; query0 = Ebean.createQuery(ReportTopic.class, &quot;with.title&quot;);
*
* query0.set(&quot;likeTitle&quot;, &quot;Bana%&quot;);
*
* List&lt;ReportTopic&gt; list0 = query0.findList();
* </pre>
*
*/
String where() default "";
/**
* Specify a having clause typically containing named parameters.
* <p>
* If a having clause is specified with named parameters then they will need
* to be set on the query via {@link Query#setParameter(String, Object)}.
* </p>
*/
String having() default "";
/**
* (Optional) Explicitly specify column to property mapping.
* <p>
* This is required when Ebean is unable to parse the sql. This could occur if
* the sql contains multiple select keywords etc.
* </p>
* <p>
* Specify the columns and property names they map to in the format.
* </p>
*
* <pre class="code">
* column1 propertyName1, column2 propertyName2, ...
* </pre>
*
* <p>
* Optionally put a AS keyword between the column and property.
* </p>
*
* <pre class="code">
* // the AS keyword is optional
* column1 AS propertyName1, column2 propertyName2, ...
* </pre>
*
* <p>
* <b>column</b> should contain the table alias if there is one
* </p>
* <p>
* <b>propertyName</b> should match the property name.
* </p>
*
* <p>
* Example mapping 5 columns to properties.
* </p>
*
* <pre class="code">
* columnMapping=&quot;t.id, t.bug_body description, t.bug_title as title, count(p.id) as scoreValue&quot;,
* </pre>
*
* <p>
* Without this set Ebean will parse the sql looking for the select clause and
* try to map the columns to property names. It is expected that Ebean will
* not be able to successfully parse some sql and for those cases you should
* specify the column to property mapping explicitly.
* </p>
*
*/
String columnMapping() default "";
/**
* Set this to true to have debug output when Ebean parses the sql-select.
*/
boolean debug() default false;
}
@@ -125,4 +125,4 @@ public @interface Transactional {
*/
Class<? extends Throwable>[] noRollbackFor() default {};
};
}
@@ -1,34 +1,34 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specify the update mode for the specific entity type.
* <p>
* Control whether all 'loaded' properties are included in an Update or whether
* just properties that have changed will be included in the update.
* </p>
* <p>
* Note that the default can be set via ebean.properties.
* </p>
*
* <pre>
* ## Set to update all loaded properties
* ebean.updateChangesOnly=false
* </pre>
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface UpdateMode {
/**
* Set to false if you want to include all the 'loaded' properties in the
* update. Otherwise, just the properties that have changed will be included
* in the update.
*/
boolean updateChangesOnly() default true;
};
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specify the update mode for the specific entity type.
* <p>
* Control whether all 'loaded' properties are included in an Update or whether
* just properties that have changed will be included in the update.
* </p>
* <p>
* Note that the default can be set via ebean.properties.
* </p>
*
* <pre>
* ## Set to update all loaded properties
* ebean.updateChangesOnly=false
* </pre>
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface UpdateMode {
/**
* Set to false if you want to include all the 'loaded' properties in the
* update. Otherwise, just the properties that have changed will be included
* in the update.
*/
boolean updateChangesOnly() default true;
}
@@ -1,16 +1,16 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* For a timestamp property that is set to the datetime when the entity was last
* updated.
*/
@Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface UpdatedTimestamp {
};
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* For a timestamp property that is set to the datetime when the entity was last
* updated.
*/
@Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface UpdatedTimestamp {
}
@@ -1,51 +1,54 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Add an Literal to add to the where clause when a many property (List, Set or
* Map) is loaded or refreshed.
*
* <pre class="code">
* // on a OneToMany property...
*
* &#064;OneToMany
* &#064;Where(clause = &quot;deleted='y'&quot;)
* List&lt;Topic&gt; topics;
* </pre>
*
* <p>
* Note that you can include "${ta}" as a place holder for the table alias if
* you need to include the table alias in the clause.
* </p>
*
* <pre class="code">
* // ... including the ${ta} table alias placeholder...
*
* &#064;OneToMany
* &#064;Where(clause = &quot;${ta}.deleted='y'&quot;)
* List&lt;Topic&gt; topics;
* </pre>
*
* <p>
* This will be added to the where clause when lazy loading the OneToMany
* property or when there is a join to that OneToMany property.
* </p>
*/
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Where {
/**
* The clause added to the lazy load query.
* <p>
* Note that you can include "${ta}" as a place holder for the table alias if
* you need to include the table alias in the clause.
* </p>
*/
String clause();
};
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Add an Literal to add to the where clause when a many property (List, Set or
* Map) is loaded or refreshed.
*
* <pre>{@code
*
* // on a OneToMany property...
*
* @OneToMany
* @Where(clause = "deleted='y'")
* List<Topic> topics;
*
* }</pre>
*
* <p>
* Note that you can include "${ta}" as a place holder for the table alias if
* you need to include the table alias in the clause.
* </p>
*
* <pre>{@code
* // ... including the ${ta} table alias placeholder...
*
* @OneToMany
* @Where(clause = "${ta}.deleted='y'")
* List<Topic> topics;
*
* }</pre>
*
* <p>
* This will be added to the where clause when lazy loading the OneToMany
* property or when there is a join to that OneToMany property.
* </p>
*/
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Where {
/**
* The clause added to the lazy load query.
* <p>
* Note that you can include "${ta}" as a place holder for the table alias if
* you need to include the table alias in the clause.
* </p>
*/
String clause();
}
@@ -1,193 +1,201 @@
package com.avaje.ebean.bean;
import java.io.Serializable;
import java.util.Collection;
import java.util.Set;
import com.avaje.ebean.ExpressionList;
/**
* Lazy loading capable Maps, Lists and Sets.
* <p>
* This also includes the ability to listen for additions and removals to or
* from the Map Set or List. The purpose of gathering the additions and removals
* is to support persisting ManyToMany objects. The additions and removals
* become inserts and deletes from the intersection table.
* </p>
* <p>
* Technically this is <em>NOT</em> an extension of
* <em>java.util.Collection</em>. The reason being that java.util.Map is not a
* Collection. I realise this makes this name confusing so I apologise for that.
* </p>
*/
public interface BeanCollection<E> extends Serializable {
public enum ModifyListenMode {
/** The common mode */
NONE,
/** Mode used for PrivateOwned */
REMOVALS,
/** Mode used for ManyToMany relationships */
ALL
}
/**
* Reset the collection back to an empty state ready for reloading.
* <p>
* This is done as part of bean refresh.
*/
public void reset(EntityBean ownerBean, String propertyName);
/**
* Return true if the collection is empty and untouched. Used to detect if a
* collection was 'cleared' deliberately or just un-initialised.
*/
public boolean isEmptyAndUntouched();
/**
* Return the bean that owns this collection.
*/
public EntityBean getOwnerBean();
/**
* Return the bean property name this collection represents.
*/
public String getPropertyName();
/**
* Check after the lazy load that the underlying collection is not null
* (handle case where join to many not outer).
* <p>
* That is, if the collection was not loaded due to filterMany predicates etc
* then make sure the collection is set to empty.
* </p>
*/
public boolean checkEmptyLazyLoad();
/**
* Return the filter (if any) that was used in building this collection.
* <p>
* This is so that the filter can be applied on refresh.
* </p>
*/
public ExpressionList<?> getFilterMany();
/**
* Set the filter that was used in building this collection.
*/
public void setFilterMany(ExpressionList<?> filterMany);
/**
* Set a listener to be notified when the BeanCollection is first touched.
*/
public void setBeanCollectionTouched(BeanCollectionTouched notify);
/**
* Set the loader that will be used to lazy/query load this collection.
*/
public void setLoader(int beanLoaderIndex, BeanCollectionLoader beanLoader);
/**
* Set to true if you want the BeanCollection to be treated as read only. This
* means no elements can be added or removed etc.
*/
public void setReadOnly(boolean readOnly);
/**
* Return true if the collection should be treated as readOnly and no elements
* can be added or removed etc.
*/
public boolean isReadOnly();
/**
* Add the bean to the collection.
* <p>
* This is disallowed for BeanMap.
* </p>
*/
public void internalAdd(Object bean);
/**
* Return the number of elements in the List Set or Map.
*/
public int size();
/**
* Return true if the List Set or Map is empty.
*/
public boolean isEmpty();
/**
* Returns the underlying collection of beans from the Set, Map or List.
*/
public Collection<E> getActualDetails();
/**
* Returns the underlying entries so for Maps this is a collection of
* Map.Entry.
* <p>
* For maps this returns the entrySet as we need the keys of the map.
* </p>
*/
public Collection<?> getActualEntries();
/**
* return true if there are real rows held. Return false is this is using
* Deferred fetch to lazy load the rows and the rows have not yet been
* fetched.
*/
public boolean isPopulated();
/**
* Return true if this is a reference (lazy loading) bean collection. This is
* the same as !isPopulated();
*/
public boolean isReference();
/**
* Set modify listening on or off. This is used to keep track of objects that
* have been added to or removed from the list set or map.
* <p>
* This is required only for ManyToMany collections. The additions and
* deletions are used to insert or delete entries from the intersection table.
* Otherwise modifyListening is false.
* </p>
*/
public void setModifyListening(ModifyListenMode modifyListenMode);
/**
* Add an object to the additions list.
* <p>
* This will potentially end up as an insert into a intersection table for a
* ManyToMany.
* </p>
*/
public void modifyAddition(E bean);
/**
* Add an object to the deletions list.
* <p>
* This will potentially end up as an delete from an intersection table for a
* ManyToMany.
* </p>
*/
public void modifyRemoval(Object bean);
/**
* Return the list of objects added to the list set or map. These will used to
* insert rows into the intersection table of a ManyToMany.
*/
public Set<E> getModifyAdditions();
/**
* Return the list of objects removed from the list set or map. These will
* used to delete rows from the intersection table of a ManyToMany.
*/
public Set<E> getModifyRemovals();
/**
* Reset the set of additions and deletions. This is called after the
* additions and removals have been processed.
*/
public void modifyReset();
}
package com.avaje.ebean.bean;
import java.io.Serializable;
import java.util.Collection;
import java.util.Set;
import com.avaje.ebean.ExpressionList;
/**
* Lazy loading capable Maps, Lists and Sets.
* <p>
* This also includes the ability to listen for additions and removals to or
* from the Map Set or List. The purpose of gathering the additions and removals
* is to support persisting ManyToMany objects. The additions and removals
* become inserts and deletes from the intersection table.
* </p>
* <p>
* Technically this is <em>NOT</em> an extension of
* <em>java.util.Collection</em>. The reason being that java.util.Map is not a
* Collection. I realise this makes this name confusing so I apologise for that.
* </p>
*/
public interface BeanCollection<E> extends Serializable {
enum ModifyListenMode {
/** The common mode */
NONE,
/** Mode used for PrivateOwned */
REMOVALS,
/** Mode used for ManyToMany relationships */
ALL
}
/**
* Reset the collection back to an empty state ready for reloading.
* <p>
* This is done as part of bean refresh.
*/
void reset(EntityBean ownerBean, String propertyName);
/**
* Return true if the collection is empty and untouched. Used to detect if a
* collection was 'cleared' deliberately or just un-initialised.
*/
boolean isEmptyAndUntouched();
/**
* Return the bean that owns this collection.
*/
EntityBean getOwnerBean();
/**
* Return the bean property name this collection represents.
*/
String getPropertyName();
/**
* Check after the lazy load that the underlying collection is not null
* (handle case where join to many not outer).
* <p>
* That is, if the collection was not loaded due to filterMany predicates etc
* then make sure the collection is set to empty.
* </p>
*/
boolean checkEmptyLazyLoad();
/**
* Return the filter (if any) that was used in building this collection.
* <p>
* This is so that the filter can be applied on refresh.
* </p>
*/
ExpressionList<?> getFilterMany();
/**
* Set the filter that was used in building this collection.
*/
void setFilterMany(ExpressionList<?> filterMany);
/**
* Set a listener to be notified when the BeanCollection is first touched.
*/
void setBeanCollectionTouched(BeanCollectionTouched notify);
/**
* Return true if the collection has been registered with the batch loading context.
*/
boolean isRegisteredWithLoadContext();
/**
* Set the loader that will be used to lazy/query load this collection.
* <p>
* This is effectively the batch loading context this collection is registered with.
* </p>
*/
void setLoader(BeanCollectionLoader beanLoader);
/**
* Set to true if you want the BeanCollection to be treated as read only. This
* means no elements can be added or removed etc.
*/
void setReadOnly(boolean readOnly);
/**
* Return true if the collection should be treated as readOnly and no elements
* can be added or removed etc.
*/
boolean isReadOnly();
/**
* Add the bean to the collection.
* <p>
* This is disallowed for BeanMap.
* </p>
*/
void internalAdd(Object bean);
/**
* Return the number of elements in the List Set or Map.
*/
int size();
/**
* Return true if the List Set or Map is empty.
*/
boolean isEmpty();
/**
* Returns the underlying collection of beans from the Set, Map or List.
*/
Collection<E> getActualDetails();
/**
* Returns the underlying entries so for Maps this is a collection of
* Map.Entry.
* <p>
* For maps this returns the entrySet as we need the keys of the map.
* </p>
*/
Collection<?> getActualEntries();
/**
* return true if there are real rows held. Return false is this is using
* Deferred fetch to lazy load the rows and the rows have not yet been
* fetched.
*/
boolean isPopulated();
/**
* Return true if this is a reference (lazy loading) bean collection. This is
* the same as !isPopulated();
*/
boolean isReference();
/**
* Set modify listening on or off. This is used to keep track of objects that
* have been added to or removed from the list set or map.
* <p>
* This is required only for ManyToMany collections. The additions and
* deletions are used to insert or delete entries from the intersection table.
* Otherwise modifyListening is false.
* </p>
*/
void setModifyListening(ModifyListenMode modifyListenMode);
/**
* Add an object to the additions list.
* <p>
* This will potentially end up as an insert into a intersection table for a
* ManyToMany.
* </p>
*/
void modifyAddition(E bean);
/**
* Add an object to the deletions list.
* <p>
* This will potentially end up as an delete from an intersection table for a
* ManyToMany.
* </p>
*/
void modifyRemoval(Object bean);
/**
* Return the list of objects added to the list set or map. These will used to
* insert rows into the intersection table of a ManyToMany.
*/
Set<E> getModifyAdditions();
/**
* Return the list of objects removed from the list set or map. These will
* used to delete rows from the intersection table of a ManyToMany.
*/
Set<E> getModifyRemovals();
/**
* Reset the set of additions and deletions. This is called after the
* additions and removals have been processed.
*/
void modifyReset();
}
@@ -1,16 +1,16 @@
package com.avaje.ebean.bean;
/**
* Interface to define the addition of a bean to the underlying collection.
* <p>
* For maps this takes into account the map key. For List and Set this simply
* adds the bean to the underlying list or set.
* </p>
*/
public interface BeanCollectionAdd {
/**
* Add a loaded bean to the collection.
*/
public void addBean(EntityBean bean);
}
package com.avaje.ebean.bean;
/**
* Interface to define the addition of a bean to the underlying collection.
* <p>
* For maps this takes into account the map key. For List and Set this simply
* adds the bean to the underlying list or set.
* </p>
*/
public interface BeanCollectionAdd {
/**
* Add a loaded bean to the collection.
*/
void addBean(EntityBean bean);
}
@@ -1,21 +1,21 @@
package com.avaje.ebean.bean;
/**
* Loads a entity bean collection.
* <p>
* Typically invokes lazy loading for a single or batch of collections.
* </p>
*/
public interface BeanCollectionLoader {
/**
* Return the name of the associated EbeanServer.
*/
public String getName();
/**
* Invoke the lazy loading for this bean collection.
*/
public void loadMany(BeanCollection<?> collection, boolean onlyIds);
}
package com.avaje.ebean.bean;
/**
* Loads a entity bean collection.
* <p>
* Typically invokes lazy loading for a single or batch of collections.
* </p>
*/
public interface BeanCollectionLoader {
/**
* Return the name of the associated EbeanServer.
*/
String getName();
/**
* Invoke the lazy loading for this bean collection.
*/
void loadMany(BeanCollection<?> collection, boolean onlyIds);
}
@@ -1,20 +1,20 @@
package com.avaje.ebean.bean;
/**
* Used to specify a listener to be notified when a BeanCollection is first
* used.
* <p>
* To use this you can set a BeanCollectionTouched onto a BeanCollection before
* it has been used. When the BeanCollection is first used by the client code
* then the BeanCollectionTouched is notified. It can only be notified once.
* </p>
*
* @author rbygrave
*/
public interface BeanCollectionTouched {
/**
* Notify the listener that the bean collection has been used.
*/
public void notifyTouched(BeanCollection<?> c);
}
package com.avaje.ebean.bean;
/**
* Used to specify a listener to be notified when a BeanCollection is first
* used.
* <p>
* To use this you can set a BeanCollectionTouched onto a BeanCollection before
* it has been used. When the BeanCollection is first used by the client code
* then the BeanCollectionTouched is notified. It can only be notified once.
* </p>
*
* @author rbygrave
*/
public interface BeanCollectionTouched {
/**
* Notify the listener that the bean collection has been used.
*/
void notifyTouched(BeanCollection<?> c);
}
@@ -1,21 +1,21 @@
package com.avaje.ebean.bean;
/**
* Loads a entity bean.
* <p>
* Typically invokes lazy loading for a single or batch of entity beans.
* </p>
*/
public interface BeanLoader {
/**
* Return the name of the associated EbeanServer.
*/
public String getName();
/**
* Invoke the lazy loading for this bean.
*/
public void loadBean(EntityBeanIntercept ebi);
}
package com.avaje.ebean.bean;
/**
* Loads a entity bean.
* <p>
* Typically invokes lazy loading for a single or batch of entity beans.
* </p>
*/
public interface BeanLoader {
/**
* Return the name of the associated EbeanServer.
*/
String getName();
/**
* Invoke the lazy loading for this bean.
*/
void loadBean(EntityBeanIntercept ebi);
}
+118 -118
View File
@@ -1,118 +1,118 @@
package com.avaje.ebean.bean;
import java.io.Serializable;
import java.util.Arrays;
/**
* Represent the call stack (stack trace elements).
* <p>
* Used with a query to identify a CallStackQuery for AutoFetch automatic query
* tuning.
* </p>
* <p>
* This is used so that a single query called from different methods can be
* tuned for each different call stack.
* </p>
* <p>
* Note the call stack is trimmed to remove the common ebean internal elements.
* </p>
*/
public final class CallStack implements Serializable {
private static final long serialVersionUID = -8590644046907438579L;
private final String zeroHash;
private final String pathHash;
private final StackTraceElement[] callStack;
public CallStack(StackTraceElement[] callStack) {
this.callStack = callStack;
this.zeroHash = enc(callStack[0].hashCode());
int hc = 0;
for (int i = 1; i < callStack.length; i++) {
hc = 31 * hc + callStack[i].hashCode();
}
this.pathHash = enc(hc);
}
public int hashCode() {
int hc = 0;
for (int i = 0; i < callStack.length; i++) {
hc = 31 * hc + callStack[i].hashCode();
}
return hc;
}
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof CallStack)) {
return false;
}
CallStack e = (CallStack) obj;
return Arrays.equals(callStack, e.callStack);
}
/**
* Return the first element of the call stack.
*/
public StackTraceElement getFirstStackTraceElement() {
return callStack[0];
}
/**
* Return the call stack.
*/
public StackTraceElement[] getCallStack() {
return callStack;
}
/**
* Return the hash for the first stack element.
*/
public String getZeroHash() {
return zeroHash;
}
/**
* Return the hash for the stack elements (excluding first stack element).
*/
public String getPathHash() {
return pathHash;
}
public String toString() {
return zeroHash + ":" + pathHash + ":" + callStack[0];
}
public String getOriginKey(int queryHash) {
return zeroHash + "." + enc(queryHash) + "." + pathHash;
}
private static final int radix = 1 << 6;
private static final int mask = radix - 1;
/**
* Convert the integer to unsigned base 64.
*/
public static String enc(int i) {
char[] buf = new char[32];
int charPos = 32;
do {
buf[--charPos] = intToBase64[i & mask];
i >>>= 6;
} while (i != 0);
return new String(buf, charPos, (32 - charPos));
}
private static final char intToBase64[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
};
}
package com.avaje.ebean.bean;
import java.io.Serializable;
import java.util.Arrays;
/**
* Represent the call stack (stack trace elements).
* <p>
* Used with a query to identify a CallStackQuery for AutoFetch automatic query
* tuning.
* </p>
* <p>
* This is used so that a single query called from different methods can be
* tuned for each different call stack.
* </p>
* <p>
* Note the call stack is trimmed to remove the common ebean internal elements.
* </p>
*/
public final class CallStack implements Serializable {
private static final long serialVersionUID = -8590644046907438579L;
private final String zeroHash;
private final String pathHash;
private final StackTraceElement[] callStack;
public CallStack(StackTraceElement[] callStack) {
this.callStack = callStack;
this.zeroHash = enc(callStack[0].hashCode());
int hc = 0;
for (int i = 1; i < callStack.length; i++) {
hc = 31 * hc + callStack[i].hashCode();
}
this.pathHash = enc(hc);
}
public int hashCode() {
int hc = 0;
for (int i = 0; i < callStack.length; i++) {
hc = 31 * hc + callStack[i].hashCode();
}
return hc;
}
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof CallStack)) {
return false;
}
CallStack e = (CallStack) obj;
return Arrays.equals(callStack, e.callStack);
}
/**
* Return the first element of the call stack.
*/
public StackTraceElement getFirstStackTraceElement() {
return callStack[0];
}
/**
* Return the call stack.
*/
public StackTraceElement[] getCallStack() {
return callStack;
}
/**
* Return the hash for the first stack element.
*/
public String getZeroHash() {
return zeroHash;
}
/**
* Return the hash for the stack elements (excluding first stack element).
*/
public String getPathHash() {
return pathHash;
}
public String toString() {
return zeroHash + ":" + pathHash + ":" + callStack[0];
}
public String getOriginKey(int queryHash) {
return zeroHash + "." + enc(queryHash) + "." + pathHash;
}
private static final int radix = 1 << 6;
private static final int mask = radix - 1;
/**
* Convert the integer to unsigned base 64.
*/
public static String enc(int i) {
char[] buf = new char[32];
int charPos = 32;
do {
buf[--charPos] = intToBase64[i & mask];
i >>>= 6;
} while (i != 0);
return new String(buf, charPos, (32 - charPos));
}
private static final char intToBase64[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
};
}
+114 -114
View File
@@ -1,114 +1,114 @@
package com.avaje.ebean.bean;
import java.beans.PropertyChangeListener;
import java.io.Serializable;
/**
* Bean that is aware of EntityBeanIntercept.
* <p>
* This interface and implementation of these methods is added to Entity Beans
* via instrumentation. These methods have a funny _ebean_ prefix to avoid any
* clash with normal methods these beans would have. These methods are not for
* general application consumption.
* </p>
*/
public interface EntityBean extends Serializable {
public String[] _ebean_getPropertyNames();
public String _ebean_getPropertyName(int pos);
/**
* Return the enhancement marker value.
* <p>
* This is the class name of the enhanced class and used to check that all
* entity classes are enhanced (specifically not just a super class).
* </p>
*/
public String _ebean_getMarker();
/**
* Create and return a new entity bean instance.
*/
public Object _ebean_newInstance();
/**
* Add a PropertyChangeListener to this bean.
*/
public void addPropertyChangeListener(PropertyChangeListener listener);
/**
* Remove a PropertyChangeListener from this bean.
*/
public void removePropertyChangeListener(PropertyChangeListener listener);
/**
* Generated method that sets the loaded state on all the embedded beans on
* this entity bean by using EntityBeanIntercept.setEmbeddedLoaded(Object o);
*/
public void _ebean_setEmbeddedLoaded();
/**
* Return true if any embedded beans are new or dirty.
*/
public boolean _ebean_isEmbeddedNewOrDirty();
/**
* Return the intercept for this object.
*/
public EntityBeanIntercept _ebean_getIntercept();
/**
* Similar to _ebean_getIntercept() except it checks to see if the intercept
* field is null and will create it if required.
* <p>
* This is really only required when transientInternalFields=true as an
* enhancement option. In this case the intercept field is transient and will
* be null after a bean has been deserialised.
* </p>
* <p>
* This transientInternalFields=true option was to support some serialization
* frameworks that can't take into account our ebean fields.
* </p>
*/
public EntityBeanIntercept _ebean_intercept();
/**
* Create a copy of this entity bean.
* <p>
* This occurs when a bean is changed. The copy represents the bean as it was
* initially (oldValues) before any changes where made. This is used for
* optimistic concurrency control.
* </p>
*/
public Object _ebean_createCopy();
/**
* Set the value of a field of an entity bean of this type.
* <p>
* Note that using this method bypasses any interception that otherwise occurs
* on entity beans. That means lazy loading and oldValues creation.
* </p>
*/
public void _ebean_setField(int fieldIndex, Object value);
/**
* Set the field value with interception.
*/
public void _ebean_setFieldIntercept(int fieldIndex, Object value);
/**
* Return the value of a field from an entity bean of this type.
* <p>
* Note that using this method bypasses any interception that otherwise occurs
* on entity beans. That means lazy loading.
* </p>
*/
public Object _ebean_getField(int fieldIndex);
/**
* Return the field value with interception.
*/
public Object _ebean_getFieldIntercept(int fieldIndex);
}
package com.avaje.ebean.bean;
import java.beans.PropertyChangeListener;
import java.io.Serializable;
/**
* Bean that is aware of EntityBeanIntercept.
* <p>
* This interface and implementation of these methods is added to Entity Beans
* via instrumentation. These methods have a funny _ebean_ prefix to avoid any
* clash with normal methods these beans would have. These methods are not for
* general application consumption.
* </p>
*/
public interface EntityBean extends Serializable {
String[] _ebean_getPropertyNames();
String _ebean_getPropertyName(int pos);
/**
* Return the enhancement marker value.
* <p>
* This is the class name of the enhanced class and used to check that all
* entity classes are enhanced (specifically not just a super class).
* </p>
*/
String _ebean_getMarker();
/**
* Create and return a new entity bean instance.
*/
Object _ebean_newInstance();
/**
* Add a PropertyChangeListener to this bean.
*/
void addPropertyChangeListener(PropertyChangeListener listener);
/**
* Remove a PropertyChangeListener from this bean.
*/
void removePropertyChangeListener(PropertyChangeListener listener);
/**
* Generated method that sets the loaded state on all the embedded beans on
* this entity bean by using EntityBeanIntercept.setEmbeddedLoaded(Object o);
*/
void _ebean_setEmbeddedLoaded();
/**
* Return true if any embedded beans are new or dirty.
*/
boolean _ebean_isEmbeddedNewOrDirty();
/**
* Return the intercept for this object.
*/
EntityBeanIntercept _ebean_getIntercept();
/**
* Similar to _ebean_getIntercept() except it checks to see if the intercept
* field is null and will create it if required.
* <p>
* This is really only required when transientInternalFields=true as an
* enhancement option. In this case the intercept field is transient and will
* be null after a bean has been deserialised.
* </p>
* <p>
* This transientInternalFields=true option was to support some serialization
* frameworks that can't take into account our ebean fields.
* </p>
*/
EntityBeanIntercept _ebean_intercept();
/**
* Create a copy of this entity bean.
* <p>
* This occurs when a bean is changed. The copy represents the bean as it was
* initially (oldValues) before any changes where made. This is used for
* optimistic concurrency control.
* </p>
*/
Object _ebean_createCopy();
/**
* Set the value of a field of an entity bean of this type.
* <p>
* Note that using this method bypasses any interception that otherwise occurs
* on entity beans. That means lazy loading and oldValues creation.
* </p>
*/
void _ebean_setField(int fieldIndex, Object value);
/**
* Set the field value with interception.
*/
void _ebean_setFieldIntercept(int fieldIndex, Object value);
/**
* Return the value of a field from an entity bean of this type.
* <p>
* Note that using this method bypasses any interception that otherwise occurs
* on entity beans. That means lazy loading.
* </p>
*/
Object _ebean_getField(int fieldIndex);
/**
* Return the field value with interception.
*/
Object _ebean_getFieldIntercept(int fieldIndex);
}
File diff suppressed because it is too large Load Diff
@@ -1,126 +1,126 @@
package com.avaje.ebean.bean;
import java.lang.ref.WeakReference;
import java.util.HashSet;
/**
* Collects profile information for a bean (or reference/proxy bean) at a given
* AutoFetchNode.
* <p>
* The AutoFetchNode identifies the location of the bean in the object graph.
* </p>
* <p>
* It has to use a weak reference so as to ensure that it does not stop the
* associated bean from being garbage collected.
* </p>
*/
public final class NodeUsageCollector {
/**
* The point in the object graph for a specific query and call stack point.
*/
private final ObjectGraphNode node;
/**
* Weak to allow garbage collection.
*/
private final WeakReference<NodeUsageListener> managerRef;
/**
* The properties used at this profile point.
*/
private final HashSet<String> used = new HashSet<String>();
/**
* set to true if the bean is modified (setter called)
*/
private boolean modified;
/**
* The property that cause a reference to lazy load.
*/
private String loadProperty;
public NodeUsageCollector(ObjectGraphNode node, WeakReference<NodeUsageListener> managerRef) {
this.node = node;
// weak to allow garbage collection.
this.managerRef = managerRef;
}
/**
* The bean has been modified by a setter method.
*/
public void setModified() {
modified = true;
}
/**
* Add the name of a property that has been used.
*/
public void addUsed(String property) {
used.add(property);
}
/**
* The property that invoked a lazy load.
*/
public void setLoadProperty(String loadProperty) {
this.loadProperty = loadProperty;
}
/**
* Publish the usage info to the manager.
*/
private void publishUsageInfo() {
NodeUsageListener manager = managerRef.get();
if (manager != null) {
manager.collectNodeUsage(this);
}
}
/**
* publish the collected usage information when garbage collection occurs.
*/
@Override
protected void finalize() throws Throwable {
publishUsageInfo();
super.finalize();
}
/**
* Return the associated node which identifies the location in the object
* graph of the bean/reference.
*/
public ObjectGraphNode getNode() {
return node;
}
/**
* Return true if no properties where used.
*/
public boolean isEmpty() {
return used.isEmpty();
}
/**
* Return the set of used properties.
*/
public HashSet<String> getUsed() {
return used;
}
/**
* Return true if the bean was modified by a setter.
*/
public boolean isModified() {
return modified;
}
public String getLoadProperty() {
return loadProperty;
}
public String toString() {
return node + " read:" + used + " modified:" + modified;
}
}
package com.avaje.ebean.bean;
import java.lang.ref.WeakReference;
import java.util.HashSet;
/**
* Collects profile information for a bean (or reference/proxy bean) at a given
* AutoFetchNode.
* <p>
* The AutoFetchNode identifies the location of the bean in the object graph.
* </p>
* <p>
* It has to use a weak reference so as to ensure that it does not stop the
* associated bean from being garbage collected.
* </p>
*/
public final class NodeUsageCollector {
/**
* The point in the object graph for a specific query and call stack point.
*/
private final ObjectGraphNode node;
/**
* Weak to allow garbage collection.
*/
private final WeakReference<NodeUsageListener> managerRef;
/**
* The properties used at this profile point.
*/
private final HashSet<String> used = new HashSet<String>();
/**
* set to true if the bean is modified (setter called)
*/
private boolean modified;
/**
* The property that cause a reference to lazy load.
*/
private String loadProperty;
public NodeUsageCollector(ObjectGraphNode node, WeakReference<NodeUsageListener> managerRef) {
this.node = node;
// weak to allow garbage collection.
this.managerRef = managerRef;
}
/**
* The bean has been modified by a setter method.
*/
public void setModified() {
modified = true;
}
/**
* Add the name of a property that has been used.
*/
public void addUsed(String property) {
used.add(property);
}
/**
* The property that invoked a lazy load.
*/
public void setLoadProperty(String loadProperty) {
this.loadProperty = loadProperty;
}
/**
* Publish the usage info to the manager.
*/
private void publishUsageInfo() {
NodeUsageListener manager = managerRef.get();
if (manager != null) {
manager.collectNodeUsage(this);
}
}
/**
* publish the collected usage information when garbage collection occurs.
*/
@Override
protected void finalize() throws Throwable {
publishUsageInfo();
super.finalize();
}
/**
* Return the associated node which identifies the location in the object
* graph of the bean/reference.
*/
public ObjectGraphNode getNode() {
return node;
}
/**
* Return true if no properties where used.
*/
public boolean isEmpty() {
return used.isEmpty();
}
/**
* Return the set of used properties.
*/
public HashSet<String> getUsed() {
return used;
}
/**
* Return true if the bean was modified by a setter.
*/
public boolean isModified() {
return modified;
}
public String getLoadProperty() {
return loadProperty;
}
public String toString() {
return node + " read:" + used + " modified:" + modified;
}
}
@@ -1,16 +1,16 @@
package com.avaje.ebean.bean;
/**
* Collects the profile information.
*/
public interface NodeUsageListener {
/**
* Collect node usage "profiling" information.
* <p>
* This is the properties that are used for a given bean in the object graph.
* This information is used by autoFetch to tune queries.
* </p>
*/
public void collectNodeUsage(NodeUsageCollector collector);
}
package com.avaje.ebean.bean;
/**
* Collects the profile information.
*/
public interface NodeUsageListener {
/**
* Collect node usage "profiling" information.
* <p>
* This is the properties that are used for a given bean in the object graph.
* This information is used by autoFetch to tune queries.
* </p>
*/
void collectNodeUsage(NodeUsageCollector collector);
}
@@ -1,88 +1,88 @@
package com.avaje.ebean.bean;
import java.io.Serializable;
/**
* Identifies a unique node of an object graph.
* <p>
* It represents a location relative to the root of an object graph and specific
* to a query and call stack hash.
* </p>
*/
public final class ObjectGraphNode implements Serializable {
private static final long serialVersionUID = 2087081778650228996L;
/**
* Identifies the origin.
*/
private final ObjectGraphOrigin originQueryPoint;
/**
* The path relative to the root.
*/
private final String path;
/**
* Create at a sub level.
*/
public ObjectGraphNode(ObjectGraphNode parent, String path) {
this.originQueryPoint = parent.getOriginQueryPoint();
this.path = parent.getChildPath(path);
}
/**
* Create an the root level.
*/
public ObjectGraphNode(ObjectGraphOrigin originQueryPoint, String path) {
this.originQueryPoint = originQueryPoint;
this.path = path;
}
/**
* Return the origin query point.
*/
public ObjectGraphOrigin getOriginQueryPoint() {
return originQueryPoint;
}
private String getChildPath(String childPath) {
if (path == null) {
return childPath;
} else if (childPath == null) {
return path;
} else {
return path + "." + childPath;
}
}
/**
* Return the path relative to the root.
*/
public String getPath() {
return path;
}
public String toString() {
return "origin:" + originQueryPoint + " path[" + path+"]";
}
public int hashCode() {
int hc = 31 * originQueryPoint.hashCode();
hc = 31 * hc + (path == null ? 0 : path.hashCode());
return hc;
}
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof ObjectGraphNode)) {
return false;
}
ObjectGraphNode e = (ObjectGraphNode) obj;
return ((e.path == path) || (e.path != null && e.path.equals(path)))
&& e.originQueryPoint.equals(originQueryPoint);
}
}
package com.avaje.ebean.bean;
import java.io.Serializable;
/**
* Identifies a unique node of an object graph.
* <p>
* It represents a location relative to the root of an object graph and specific
* to a query and call stack hash.
* </p>
*/
public final class ObjectGraphNode implements Serializable {
private static final long serialVersionUID = 2087081778650228996L;
/**
* Identifies the origin.
*/
private final ObjectGraphOrigin originQueryPoint;
/**
* The path relative to the root.
*/
private final String path;
/**
* Create at a sub level.
*/
public ObjectGraphNode(ObjectGraphNode parent, String path) {
this.originQueryPoint = parent.getOriginQueryPoint();
this.path = parent.getChildPath(path);
}
/**
* Create an the root level.
*/
public ObjectGraphNode(ObjectGraphOrigin originQueryPoint, String path) {
this.originQueryPoint = originQueryPoint;
this.path = path;
}
/**
* Return the origin query point.
*/
public ObjectGraphOrigin getOriginQueryPoint() {
return originQueryPoint;
}
private String getChildPath(String childPath) {
if (path == null) {
return childPath;
} else if (childPath == null) {
return path;
} else {
return path + "." + childPath;
}
}
/**
* Return the path relative to the root.
*/
public String getPath() {
return path;
}
public String toString() {
return "origin:" + originQueryPoint + " path[" + path+"]";
}
public int hashCode() {
int hc = 31 * originQueryPoint.hashCode();
hc = 31 * hc + (path == null ? 0 : path.hashCode());
return hc;
}
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof ObjectGraphNode)) {
return false;
}
ObjectGraphNode e = (ObjectGraphNode) obj;
return ((e.path == path) || (e.path != null && e.path.equals(path)))
&& e.originQueryPoint.equals(originQueryPoint);
}
}
@@ -1,84 +1,84 @@
package com.avaje.ebean.bean;
import java.io.Serializable;
/**
* Represents a "origin" of an ORM object graph. This combines the call stack
* and query plan hash.
* <p>
* The call stack is included so that the query can have different tuned fetches
* for each unique call stack. For example, a query to fetch a customer could be
* called by three different methods and each can be treated as a separate
* origin point (and autoFetch can tune each one separately).
* </p>
*/
public final class ObjectGraphOrigin implements Serializable {
private static final long serialVersionUID = 410937765287968708L;
private final CallStack callStack;
private final String beanType;
private final int queryHash;
private final String key;
public ObjectGraphOrigin(int queryHash, CallStack callStack, String beanType) {
this.callStack = callStack;
this.beanType = beanType;
this.queryHash = queryHash;
this.key = callStack.getOriginKey(queryHash);
}
/**
* The key includes the queryPlan hash and the callStack hash. This becomes
* the unique identifier for a query point.
*/
public String getKey() {
return key;
}
/**
* The type of bean the query is fetching.
*/
public String getBeanType() {
return beanType;
}
/**
* The call stack involved.
*/
public CallStack getCallStack() {
return callStack;
}
public String getFirstStackElement() {
return callStack.getFirstStackTraceElement().toString();
}
public String toString() {
return "key["+ key + "] type[" + beanType + "] " + callStack.getFirstStackTraceElement()+" ";
}
public int hashCode() {
int hc = 31 * callStack.hashCode();
hc = 31 * hc + beanType.hashCode();
hc = 31 * hc + queryHash;
return hc;
}
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof ObjectGraphOrigin)) {
return false;
}
ObjectGraphOrigin e = (ObjectGraphOrigin) obj;
return e.queryHash == queryHash
&& e.beanType.equals(beanType)
&& e.callStack.equals(callStack);
}
}
package com.avaje.ebean.bean;
import java.io.Serializable;
/**
* Represents a "origin" of an ORM object graph. This combines the call stack
* and query plan hash.
* <p>
* The call stack is included so that the query can have different tuned fetches
* for each unique call stack. For example, a query to fetch a customer could be
* called by three different methods and each can be treated as a separate
* origin point (and autoFetch can tune each one separately).
* </p>
*/
public final class ObjectGraphOrigin implements Serializable {
private static final long serialVersionUID = 410937765287968708L;
private final CallStack callStack;
private final String beanType;
private final int queryHash;
private final String key;
public ObjectGraphOrigin(int queryHash, CallStack callStack, String beanType) {
this.callStack = callStack;
this.beanType = beanType;
this.queryHash = queryHash;
this.key = callStack.getOriginKey(queryHash);
}
/**
* The key includes the queryPlan hash and the callStack hash. This becomes
* the unique identifier for a query point.
*/
public String getKey() {
return key;
}
/**
* The type of bean the query is fetching.
*/
public String getBeanType() {
return beanType;
}
/**
* The call stack involved.
*/
public CallStack getCallStack() {
return callStack;
}
public String getFirstStackElement() {
return callStack.getFirstStackTraceElement().toString();
}
public String toString() {
return "key["+ key + "] type[" + beanType + "] " + callStack.getFirstStackTraceElement()+" ";
}
public int hashCode() {
int hc = 31 * callStack.hashCode();
hc = 31 * hc + beanType.hashCode();
hc = 31 * hc + queryHash;
return hc;
}
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof ObjectGraphOrigin)) {
return false;
}
ObjectGraphOrigin e = (ObjectGraphOrigin) obj;
return e.queryHash == queryHash
&& e.beanType.equals(beanType)
&& e.callStack.equals(callStack);
}
}
@@ -1,110 +1,110 @@
package com.avaje.ebean.bean;
/**
* Holds entity beans by there type and id.
* <p>
* This is used to ensure only one instance for a given entity type and id is
* used to build object graphs from queries and lazy loading.
* </p>
*/
public interface PersistenceContext {
/**
* Put the entity bean into the PersistanceContext.
*/
public void put(Object id, Object bean);
/**
* Put the entity bean into the PersistanceContext if one is not already
* present (for this id).
* <p>
* Returns an existing entity bean (if one is already there) and otherwise
* returns null.
* </p>
*/
public Object putIfAbsent(Object id, Object bean);
/**
* Return an object given its type and unique id.
*/
public Object get(Class<?> beanType, Object uid);
/**
* Get the bean from the persistence context also checked to see if it had
* been previously deleted (if so then you also can't hit the L2 cache to
* fetch the bean for this particular persistence context).
*/
public WithOption getWithOption(Class<?> beanType, Object uid);
/**
* Clear all the references.
*/
public void clear();
/**
* Clear all the references for a given type of entity bean.
*/
public void clear(Class<?> beanType);
/**
* Clear the reference to a specific entity bean.
*/
public void clear(Class<?> beanType, Object uid);
/**
* Clear the reference as a result of an entity being deleted.
*/
public void deleted(Class<?> beanType, Object id);
/**
* Return the number of beans of the given type in the persistence context.
*/
public int size(Class<?> beanType);
/**
* Wrapper on a bean to also indicate if a bean has been deleted.
* <p>
* If a bean has been deleted then for the same persistence context is should
* not be able to be fetched from persistence context or L2 cache.
* </p>
*/
public static class WithOption {
/**
* The bean was previously deleted from this persistence context (can't hit
* L2 cache).
*/
public static WithOption DELETED = new WithOption(true);
private final boolean deleted;
private final Object bean;
private WithOption(boolean deleted) {
this.deleted = true;
this.bean = null;
}
/**
* The bean exists in the persistence context (and not been previously deleted).
*/
public WithOption(Object bean) {
this.deleted = false;
this.bean = bean;
}
/**
* Return true if the bean was deleted. This means you can't hit the L2
* cache.
*/
public boolean isDeleted() {
return deleted;
}
/**
* Return the bean (from the persistence context).
*/
public Object getBean() {
return bean;
}
}
}
package com.avaje.ebean.bean;
/**
* Holds entity beans by there type and id.
* <p>
* This is used to ensure only one instance for a given entity type and id is
* used to build object graphs from queries and lazy loading.
* </p>
*/
public interface PersistenceContext {
/**
* Put the entity bean into the PersistanceContext.
*/
void put(Object id, Object bean);
/**
* Put the entity bean into the PersistanceContext if one is not already
* present (for this id).
* <p>
* Returns an existing entity bean (if one is already there) and otherwise
* returns null.
* </p>
*/
Object putIfAbsent(Object id, Object bean);
/**
* Return an object given its type and unique id.
*/
Object get(Class<?> beanType, Object uid);
/**
* Get the bean from the persistence context also checked to see if it had
* been previously deleted (if so then you also can't hit the L2 cache to
* fetch the bean for this particular persistence context).
*/
WithOption getWithOption(Class<?> beanType, Object uid);
/**
* Clear all the references.
*/
void clear();
/**
* Clear all the references for a given type of entity bean.
*/
void clear(Class<?> beanType);
/**
* Clear the reference to a specific entity bean.
*/
void clear(Class<?> beanType, Object uid);
/**
* Clear the reference as a result of an entity being deleted.
*/
void deleted(Class<?> beanType, Object id);
/**
* Return the number of beans of the given type in the persistence context.
*/
int size(Class<?> beanType);
/**
* Wrapper on a bean to also indicate if a bean has been deleted.
* <p>
* If a bean has been deleted then for the same persistence context is should
* not be able to be fetched from persistence context or L2 cache.
* </p>
*/
class WithOption {
/**
* The bean was previously deleted from this persistence context (can't hit
* L2 cache).
*/
public static WithOption DELETED = new WithOption(true);
private final boolean deleted;
private final Object bean;
private WithOption(boolean deleted) {
this.deleted = true;
this.bean = null;
}
/**
* The bean exists in the persistence context (and not been previously deleted).
*/
public WithOption(Object bean) {
this.deleted = false;
this.bean = bean;
}
/**
* Return true if the bean was deleted. This means you can't hit the L2
* cache.
*/
public boolean isDeleted() {
return deleted;
}
/**
* Return the bean (from the persistence context).
*/
public Object getBean() {
return bean;
}
}
}
+83 -89
View File
@@ -1,89 +1,83 @@
package com.avaje.ebean.cache;
import com.avaje.ebean.EbeanServer;
/**
* Represents part of the "L2" server side cache.
* <p>
* This is used to cache beans or query results (bean collections).
* </p>
* <p>
* There are 2 ServerCache's for each bean type. One is used as the 'bean cache'
* which holds beans of a given type. The other is the 'query cache' holding
* query results for a given type.
* </p>
*
* @author rbygrave
*/
public interface ServerCache {
/**
* Just after a cache is created this init method is called. This is so that a
* cache implementation can make use of the BackgroundExecutor service to
* trim/cleanup itself or use the EbeanServer to populate itself.
* <p>
* This method is called after the cache is constructed but before the cache
* is made available for use.
* </p>
*/
public void init(EbeanServer ebeanServer);
/**
* Return the configuration options for this cache.
*/
public ServerCacheOptions getOptions();
/**
* Update the configuration options for this cache.
*/
public void setOptions(ServerCacheOptions options);
/**
* Return the value given the key.
*/
public Object get(Object id);
/**
* Put the value in the cache with a given id.
*/
public Object put(Object id, Object value);
/**
* Put the value in the cache but only if a matching value is not already in
* the cache.
*/
public Object putIfAbsent(Object id, Object value);
/**
* Remove a entry from the cache given its id.
*/
public Object remove(Object id);
/**
* Clear all entries from the cache.
* <p>
* NOTE: Be careful using this method in that most of the time application
* code should clear BOTH the bean and query caches at the same time. This can
* be done via {@link ServerCacheManager#clear(Class)}.
* </p>
*/
public void clear();
/**
* Return the number of entries in the cache.
*/
public int size();
/**
* Return the hit ratio the cache is currently getting.
*/
public int getHitRatio();
/**
* Return statistics for the cache.
*
* @param reset
* if true the statistics are reset.
*/
public ServerCacheStatistics getStatistics(boolean reset);
}
package com.avaje.ebean.cache;
import com.avaje.ebean.EbeanServer;
/**
* Represents part of the "L2" server side cache.
* <p>
* This is used to cache beans or query results (bean collections).
* </p>
* <p>
* There are 2 ServerCache's for each bean type. One is used as the 'bean cache'
* which holds beans of a given type. The other is the 'query cache' holding
* query results for a given type.
* </p>
*
* @author rbygrave
*/
public interface ServerCache {
/**
* Just after a cache is created this init method is called. This is so that a
* cache implementation can make use of the BackgroundExecutor service to
* trim/cleanup itself or use the EbeanServer to populate itself.
* <p>
* This method is called after the cache is constructed but before the cache
* is made available for use.
* </p>
*/
void init(EbeanServer ebeanServer);
/**
* Return the configuration options for this cache.
*/
ServerCacheOptions getOptions();
/**
* Update the configuration options for this cache.
*/
void setOptions(ServerCacheOptions options);
/**
* Return the value given the key.
*/
Object get(Object id);
/**
* Put the value in the cache with a given id.
*/
Object put(Object id, Object value);
/**
* Remove a entry from the cache given its id.
*/
Object remove(Object id);
/**
* Clear all entries from the cache.
* <p>
* NOTE: Be careful using this method in that most of the time application
* code should clear BOTH the bean and query caches at the same time. This can
* be done via {@link ServerCacheManager#clear(Class)}.
* </p>
*/
void clear();
/**
* Return the number of entries in the cache.
*/
int size();
/**
* Return the hit ratio the cache is currently getting.
*/
int getHitRatio();
/**
* Return statistics for the cache.
*
* @param reset
* if true the statistics are reset.
*/
ServerCacheStatistics getStatistics(boolean reset);
}
+26 -26
View File
@@ -1,26 +1,26 @@
package com.avaje.ebean.cache;
import com.avaje.ebean.EbeanServer;
/**
* Defines method for constructing caches for beans and queries.
*/
public interface ServerCacheFactory {
/**
* Just after the ServerCacheFactory is constructed this method is called
* passing the EbeanServer.
* <p>
* This is so that a cache implementation can utilise the EbeanServer to
* populate itself or use the BackgroundExecutor service to schedule periodic
* cache trimming/cleanup.
* </p>
*/
public void init(EbeanServer ebeanServer);
/**
* Create the cache for the given type with options.
*/
public ServerCache createCache(String cacheKey, ServerCacheOptions cacheOptions);
}
package com.avaje.ebean.cache;
import com.avaje.ebean.EbeanServer;
/**
* Defines method for constructing caches for beans and queries.
*/
public interface ServerCacheFactory {
/**
* Just after the ServerCacheFactory is constructed this method is called
* passing the EbeanServer.
* <p>
* This is so that a cache implementation can utilise the EbeanServer to
* populate itself or use the BackgroundExecutor service to schedule periodic
* cache trimming/cleanup.
* </p>
*/
void init(EbeanServer ebeanServer);
/**
* Create the cache for the given type with options.
*/
ServerCache createCache(String cacheKey, ServerCacheOptions cacheOptions);
}
+55 -55
View File
@@ -1,55 +1,55 @@
package com.avaje.ebean.cache;
import com.avaje.ebean.EbeanServer;
/**
* The cache service for server side caching of beans and query results.
*/
public interface ServerCacheManager {
/**
* This method is called just after the construction of the
* ServerCacheManager.
* <p>
* The EbeanServer is provided so that cache implementations can make use of
* EbeanServer and BackgroundExecutor for automatically populating and
* background trimming of the cache.
* </p>
*/
public void init(EbeanServer server);
public void setCaching(Class<?> beanType, boolean useCache);
/**
* Return true if there is an active bean cache for this type of bean.
*/
public boolean isBeanCaching(Class<?> beanType);
/**
* Return the cache for mapping natural keys to id values.
*/
public ServerCache getNaturalKeyCache(Class<?> beanType);
/**
* Return the cache for beans of a particular type.
*/
public ServerCache getBeanCache(Class<?> beanType);
public ServerCache getCollectionIdsCache(Class<?> beanType, String propertyName);
/**
* Return the cache for query results of a particular type of bean.
*/
public ServerCache getQueryCache(Class<?> beanType);
/**
* This clears both the bean and query cache for a given type.
*/
public void clear(Class<?> beanType);
/**
* Clear all the caches.
*/
public void clearAll();
}
package com.avaje.ebean.cache;
import com.avaje.ebean.EbeanServer;
/**
* The cache service for server side caching of beans and query results.
*/
public interface ServerCacheManager {
/**
* This method is called just after the construction of the
* ServerCacheManager.
* <p>
* The EbeanServer is provided so that cache implementations can make use of
* EbeanServer and BackgroundExecutor for automatically populating and
* background trimming of the cache.
* </p>
*/
void init(EbeanServer server);
void setCaching(Class<?> beanType, boolean useCache);
/**
* Return true if there is an active bean cache for this type of bean.
*/
boolean isBeanCaching(Class<?> beanType);
/**
* Return the cache for mapping natural keys to id values.
*/
ServerCache getNaturalKeyCache(Class<?> beanType);
/**
* Return the cache for beans of a particular type.
*/
ServerCache getBeanCache(Class<?> beanType);
ServerCache getCollectionIdsCache(Class<?> beanType, String propertyName);
/**
* Return the cache for query results of a particular type of bean.
*/
ServerCache getQueryCache(Class<?> beanType);
/**
* This clears both the bean and query cache for a given type.
*/
void clear(Class<?> beanType);
/**
* Clear all the caches.
*/
void clearAll();
}
+129 -110
View File
@@ -1,110 +1,129 @@
package com.avaje.ebean.cache;
import com.avaje.ebean.annotation.CacheTuning;
/**
* Options for controlling a cache.
*/
public class ServerCacheOptions {
private int maxSize;
private int maxIdleSecs;
private int maxSecsToLive;
/**
* Construct with no set options.
*/
public ServerCacheOptions() {
}
/**
* Create from the cacheTuning deployment annotation.
*/
public ServerCacheOptions(CacheTuning cacheTuning) {
this.maxSize = cacheTuning.maxSize();
this.maxIdleSecs = cacheTuning.maxIdleSecs();
this.maxSecsToLive = cacheTuning.maxSecsToLive();
}
/**
* Create merging default options with the deployment specified ones.
*/
public ServerCacheOptions(ServerCacheOptions d) {
this.maxSize = d.getMaxSize();
this.maxIdleSecs = d.getMaxIdleSecs();
this.maxSecsToLive = d.getMaxIdleSecs();
}
/**
* Apply any settings from the default settings that have not already been
* specifically set.
*/
public void applyDefaults(ServerCacheOptions defaults) {
if (maxSize == 0) {
maxSize = defaults.getMaxSize();
}
if (maxIdleSecs == 0) {
maxIdleSecs = defaults.getMaxIdleSecs();
}
if (maxSecsToLive == 0) {
maxSecsToLive = defaults.getMaxSecsToLive();
}
}
/**
* Return a copy of this object.
*/
public ServerCacheOptions copy() {
ServerCacheOptions copy = new ServerCacheOptions();
copy.maxSize = maxSize;
copy.maxIdleSecs = maxIdleSecs;
copy.maxSecsToLive = maxSecsToLive;
return copy;
}
/**
* Return the maximum cache size.
*/
public int getMaxSize() {
return maxSize;
}
/**
* Set the maximum cache size.
*/
public void setMaxSize(int maxSize) {
this.maxSize = maxSize;
}
/**
* Return the maximum idle time.
*/
public int getMaxIdleSecs() {
return maxIdleSecs;
}
/**
* Set the maximum idle time.
*/
public void setMaxIdleSecs(int maxIdleSecs) {
this.maxIdleSecs = maxIdleSecs;
}
/**
* Return the maximum time to live.
*/
public int getMaxSecsToLive() {
return maxSecsToLive;
}
/**
* Set the maximum time to live.
*/
public void setMaxSecsToLive(int maxSecsToLive) {
this.maxSecsToLive = maxSecsToLive;
}
}
package com.avaje.ebean.cache;
import com.avaje.ebean.annotation.CacheTuning;
/**
* Options for controlling a cache.
*/
public class ServerCacheOptions {
private int maxSize;
private int maxIdleSecs;
private int maxSecsToLive;
private int trimFrequency;
/**
* Construct with no set options.
*/
public ServerCacheOptions() {
}
/**
* Create from the cacheTuning deployment annotation.
*/
public ServerCacheOptions(CacheTuning cacheTuning) {
this.maxSize = cacheTuning.maxSize();
this.maxIdleSecs = cacheTuning.maxIdleSecs();
this.maxSecsToLive = cacheTuning.maxSecsToLive();
this.trimFrequency = cacheTuning.trimFrequency();
}
/**
* Create merging default options with the deployment specified ones.
*/
public ServerCacheOptions(ServerCacheOptions defaults) {
this.maxSize = defaults.getMaxSize();
this.maxIdleSecs = defaults.getMaxIdleSecs();
this.maxSecsToLive = defaults.getMaxIdleSecs();
this.trimFrequency = defaults.getTrimFrequency();
}
/**
* Apply any settings from the default settings that have not already been
* specifically set.
*/
public void applyDefaults(ServerCacheOptions defaults) {
if (maxSize == 0) {
maxSize = defaults.getMaxSize();
}
if (maxIdleSecs == 0) {
maxIdleSecs = defaults.getMaxIdleSecs();
}
if (maxSecsToLive == 0) {
maxSecsToLive = defaults.getMaxSecsToLive();
}
if (trimFrequency == 0) {
trimFrequency = defaults.getTrimFrequency();
}
}
/**
* Return a copy of this object.
*/
public ServerCacheOptions copy() {
ServerCacheOptions copy = new ServerCacheOptions();
copy.maxSize = maxSize;
copy.maxIdleSecs = maxIdleSecs;
copy.maxSecsToLive = maxSecsToLive;
copy.trimFrequency = trimFrequency;
return copy;
}
/**
* Return the maximum cache size.
*/
public int getMaxSize() {
return maxSize;
}
/**
* Set the maximum cache size.
*/
public void setMaxSize(int maxSize) {
this.maxSize = maxSize;
}
/**
* Return the maximum idle time.
*/
public int getMaxIdleSecs() {
return maxIdleSecs;
}
/**
* Set the maximum idle time.
*/
public void setMaxIdleSecs(int maxIdleSecs) {
this.maxIdleSecs = maxIdleSecs;
}
/**
* Return the maximum time to live.
*/
public int getMaxSecsToLive() {
return maxSecsToLive;
}
/**
* Set the maximum time to live.
*/
public void setMaxSecsToLive(int maxSecsToLive) {
this.maxSecsToLive = maxSecsToLive;
}
/**
* Return the trim frequency in seconds.
*/
public int getTrimFrequency() {
return trimFrequency;
}
/**
* Set the trim frequency in seconds.
*/
public void setTrimFrequency(int trimFrequency) {
this.trimFrequency = trimFrequency;
}
}
+276 -124
View File
@@ -1,124 +1,276 @@
package com.avaje.ebean.cache;
/**
* The statistics collected per cache.
* <p>
* These can be monitored to review the effectiveness of a particular cache.
* </p>
*
* @author rbygrave
*
*/
public class ServerCacheStatistics {
protected String cacheName;
protected int maxSize;
protected int size;
protected int hitCount;
protected int missCount;
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(cacheName);
sb.append(" size:").append(size);
sb.append(" hitRatio:").append(getHitRatio());
sb.append(" hitCount:").append(hitCount);
sb.append(" missCount:").append(missCount);
sb.append(" maxSize:").append(maxSize);
return sb.toString();
}
/**
* Return the name of the cache.
*/
public String getCacheName() {
return cacheName;
}
/**
* Set the name of the cache.
*/
public void setCacheName(String cacheName) {
this.cacheName = cacheName;
}
/**
* Return the hit count. The number of successful gets.
*/
public int getHitCount() {
return hitCount;
}
/**
* Set the hit count.
*/
public void setHitCount(int hitCount) {
this.hitCount = hitCount;
}
/**
* Return the miss count. The number of gets that returned null.
*/
public int getMissCount() {
return missCount;
}
/**
* Set the miss count.
*/
public void setMissCount(int missCount) {
this.missCount = missCount;
}
/**
* Return the size of the cache.
*/
public int getSize() {
return size;
}
/**
* Set the size of the cache.
*/
public void setSize(int size) {
this.size = size;
}
/**
* Return the maximum size of the cache.
* <p>
* Can be used in conjunction with the size to determine if the cache use is
* being potentially limited by its maximum size.
* </p>
*/
public int getMaxSize() {
return maxSize;
}
/**
* Set the maximum size of the cache.
*/
public void setMaxSize(int maxSize) {
this.maxSize = maxSize;
}
/**
* Returns an int from 0 to 100 (percentage) for the hit ratio.
* <p>
* A hit ratio of 100 means every get request against the cache hits an entry.
* </p>
*/
public int getHitRatio() {
int totalCount = hitCount + missCount;
if (totalCount == 0) {
return 0;
} else {
return hitCount * 100 / totalCount;
}
}
}
package com.avaje.ebean.cache;
/**
* The statistics collected per cache.
* <p>
* These can be monitored to review the effectiveness of a particular cache.
* </p>
* <p>
* Depending on the cache implementation not all the statistics may be collected.
* </p>
*/
public class ServerCacheStatistics {
protected String cacheName;
protected int maxSize;
protected int size;
protected long hitCount;
protected long missCount;
protected long insertCount;
protected long updateCount;
protected long removeCount;
protected long clearCount;
protected long evictionRunCount;
protected long evictionRunMicros;
protected long evictByIdle;
protected long evictByTTL;
protected long evictByLRU;
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(cacheName);
sb.append(" maxSize:").append(maxSize);
sb.append(" size:").append(size);
sb.append(" hitRatio:").append(getHitRatio());
sb.append(" hit:").append(hitCount);
sb.append(" miss:").append(missCount);
sb.append(" insert:").append(insertCount);
sb.append(" update:").append(updateCount);
sb.append(" remove:").append(removeCount);
sb.append(" clear:").append(clearCount);
sb.append(" evictByIdle:").append(evictByIdle);
sb.append(" evictByTTL:").append(evictByTTL);
sb.append(" evictByLRU:").append(evictByLRU);
sb.append(" evictionRunCount:").append(evictionRunCount);
sb.append(" evictionRunMicros:").append(evictionRunMicros);
return sb.toString();
}
/**
* Returns an int from 0 to 100 (percentage) for the hit ratio.
* <p>
* A hit ratio of 100 means every get request against the cache hits an entry.
* </p>
*/
public int getHitRatio() {
long totalCount = hitCount + missCount;
if (totalCount == 0) {
return 0;
} else {
return (int)(hitCount * 100 / totalCount);
}
}
/**
* Return the name of the cache.
*/
public String getCacheName() {
return cacheName;
}
/**
* Set the name of the cache.
*/
public void setCacheName(String cacheName) {
this.cacheName = cacheName;
}
/**
* Return the hit count. The number of successful gets.
*/
public long getHitCount() {
return hitCount;
}
/**
* Set the hit count.
*/
public void setHitCount(long hitCount) {
this.hitCount = hitCount;
}
/**
* Return the miss count. The number of gets that returned null.
*/
public long getMissCount() {
return missCount;
}
/**
* Set the miss count.
*/
public void setMissCount(long missCount) {
this.missCount = missCount;
}
/**
* Return the size of the cache.
*/
public int getSize() {
return size;
}
/**
* Set the size of the cache.
*/
public void setSize(int size) {
this.size = size;
}
/**
* Return the maximum size of the cache.
* <p>
* Can be used in conjunction with the size to determine if the cache use is
* being potentially limited by its maximum size.
* </p>
*/
public int getMaxSize() {
return maxSize;
}
/**
* Set the maximum size of the cache.
*/
public void setMaxSize(int maxSize) {
this.maxSize = maxSize;
}
/**
* Set the put insert count.
*/
public void setInsertCount(long insertCount) {
this.insertCount = insertCount;
}
/**
* Return the put insert count.
*/
public long getInsertCount() {
return insertCount;
}
/**
* Set the put update count.
*/
public void setUpdateCount(long updateCount) {
this.updateCount = updateCount;
}
/**
* Return the put update count.
*/
public long getUpdateCount() {
return updateCount;
}
/**
* Set the remove count.
*/
public void setRemoveCount(long removeCount) {
this.removeCount = removeCount;
}
/**
* Return the remove count.
*/
public long getRemoveCount() {
return removeCount;
}
/**
* Set the clear count.
*/
public void setClearCount(long clearCount) {
this.clearCount = clearCount;
}
/**
* Return the clear count.
*/
public long getClearCount() {
return clearCount;
}
/**
* Set the eviction run count.
*/
public void setEvictionRunCount(long evictCount) {
this.evictionRunCount = evictCount;
}
/**
* Return the eviction run count.
*/
public long getEvictionRunCount() {
return evictionRunCount;
}
/**
* Set the eviction run time in micros.
*/
public void setEvictionRunMicros(long evictionRunMicros) {
this.evictionRunMicros = evictionRunMicros;
}
/**
* Return the eviction run time in micros.
*/
public long getEvictionRunMicros() {
return evictionRunMicros;
}
/**
* Set the count of entries evicted due to idle time.
*/
public void setEvictByIdle(long evictByIdle) {
this.evictByIdle = evictByIdle;
}
/**
* Return the count of entries evicted due to idle time.
*/
public long getEvictByIdle() {
return evictByIdle;
}
/**
* Set the count of entries evicted due to time to live.
*/
public void setEvictByTTL(long evictByTTL) {
this.evictByTTL = evictByTTL;
}
/**
* Return the count of entries evicted due to time to live.
*/
public long getEvictByTTL() {
return evictByTTL;
}
/**
* Set the count of entries evicted due to time least recently used.
*/
public void setEvictByLRU(long evictByLRU) {
this.evictByLRU = evictByLRU;
}
/**
* Return the count of entries evicted due to time least recently used.
*/
public long getEvictByLRU() {
return evictByLRU;
}
}
@@ -1,215 +1,222 @@
package com.avaje.ebean.common;
import java.util.Set;
import javax.persistence.PersistenceException;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.ExpressionList;
import com.avaje.ebean.bean.BeanCollection;
import com.avaje.ebean.bean.BeanCollectionLoader;
import com.avaje.ebean.bean.BeanCollectionTouched;
import com.avaje.ebean.bean.EntityBean;
/**
* Base class for List Set and Map implementations of BeanCollection.
*
* @author rbygrave
*/
public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
private static final long serialVersionUID = 3365725236140187588L;
protected boolean readOnly;
/**
* The EbeanServer this is associated with. (used for lazy fetch).
*/
protected transient BeanCollectionLoader loader;
protected transient ExpressionList<?> filterMany;
protected int loaderIndex;
protected String ebeanServerName;
protected transient BeanCollectionTouched beanCollectionTouched;
/**
* The owning bean (used for lazy fetch).
*/
protected EntityBean ownerBean;
/**
* The name of this property in the owning bean (used for lazy fetch).
*/
protected String propertyName;
protected ModifyHolder<E> modifyHolder;
protected ModifyListenMode modifyListenMode;
protected boolean modifyAddListening;
protected boolean modifyRemoveListening;
protected boolean modifyListening;
/**
* Flag used to tell if empty collections have been cleared etc or just
* uninitialised.
*/
protected boolean touched;
/**
* Constructor not non-lazy loading collection.
*/
public AbstractBeanCollection() {
}
/**
* Used to create deferred fetch proxy.
*/
public AbstractBeanCollection(BeanCollectionLoader loader, EntityBean ownerBean, String propertyName) {
this.loader = loader;
this.ebeanServerName = loader.getName();
this.ownerBean = ownerBean;
this.propertyName = propertyName;
this.readOnly = ownerBean._ebean_getIntercept().isReadOnly();
}
public EntityBean getOwnerBean() {
return ownerBean;
}
public String getPropertyName() {
return propertyName;
}
public ExpressionList<?> getFilterMany() {
return filterMany;
}
public void setFilterMany(ExpressionList<?> filterMany) {
this.filterMany = filterMany;
}
protected void lazyLoadCollection(boolean onlyIds) {
if (loader == null) {
loader = (BeanCollectionLoader) Ebean.getServer(ebeanServerName);
}
if (loader == null) {
String msg = "Lazy loading but LazyLoadEbeanServer is null?"
+ " The LazyLoadEbeanServer needs to be set after deserialization"
+ " to support lazy loading.";
throw new PersistenceException(msg);
}
loader.loadMany(this, onlyIds);
checkEmptyLazyLoad();
}
/**
* Set touched. If setFlag is false then typically an isEmpty() call and still
* considering that to be untouched.
*/
protected void touched(boolean setFlag) {
if (setFlag) {
touched = true;
}
if (beanCollectionTouched != null) {
// only call this once
beanCollectionTouched.notifyTouched(this);
beanCollectionTouched = null;
}
}
public void setBeanCollectionTouched(BeanCollectionTouched notify) {
this.beanCollectionTouched = notify;
}
public void setLoader(int beanLoaderIndex, BeanCollectionLoader loader) {
this.loaderIndex = beanLoaderIndex;
this.loader = loader;
this.ebeanServerName = loader.getName();
}
public boolean isReadOnly() {
return readOnly;
}
public void setReadOnly(boolean readOnly) {
this.readOnly = readOnly;
}
protected void checkReadOnly() {
if (readOnly) {
String msg = "This collection is in ReadOnly mode";
throw new IllegalStateException(msg);
}
}
// ---------------------------------------------------------
// Support for modify additions deletions etc - ManyToMany
// ---------------------------------------------------------
/**
* set modifyListening to be on or off.
*/
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;
if (modifyListening) {
// lose any existing modifications
modifyHolder = null;
}
}
/**
* Return the modify listening mode this collection is using.
*/
public ModifyListenMode getModifyListenMode() {
return modifyListenMode;
}
protected ModifyHolder<E> getModifyHolder() {
if (modifyHolder == null) {
modifyHolder = new ModifyHolder<E>();
}
return modifyHolder;
}
public void modifyAddition(E bean) {
if (modifyAddListening) {
getModifyHolder().modifyAddition(bean);
}
}
public void modifyRemoval(Object bean) {
if (modifyRemoveListening) {
getModifyHolder().modifyRemoval(bean);
}
}
public void modifyReset() {
if (modifyHolder != null) {
modifyHolder.reset();
}
}
public Set<E> getModifyAdditions() {
if (modifyHolder == null) {
return null;
} else {
return modifyHolder.getModifyAdditions();
}
}
public Set<E> getModifyRemovals() {
if (modifyHolder == null) {
return null;
} else {
return modifyHolder.getModifyRemovals();
}
}
}
package com.avaje.ebean.common;
import java.util.Set;
import javax.persistence.PersistenceException;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.ExpressionList;
import com.avaje.ebean.bean.BeanCollection;
import com.avaje.ebean.bean.BeanCollectionLoader;
import com.avaje.ebean.bean.BeanCollectionTouched;
import com.avaje.ebean.bean.EntityBean;
/**
* Base class for List Set and Map implementations of BeanCollection.
*
* @author rbygrave
*/
public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
private static final long serialVersionUID = 3365725236140187588L;
protected boolean readOnly;
/**
* The EbeanServer this is associated with. (used for lazy fetch).
*/
protected transient BeanCollectionLoader loader;
protected transient ExpressionList<?> filterMany;
/**
* Flag set when registered with the batch loading context.
*/
protected boolean registeredWithLoadContext;
protected String ebeanServerName;
protected transient BeanCollectionTouched beanCollectionTouched;
/**
* The owning bean (used for lazy fetch).
*/
protected EntityBean ownerBean;
/**
* The name of this property in the owning bean (used for lazy fetch).
*/
protected String propertyName;
protected ModifyHolder<E> modifyHolder;
protected ModifyListenMode modifyListenMode;
protected boolean modifyAddListening;
protected boolean modifyRemoveListening;
protected boolean modifyListening;
/**
* Flag used to tell if empty collections have been cleared etc or just
* uninitialised.
*/
protected boolean touched;
/**
* Constructor not non-lazy loading collection.
*/
public AbstractBeanCollection() {
}
/**
* Used to create deferred fetch proxy.
*/
public AbstractBeanCollection(BeanCollectionLoader loader, EntityBean ownerBean, String propertyName) {
this.loader = loader;
this.ebeanServerName = loader.getName();
this.ownerBean = ownerBean;
this.propertyName = propertyName;
this.readOnly = ownerBean._ebean_getIntercept().isReadOnly();
}
public EntityBean getOwnerBean() {
return ownerBean;
}
public String getPropertyName() {
return propertyName;
}
public ExpressionList<?> getFilterMany() {
return filterMany;
}
public void setFilterMany(ExpressionList<?> filterMany) {
this.filterMany = filterMany;
}
protected void lazyLoadCollection(boolean onlyIds) {
if (loader == null) {
loader = (BeanCollectionLoader) Ebean.getServer(ebeanServerName);
}
if (loader == null) {
String msg = "Lazy loading but LazyLoadEbeanServer is null?"
+ " The LazyLoadEbeanServer needs to be set after deserialization"
+ " to support lazy loading.";
throw new PersistenceException(msg);
}
loader.loadMany(this, onlyIds);
checkEmptyLazyLoad();
}
/**
* Set touched. If setFlag is false then typically an isEmpty() call and still
* considering that to be untouched.
*/
protected void touched(boolean setFlag) {
if (setFlag) {
touched = true;
}
if (beanCollectionTouched != null) {
// only call this once
beanCollectionTouched.notifyTouched(this);
beanCollectionTouched = null;
}
}
public void setBeanCollectionTouched(BeanCollectionTouched notify) {
this.beanCollectionTouched = notify;
}
public boolean isRegisteredWithLoadContext() {
return registeredWithLoadContext;
}
public void setLoader(BeanCollectionLoader loader) {
this.registeredWithLoadContext = true;
this.loader = loader;
this.ebeanServerName = loader.getName();
}
public boolean isReadOnly() {
return readOnly;
}
public void setReadOnly(boolean readOnly) {
this.readOnly = readOnly;
}
protected void checkReadOnly() {
if (readOnly) {
String msg = "This collection is in ReadOnly mode";
throw new IllegalStateException(msg);
}
}
// ---------------------------------------------------------
// Support for modify additions deletions etc - ManyToMany
// ---------------------------------------------------------
/**
* set modifyListening to be on or off.
*/
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;
if (modifyListening) {
// lose any existing modifications
modifyHolder = null;
}
}
/**
* Return the modify listening mode this collection is using.
*/
public ModifyListenMode getModifyListenMode() {
return modifyListenMode;
}
protected ModifyHolder<E> getModifyHolder() {
if (modifyHolder == null) {
modifyHolder = new ModifyHolder<E>();
}
return modifyHolder;
}
public void modifyAddition(E bean) {
if (modifyAddListening) {
getModifyHolder().modifyAddition(bean);
}
}
public void modifyRemoval(Object bean) {
if (modifyRemoveListening) {
getModifyHolder().modifyRemoval(bean);
}
}
public void modifyReset() {
if (modifyHolder != null) {
modifyHolder.reset();
}
}
public Set<E> getModifyAdditions() {
if (modifyHolder == null) {
return null;
} else {
return modifyHolder.getModifyAdditions();
}
}
public Set<E> getModifyRemovals() {
if (modifyHolder == null) {
return null;
} else {
return modifyHolder.getModifyRemovals();
}
}
}
+468 -466
View File
@@ -1,466 +1,468 @@
package com.avaje.ebean.common;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import com.avaje.ebean.bean.BeanCollectionAdd;
import com.avaje.ebean.bean.BeanCollectionLoader;
import com.avaje.ebean.bean.EntityBean;
/**
* List capable of lazy loading.
*/
public final class BeanList<E> extends AbstractBeanCollection<E> implements List<E>, BeanCollectionAdd {
private static final long serialVersionUID = 1L;
/**
* The underlying List implementation.
*/
private List<E> list;
/**
* Specify the underlying List implementation.
*/
public BeanList(List<E> list) {
super();
this.list = list;
}
/**
* Uses an ArrayList as the underlying List implementation.
*/
public BeanList() {
this(new ArrayList<E>());
}
/**
* Used to create deferred fetch proxy.
*/
public BeanList(BeanCollectionLoader loader, EntityBean ownerBean, String propertyName) {
super(loader, ownerBean, propertyName);
}
@Override
public void reset(EntityBean ownerBean, String propertyName) {
this.ownerBean = ownerBean;
this.propertyName = propertyName;
this.list = null;
this.touched = false;
}
@Override
public boolean isEmptyAndUntouched() {
return !touched && (list == null || list.isEmpty());
}
@SuppressWarnings("unchecked")
public void addBean(EntityBean bean) {
list.add((E) bean);
}
@SuppressWarnings("unchecked")
public void internalAdd(Object bean) {
if (list == null) {
list = new ArrayList<E>();
}
list.add((E) bean);
}
public boolean checkEmptyLazyLoad() {
if (list == null) {
list = new ArrayList<E>();
return true;
} else {
return false;
}
}
private void initClear() {
synchronized (this) {
if (list == null) {
if (modifyListening) {
lazyLoadCollection(true);
} else {
list = new ArrayList<E>();
}
}
touched(true);
}
}
private void initAsUntouched() {
init(false);
}
private void init() {
init(true);
}
private void init(boolean setTouched) {
synchronized (this) {
if (list == null) {
lazyLoadCollection(false);
}
touched(setTouched);
}
}
/**
* Set the actual underlying list.
* <p>
* This is primarily for the deferred fetching function.
* </p>
*/
@SuppressWarnings("unchecked")
public void setActualList(List<?> list) {
this.list = (List<E>) list;
}
/**
* Return the actual underlying list.
*/
public List<E> getActualList() {
return list;
}
public Collection<E> getActualDetails() {
return list;
}
@Override
public Collection<?> getActualEntries() {
return list;
}
/**
* Return true if the underlying list is populated.
*/
public boolean isPopulated() {
return list != null;
}
/**
* Return true if this is a reference (lazy loading) bean collection. This is
* the same as !isPopulated();
*/
public boolean isReference() {
return list == null;
}
public String toString() {
StringBuffer sb = new StringBuffer(50);
sb.append("BeanList ");
if (isReadOnly()) {
sb.append("readOnly ");
}
if (list == null) {
sb.append("deferred ");
} else {
sb.append("size[").append(list.size()).append("] ");
sb.append("list").append(list).append("");
}
return sb.toString();
}
/**
* Equal if obj is a List and equal in a list sense.
* <p>
* Specifically obj does not need to be a BeanList but any list. This does not
* use the FindMany, fetchedMaxRows or finishedFetch properties in the equals
* test.
* </p>
*/
public boolean equals(Object obj) {
init();
return list.equals(obj);
}
public int hashCode() {
init();
return list.hashCode();
}
// -----------------------------------------------------//
// The additional methods are here
// -----------------------------------------------------//
// -----------------------------------------------------//
// proxy method for List
// -----------------------------------------------------//
public void add(int index, E element) {
checkReadOnly();
init();
if (modifyAddListening) {
modifyAddition(element);
}
list.add(index, element);
}
public boolean add(E o) {
checkReadOnly();
init();
if (modifyAddListening) {
if (list.add(o)) {
modifyAddition(o);
return true;
} else {
return false;
}
}
return list.add(o);
}
public boolean addAll(Collection<? extends E> c) {
checkReadOnly();
init();
if (modifyAddListening) {
// all elements in c are added (no contains checking)
getModifyHolder().modifyAdditionAll(c);
}
return list.addAll(c);
}
public boolean addAll(int index, Collection<? extends E> c) {
checkReadOnly();
init();
if (modifyAddListening) {
// all elements in c are added (no contains checking)
getModifyHolder().modifyAdditionAll(c);
}
return list.addAll(index, c);
}
public void clear() {
checkReadOnly();
// TODO: when clear() and not initialised could be more clever
// and fetch just the Id's
initClear();
if (modifyRemoveListening) {
for (int i = 0; i < list.size(); i++) {
getModifyHolder().modifyRemoval(list.get(i));
}
}
list.clear();
}
public boolean contains(Object o) {
init();
return list.contains(o);
}
public boolean containsAll(Collection<?> c) {
init();
return list.containsAll(c);
}
public E get(int index) {
init();
return list.get(index);
}
public int indexOf(Object o) {
init();
return list.indexOf(o);
}
public boolean isEmpty() {
initAsUntouched();
return list.isEmpty();
}
public Iterator<E> iterator() {
init();
if (isReadOnly()) {
return new ReadOnlyListIterator<E>(list.listIterator());
}
if (modifyListening) {
Iterator<E> it = list.iterator();
return new ModifyIterator<E>(this, it);
}
return list.iterator();
}
public int lastIndexOf(Object o) {
init();
return list.lastIndexOf(o);
}
public ListIterator<E> listIterator() {
init();
if (isReadOnly()) {
return new ReadOnlyListIterator<E>(list.listIterator());
}
if (modifyListening) {
ListIterator<E> it = list.listIterator();
return new ModifyListIterator<E>(this, it);
}
return list.listIterator();
}
public ListIterator<E> listIterator(int index) {
init();
if (isReadOnly()) {
return new ReadOnlyListIterator<E>(list.listIterator(index));
}
if (modifyListening) {
ListIterator<E> it = list.listIterator(index);
return new ModifyListIterator<E>(this, it);
}
return list.listIterator(index);
}
public E remove(int index) {
checkReadOnly();
init();
if (modifyRemoveListening) {
E o = list.remove(index);
modifyRemoval(o);
return o;
}
return list.remove(index);
}
public boolean remove(Object o) {
checkReadOnly();
init();
if (modifyRemoveListening) {
boolean isRemove = list.remove(o);
if (isRemove) {
modifyRemoval(o);
}
return isRemove;
}
return list.remove(o);
}
public boolean removeAll(Collection<?> c) {
checkReadOnly();
init();
if (modifyRemoveListening) {
boolean changed = false;
Iterator<?> it = c.iterator();
while (it.hasNext()) {
Object o = (Object) it.next();
if (list.remove(o)) {
modifyRemoval(o);
changed = true;
}
}
return changed;
}
return list.removeAll(c);
}
public boolean retainAll(Collection<?> c) {
checkReadOnly();
init();
if (modifyRemoveListening) {
boolean changed = false;
Iterator<E> it = list.iterator();
while (it.hasNext()) {
Object o = (Object) it.next();
if (!c.contains(o)) {
it.remove();
modifyRemoval(o);
changed = true;
}
}
return changed;
}
return list.retainAll(c);
}
public E set(int index, E element) {
checkReadOnly();
init();
if (modifyListening) {
E o = list.set(index, element);
modifyAddition(element);
modifyRemoval(o);
return o;
}
return list.set(index, element);
}
public int size() {
init();
return list.size();
}
public List<E> subList(int fromIndex, int toIndex) {
init();
if (isReadOnly()) {
return Collections.unmodifiableList(list.subList(fromIndex, toIndex));
}
if (modifyListening) {
return new ModifyList<E>(this, list.subList(fromIndex, toIndex));
}
return list.subList(fromIndex, toIndex);
}
public Object[] toArray() {
init();
return list.toArray();
}
public <T> T[] toArray(T[] a) {
init();
return list.toArray(a);
}
private static class ReadOnlyListIterator<E> implements ListIterator<E>, Serializable {
private static final long serialVersionUID = 3097271091406323699L;
private final ListIterator<E> i;
ReadOnlyListIterator(ListIterator<E> i) {
this.i = i;
}
public void add(E o) {
throw new IllegalStateException("This collection is in ReadOnly mode");
}
public void remove() {
throw new IllegalStateException("This collection is in ReadOnly mode");
}
public void set(E o) {
throw new IllegalStateException("This collection is in ReadOnly mode");
}
public boolean hasNext() {
return i.hasNext();
}
public boolean hasPrevious() {
return i.hasPrevious();
}
public E next() {
return i.next();
}
public int nextIndex() {
return i.nextIndex();
}
public E previous() {
return i.previous();
}
public int previousIndex() {
return i.previousIndex();
}
}
}
package com.avaje.ebean.common;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import com.avaje.ebean.bean.BeanCollectionAdd;
import com.avaje.ebean.bean.BeanCollectionLoader;
import com.avaje.ebean.bean.EntityBean;
/**
* List capable of lazy loading.
*/
public final class BeanList<E> extends AbstractBeanCollection<E> implements List<E>, BeanCollectionAdd {
private static final long serialVersionUID = 1L;
/**
* The underlying List implementation.
*/
private List<E> list;
/**
* Specify the underlying List implementation.
*/
public BeanList(List<E> list) {
super();
this.list = list;
}
/**
* Uses an ArrayList as the underlying List implementation.
*/
public BeanList() {
this(new ArrayList<E>());
}
/**
* Used to create deferred fetch proxy.
*/
public BeanList(BeanCollectionLoader loader, EntityBean ownerBean, String propertyName) {
super(loader, ownerBean, propertyName);
}
@Override
public void reset(EntityBean ownerBean, String propertyName) {
this.ownerBean = ownerBean;
this.propertyName = propertyName;
this.list = null;
this.touched = false;
}
@Override
public boolean isEmptyAndUntouched() {
return !touched && (list == null || list.isEmpty());
}
@SuppressWarnings("unchecked")
public void addBean(EntityBean bean) {
list.add((E) bean);
}
@SuppressWarnings("unchecked")
public void internalAdd(Object bean) {
if (list == null) {
list = new ArrayList<E>();
}
if (bean != null) {
list.add((E) bean);
}
}
public boolean checkEmptyLazyLoad() {
if (list == null) {
list = new ArrayList<E>();
return true;
} else {
return false;
}
}
private void initClear() {
synchronized (this) {
if (list == null) {
if (modifyListening) {
lazyLoadCollection(true);
} else {
list = new ArrayList<E>();
}
}
touched(true);
}
}
private void initAsUntouched() {
init(false);
}
private void init() {
init(true);
}
private void init(boolean setTouched) {
synchronized (this) {
if (list == null) {
lazyLoadCollection(false);
}
touched(setTouched);
}
}
/**
* Set the actual underlying list.
* <p>
* This is primarily for the deferred fetching function.
* </p>
*/
@SuppressWarnings("unchecked")
public void setActualList(List<?> list) {
this.list = (List<E>) list;
}
/**
* Return the actual underlying list.
*/
public List<E> getActualList() {
return list;
}
public Collection<E> getActualDetails() {
return list;
}
@Override
public Collection<?> getActualEntries() {
return list;
}
/**
* Return true if the underlying list is populated.
*/
public boolean isPopulated() {
return list != null;
}
/**
* Return true if this is a reference (lazy loading) bean collection. This is
* the same as !isPopulated();
*/
public boolean isReference() {
return list == null;
}
public String toString() {
StringBuilder sb = new StringBuilder(50);
sb.append("BeanList ");
if (isReadOnly()) {
sb.append("readOnly ");
}
if (list == null) {
sb.append("deferred ");
} else {
sb.append("size[").append(list.size()).append("] ");
sb.append("list").append(list).append("");
}
return sb.toString();
}
/**
* Equal if obj is a List and equal in a list sense.
* <p>
* Specifically obj does not need to be a BeanList but any list. This does not
* use the FindMany, fetchedMaxRows or finishedFetch properties in the equals
* test.
* </p>
*/
public boolean equals(Object obj) {
init();
return list.equals(obj);
}
public int hashCode() {
init();
return list.hashCode();
}
// -----------------------------------------------------//
// The additional methods are here
// -----------------------------------------------------//
// -----------------------------------------------------//
// proxy method for List
// -----------------------------------------------------//
public void add(int index, E element) {
checkReadOnly();
init();
if (modifyAddListening) {
modifyAddition(element);
}
list.add(index, element);
}
public boolean add(E o) {
checkReadOnly();
init();
if (modifyAddListening) {
if (list.add(o)) {
modifyAddition(o);
return true;
} else {
return false;
}
}
return list.add(o);
}
public boolean addAll(Collection<? extends E> c) {
checkReadOnly();
init();
if (modifyAddListening) {
// all elements in c are added (no contains checking)
getModifyHolder().modifyAdditionAll(c);
}
return list.addAll(c);
}
public boolean addAll(int index, Collection<? extends E> c) {
checkReadOnly();
init();
if (modifyAddListening) {
// all elements in c are added (no contains checking)
getModifyHolder().modifyAdditionAll(c);
}
return list.addAll(index, c);
}
public void clear() {
checkReadOnly();
// TODO: when clear() and not initialised could be more clever
// and fetch just the Id's
initClear();
if (modifyRemoveListening) {
for (int i = 0; i < list.size(); i++) {
getModifyHolder().modifyRemoval(list.get(i));
}
}
list.clear();
}
public boolean contains(Object o) {
init();
return list.contains(o);
}
public boolean containsAll(Collection<?> c) {
init();
return list.containsAll(c);
}
public E get(int index) {
init();
return list.get(index);
}
public int indexOf(Object o) {
init();
return list.indexOf(o);
}
public boolean isEmpty() {
initAsUntouched();
return list.isEmpty();
}
public Iterator<E> iterator() {
init();
if (isReadOnly()) {
return new ReadOnlyListIterator<E>(list.listIterator());
}
if (modifyListening) {
Iterator<E> it = list.iterator();
return new ModifyIterator<E>(this, it);
}
return list.iterator();
}
public int lastIndexOf(Object o) {
init();
return list.lastIndexOf(o);
}
public ListIterator<E> listIterator() {
init();
if (isReadOnly()) {
return new ReadOnlyListIterator<E>(list.listIterator());
}
if (modifyListening) {
ListIterator<E> it = list.listIterator();
return new ModifyListIterator<E>(this, it);
}
return list.listIterator();
}
public ListIterator<E> listIterator(int index) {
init();
if (isReadOnly()) {
return new ReadOnlyListIterator<E>(list.listIterator(index));
}
if (modifyListening) {
ListIterator<E> it = list.listIterator(index);
return new ModifyListIterator<E>(this, it);
}
return list.listIterator(index);
}
public E remove(int index) {
checkReadOnly();
init();
if (modifyRemoveListening) {
E o = list.remove(index);
modifyRemoval(o);
return o;
}
return list.remove(index);
}
public boolean remove(Object o) {
checkReadOnly();
init();
if (modifyRemoveListening) {
boolean isRemove = list.remove(o);
if (isRemove) {
modifyRemoval(o);
}
return isRemove;
}
return list.remove(o);
}
public boolean removeAll(Collection<?> c) {
checkReadOnly();
init();
if (modifyRemoveListening) {
boolean changed = false;
Iterator<?> it = c.iterator();
while (it.hasNext()) {
Object o = it.next();
if (list.remove(o)) {
modifyRemoval(o);
changed = true;
}
}
return changed;
}
return list.removeAll(c);
}
public boolean retainAll(Collection<?> c) {
checkReadOnly();
init();
if (modifyRemoveListening) {
boolean changed = false;
Iterator<E> it = list.iterator();
while (it.hasNext()) {
Object o = it.next();
if (!c.contains(o)) {
it.remove();
modifyRemoval(o);
changed = true;
}
}
return changed;
}
return list.retainAll(c);
}
public E set(int index, E element) {
checkReadOnly();
init();
if (modifyListening) {
E o = list.set(index, element);
modifyAddition(element);
modifyRemoval(o);
return o;
}
return list.set(index, element);
}
public int size() {
init();
return list.size();
}
public List<E> subList(int fromIndex, int toIndex) {
init();
if (isReadOnly()) {
return Collections.unmodifiableList(list.subList(fromIndex, toIndex));
}
if (modifyListening) {
return new ModifyList<E>(this, list.subList(fromIndex, toIndex));
}
return list.subList(fromIndex, toIndex);
}
public Object[] toArray() {
init();
return list.toArray();
}
public <T> T[] toArray(T[] a) {
init();
return list.toArray(a);
}
private static class ReadOnlyListIterator<E> implements ListIterator<E>, Serializable {
private static final long serialVersionUID = 3097271091406323699L;
private final ListIterator<E> i;
ReadOnlyListIterator(ListIterator<E> i) {
this.i = i;
}
public void add(E o) {
throw new IllegalStateException("This collection is in ReadOnly mode");
}
public void remove() {
throw new IllegalStateException("This collection is in ReadOnly mode");
}
public void set(E o) {
throw new IllegalStateException("This collection is in ReadOnly mode");
}
public boolean hasNext() {
return i.hasNext();
}
public boolean hasPrevious() {
return i.hasPrevious();
}
public E next() {
return i.next();
}
public int nextIndex() {
return i.nextIndex();
}
public E previous() {
return i.previous();
}
public int previousIndex() {
return i.previousIndex();
}
}
}
+303 -295
View File
@@ -1,295 +1,303 @@
package com.avaje.ebean.common;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import com.avaje.ebean.bean.BeanCollectionLoader;
import com.avaje.ebean.bean.EntityBean;
/**
* Map capable of lazy loading.
*/
public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Map<K, E> {
private static final long serialVersionUID = 1L;
/**
* The underlying map implementation.
*/
private Map<K, E> map;
/**
* Create with a given Map.
*/
public BeanMap(Map<K, E> map) {
this.map = map;
}
/**
* Create using a underlying LinkedHashMap.
*/
public BeanMap() {
this(new LinkedHashMap<K, E>());
}
public BeanMap(BeanCollectionLoader ebeanServer, EntityBean ownerBean, String propertyName) {
super(ebeanServer, ownerBean, propertyName);
}
@Override
public void reset(EntityBean ownerBean, String propertyName) {
this.ownerBean = ownerBean;
this.propertyName = propertyName;
this.map = null;
this.touched = false;
}
public boolean isEmptyAndUntouched() {
return !touched && (map == null || map.isEmpty());
}
@SuppressWarnings("unchecked")
public void internalPut(Object key, Object bean) {
if (map == null) {
map = new LinkedHashMap<K, E>();
}
map.put((K)key, (E)bean);
}
public void internalAdd(Object bean) {
throw new RuntimeException("Not allowed for map");
}
/**
* Return true if the underlying map has been populated. Returns false if it
* has a deferred fetch pending.
*/
public boolean isPopulated() {
return map != null;
}
/**
* Return true if this is a reference (lazy loading) bean collection. This is
* the same as !isPopulated();
*/
public boolean isReference() {
return map == null;
}
public boolean checkEmptyLazyLoad() {
if (map == null) {
map = new LinkedHashMap<K, E>();
return true;
} else {
return false;
}
}
private void initClear() {
synchronized (this) {
if (map == null) {
if (modifyListening) {
lazyLoadCollection(true);
} else {
map = new LinkedHashMap<K, E>();
}
}
touched(true);
}
}
private void initAsUntouched() {
init(false);
}
private void init() {
init(true);
}
private void init(boolean setTouched) {
synchronized (this) {
if (map == null) {
lazyLoadCollection(false);
}
touched(setTouched);
}
}
/**
* Set the actual underlying map. Used for performing lazy fetch.
*/
@SuppressWarnings("unchecked")
public void setActualMap(Map<?, ?> map) {
this.map = (Map<K, E>) map;
}
/**
* Return the actual underlying map.
*/
public Map<K, E> getActualMap() {
return map;
}
/**
* Returns the collection of beans (map values).
*/
public Collection<E> getActualDetails() {
return map.values();
}
/**
* Returns the map entrySet.
* <p>
* This is because the key values may need to be set against the details (so
* they don't need to be set twice).
* </p>
*/
public Collection<?> getActualEntries() {
return map.entrySet();
}
public String toString() {
StringBuilder sb = new StringBuilder(50);
sb.append("BeanMap ");
if (isReadOnly()) {
sb.append("readOnly ");
}
if (map == null) {
sb.append("deferred ");
} else {
sb.append("size[").append(map.size()).append("]");
sb.append(" map").append(map);
}
return sb.toString();
}
/**
* Equal if obj is a Map and equal in a Map sense.
*/
public boolean equals(Object obj) {
init();
return map.equals(obj);
}
public int hashCode() {
init();
return map.hashCode();
}
public void clear() {
checkReadOnly();
initClear();
if (modifyRemoveListening) {
for (K key : map.keySet()) {
E o = map.remove(key);
modifyRemoval(o);
}
}
map.clear();
}
public boolean containsKey(Object key) {
init();
return map.containsKey(key);
}
public boolean containsValue(Object value) {
init();
return map.containsValue(value);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public Set<Entry<K, E>> entrySet() {
init();
if (isReadOnly()) {
return Collections.unmodifiableSet(map.entrySet());
}
if (modifyListening) {
Set<Entry<K, E>> s = map.entrySet();
return new ModifySet(this, s);
}
return map.entrySet();
}
public E get(Object key) {
init();
return map.get(key);
}
public boolean isEmpty() {
initAsUntouched();
return map.isEmpty();
}
public Set<K> keySet() {
init();
if (isReadOnly()) {
return Collections.unmodifiableSet(map.keySet());
}
// we don't really care about modifications to the ketSet?
return map.keySet();
}
public E put(K key, E value) {
checkReadOnly();
init();
if (modifyListening) {
Object o = map.put(key, value);
modifyAddition(value);
modifyRemoval(o);
}
return map.put(key, value);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public void putAll(Map<? extends K, ? extends E> t) {
checkReadOnly();
init();
if (modifyListening) {
Iterator it = t.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
Object o = map.put((K) entry.getKey(), (E) entry.getValue());
modifyAddition((E) entry.getValue());
modifyRemoval(o);
}
}
map.putAll(t);
}
public E remove(Object key) {
checkReadOnly();
init();
if (modifyRemoveListening) {
E o = map.remove(key);
modifyRemoval(o);
return o;
}
return map.remove(key);
}
public int size() {
init();
return map.size();
}
public Collection<E> values() {
init();
if (isReadOnly()) {
return Collections.unmodifiableCollection(map.values());
}
if (modifyListening) {
Collection<E> c = map.values();
return new ModifyCollection<E>(this, c);
}
return map.values();
}
}
package com.avaje.ebean.common;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import com.avaje.ebean.bean.BeanCollectionLoader;
import com.avaje.ebean.bean.EntityBean;
/**
* Map capable of lazy loading.
*/
public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Map<K, E> {
private static final long serialVersionUID = 1L;
/**
* The underlying map implementation.
*/
private Map<K, E> map;
/**
* Create with a given Map.
*/
public BeanMap(Map<K, E> map) {
this.map = map;
}
/**
* Create using a underlying LinkedHashMap.
*/
public BeanMap() {
this(new LinkedHashMap<K, E>());
}
public BeanMap(BeanCollectionLoader ebeanServer, EntityBean ownerBean, String propertyName) {
super(ebeanServer, ownerBean, propertyName);
}
@Override
public void reset(EntityBean ownerBean, String propertyName) {
this.ownerBean = ownerBean;
this.propertyName = propertyName;
this.map = null;
this.touched = false;
}
public boolean isEmptyAndUntouched() {
return !touched && (map == null || map.isEmpty());
}
public void internalPutNull() {
if (map == null) {
map = new LinkedHashMap<K, E>();
}
}
@SuppressWarnings("unchecked")
public void internalPut(Object key, Object bean) {
if (map == null) {
map = new LinkedHashMap<K, E>();
}
if (key != null) {
map.put((K) key, (E) bean);
}
}
public void internalAdd(Object bean) {
throw new RuntimeException("Not allowed for map");
}
/**
* Return true if the underlying map has been populated. Returns false if it
* has a deferred fetch pending.
*/
public boolean isPopulated() {
return map != null;
}
/**
* Return true if this is a reference (lazy loading) bean collection. This is
* the same as !isPopulated();
*/
public boolean isReference() {
return map == null;
}
public boolean checkEmptyLazyLoad() {
if (map == null) {
map = new LinkedHashMap<K, E>();
return true;
} else {
return false;
}
}
private void initClear() {
synchronized (this) {
if (map == null) {
if (modifyListening) {
lazyLoadCollection(true);
} else {
map = new LinkedHashMap<K, E>();
}
}
touched(true);
}
}
private void initAsUntouched() {
init(false);
}
private void init() {
init(true);
}
private void init(boolean setTouched) {
synchronized (this) {
if (map == null) {
lazyLoadCollection(false);
}
touched(setTouched);
}
}
/**
* Set the actual underlying map. Used for performing lazy fetch.
*/
@SuppressWarnings("unchecked")
public void setActualMap(Map<?, ?> map) {
this.map = (Map<K, E>) map;
}
/**
* Return the actual underlying map.
*/
public Map<K, E> getActualMap() {
return map;
}
/**
* Returns the collection of beans (map values).
*/
public Collection<E> getActualDetails() {
return map.values();
}
/**
* Returns the map entrySet.
* <p>
* This is because the key values may need to be set against the details (so
* they don't need to be set twice).
* </p>
*/
public Collection<?> getActualEntries() {
return map.entrySet();
}
public String toString() {
StringBuilder sb = new StringBuilder(50);
sb.append("BeanMap ");
if (isReadOnly()) {
sb.append("readOnly ");
}
if (map == null) {
sb.append("deferred ");
} else {
sb.append("size[").append(map.size()).append("]");
sb.append(" map").append(map);
}
return sb.toString();
}
/**
* Equal if obj is a Map and equal in a Map sense.
*/
public boolean equals(Object obj) {
init();
return map.equals(obj);
}
public int hashCode() {
init();
return map.hashCode();
}
public void clear() {
checkReadOnly();
initClear();
if (modifyRemoveListening) {
for (K key : map.keySet()) {
E o = map.remove(key);
modifyRemoval(o);
}
}
map.clear();
}
public boolean containsKey(Object key) {
init();
return map.containsKey(key);
}
public boolean containsValue(Object value) {
init();
return map.containsValue(value);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public Set<Entry<K, E>> entrySet() {
init();
if (isReadOnly()) {
return Collections.unmodifiableSet(map.entrySet());
}
if (modifyListening) {
Set<Entry<K, E>> s = map.entrySet();
return new ModifySet(this, s);
}
return map.entrySet();
}
public E get(Object key) {
init();
return map.get(key);
}
public boolean isEmpty() {
initAsUntouched();
return map.isEmpty();
}
public Set<K> keySet() {
init();
if (isReadOnly()) {
return Collections.unmodifiableSet(map.keySet());
}
// we don't really care about modifications to the ketSet?
return map.keySet();
}
public E put(K key, E value) {
checkReadOnly();
init();
if (modifyListening) {
Object o = map.put(key, value);
modifyAddition(value);
modifyRemoval(o);
}
return map.put(key, value);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public void putAll(Map<? extends K, ? extends E> t) {
checkReadOnly();
init();
if (modifyListening) {
Iterator it = t.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
Object o = map.put((K) entry.getKey(), (E) entry.getValue());
modifyAddition((E) entry.getValue());
modifyRemoval(o);
}
}
map.putAll(t);
}
public E remove(Object key) {
checkReadOnly();
init();
if (modifyRemoveListening) {
E o = map.remove(key);
modifyRemoval(o);
return o;
}
return map.remove(key);
}
public int size() {
init();
return map.size();
}
public Collection<E> values() {
init();
if (isReadOnly()) {
return Collections.unmodifiableCollection(map.values());
}
if (modifyListening) {
Collection<E> c = map.values();
return new ModifyCollection<E>(this, c);
}
return map.values();
}
}
+340 -345
View File
@@ -1,345 +1,340 @@
package com.avaje.ebean.common;
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import com.avaje.ebean.bean.BeanCollectionAdd;
import com.avaje.ebean.bean.BeanCollectionLoader;
import com.avaje.ebean.bean.EntityBean;
/**
* Set capable of lazy loading.
*/
public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E>, BeanCollectionAdd {
private static final long serialVersionUID = 1L;
/**
* The underlying Set implementation.
*/
private Set<E> set;
/**
* Create with a specific Set implementation.
*/
public BeanSet(Set<E> set) {
this.set = set;
}
/**
* Create using an underlying LinkedHashSet.
*/
public BeanSet() {
this(new LinkedHashSet<E>());
}
public BeanSet(BeanCollectionLoader loader, EntityBean ownerBean, String propertyName) {
super(loader, ownerBean, propertyName);
}
@Override
public void reset(EntityBean ownerBean, String propertyName) {
this.ownerBean = ownerBean;
this.propertyName = propertyName;
this.set = null;
this.touched = false;
}
public boolean isEmptyAndUntouched() {
return !touched && (set == null || set.isEmpty());
}
@SuppressWarnings("unchecked")
public void addBean(EntityBean bean) {
set.add((E) bean);
}
@SuppressWarnings("unchecked")
public void internalAdd(Object bean) {
if (set == null) {
set = new LinkedHashSet<E>();
}
set.add((E) bean);
}
/**
* Returns true if the underlying set has its data.
*/
public boolean isPopulated() {
return set != null;
}
/**
* Return true if this is a reference (lazy loading) bean collection. This is
* the same as !isPopulated();
*/
public boolean isReference() {
return set == null;
}
public boolean checkEmptyLazyLoad() {
if (set == null) {
set = new LinkedHashSet<E>();
return true;
} else {
return false;
}
}
private void initClear() {
synchronized (this) {
if (set == null) {
if (modifyListening) {
lazyLoadCollection(true);
} else {
set = new LinkedHashSet<E>();
}
}
touched(true);
}
}
private void initAsUntouched() {
init(false);
}
private void init() {
init(true);
}
private void init(boolean setTouched) {
synchronized (this) {
if (set == null) {
lazyLoadCollection(true);
}
touched(setTouched);
}
}
/**
* Set the underlying set (used for lazy fetch).
*/
@SuppressWarnings("unchecked")
public void setActualSet(Set<?> set) {
this.set = (Set<E>) set;
}
/**
* Return the actual underlying set.
*/
public Set<E> getActualSet() {
return set;
}
public Collection<E> getActualDetails() {
return set;
}
@Override
public Collection<?> getActualEntries() {
return set;
}
/**
* Returns the underlying set.
*/
public Object getActualCollection() {
return set;
}
public String toString() {
StringBuffer sb = new StringBuffer(50);
sb.append("BeanSet ");
if (isReadOnly()) {
sb.append("readOnly ");
}
if (set == null) {
sb.append("deferred ");
} else {
sb.append("size[").append(set.size()).append("]");
sb.append(" set").append(set);
}
return sb.toString();
}
/**
* Equal if obj is a Set and equal in a Set sense.
*/
public boolean equals(Object obj) {
init();
return set.equals(obj);
}
public int hashCode() {
init();
return set.hashCode();
}
// -----------------------------------------------------//
// proxy method for map
// -----------------------------------------------------//
public boolean add(E o) {
checkReadOnly();
init();
if (modifyAddListening) {
if (set.add(o)) {
modifyAddition(o);
return true;
} else {
return false;
}
}
return set.add(o);
}
public boolean addAll(Collection<? extends E> c) {
checkReadOnly();
init();
if (modifyAddListening) {
boolean changed = false;
Iterator<? extends E> it = c.iterator();
while (it.hasNext()) {
E o = it.next();
if (set.add(o)) {
modifyAddition(o);
changed = true;
}
}
return changed;
}
return set.addAll(c);
}
public void clear() {
checkReadOnly();
initClear();
if (modifyRemoveListening) {
Iterator<E> it = set.iterator();
while (it.hasNext()) {
E e = it.next();
modifyRemoval(e);
}
}
set.clear();
}
public boolean contains(Object o) {
init();
return set.contains(o);
}
public boolean containsAll(Collection<?> c) {
init();
return set.containsAll(c);
}
public boolean isEmpty() {
initAsUntouched();
return set.isEmpty();
}
public Iterator<E> iterator() {
init();
if (isReadOnly()) {
return new ReadOnlyIterator<E>(set.iterator());
}
if (modifyListening) {
return new ModifyIterator<E>(this, set.iterator());
}
return set.iterator();
}
public boolean remove(Object o) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (set.remove(o)) {
modifyRemoval(o);
return true;
}
return false;
}
return set.remove(o);
}
public boolean removeAll(Collection<?> c) {
checkReadOnly();
init();
if (modifyRemoveListening) {
boolean changed = false;
Iterator<?> it = c.iterator();
while (it.hasNext()) {
Object o = (Object) it.next();
if (set.remove(o)) {
modifyRemoval(o);
changed = true;
}
}
return changed;
}
return set.removeAll(c);
}
public boolean retainAll(Collection<?> c) {
checkReadOnly();
init();
if (modifyRemoveListening) {
boolean changed = false;
Iterator<?> it = set.iterator();
while (it.hasNext()) {
Object o = it.next();
if (!c.contains(o)) {
it.remove();
modifyRemoval(o);
changed = true;
}
}
return changed;
}
return set.retainAll(c);
}
public int size() {
init();
return set.size();
}
public Object[] toArray() {
init();
return set.toArray();
}
public <T> T[] toArray(T[] a) {
init();
return set.toArray(a);
}
private static class ReadOnlyIterator<E> implements Iterator<E>, Serializable {
private static final long serialVersionUID = 2577697326745352605L;
private final Iterator<E> it;
ReadOnlyIterator(Iterator<E> it) {
this.it = it;
}
public boolean hasNext() {
return it.hasNext();
}
public E next() {
return it.next();
}
public void remove() {
throw new IllegalStateException("This collection is in ReadOnly mode");
}
}
}
package com.avaje.ebean.common;
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import com.avaje.ebean.bean.BeanCollectionAdd;
import com.avaje.ebean.bean.BeanCollectionLoader;
import com.avaje.ebean.bean.EntityBean;
/**
* Set capable of lazy loading.
*/
public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E>, BeanCollectionAdd {
private static final long serialVersionUID = 1L;
/**
* The underlying Set implementation.
*/
private Set<E> set;
/**
* Create with a specific Set implementation.
*/
public BeanSet(Set<E> set) {
this.set = set;
}
/**
* Create using an underlying LinkedHashSet.
*/
public BeanSet() {
this(new LinkedHashSet<E>());
}
public BeanSet(BeanCollectionLoader loader, EntityBean ownerBean, String propertyName) {
super(loader, ownerBean, propertyName);
}
@Override
public void reset(EntityBean ownerBean, String propertyName) {
this.ownerBean = ownerBean;
this.propertyName = propertyName;
this.set = null;
this.touched = false;
}
public boolean isEmptyAndUntouched() {
return !touched && (set == null || set.isEmpty());
}
@SuppressWarnings("unchecked")
public void addBean(EntityBean bean) {
set.add((E) bean);
}
@SuppressWarnings("unchecked")
public void internalAdd(Object bean) {
if (set == null) {
set = new LinkedHashSet<E>();
}
if (bean != null) {
set.add((E) bean);
}
}
/**
* Returns true if the underlying set has its data.
*/
public boolean isPopulated() {
return set != null;
}
/**
* Return true if this is a reference (lazy loading) bean collection. This is
* the same as !isPopulated();
*/
public boolean isReference() {
return set == null;
}
public boolean checkEmptyLazyLoad() {
if (set == null) {
set = new LinkedHashSet<E>();
return true;
} else {
return false;
}
}
private void initClear() {
synchronized (this) {
if (set == null) {
if (modifyListening) {
lazyLoadCollection(true);
} else {
set = new LinkedHashSet<E>();
}
}
touched(true);
}
}
private void initAsUntouched() {
init(false);
}
private void init() {
init(true);
}
private void init(boolean setTouched) {
synchronized (this) {
if (set == null) {
lazyLoadCollection(true);
}
touched(setTouched);
}
}
/**
* Set the underlying set (used for lazy fetch).
*/
@SuppressWarnings("unchecked")
public void setActualSet(Set<?> set) {
this.set = (Set<E>) set;
}
/**
* Return the actual underlying set.
*/
public Set<E> getActualSet() {
return set;
}
public Collection<E> getActualDetails() {
return set;
}
@Override
public Collection<?> getActualEntries() {
return set;
}
public String toString() {
StringBuilder sb = new StringBuilder(50);
sb.append("BeanSet ");
if (isReadOnly()) {
sb.append("readOnly ");
}
if (set == null) {
sb.append("deferred ");
} else {
sb.append("size[").append(set.size()).append("]");
sb.append(" set").append(set);
}
return sb.toString();
}
/**
* Equal if obj is a Set and equal in a Set sense.
*/
public boolean equals(Object obj) {
init();
return set.equals(obj);
}
public int hashCode() {
init();
return set.hashCode();
}
// -----------------------------------------------------//
// proxy method for map
// -----------------------------------------------------//
public boolean add(E o) {
checkReadOnly();
init();
if (modifyAddListening) {
if (set.add(o)) {
modifyAddition(o);
return true;
} else {
return false;
}
}
return set.add(o);
}
public boolean addAll(Collection<? extends E> c) {
checkReadOnly();
init();
if (modifyAddListening) {
boolean changed = false;
Iterator<? extends E> it = c.iterator();
while (it.hasNext()) {
E o = it.next();
if (set.add(o)) {
modifyAddition(o);
changed = true;
}
}
return changed;
}
return set.addAll(c);
}
public void clear() {
checkReadOnly();
initClear();
if (modifyRemoveListening) {
Iterator<E> it = set.iterator();
while (it.hasNext()) {
E e = it.next();
modifyRemoval(e);
}
}
set.clear();
}
public boolean contains(Object o) {
init();
return set.contains(o);
}
public boolean containsAll(Collection<?> c) {
init();
return set.containsAll(c);
}
public boolean isEmpty() {
initAsUntouched();
return set.isEmpty();
}
public Iterator<E> iterator() {
init();
if (isReadOnly()) {
return new ReadOnlyIterator<E>(set.iterator());
}
if (modifyListening) {
return new ModifyIterator<E>(this, set.iterator());
}
return set.iterator();
}
public boolean remove(Object o) {
checkReadOnly();
init();
if (modifyRemoveListening) {
if (set.remove(o)) {
modifyRemoval(o);
return true;
}
return false;
}
return set.remove(o);
}
public boolean removeAll(Collection<?> c) {
checkReadOnly();
init();
if (modifyRemoveListening) {
boolean changed = false;
Iterator<?> it = c.iterator();
while (it.hasNext()) {
Object o = it.next();
if (set.remove(o)) {
modifyRemoval(o);
changed = true;
}
}
return changed;
}
return set.removeAll(c);
}
public boolean retainAll(Collection<?> c) {
checkReadOnly();
init();
if (modifyRemoveListening) {
boolean changed = false;
Iterator<?> it = set.iterator();
while (it.hasNext()) {
Object o = it.next();
if (!c.contains(o)) {
it.remove();
modifyRemoval(o);
changed = true;
}
}
return changed;
}
return set.retainAll(c);
}
public int size() {
init();
return set.size();
}
public Object[] toArray() {
init();
return set.toArray();
}
public <T> T[] toArray(T[] a) {
init();
return set.toArray(a);
}
private static class ReadOnlyIterator<E> implements Iterator<E>, Serializable {
private static final long serialVersionUID = 2577697326745352605L;
private final Iterator<E> it;
ReadOnlyIterator(Iterator<E> it) {
this.it = it;
}
public boolean hasNext() {
return it.hasNext();
}
public E next() {
return it.next();
}
public void remove() {
throw new IllegalStateException("This collection is in ReadOnly mode");
}
}
}
@@ -1,38 +0,0 @@
package com.avaje.ebean.common;
import com.avaje.ebean.EbeanServer;
import com.avaje.ebean.config.ServerConfig;
/**
* Creates the EbeanServer implementations. This is used by the Ebean singleton
* to determine the implementation for each server name.
* <p>
* Note that on a remote client it is expected that this factory will return
* EbeanServers that behave as a proxy using http or tcp sockets etc to talk to
* the EbeanServer on the application server.
* </p>
*/
public interface BootupEbeanManager {
/**
* Create the EbeanServer for a given configuration.
*
* @param configuration
* The configuration information for this server.
*/
public EbeanServer createServer(ServerConfig configuration);
/**
* Create an EbeanServer just using the name.
* <p>
* In this case the dataSource parameters etc will be defined on the global
* avaje.properties file.
* </p>
*/
public EbeanServer createServer(String name);
/**
* Shutdown any Ebean wide resources such as clustering.
*/
public void shutdown();
}
@@ -1,122 +1,122 @@
package com.avaje.ebean.common;
import java.util.Collection;
import java.util.Iterator;
import com.avaje.ebean.bean.BeanCollection;
/**
* Wraps a collection for the purposes of notifying removals and additions to
* the BeanCollection owner.
* <p>
* This is required for persisting ManyToMany objects. Additions and removals
* become inserts and deletes to the intersection table.
* </p>
*/
class ModifyCollection<E> implements Collection<E> {
protected final BeanCollection<E> owner;
protected final Collection<E> c;
/**
* Create with an Owner and the underlying collection this wraps.
* <p>
* The owner is notified of the additions and removals.
* </p>
*/
public ModifyCollection(BeanCollection<E> owner, Collection<E> c) {
this.owner = owner;
this.c = c;
}
public boolean add(E o) {
if (c.add(o)) {
owner.modifyAddition(o);
return true;
}
return false;
}
public boolean addAll(Collection<? extends E> collection) {
boolean changed = false;
Iterator<? extends E> it = collection.iterator();
while (it.hasNext()) {
E o = it.next();
if (c.add(o)) {
owner.modifyAddition(o);
changed = true;
}
}
return changed;
}
public void clear() {
c.clear();
}
public boolean contains(Object o) {
return c.contains(o);
}
public boolean containsAll(Collection<?> collection) {
return c.containsAll(collection);
}
public boolean isEmpty() {
return c.isEmpty();
}
public Iterator<E> iterator() {
Iterator<E> it = c.iterator();
return new ModifyIterator<E>(owner, it);
}
public boolean remove(Object o) {
if (c.remove(o)) {
owner.modifyRemoval(o);
return true;
}
return false;
}
public boolean removeAll(Collection<?> collection) {
boolean changed = false;
Iterator<?> it = collection.iterator();
while (it.hasNext()) {
Object o = (Object) it.next();
if (c.remove(o)) {
owner.modifyRemoval(o);
changed = true;
}
}
return changed;
}
public boolean retainAll(Collection<?> collection) {
boolean changed = false;
Iterator<?> it = c.iterator();
while (it.hasNext()) {
Object o = (Object) it.next();
if (!collection.contains(o)) {
it.remove();
owner.modifyRemoval(o);
changed = true;
}
}
return changed;
}
public int size() {
return c.size();
}
public Object[] toArray() {
return c.toArray();
}
public <T> T[] toArray(T[] a) {
return c.toArray(a);
}
}
package com.avaje.ebean.common;
import java.util.Collection;
import java.util.Iterator;
import com.avaje.ebean.bean.BeanCollection;
/**
* Wraps a collection for the purposes of notifying removals and additions to
* the BeanCollection owner.
* <p>
* This is required for persisting ManyToMany objects. Additions and removals
* become inserts and deletes to the intersection table.
* </p>
*/
class ModifyCollection<E> implements Collection<E> {
protected final BeanCollection<E> owner;
protected final Collection<E> c;
/**
* Create with an Owner and the underlying collection this wraps.
* <p>
* The owner is notified of the additions and removals.
* </p>
*/
public ModifyCollection(BeanCollection<E> owner, Collection<E> c) {
this.owner = owner;
this.c = c;
}
public boolean add(E o) {
if (c.add(o)) {
owner.modifyAddition(o);
return true;
}
return false;
}
public boolean addAll(Collection<? extends E> collection) {
boolean changed = false;
Iterator<? extends E> it = collection.iterator();
while (it.hasNext()) {
E o = it.next();
if (c.add(o)) {
owner.modifyAddition(o);
changed = true;
}
}
return changed;
}
public void clear() {
c.clear();
}
public boolean contains(Object o) {
return c.contains(o);
}
public boolean containsAll(Collection<?> collection) {
return c.containsAll(collection);
}
public boolean isEmpty() {
return c.isEmpty();
}
public Iterator<E> iterator() {
Iterator<E> it = c.iterator();
return new ModifyIterator<E>(owner, it);
}
public boolean remove(Object o) {
if (c.remove(o)) {
owner.modifyRemoval(o);
return true;
}
return false;
}
public boolean removeAll(Collection<?> collection) {
boolean changed = false;
Iterator<?> it = collection.iterator();
while (it.hasNext()) {
Object o = (Object) it.next();
if (c.remove(o)) {
owner.modifyRemoval(o);
changed = true;
}
}
return changed;
}
public boolean retainAll(Collection<?> collection) {
boolean changed = false;
Iterator<?> it = c.iterator();
while (it.hasNext()) {
Object o = (Object) it.next();
if (!collection.contains(o)) {
it.remove();
owner.modifyRemoval(o);
changed = true;
}
}
return changed;
}
public int size() {
return c.size();
}
public Object[] toArray() {
return c.toArray();
}
public <T> T[] toArray(T[] a) {
return c.toArray(a);
}
}
@@ -1,74 +1,74 @@
package com.avaje.ebean.common;
import java.io.Serializable;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* Holds sets of additions and deletions from a 'owner' List Set or Map.
* <p>
* These sets of additions and deletions are used to support persisting
* ManyToMany relationships. The additions becoming inserts into the
* intersection table and the removals becoming deletes from the intersection
* table.
* </p>
*/
class ModifyHolder<E> implements Serializable {
private static final long serialVersionUID = 2572572897923801083L;
/**
* Deletions list for manyToMany persistence.
*/
private Set<E> modifyDeletions = new LinkedHashSet<E>();
/**
* Additions list for manyToMany persistence.
*/
private Set<E> modifyAdditions = new LinkedHashSet<E>();
void reset() {
modifyDeletions = new LinkedHashSet<E>();
modifyAdditions = new LinkedHashSet<E>();
}
/**
* Used by BeanList.addAll() methods.
*/
void modifyAdditionAll(Collection<? extends E> c) {
if (c != null) {
for (E e : c) {
modifyAddition(e);
}
}
}
void modifyAddition(E bean) {
if (bean != null) {
// If it is to delete then just remove the deletion
if (!modifyDeletions.remove(bean)) {
// Insert
modifyAdditions.add(bean);
}
}
}
@SuppressWarnings("unchecked")
void modifyRemoval(Object bean) {
if (bean != null) {
// If it is to be added then just remove the addition
if (!modifyAdditions.remove((E) bean)) {
modifyDeletions.add((E) bean);
}
}
}
Set<E> getModifyAdditions() {
return modifyAdditions;
}
Set<E> getModifyRemovals() {
return modifyDeletions;
}
}
package com.avaje.ebean.common;
import java.io.Serializable;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* Holds sets of additions and deletions from a 'owner' List Set or Map.
* <p>
* These sets of additions and deletions are used to support persisting
* ManyToMany relationships. The additions becoming inserts into the
* intersection table and the removals becoming deletes from the intersection
* table.
* </p>
*/
class ModifyHolder<E> implements Serializable {
private static final long serialVersionUID = 2572572897923801083L;
/**
* Deletions list for manyToMany persistence.
*/
private Set<E> modifyDeletions = new LinkedHashSet<E>();
/**
* Additions list for manyToMany persistence.
*/
private Set<E> modifyAdditions = new LinkedHashSet<E>();
void reset() {
modifyDeletions = new LinkedHashSet<E>();
modifyAdditions = new LinkedHashSet<E>();
}
/**
* Used by BeanList.addAll() methods.
*/
void modifyAdditionAll(Collection<? extends E> c) {
if (c != null) {
for (E e : c) {
modifyAddition(e);
}
}
}
void modifyAddition(E bean) {
if (bean != null) {
// If it is to delete then just remove the deletion
if (!modifyDeletions.remove(bean)) {
// Insert
modifyAdditions.add(bean);
}
}
}
@SuppressWarnings("unchecked")
void modifyRemoval(Object bean) {
if (bean != null) {
// If it is to be added then just remove the addition
if (!modifyAdditions.remove((E) bean)) {
modifyDeletions.add((E) bean);
}
}
}
Set<E> getModifyAdditions() {
return modifyAdditions;
}
Set<E> getModifyRemovals() {
return modifyDeletions;
}
}
@@ -1,48 +1,48 @@
package com.avaje.ebean.common;
import java.util.Iterator;
import com.avaje.ebean.bean.BeanCollection;
/**
* Wraps an iterator for the purposes of notifying removals and additions to the
* BeanCollection owner.
* <p>
* This is required for persisting ManyToMany objects. Additions and removals
* become inserts and deletes to the intersection table.
* </p>
*/
class ModifyIterator<E> implements Iterator<E> {
private final BeanCollection<E> owner;
private final Iterator<E> it;
private E last;
/**
* Create with an Owner and the underlying Iterator this wraps.
* <p>
* The owner is notified of the removals.
* </p>
*/
ModifyIterator(BeanCollection<E> owner, Iterator<E> it) {
this.owner = owner;
this.it = it;
}
public boolean hasNext() {
return it.hasNext();
}
public E next() {
last = it.next();
return last;
}
public void remove() {
owner.modifyRemoval(last);
it.remove();
}
}
package com.avaje.ebean.common;
import java.util.Iterator;
import com.avaje.ebean.bean.BeanCollection;
/**
* Wraps an iterator for the purposes of notifying removals and additions to the
* BeanCollection owner.
* <p>
* This is required for persisting ManyToMany objects. Additions and removals
* become inserts and deletes to the intersection table.
* </p>
*/
class ModifyIterator<E> implements Iterator<E> {
private final BeanCollection<E> owner;
private final Iterator<E> it;
private E last;
/**
* Create with an Owner and the underlying Iterator this wraps.
* <p>
* The owner is notified of the removals.
* </p>
*/
ModifyIterator(BeanCollection<E> owner, Iterator<E> it) {
this.owner = owner;
this.it = it;
}
public boolean hasNext() {
return it.hasNext();
}
public E next() {
last = it.next();
return last;
}
public void remove() {
owner.modifyRemoval(last);
it.remove();
}
}
@@ -1,91 +1,91 @@
package com.avaje.ebean.common;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import com.avaje.ebean.bean.BeanCollection;
/**
* Wraps a List for the purposes of notifying removals and additions to the
* BeanCollection owner.
* <p>
* This is required for persisting ManyToMany objects. Additions and removals
* become inserts and deletes to the intersection table.
* </p>
* <p>
* Note that this is created by a call to subList() on a BeanList. Thats its
* only purpose really. BeanList holds the actual List.
* </p>
*/
class ModifyList<E> extends ModifyCollection<E> implements List<E> {
/**
* The underlying list.
*/
private final List<E> list;
/**
* Create with an Owner that is notified of any additions or deletions.
*/
ModifyList(BeanCollection<E> owner, List<E> list) {
super(owner, list);
this.list = list;
}
public void add(int index, E element) {
list.add(index, element);
owner.modifyAddition(element);
}
public boolean addAll(int index, Collection<? extends E> co) {
if (list.addAll(index, co)) {
Iterator<? extends E> it = co.iterator();
while (it.hasNext()) {
E o = it.next();
owner.modifyAddition(o);
}
return true;
}
return false;
}
public E get(int index) {
return list.get(index);
}
public int indexOf(Object o) {
return list.indexOf(o);
}
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
public ListIterator<E> listIterator() {
return new ModifyListIterator<E>(owner, list.listIterator());
}
public ListIterator<E> listIterator(int index) {
return new ModifyListIterator<E>(owner, list.listIterator(index));
}
public E remove(int index) {
E o = list.remove(index);
owner.modifyRemoval(o);
return o;
}
public E set(int index, E element) {
E o = list.set(index, element);
owner.modifyAddition(element);
owner.modifyRemoval(o);
return o;
}
public List<E> subList(int fromIndex, int toIndex) {
return new ModifyList<E>(owner, list.subList(fromIndex, toIndex));
}
}
package com.avaje.ebean.common;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import com.avaje.ebean.bean.BeanCollection;
/**
* Wraps a List for the purposes of notifying removals and additions to the
* BeanCollection owner.
* <p>
* This is required for persisting ManyToMany objects. Additions and removals
* become inserts and deletes to the intersection table.
* </p>
* <p>
* Note that this is created by a call to subList() on a BeanList. Thats its
* only purpose really. BeanList holds the actual List.
* </p>
*/
class ModifyList<E> extends ModifyCollection<E> implements List<E> {
/**
* The underlying list.
*/
private final List<E> list;
/**
* Create with an Owner that is notified of any additions or deletions.
*/
ModifyList(BeanCollection<E> owner, List<E> list) {
super(owner, list);
this.list = list;
}
public void add(int index, E element) {
list.add(index, element);
owner.modifyAddition(element);
}
public boolean addAll(int index, Collection<? extends E> co) {
if (list.addAll(index, co)) {
Iterator<? extends E> it = co.iterator();
while (it.hasNext()) {
E o = it.next();
owner.modifyAddition(o);
}
return true;
}
return false;
}
public E get(int index) {
return list.get(index);
}
public int indexOf(Object o) {
return list.indexOf(o);
}
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
public ListIterator<E> listIterator() {
return new ModifyListIterator<E>(owner, list.listIterator());
}
public ListIterator<E> listIterator(int index) {
return new ModifyListIterator<E>(owner, list.listIterator(index));
}
public E remove(int index) {
E o = list.remove(index);
owner.modifyRemoval(o);
return o;
}
public E set(int index, E element) {
E o = list.set(index, element);
owner.modifyAddition(element);
owner.modifyRemoval(o);
return o;
}
public List<E> subList(int fromIndex, int toIndex) {
return new ModifyList<E>(owner, list.subList(fromIndex, toIndex));
}
}
@@ -1,79 +1,79 @@
package com.avaje.ebean.common;
import java.util.ListIterator;
import com.avaje.ebean.bean.BeanCollection;
/**
* Wraps a ListIterator for the purposes of notifying removals and additions to
* the BeanCollection owner.
* <p>
* This is required for persisting ManyToMany objects. Additions and removals
* become inserts and deletes to the intersection table.
* </p>
*/
class ModifyListIterator<E> implements ListIterator<E> {
private final BeanCollection<E> owner;
private final ListIterator<E> it;
private E last;
/**
* Create with an Owner that is notified of any additions or deletions.
*/
ModifyListIterator(BeanCollection<E> owner, ListIterator<E> it) {
this.owner = owner;
this.it = it;
}
public void add(E bean) {
owner.modifyAddition(bean);
last = null;
it.add(bean);
}
public boolean hasNext() {
return it.hasNext();
}
public boolean hasPrevious() {
return it.hasPrevious();
}
public E next() {
last = it.next();
return last;
}
public int nextIndex() {
return it.nextIndex();
}
public E previous() {
last = it.previous();
return last;
}
public int previousIndex() {
return it.previousIndex();
}
public void remove() {
owner.modifyRemoval(last);
last = null;
it.remove();
}
public void set(E o) {
if (last == null) {
// in theory this is not allowed
} else {
owner.modifyRemoval(last);
owner.modifyAddition(o);
}
it.set(o);
}
}
package com.avaje.ebean.common;
import java.util.ListIterator;
import com.avaje.ebean.bean.BeanCollection;
/**
* Wraps a ListIterator for the purposes of notifying removals and additions to
* the BeanCollection owner.
* <p>
* This is required for persisting ManyToMany objects. Additions and removals
* become inserts and deletes to the intersection table.
* </p>
*/
class ModifyListIterator<E> implements ListIterator<E> {
private final BeanCollection<E> owner;
private final ListIterator<E> it;
private E last;
/**
* Create with an Owner that is notified of any additions or deletions.
*/
ModifyListIterator(BeanCollection<E> owner, ListIterator<E> it) {
this.owner = owner;
this.it = it;
}
public void add(E bean) {
owner.modifyAddition(bean);
last = null;
it.add(bean);
}
public boolean hasNext() {
return it.hasNext();
}
public boolean hasPrevious() {
return it.hasPrevious();
}
public E next() {
last = it.next();
return last;
}
public int nextIndex() {
return it.nextIndex();
}
public E previous() {
last = it.previous();
return last;
}
public int previousIndex() {
return it.previousIndex();
}
public void remove() {
owner.modifyRemoval(last);
last = null;
it.remove();
}
public void set(E o) {
if (last == null) {
// in theory this is not allowed
} else {
owner.modifyRemoval(last);
owner.modifyAddition(o);
}
it.set(o);
}
}
@@ -1,24 +1,24 @@
package com.avaje.ebean.common;
import java.util.Set;
import com.avaje.ebean.bean.BeanCollection;
/**
* Wraps a Set for the purposes of notifying removals and additions to the
* BeanCollection owner.
* <p>
* This is required for persisting ManyToMany objects. Additions and removals
* become inserts and deletes to the intersection table.
* </p>
*/
class ModifySet<E> extends ModifyCollection<E> implements Set<E> {
/**
* Create with an Owner that is notified of any additions or deletions.
*/
public ModifySet(BeanCollection<E> owner, Set<E> s) {
super(owner, s);
}
}
package com.avaje.ebean.common;
import java.util.Set;
import com.avaje.ebean.bean.BeanCollection;
/**
* Wraps a Set for the purposes of notifying removals and additions to the
* BeanCollection owner.
* <p>
* This is required for persisting ManyToMany objects. Additions and removals
* become inserts and deletes to the intersection table.
* </p>
*/
class ModifySet<E> extends ModifyCollection<E> implements Set<E> {
/**
* Create with an Owner that is notified of any additions or deletions.
*/
public ModifySet(BeanCollection<E> owner, Set<E> s) {
super(owner, s);
}
}
@@ -0,0 +1,33 @@
package com.avaje.ebean.common;
import com.avaje.ebean.EbeanServer;
import com.avaje.ebean.config.ServerConfig;
/**
* Creates the EbeanServer implementations. This is used internally by the EbeanServerFactory and is not currently
* exposed as public API.
*/
public interface SpiContainer {
/**
* Create the EbeanServer for a given configuration.
*
* @param configuration
* The configuration information for this server.
*/
EbeanServer createServer(ServerConfig configuration);
/**
* Create an EbeanServer just using the name.
* <p>
* In this case the dataSource parameters etc will be defined on the global
* avaje.properties file.
* </p>
*/
EbeanServer createServer(String name);
/**
* Shutdown any Ebean wide resources such as clustering.
*/
void shutdown();
}
@@ -1,46 +1,46 @@
package com.avaje.ebean.config;
/**
* API from creating and getting property values from an Immutable Compound
* Value Object.
*
* <p>
* A Compound Value object should contain multiple properties that are stored
* separately. If you only have a single scalar value you should instead look to
* use {@link ScalarTypeConverter}.
* </p>
* <p>
* For each property in the compound type you need to implement the
* {@link CompoundTypeProperty} interface. These must be returned from
* {@link #getProperties()} in the same order that the properties appear in the
* constructor.
* </p>
* <p>
* If your compound type is mutable then you should look to use the JPA Embedded
* annotation instead of implementing this interface.
* </p>
* <p>
* When using classpath search Ebean will detect and automatically register any
* implementations of this interface (along with detecting the entity classes
* etc).
* </p>
*
* @author rbygrave
*
* @param <V>
* The type of the Value Object
*
* @see ScalarTypeConverter
*/
public interface CompoundType<V> {
/**
* Create an instance of the compound type given its property values.
*/
public V create(Object[] propertyValues);
/**
* Return the properties in the order they appear in the constructor.
*/
public CompoundTypeProperty<V, ?>[] getProperties();
}
package com.avaje.ebean.config;
/**
* API from creating and getting property values from an Immutable Compound
* Value Object.
*
* <p>
* A Compound Value object should contain multiple properties that are stored
* separately. If you only have a single scalar value you should instead look to
* use {@link ScalarTypeConverter}.
* </p>
* <p>
* For each property in the compound type you need to implement the
* {@link CompoundTypeProperty} interface. These must be returned from
* {@link #getProperties()} in the same order that the properties appear in the
* constructor.
* </p>
* <p>
* If your compound type is mutable then you should look to use the JPA Embedded
* annotation instead of implementing this interface.
* </p>
* <p>
* When using classpath search Ebean will detect and automatically register any
* implementations of this interface (along with detecting the entity classes
* etc).
* </p>
*
* @author rbygrave
*
* @param <V>
* The type of the Value Object
*
* @see ScalarTypeConverter
*/
public interface CompoundType<V> {
/**
* Create an instance of the compound type given its property values.
*/
V create(Object[] propertyValues);
/**
* Return the properties in the order they appear in the constructor.
*/
CompoundTypeProperty<V, ?>[] getProperties();
}
@@ -1,51 +1,51 @@
package com.avaje.ebean.config;
/**
* Represents a Property of a Compound Value Object.
* <p>
* For each property in a {@link CompoundType} you need an implementation of
* this CompoundTypeProperty interface.
*
* </p>
*
* @author rbygrave
*
* @param <V>
* The type of the Compound value object
* @param <P>
* The type of the property
*
* @see CompoundType
* @see ScalarTypeConverter
*/
public interface CompoundTypeProperty<V, P> {
/**
* The name of this property.
*/
public String getName();
/**
* Return the property value from the containing compound value object.
*
* @param valueObject
* the compound value object
* @return the property value.
*/
public P getValue(V valueObject);
/**
* This should <b>ONLY</b> be used when the persistence type is different from
* the logical type returned. It most cases just return 0 and Ebean will
* persist the logical type.
* <p>
* Typically this should be used when the logical type is long but the
* persistence type is java.sql.Timestamp. In this case return
* java.sql.Types.TIMESTAMP (rather than 0).
* </p>
*
* @return Return the java.sql.Type that you want to use to persist this
* property or 0 and Ebean will use the logical type.
*/
public int getDbType();
}
package com.avaje.ebean.config;
/**
* Represents a Property of a Compound Value Object.
* <p>
* For each property in a {@link CompoundType} you need an implementation of
* this CompoundTypeProperty interface.
*
* </p>
*
* @author rbygrave
*
* @param <V>
* The type of the Compound value object
* @param <P>
* The type of the property
*
* @see CompoundType
* @see ScalarTypeConverter
*/
public interface CompoundTypeProperty<V, P> {
/**
* The name of this property.
*/
String getName();
/**
* Return the property value from the containing compound value object.
*
* @param valueObject
* the compound value object
* @return the property value.
*/
P getValue(V valueObject);
/**
* This should <b>ONLY</b> be used when the persistence type is different from
* the logical type returned. It most cases just return 0 and Ebean will
* persist the logical type.
* <p>
* Typically this should be used when the logical type is long but the
* persistence type is java.sql.Timestamp. In this case return
* java.sql.Types.TIMESTAMP (rather than 0).
* </p>
*
* @return Return the java.sql.Type that you want to use to persist this
* property or 0 and Ebean will use the logical type.
*/
int getDbType();
}
@@ -1,111 +1,111 @@
package com.avaje.ebean.config;
/**
* Define the encryption options for a bean property.
* <p>
* You can define the encryption options for a Bean property via the Encrypt
* annotation and programmatically via {@link EncryptDeployManager}.
* </p>
*
* @author rbygrave
*
* @see EncryptDeployManager#getEncryptDeploy(TableName, String)
*/
public class EncryptDeploy {
/**
* Use to define that no encryption should be used.
*/
public static final EncryptDeploy NO_ENCRYPT = new EncryptDeploy(Mode.MODE_NO_ENCRYPT, true, 0);
/**
* Use to define that the Encrypt annotation should be used to control
* encryption.
*/
public static final EncryptDeploy ANNOTATION = new EncryptDeploy(Mode.MODE_ANNOTATION, true, 0);
/**
* Use to define that Encryption should be used and String types should use DB
* encryption.
*/
public static final EncryptDeploy ENCRYPT_DB = new EncryptDeploy(Mode.MODE_ENCRYPT, true, 0);
/**
* Use to define that Java client Encryption should be used (rather than DB
* encryption).
*/
public static final EncryptDeploy ENCRYPT_CLIENT = new EncryptDeploy(Mode.MODE_ENCRYPT, false, 0);
/**
* The Encryption mode.
*/
public enum Mode {
/**
* Encrypt the property using DB encryption or Java client encryption
* depending on the type and dbEncryption flag.
*/
MODE_ENCRYPT,
/**
* No encryption is used, even if there is an Encryption annotation on the
* property.
*/
MODE_NO_ENCRYPT,
/**
* Use encryption options defined by the Encryption annotation on the
* property. If no annotation is on the property it is not encrypted.
*/
MODE_ANNOTATION
}
private final Mode mode;
private final boolean dbEncrypt;
private final int dbLength;
/**
* Construct with all options for Encryption including the dbLength.
*
* @param mode
* the Encryption mode
* @param dbEncrypt
* set to false if you want to use Java client side encryption rather
* than DB encryption.
* @param dbLength
* set the DB length to use.
*/
public EncryptDeploy(Mode mode, boolean dbEncrypt, int dbLength) {
this.mode = mode;
this.dbEncrypt = dbEncrypt;
this.dbLength = dbLength;
}
/**
* Return the encryption mode.
*/
public Mode getMode() {
return mode;
}
/**
* Return true if String type should use DB encryption.
* <p>
* Return false if String type should use java client encryption instead.
* </p>
*/
public boolean isDbEncrypt() {
return dbEncrypt;
}
/**
* Return a hint to specify the DB length.
* <p>
* Returning 0 means just use the normal DB length determination.
* </p>
*/
public int getDbLength() {
return dbLength;
}
}
package com.avaje.ebean.config;
/**
* Define the encryption options for a bean property.
* <p>
* You can define the encryption options for a Bean property via the Encrypt
* annotation and programmatically via {@link EncryptDeployManager}.
* </p>
*
* @author rbygrave
*
* @see EncryptDeployManager#getEncryptDeploy(TableName, String)
*/
public class EncryptDeploy {
/**
* Use to define that no encryption should be used.
*/
public static final EncryptDeploy NO_ENCRYPT = new EncryptDeploy(Mode.MODE_NO_ENCRYPT, true, 0);
/**
* Use to define that the Encrypt annotation should be used to control
* encryption.
*/
public static final EncryptDeploy ANNOTATION = new EncryptDeploy(Mode.MODE_ANNOTATION, true, 0);
/**
* Use to define that Encryption should be used and String types should use DB
* encryption.
*/
public static final EncryptDeploy ENCRYPT_DB = new EncryptDeploy(Mode.MODE_ENCRYPT, true, 0);
/**
* Use to define that Java client Encryption should be used (rather than DB
* encryption).
*/
public static final EncryptDeploy ENCRYPT_CLIENT = new EncryptDeploy(Mode.MODE_ENCRYPT, false, 0);
/**
* The Encryption mode.
*/
public enum Mode {
/**
* Encrypt the property using DB encryption or Java client encryption
* depending on the type and dbEncryption flag.
*/
MODE_ENCRYPT,
/**
* No encryption is used, even if there is an Encryption annotation on the
* property.
*/
MODE_NO_ENCRYPT,
/**
* Use encryption options defined by the Encryption annotation on the
* property. If no annotation is on the property it is not encrypted.
*/
MODE_ANNOTATION
}
private final Mode mode;
private final boolean dbEncrypt;
private final int dbLength;
/**
* Construct with all options for Encryption including the dbLength.
*
* @param mode
* the Encryption mode
* @param dbEncrypt
* set to false if you want to use Java client side encryption rather
* than DB encryption.
* @param dbLength
* set the DB length to use.
*/
public EncryptDeploy(Mode mode, boolean dbEncrypt, int dbLength) {
this.mode = mode;
this.dbEncrypt = dbEncrypt;
this.dbLength = dbLength;
}
/**
* Return the encryption mode.
*/
public Mode getMode() {
return mode;
}
/**
* Return true if String type should use DB encryption.
* <p>
* Return false if String type should use java client encryption instead.
* </p>
*/
public boolean isDbEncrypt() {
return dbEncrypt;
}
/**
* Return a hint to specify the DB length.
* <p>
* Returning 0 means just use the normal DB length determination.
* </p>
*/
public int getDbLength() {
return dbLength;
}
}
@@ -1,15 +1,15 @@
package com.avaje.ebean.config;
/**
* Programmatically define which database columns are encrypted.
*
* @author rbygrave
*
*/
public interface EncryptDeployManager {
/**
* Return true if the table column is encrypted.
*/
public EncryptDeploy getEncryptDeploy(TableName table, String column);
}
package com.avaje.ebean.config;
/**
* Programmatically define which database columns are encrypted.
*
* @author rbygrave
*
*/
public interface EncryptDeployManager {
/**
* Return true if the table column is encrypted.
*/
EncryptDeploy getEncryptDeploy(TableName table, String column);
}
@@ -1,18 +1,18 @@
package com.avaje.ebean.config;
/**
* Represents the key used for encryption.
* <p>
* For simple cases this often represent a simple String key but depending on
* the encryption method this could contain other details.
* </p>
*
* @author rbygrave
*/
public interface EncryptKey {
/**
* Return the string key value.
*/
public String getStringValue();
}
package com.avaje.ebean.config;
/**
* Represents the key used for encryption.
* <p>
* For simple cases this often represent a simple String key but depending on
* the encryption method this could contain other details.
* </p>
*
* @author rbygrave
*/
public interface EncryptKey {
/**
* Return the string key value.
*/
String getStringValue();
}

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