Compare commits

..
Author SHA1 Message Date
Robin Bygrave 2cc4c2c265 [maven-release-plugin] prepare release ebean-8.2.1 2016-08-05 13:53:03 +12:00
Robin Bygrave 0a830841c4 Bump pom to 8.2.1-SNAPSHOT 2016-08-05 13:52:09 +12:00
Robin Bygrave c427009b93 #812 - Remove deprecated includeSoftDeletes() ... migrate to setIncludeSoftDeletes() 2016-08-05 13:47:32 +12:00
Robin Bygrave 7f42d045ac No effective change - javadoc typo 2016-08-05 13:29:28 +12:00
Robin Bygrave 43afaf1344 #811 - ENH: Restore findIterate() as alternative to findEach / findEachWhile 2016-08-05 13:01:42 +12:00
Robin Bygrave 6c182ecaa5 #810 - ENH: Add transaction.isRollbackOnly() 2016-08-05 12:14:58 +12:00
Robin Bygrave fdb839f90e #809 - Add test / example showing ... transaction.setPersistCascade(false) and transaction.commitAndContinue(); 2016-08-05 11:20:12 +12:00
Robin Bygrave 16be213faf #808 - ENH: Add Transaction commitAndContinue() ... 2016-08-05 10:39:17 +12:00
Robin Bygrave 3344f0ddb0 Refactor - remove unused method JdbcTransaction.notifyQueryOnly(). 2016-08-04 23:25:50 +12:00
Robin Bygrave 479ac38537 #807 - Deprecate TransactionEventListener ... migrate to TransactionCallback 2016-08-04 23:17:57 +12:00
Robin Bygrave e30ad80f5f #806 - Deprecate OnQueryOnly.CLOSE ... 2016-08-04 23:02:26 +12:00
Robin Bygrave 08e46d6bf3 #805 - ENH: Add BeanState.resetForInsert() ... This resets bean state such that a save() results in an insert 2016-08-04 22:49:07 +12:00
Robin Bygrave 876476fdc1 #804 - Remove API - findMap(property, type) ... migrate to query.setMapKey() 2016-08-04 20:30:18 +12:00
Robin Bygrave 81de83a6e7 #803 - Fix generics on findMap() to ... <K> Map<K, T> findMap(); 2016-08-04 20:23:11 +12:00
Robin Bygrave b5b221ffb1 No effective change - remove unused constructors 2016-08-04 17:32:18 +12:00
Robin Bygrave 3c6eab6c85 #802 - Find generics on findIds() - refactor internals of find ids to use find single attribute 2016-08-04 17:28:41 +12:00
Robin Bygrave 1be30f1671 #125 - ENH: Add support for query returning a List of single Attribute type 2016-08-04 16:41:50 +12:00
Robin Bygrave 9a5cb242ce No effective change - remove commented out line from pom 2016-08-04 13:56:09 +12:00
Robin Bygrave ea69cae4a3 [maven-release-plugin] prepare for next development iteration 2016-08-03 16:24:43 +12:00
Robin Bygrave 629fb7a433 [maven-release-plugin] prepare release ebean-8.1.1 2016-08-03 16:24:23 +12:00
Robin Bygrave 4ff10da739 #801 - Change maven groupId ... to org.avaje.ebean, artifactId to ebean 2016-08-03 16:23:26 +12:00
Robin Bygrave 9472592a50 [maven-release-plugin] prepare for next development iteration 2016-08-03 00:40:37 +12:00
Robin Bygrave f42682ca90 [maven-release-plugin] prepare release avaje-ebeanorm-8.1.1 2016-08-03 00:40:18 +12:00
Robin Bygrave 5dc296e644 #798 - Add @Transactional based test 2016-08-03 00:38:58 +12:00
Robin Bygrave 380660913f No effective change - javadoc update on Query 2016-08-02 23:42:00 +12:00
Robin Bygrave d08ac6973e #800 - ENH: Add query.fetchQuery() and query.fetchLazy() ... as nicer alternatives to FetchConfig use 2016-08-02 23:33:02 +12:00
Robin Bygrave 9d23c1d56e #800 - ENH: Add query.fetchQuery() and query.fetchLazy() ... as nicer alternatives to FetchConfig use 2016-08-02 23:30:26 +12:00
Robin Bygrave b5d6c5f70b #800 - ENH: Add query.fetchQuery() and query.fetchLazy() ... as nicer alternatives to FetchConfig use 2016-08-02 23:30:04 +12:00
Robin Bygrave 3657d05774 #798 - ENH: Add support for transparent full JDBC batch. Via enhancement agent 8.1.1 ... 2016-08-02 21:41:13 +12:00
Robin Bygrave 2de8ae777d Merge branch 'wip/getterCallback' 2016-08-02 21:34:41 +12:00
Robin Bygrave 16950a5641 [maven-release-plugin] prepare for next development iteration 2016-08-02 21:32:08 +12:00
Robin Bygrave ad992d07ce [maven-release-plugin] prepare release avaje-ebeanorm-7.21.2 2016-08-02 21:31:47 +12:00
Robin Bygrave cbcec8f5ea No effective change - tidy 2016-08-02 20:32:59 +12:00
Robin Bygrave 6e2148d20b #799 - Query.fetch(path) when converted to query join default to batchSize 10 rather than 100 2016-08-02 20:19:38 +12:00
Robin Bygrave ca1c0a08f3 No effective change - remove whitespace on DLoadBeanContext 2016-08-02 20:14:46 +12:00
Robin Bygrave baa6fc355e No effective change - javadoc update on FetchConfig 2016-08-02 20:14:07 +12:00
Robin Bygrave dacdc26902 #798 - ENH: Add support for transparent full JDBC batch. Via enhancement agent 8.1.1 intercept bean getter to automatically flush the JDBC batch buffer. 2016-08-02 16:16:34 +12:00
Robin Bygrave 48edf64013 No effective change - typo in javadoc 2016-08-02 11:10:19 +12:00
Robin Bygrave e2ee6e8e98 No effective change - update tests with EBasicVer new constructor 2016-08-02 11:06:09 +12:00
Robin Bygrave e6e6a28245 No effective change - tidy asserts on TestQueryDistinct (AssertJ string contains etc) 2016-08-01 22:53:47 +12:00
Rob BygraveandGitHub 82a695a98a Merge pull request #797 from backslash47/master
Add check for distinct query when adding id attribute to order clause in paging query
2016-08-01 22:47:34 +12:00
Matus Zamborsky cdad31bd8a Added test for distinct paging query 2016-08-01 12:20:50 +02:00
Matus Zamborsky 4d16cf9caa Add check for distinct query when adding id attribute to order clause in paging query 2016-08-01 10:13:05 +02:00
Robin Bygrave 84a86cad0e #794 - Refactor - tidy code, remove unused mimetypes properties 2016-07-31 23:34:55 +12:00
Robin Bygrave dfdf87fa2d #794 - Refactor - tidy code, javadoc tidy 2016-07-31 23:33:29 +12:00
Robin Bygrave ee0615caec #794 - Refactor - tidy code, use uppercase L for Long literal 2016-07-31 23:33:07 +12:00
Robin Bygrave 79b8395f8f #794 - Refactor - tidy code, simplify if 2016-07-31 23:32:37 +12:00
Robin Bygrave 87c479cd95 #794 - Refactor - tidy code, remove unused imports 2016-07-31 23:24:30 +12:00
Robin Bygrave abbdda810a #794 - Refactor - tidy code, remove unused method arguments 2016-07-31 23:23:57 +12:00
Robin Bygrave e621900de9 #794 - Refactor - tidy code, remove unused method arguments 2016-07-31 23:23:43 +12:00
Robin Bygrave 76b33511e1 #793 - com.avaje.ebean.event.changelog.BeanChange not keeping passed id value 2016-07-31 23:14:08 +12:00
Robin Bygrave 77deab5cf0 #792 - Change Logging Rollback message on org.avaje.ebean.TXN from INFO level to DEBUG level 2016-07-31 22:52:48 +12:00
Robin Bygrave 4a9f8cef0e No effective change - rename SpiQuery method for m2mIncludeJoin and simplify OrmQueryPlanKey to associated intersection table name 2016-07-31 22:49:10 +12:00
Robin Bygrave 4d1340c16c No effective change - rename SpiQuery method for m2mIncludeJoin and simplify OrmQueryPlanKey to associated intersection table name 2016-07-31 22:46:07 +12:00
Robin Bygrave 74c6c71301 [maven-release-plugin] prepare for next development iteration 2016-07-31 21:28:17 +12:00
Robin Bygrave 0f0028eb1f [maven-release-plugin] prepare release avaje-ebeanorm-7.21.1 2016-07-31 21:27:58 +12:00
Robin Bygrave b4a1d52067 #791 - ENH: Add transaction.setRollbackOnly() ... (and Ebean.setRollbackOnly()) 2016-07-31 21:24:31 +12:00
Robin Bygrave d82148248c No effective change - javadoc tidy 2016-07-31 20:55:34 +12:00
Robin Bygrave dc7c854432 #788 - Deprecate findRowCount() ... add findCount(). Effectively renaming findRowCount() to findCount() 2016-07-31 19:06:21 +12:00
Robin Bygrave 7c83010df1 #788 - Deprecate findRowCount() ... add findCount(). Effectively renaming findRowCount() to findCount() 2016-07-31 16:39:23 +12:00
Robin Bygrave ed41e58073 Bump pom version to 7.21.1-SNAPSHOT 2016-07-31 16:01:00 +12:00
Robin Bygrave 5bab9eb648 #790 - DB Migration with multiple platforms (and no maven H2 dependency) gives: java.lang.NoClassDefFoundError: org/h2/api/Trigger 2016-07-31 15:59:54 +12:00
Robin Bygrave 5ce8eb6046 No effective change - remove unused methods 2016-07-31 15:02:05 +12:00
Robin Bygrave 56fee2ea9b #789 - findCount() ... with where raw(...) expression that includes a "many" produces incorrect SQL 2016-07-31 14:57:12 +12:00
Robin Bygrave 780ee7c7c0 [maven-release-plugin] prepare for next development iteration 2016-07-25 23:37:18 +12:00
Robin Bygrave 2bac7bf84d [maven-release-plugin] prepare release avaje-ebeanorm-7.20.1 2016-07-25 23:36:58 +12:00
Robin Bygrave 499862438d Bump pom to 7.20.1-SNAPSHOT 2016-07-25 23:36:12 +12:00
Robin Bygrave 4ad0b7cf66 #786 - Bump avaje-dbmigration to 1.2.1 ... which uses autoCommit true when running drop-all ddl 2016-07-25 23:34:17 +12:00
Robin Bygrave 6108ef484b #782 - History Many-To-Many Lazy-Loads fail 2016-07-25 23:31:02 +12:00
Robin Bygrave b763f4c875 #783 - HistoryExclude Many-to-Many Query-Generation Error 2016-07-25 23:29:33 +12:00
Robin Bygrave ca7285b2ad #783 - tests for ... HistoryExclude Many-to-Many Query-Generation Error 2016-07-25 23:28:45 +12:00
Robin Bygrave 75b639bc15 #782 - tests for ... History Many-To-Many Lazy-Loads fail 2016-07-25 23:22:33 +12:00
Robin Bygrave 1a7c4dac3f #1 - Change DdlGenerator.runScript() so that it uses connection.setAutoCommit(true) for drop ddl - when expectErrors is true 2016-07-25 23:03:00 +12:00
Robin Bygrave 6828fa1786 #784 - DDL DB Migration - Add @ManyToOne does not generate Foreign key and index ddl statements in migration script 2016-07-25 20:44:15 +12:00
Robin Bygrave ba7e729ae1 #785 - Bump avaje-classpath-scanner-api dependency to 2.2 for Windows fixes to classpath-scanner 2016-07-25 11:39:41 +12:00
Rob BygraveandGitHub c3fba72a24 Merge pull request #781 from FOCONIS/master
FIX: PathTests - on Windows
2016-07-25 11:14:23 +12:00
Robin Bygrave ff401cfc72 [maven-release-plugin] prepare for next development iteration 2016-07-20 00:03:20 +12:00
Robin Bygrave 7902276296 [maven-release-plugin] prepare release avaje-ebeanorm-7.19.1 2016-07-20 00:02:59 +12:00
Robin Bygrave 95f7a85aa1 Bump version to 7.19.1-SNAPSHOT 2016-07-20 00:02:08 +12:00
Roland Praml cf9eb4ed97 FIX: PathTests - they fail on windows machine, because the OS translates "/tmp" to "c:\tmp". bumped classpath-canner to current API version 2016-07-19 13:25:53 +02:00
Robin Bygrave b5cb04a6ed #780 - Remove ServerConfig registerJmxMBeans ... as it is no longer used 2016-07-18 09:22:22 +12:00
Robin Bygrave 5a9193f732 #779 - Refactor - Tidy internals of DefaultOrmQuery, remove unused String query property. 2016-07-15 23:51:27 +12:00
Robin Bygrave 55584f09d5 #778 - ENH: Add support for loading named queries from ebean.xml 2016-07-15 23:33:09 +12:00
Robin Bygrave 05eb0bfc55 #777 - ENH: Add support for @NamedQuery and @NamedQueries 2016-07-15 23:15:18 +12:00
Robin Bygrave cf13119b49 #776 - Remove ServerConfig.cacheWarmingDelay ... as it is no longer used 2016-07-15 20:51:22 +12:00
Robin Bygrave e0eff149b5 #775 - Change DefaultBackgroundExecutor to use JDK cached thread pool (rather than configure min/max size etc) 2016-07-15 20:48:41 +12:00
Robin Bygrave 474c2d5595 EQL - Add / expose via EbeanServer.createQuery(type, eql) method 2016-07-13 16:40:52 +12:00
Robin Bygrave e58cec8bdd EQL - parsing order by clause 2016-07-13 15:28:06 +12:00
Robin Bygrave 9dd82c0dd7 EQL - parsing limit offset clause 2016-07-13 14:30:12 +12:00
Robin Bygrave 49d3cc91e4 EQL - parsing select clause with distinct option 2016-07-13 14:07:59 +12:00
Robin Bygrave a8c2fc2ed5 EQL - parsing select clause 2016-07-13 13:55:56 +12:00
Robin Bygrave 45d7e3cafd EQL - parsing fetch clause with lazy/query option 2016-07-13 13:04:38 +12:00
Robin Bygrave be6754bd06 EQL - parsing fetch clause 2016-07-13 11:01:44 +12:00
Robin Bygrave 83c16ad1c6 EQL - parsing IN expressions with named parameters 2016-07-13 10:12:15 +12:00
Robin Bygrave 3f8b389999 EQL - parsing BETWEEN property expressions 2016-07-13 09:48:58 +12:00
Robin Bygrave b4b6a13e75 EQL - parsing BETWEEN expressions 2016-07-13 09:30:00 +12:00
Robin Bygrave 3fad4aae2f EQL - parsing IN expressions 2016-07-12 23:29:34 +12:00
Robin Bygrave ceab95e6c2 EQL - Simplify nested query where expressions after parsing 2016-07-12 22:51:02 +12:00
Robin Bygrave 84b37fb014 EQL Named parameter support for Like and ieq 2016-07-12 21:56:43 +12:00
Robin Bygrave 1a1c432c2a Initial add of SpiNamedParam 2016-07-12 20:45:33 +12:00
Robin Bygrave 86faa947af No effective change - tidy tests 2016-07-12 16:22:18 +12:00
Robin Bygrave 6b54b6ef46 Refactor BeanPropertyAssocOne findByParentIds use of raw expression 2016-07-12 16:11:51 +12:00
Robin Bygrave d8dfd66af3 Refactor BeanPropertyAssocMany findByParentIds use of raw expression 2016-07-12 16:01:32 +12:00
Robin Bygrave 675c51b8c1 Add IEQ support 2016-07-12 15:22:04 +12:00
Robin Bygrave 3cd7ecaa4a Merge branch 'wip/eql1' into wip/eql2 2016-07-12 15:05:00 +12:00
Robin Bygrave 1b322955ee [maven-release-plugin] prepare for next development iteration 2016-07-11 21:31:44 +12:00
Robin Bygrave 8115c5e230 [maven-release-plugin] prepare release avaje-ebeanorm-7.18.1 2016-07-11 21:31:25 +12:00
Robin Bygrave ad180c5531 No effective change - reduce test logging 2016-07-11 21:27:34 +12:00
Robin Bygrave b454f46dd4 Bump pom to 7.18.1-SNAPSHOT 2016-07-11 21:27:06 +12:00
Robin Bygrave 8a853b28f3 #772 - DB Migration DDL - alter table add column ... needs type conversion when using multiple platforms. e.g. varchar(20) ... convert to varchar2(20) for Oracle 2016-07-11 21:25:58 +12:00
Robin Bygrave a1be7ba5dd #771 - DB Migration DDL when using multiple platforms ... destination into sub directories rather than file suffix 2016-07-11 21:17:12 +12:00
Robin Bygrave 3914516793 #770 - DB Migration DDL generation run offline when using multiple platforms 2016-07-11 20:20:26 +12:00
Robin Bygrave 8c5854f77c #770 - DB Migration DDL generation run offline when using multiple platforms 2016-07-11 20:14:29 +12:00
Robin Bygrave 0bc5b94eae #770 - DB Migration DDL generation run offline when using multiple platforms 2016-07-11 20:08:26 +12:00
Robin Bygrave 12fa287f35 #769 - DB Migration DDL generation for UUID type when generating multiple platforms 2016-07-11 19:54:50 +12:00
Robin Bygrave 2991cb9ad1 #768 - Query.setDisableLazyLoading(true) ... not disabling lazy loading on @ManyToOne reference bean 2016-07-11 15:09:59 +12:00
Robin Bygrave 3b7f5496a8 #767 - Query.setDisableLazyLoading(true) ... not disabling lazy loading on @OneToMany 2016-07-11 12:28:31 +12:00
Robin Bygrave 4be703ff6e #767 - Query.setDisableLazyLoading(true) ... not disabling lazy loading on @OneToMany 2016-07-11 11:58:02 +12:00
Robin Bygrave d2c5765ac1 No effective change - tidy comments 2016-07-11 11:24:57 +12:00
Robin Bygrave aaf256b9be #766 - RawSql should automatically map column alias with underscore to camelCase ... so item_total should automatically map to bean property itemTotal 2016-07-08 23:44:11 +12:00
Robin Bygrave c7c6410cd9 #765 - ENH: Add ebean.xml with support for named RawSql, also adds EbeanServer.createNamedQuery() 2016-07-08 22:35:04 +12:00
Robin Bygrave 2c3c23725a No effective change - reformat code 2016-07-08 15:37:26 +12:00
Robin Bygrave 92069c0319 #764 - NPE on BeanDescriptorManager.processViewInvalidation(BeanDescriptorManager.java:385) 2016-07-08 15:34:43 +12:00
Robin Bygrave 630ad66ff1 #763 - Internal Code cleanup - remove redundant null checking etc 2016-07-08 15:01:39 +12:00
Robin Bygrave b732b390c7 [maven-release-plugin] prepare for next development iteration 2016-07-07 21:51:15 +12:00
Robin Bygrave 8c62fcdcb2 [maven-release-plugin] prepare release avaje-ebeanorm-7.17.1 2016-07-07 21:50:53 +12:00
Robin Bygrave e458f577fe No effective change - reduce logging for BeanDescriptorManager entity count message from INFO to DEBUG 2016-07-07 21:49:43 +12:00
Robin Bygrave 23434bab8c Bump pom to 7.17.1-SNAPSHOT 2016-07-07 21:45:40 +12:00
Robin Bygrave c47b5a1595 #762 - Change H2 Platform to IDENTITY (from SEQUENCE) with version 1.4.192 2016-07-07 21:43:15 +12:00
Robin Bygrave 411846347b #762 - Change H2 Platform to IDENTITY (from SEQUENCE) with version 1.4.192 2016-07-07 21:33:19 +12:00
Robin Bygrave 3722d19424 #761 - Change default for persistBatchOnCascade to be platform specific rather than NONE 2016-07-07 21:19:08 +12:00
Robin Bygrave 04a7310e5d [maven-release-plugin] prepare for next development iteration 2016-07-06 12:27:45 +12:00
Robin Bygrave 3490e90f03 [maven-release-plugin] prepare release avaje-ebeanorm-7.16.3 2016-07-06 12:27:26 +12:00
Robin Bygrave d89817a5c5 #760 - Change @Transactional(batchSize=100) ... to imply batch mode (remove need to also specify batch=PersistBatch.ALL) 2016-07-06 12:26:18 +12:00
Robin Bygrave db1ba5f20e #759 - Use default value of 100 for JDBC buffer fetchSize for findEach() / findEachWhile() - Add global defaults ServerConfig jdbcFetchSizeFindEach, jdbcFetchSizeFindList 2016-07-04 21:56:33 +12:00
Robin Bygrave 4f9a9a5094 No effective change - remove unused method 2016-06-30 14:45:06 +12:00
Robin Bygrave 1c6ac1289d #758 - DDL - @Index(unique=true) on field/property not creating unique index 2016-06-30 13:59:38 +12:00
Robin Bygrave b96be84106 Merge branch 'master' of github.com:ebean-orm/avaje-ebeanorm 2016-06-30 05:38:32 +12:00
Robin Bygrave 3c40293183 #757 - Reduce logging of Commit message of org.avaje.ebean.TXN from INFO to DEBUG 2016-06-30 05:38:16 +12:00
Rob BygraveandGitHub a9a6031986 Merge pull request #755 from MatthewMerrill/patch-1
Javadoc typo in SqlUpdate
2016-06-28 09:32:27 +12:00
Robin Bygrave b82085da42 [maven-release-plugin] prepare for next development iteration 2016-06-28 07:13:26 +12:00
Robin Bygrave 9a17a7752c [maven-release-plugin] prepare release avaje-ebeanorm-7.16.2 2016-06-28 07:13:06 +12:00
Robin Bygrave 92474c2b24 #754 - Logging output for bind log of UpdateQuery does not include bind values for set clause ... 2016-06-28 07:10:59 +12:00
Robin Bygrave 9a00b9df0e #753 - @History "as of" query errors when executed a second time - invalid bind parameter 2016-06-28 07:04:39 +12:00
Robin Bygrave 697f67c14a #753 - @History "as of" query errors when executed a second time - invalid bind parameter 2016-06-28 06:46:16 +12:00
Matthew MerrillandGitHub 2c34bc1636 Example code typo
Change "there where" to "there were" and added space between modify count and next word.
2016-06-27 09:07:45 -07:00
Robin Bygrave 1f9ccf1c8b [maven-release-plugin] prepare for next development iteration 2016-06-23 21:39:03 +12:00
Robin Bygrave a1f10b8704 [maven-release-plugin] prepare release avaje-ebeanorm-7.16.1 2016-06-23 21:38:42 +12:00
Robin Bygrave 3c21950b91 Bump pom to 7.16.1-SNAPSHOT 2016-06-23 21:36:57 +12:00
Robin Bygrave 3b45308ac7 Merge branch 'DevFactory-release/collection-isempty-1' 2016-06-23 13:40:23 +12:00
Robin Bygrave 00e69e1b5d No effective change - remove extra whitespace 2016-06-23 13:39:34 +12:00
Robin Bygrave 11b3f7a813 Merge branch 'release/collection-isempty-1' of https://github.com/DevFactory/avaje-ebeanorm into DevFactory-release/collection-isempty-1
Conflicts:
	src/main/java/com/avaje/ebeaninternal/server/query/DefaultDbSqlContext.java
2016-06-23 13:24:58 +12:00
Robin Bygrave 2185c8a886 #752 - Refactor: SQL generation for @History support with Postgres, MySql (views/triggers based) such that it more closely aligns with SQL 2011 based SQL 2016-06-23 11:33:01 +12:00
Robin Bygrave f8bda05b37 #751 - @History with @ManyToMany ... intersection table not getting associated history support 2016-06-23 11:05:16 +12:00
Artyom Melnikov 0a3b819991 Fixing squid:S1155 - Collection.isEmpty() should be used to test for emptiness 2016-06-22 13:43:15 +03:00
Rob BygraveandGitHub 5c8b1eb3bb Merge pull request #748 from yuqiyi/master
fix DeployBeanDescriptor.java of the method setView
2016-06-22 22:21:52 +12:00
yuqiyi 824f6dcc7e fix DeployBeanDescriptor.java of the method setView 2016-06-22 18:11:37 +08:00
Robin Bygrave 06e23b85ad #747 - @History findVersionsBetween query with Oracle has incorrect ordering 2016-06-22 20:16:35 +12:00
Robin Bygrave 09219c759b [maven-release-plugin] prepare for next development iteration 2016-06-20 22:57:36 +12:00
Robin Bygrave b861038568 [maven-release-plugin] prepare release avaje-ebeanorm-7.15.1 2016-06-20 22:57:16 +12:00
Robin Bygrave bfd8445bcd Bump pom to 7.15.1-SNAPSHOT 2016-06-20 22:56:04 +12:00
Robin Bygrave c30e3bf78c #746 - SqlQuery with named parameter and limit/offset gives SQL exception 2016-06-20 22:54:08 +12:00
Robin Bygrave c793d6652f #745 - ElasticSearch - internally translate where().id.eq(42) ... to where().setId(42) 2016-06-20 22:29:38 +12:00
Robin Bygrave d12e55c20b #744 - ElasticSearch - isEmpty() expression needs to have outer not:{} negation to work as per .. 2016-06-20 21:32:05 +12:00
Robin Bygrave 3477f590dd #743 - Fix issue with ElasticSearch nested path query with multiple nested path expressions 2016-06-20 20:57:45 +12:00
Robin Bygrave 6bbf93aba8 No effective change - extract private constant in DefaultExpressionList 2016-06-20 13:14:28 +12:00
Robin Bygrave 42d02cc521 [maven-release-plugin] prepare for next development iteration 2016-06-17 22:27:25 +12:00
Robin Bygrave 9ea58572de [maven-release-plugin] prepare release avaje-ebeanorm-7.14.1 2016-06-17 22:27:04 +12:00
Robin Bygrave 35d82c9104 Bump pom to 7.14.1-SNAPSHOT 2016-06-17 22:26:06 +12:00
Robin Bygrave 31aae38616 #742 - ENH: DocStoreConfig ... read System properties for isGenerateMapping(), isDropCreate() and isCreate() 2016-06-17 22:25:11 +12:00
Robin Bygrave f144b53651 #741 - ENH: Add DocumentStore indexSettings() method ... for setting ElasticSearch refresh_interval 2016-06-17 22:21:22 +12:00
Robin Bygrave f47cd7e7c2 Add extra-dll.xml example for .... ENH: For @Index add support for index types (like Postgres GIN) #707 ... 2016-06-17 15:04:12 +12:00
Robin Bygrave 8765cb8356 No effective change - reformat code 2016-06-17 13:24:49 +12:00
Robin Bygrave 30abe75a96 Travis - enable caching .m2 2016-06-17 13:19:01 +12:00
Robin Bygrave 164e6c71c1 Travis - stop caching .m2 2016-06-17 13:15:42 +12:00
Robin Bygrave dfa6353850 #740 - ClassCastException: java.util.ArrayList cannot be cast to com.avaje.ebean.bean.BeanCollection at com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany.resetMany(BeanPropertyAssocMany.java:273) 2016-06-17 12:30:57 +12:00
Robin Bygrave d88ff2a3b2 #739 - UpdateQuery with idEq() expression gives wrong update statement (still has table alias) 2016-06-17 11:34:47 +12:00
Robin Bygrave 713ae75464 No effective change - reformat 2016-06-17 11:03:47 +12:00
Rob BygraveandGitHub 710fb0e947 Merge pull request #738 from DevFactory/staging/using-isempty-fix-1
Refactor: Use Collection.isEmpty() instead of size() comparison to 0 etc
2016-06-15 20:55:02 +12:00
Rob BygraveandGitHub cb0cf97f3f Merge pull request #736 from DevFactory/staging/make-public-static-fields-constant-fix-1
Updating "public static" fields to add final modifier
2016-06-15 20:46:37 +12:00
Artyom Melnikov 07edb2c81f Using Collection.isEmpty() to test for emptiness 2016-06-14 15:21:23 +03:00
Artyom Melnikov 066effa5bf "public static" fields should be constant 2016-06-14 14:18:18 +03:00
Robin Bygrave bb5ca6c56e Bump agent in pom to 4.11.1 2016-06-14 22:24:50 +12:00
Robin Bygrave a64a020e36 #734 - Add ServerConfig.skipCacheAfterWrite & transaction.setSkipCache(boolean) ... to control L2 Bean cache use during transaction 2016-06-10 17:59:37 +12:00
Robin Bygrave c24ee53462 [maven-release-plugin] prepare for next development iteration 2016-06-08 14:40:18 +12:00
Robin Bygrave 06e4bdca0e [maven-release-plugin] prepare release avaje-ebeanorm-7.13.1 2016-06-08 14:39:56 +12:00
Robin Bygrave 3dbf35aca4 Bump pom version to 7.13.1-SNAPSHOT 2016-06-08 14:38:47 +12:00
Robin Bygrave cd56b3ca3c #726 - L2 cache returns stale data -> change such that when using "local L2 caching" the changes to L2 cache propagate in foreground 2016-06-08 14:38:08 +12:00
Robin Bygrave 353175626d #733 - RawSqlBuilder.columnMapping() not working using DB column alias ... java.lang.IllegalArgumentException: DB Column [detail_count] not found in mapping. 2016-06-07 17:10:37 +12:00
Robin Bygrave 1a3acb86df #732 - NPE in ScalarTypeArrayList.read(ScalarTypeArrayList.java:89) ... 2016-06-03 08:09:04 +12:00
Robin Bygrave 1304646cce #731 - ENH: Add support for using ebean.mf manifest file for finding/defining packages to search for entities 2016-06-02 17:35:06 +12:00
Robin Bygrave b3828572fd No effective change - javadoc for ServerConfig 2016-06-02 14:08:00 +12:00
Robin Bygrave eddd48f8ad #730 - Remove unused ServerConfig.classPathReaderClassName ... as replaced by org.avaje.classpath.scanner.ClassPathScanner plugin (in 7.8.1) 2016-06-02 14:03:30 +12:00
Robin Bygrave 9797502ef2 #729 - Remove unused ServerConfig.addJar(...); serverConfig.setJars(...); ... as "search jars" is no longer used in classpath scanning (since 7.8.1) 2016-06-02 13:55:14 +12:00
Robin Bygrave daba7a11b4 No effective change - remove unused code (old ClassPathReader etc) 2016-06-01 20:53:07 +12:00
Robin Bygrave 92caf69cb3 #728 - Remove Query.where(String) ... migrate to where().raw(...) 2016-06-01 19:54:02 +12:00
Robin Bygrave a954f8e9e1 EQL - initial 2016-06-01 17:27:35 +12:00
Robin Bygrave 71f70c01ae #727 - ENH: Add endOr(), endAnd(), endNot() ... to ExpressionList as synonym for endJunction() 2016-06-01 16:03:30 +12:00
Robin Bygrave 74d7652044 [maven-release-plugin] prepare for next development iteration 2016-05-30 17:28:05 +12:00
454 changed files with 15017 additions and 5122 deletions
+22 -17
View File
@@ -7,12 +7,12 @@
<version>1.1</version>
</parent>
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm</artifactId>
<version>7.12.2</version>
<groupId>org.avaje.ebean</groupId>
<artifactId>ebean</artifactId>
<version>8.2.1</version>
<packaging>jar</packaging>
<name>avaje-ebeanorm</name>
<name>ebean</name>
<url>http://ebean-orm.github.io/</url>
<properties>
@@ -37,7 +37,7 @@
<scm>
<developerConnection>scm:git:https://github.com/ebean-orm/avaje-ebeanorm.git</developerConnection>
<tag>avaje-ebeanorm-7.12.2</tag>
<tag>ebean-8.2.1</tag>
</scm>
<dependencies>
@@ -69,19 +69,19 @@
<dependency>
<groupId>org.avaje</groupId>
<artifactId>avaje-classpath-scanner-api</artifactId>
<version>2.1</version>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.avaje</groupId>
<artifactId>avaje-classpath-scanner</artifactId>
<version>2.1.1</version>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.avaje</groupId>
<artifactId>avaje-dbmigration</artifactId>
<version>1.1.1</version>
<version>1.2.1</version>
</dependency>
<dependency>
@@ -90,6 +90,12 @@
<version>[1.7.1,1.7.99)</version>
</dependency>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4-runtime</artifactId>
<version>4.5.3</version>
</dependency>
<!-- Jackson core used internally by Ebean -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
@@ -166,9 +172,9 @@
</dependency>
<dependency>
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm-agent</artifactId>
<version>4.10.1</version>
<groupId>org.avaje.ebean</groupId>
<artifactId>ebean-agent</artifactId>
<version>8.1.1</version>
<scope>test</scope>
</dependency>
@@ -177,7 +183,7 @@
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.189</version>
<version>1.4.192</version>
<scope>provided</scope>
</dependency>
@@ -241,16 +247,15 @@
</plugin>
<plugin>
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm-mavenenhancer</artifactId>
<version>4.10.1</version>
<groupId>org.avaje.ebean</groupId>
<artifactId>ebean-maven-plugin</artifactId>
<version>8.1.1</version>
<executions>
<execution>
<id>test</id>
<phase>process-test-classes</phase>
<configuration>
<classSource>target/test-classes</classSource>
<packages>com.avaje.tests.**</packages>
<transformArgs>debug=1</transformArgs>
</configuration>
<goals>
@@ -298,7 +303,7 @@
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<configuration>
<doctitle>Ebean 7</doctitle>
<doctitle>Ebean 8</doctitle>
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
<source>1.8</source>
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
@@ -38,6 +38,11 @@ public interface BeanState {
*/
void setDisableLazyLoad(boolean disableLazyLoading);
/**
* Return true if the bean has lazy loading disabled.
*/
boolean isDisableLazyLoad();
/**
* Set the loaded state of the property given it's name.
*
@@ -115,4 +120,9 @@ public interface BeanState {
* for a fully loaded entity bean.
*/
void setLoaded();
/**
* Reset the bean putting it into NEW state such that a save() results in an insert.
*/
void resetForInsert();
}
@@ -49,7 +49,7 @@ final class DRawSqlColumnsParser {
if (split.length > 1) {
ArrayList<String> tmp = new ArrayList<String>(split.length);
for (int i = 0; i < split.length; i++) {
if (split[i].trim().length() > 0) {
if (!split[i].trim().isEmpty()) {
tmp.add(split[i].trim());
}
}
@@ -5,6 +5,7 @@ import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* Document storage operations.
@@ -205,6 +206,39 @@ public interface DocumentStore {
*/
void createIndex(String indexName, String alias);
/**
* Modify the settings on an index.
* <p>
* For example, this can be used be used to set elasticSearch refresh_interval
* on an index before a bulk update.
* </p>
* <pre>{@code
*
* // refresh_interval -1 ... disable refresh while bulk loading
*
* Map<String,Object> settings = new LinkedHashMap<>();
* settings.put("refresh_interval", "-1");
*
* documentStore.indexSettings("product", settings);
*
* }</pre>
*
* <pre>{@code
*
* // refresh_interval 1s ... restore after bulk loading
*
* Map<String,Object> settings = new LinkedHashMap<>();
* settings.put("refresh_interval", "1s");
*
* documentStore.indexSettings("product", settings);
*
* }</pre>
*
* @param indexName the name of the index to update settings on
* @param settings the settings to set on the index
*/
void indexSettings(String indexName, Map<String, Object> settings);
/**
* Copy the index to a new index.
* <p>
+66 -35
View File
@@ -161,7 +161,7 @@ public final class Ebean {
// look to see if there is a default server defined
String defaultName = PrimaryServer.getDefaultServerName();
logger.debug("defaultName:" + defaultName);
if (defaultName != null && defaultName.trim().length() > 0) {
if (defaultName != null && !defaultName.trim().isEmpty()) {
defaultServer = getWithCreate(defaultName.trim());
}
}
@@ -182,7 +182,7 @@ public final class Ebean {
}
private EbeanServer get(String name) {
if (name == null || name.length() == 0) {
if (name == null || name.isEmpty()) {
return defaultServer;
}
// non-synchronized read
@@ -499,6 +499,13 @@ public final class Ebean {
serverMgr.getDefaultServer().endTransaction();
}
/**
* Mark the current transaction as rollback only.
*/
public static void setRollbackOnly() {
serverMgr.getDefaultServer().currentTransaction().setRollbackOnly();
}
/**
* Return a map of the differences between two objects of the same type.
* <p>
@@ -945,6 +952,21 @@ public final class Ebean {
return serverMgr.getDefaultServer().createCsvReader(beanType);
}
/**
* Create a named query.
* <p>
* For RawSql the named query is expected to be in ebean.xml.
* </p>
*
* @param beanType The type of entity bean
* @param namedQuery The name of the query
* @param <T> The type of entity bean
* @return The query
*/
public static <T> Query<T> createNamedQuery(Class<T> beanType, String namedQuery) {
return serverMgr.getDefaultServer().createNamedQuery(beanType, namedQuery);
}
/**
* Create a query for a type of entity bean.
* <p>
@@ -960,39 +982,7 @@ public final class Ebean {
* {@link Query#findSet()} etc will execute against the same EbeanServer from
* which is was created.
* </p>
*
* <pre>{@code
* // Find order 2 additionally fetching the customer, details and details.product
* // name.
*
* Order order = Ebean.find(Order.class)
* .fetch("customer")
* .fetch("details")
* .fetch("detail.product", "name")
* .setId(2)
* .findUnique();
*
* // Find order 2 additionally fetching the customer, details and details.product
* // name.
* // Note: same query as above but using the query language
* // Note: using a named query would be preferred practice
*
* String oql = "find order fetch customer fetch details fetch details.product (name) where id = :orderId ";
*
* Query<Order> query = Ebean.find(Order.class);
* query.setQuery(oql);
* query.setParameter("orderId", 2);
*
* Order order = query.findUnique();
*
* // Using a named query
* Query<Order> query = Ebean.find(Order.class, "with.details");
* query.setParameter("orderId", 2);
*
* Order order = query.findUnique();
*
* }</pre>
*
*
* @param beanType
* the class of entity to be fetched
* @return A ORM Query object for this beanType
@@ -1002,6 +992,47 @@ public final class Ebean {
return serverMgr.getDefaultServer().createQuery(beanType);
}
/**
* Parse the Ebean query language statement returning the query which can then
* be modified (add expressions, change order by clause, change maxRows, change
* fetch and select paths etc).
*
* <h3>Example</h3>
*
* <pre>{@code
*
*
* // Find order additionally fetching the customer, details and details.product name.
*
* String eql = "fetch customer fetch details fetch details.product (name) where id = :orderId ";
*
* Query<Order> query = Ebean.createQuery(Order.class, eql);
* query.setParameter("orderId", 2);
*
* Order order = query.findUnique();
*
* // This is the same as:
*
* Order order = Ebean.find(Order.class)
* .fetch("customer")
* .fetch("details")
* .fetch("detail.product", "name")
* .setId(2)
* .findUnique();
*
* }</pre>
*
* @param beanType The type of bean to fetch
* @param eql The Ebean query
* @param <T> The type of the entity bean
*
* @return The query with expressions defined as per the parsed query statement
*/
public static <T> Query<T> createQuery(Class<T> beanType, String eql) {
return serverMgr.getDefaultServer().createQuery(beanType, eql);
}
/**
* Create a query for a type of entity bean.
* <p>
+126 -8
View File
@@ -199,6 +199,19 @@ public interface EbeanServer {
*/
<T> UpdateQuery<T> update(Class<T> beanType);
/**
* Create a named query.
* <p>
* For RawSql the named query is expected to be in ebean.xml.
* </p>
*
* @param beanType The type of entity bean
* @param namedQuery The name of the query
* @param <T> The type of entity bean
* @return The query
*/
<T> Query<T> createNamedQuery(Class<T> beanType, String namedQuery);
/**
* Create a query for an entity bean and synonym for {@link #find(Class)}.
*
@@ -206,6 +219,43 @@ public interface EbeanServer {
*/
<T> Query<T> createQuery(Class<T> beanType);
/**
* Parse the Ebean query language statement returning the query which can then
* be modified (add expressions, change order by clause, change maxRows, change
* fetch and select paths etc).
*
* <h3>Example</h3>
*
* <pre>{@code
*
* // Find order additionally fetching the customer, details and details.product name.
*
* String eql = "fetch customer fetch details fetch details.product (name) where id = :orderId ";
*
* Query<Order> query = Ebean.createQuery(Order.class, eql);
* query.setParameter("orderId", 2);
*
* Order order = query.findUnique();
*
* // This is the same as:
*
* Order order = Ebean.find(Order.class)
* .fetch("customer")
* .fetch("details")
* .fetch("detail.product", "name")
* .setId(2)
* .findUnique();
*
* }</pre>
*
* @param beanType The type of bean to fetch
* @param eql The Ebean query
* @param <T> The type of the entity bean
*
* @return The query with expressions defined as per the parsed query statement
*/
<T> Query<T> createQuery(Class<T> beanType, String eql);
/**
* Create a query for a type of entity bean.
* <p>
@@ -689,20 +739,46 @@ public interface EbeanServer {
<T> T getReference(Class<T> beanType, Object id);
/**
* Return the number of 'top level' or 'root' entities this query should
* return.
* Return the number of 'top level' or 'root' entities this query should return.
*
* @see Query#findRowCount()
* @see com.avaje.ebean.Query#findFutureRowCount()
* @see Query#findCount()
* @see Query#findFutureCount()
*/
<T> int findCount(Query<T> query, Transaction transaction);
/**
* Deprecated in favor of findCount()
*
* Return the number of 'top level' or 'root' entities this query should return.
* @deprecated
*/
<T> int findRowCount(Query<T> query, Transaction transaction);
/**
* Return the Id values of the query as a List.
*
* @see com.avaje.ebean.Query#findIds()
* @see Query#findIds()
*/
<T> List<Object> findIds(Query<T> query, Transaction transaction);
<A> List<A> findIds(Query<?> query, Transaction transaction);
/**
* Return a QueryIterator for the query.
* <p>
* Generally using {@link #findEach(Query, QueryEachConsumer, Transaction)} or
* {@link #findEachWhile(Query, QueryEachWhileConsumer, Transaction)} is preferred
* to findIterate(). The reason is that those methods automatically take care of
* closing the queryIterator (and the underlying jdbc statement and resultSet).
* </p>
* <p>
* This is similar to findEach in that not all the result beans need to be held
* in memory at the same time and as such is good for processing large queries.
* </p>
*
* @see Query#findIterate()
* @see Query#findEach(QueryEachConsumer)
* @see Query#findEachWhile(QueryEachWhileConsumer)
*/
<T> QueryIterator<T> findIterate(Query<T> query, Transaction transaction);
/**
* Execute the query visiting the each bean one at a time.
@@ -818,7 +894,15 @@ public interface EbeanServer {
* @return a Future object for the row count query
* @see com.avaje.ebean.Query#findFutureRowCount()
*/
<T> FutureRowCount<T> findFutureRowCount(Query<T> query, Transaction transaction);
<T> FutureRowCount<T> findFutureCount(Query<T> query, Transaction transaction);
/**
* Deprecated in favor of findFutureCount().
*
* Execute find row count query in a background thread.
* @deprecated
*/
<T> FutureRowCount<T> findFutureRowCount(Query<T> query, Transaction transaction);
/**
* Execute find Id's query in a background thread.
@@ -921,7 +1005,41 @@ public interface EbeanServer {
* @return the map of fetched beans.
* @see Query#findMap()
*/
<T> Map<?, T> findMap(Query<T> query, Transaction transaction);
<K, T> Map<K, T> findMap(Query<T> query, Transaction transaction);
/**
* Execute the query returning a list of values for a single property.
*
* <h3>Example 1:</h3>
* <pre>{@code
*
* List<String> names =
* Ebean.find(Customer.class)
* .select("name")
* .orderBy().asc("name")
* .findSingleAttributeList();
*
* }</pre>
*
* <h3>Example 2:</h3>
* <pre>{@code
*
* List<String> names =
* Ebean.find(Customer.class)
* .setDistinct(true)
* .select("name")
* .where().eq("status", Customer.Status.NEW)
* .orderBy().asc("name")
* .setMaxRows(100)
* .findSingleAttributeList();
*
* }</pre>
*
* @return the list of values for the selected property
*
* @see Query#findSingleAttributeList()
*/
<A> List<A> findSingleAttributeList(Query<?> query, Transaction transaction);
/**
* Execute the query returning at most one entity bean or null (if no matching
@@ -135,6 +135,11 @@ public interface ExpressionFactory {
*/
Expression ieq(String propertyName, String value);
/**
* Case Insensitive Equal To that allows for named parameter use.
*/
Expression ieqObject(String propertyName, Object value);
/**
* Between - property between the two given values.
*/
@@ -192,6 +197,11 @@ public interface ExpressionFactory {
*/
ExampleExpression exampleLike(Object example, boolean caseInsensitive, LikeType likeType);
/**
* Like with support for named parameters.
*/
Expression like(String propertyName, Object value, boolean caseInsensitive, LikeType likeType);
/**
* Like - property like value where the value contains the SQL wild card
* characters % (percentage) and _ (underscore).
+100 -43
View File
@@ -31,7 +31,7 @@ import java.util.Set;
* more methods than you would initially expect (the ones duplicated from
* Query).
* </p>
*
*
* @see Query#where()
*/
public interface ExpressionList<T> {
@@ -83,14 +83,14 @@ public interface ExpressionList<T> {
/**
* Add an orderBy clause to the query.
*
*
* @see Query#orderBy(String)
*/
Query<T> orderBy(String orderBy);
/**
* Add an orderBy clause to the query.
*
*
* @see Query#orderBy(String)
*/
Query<T> setOrderBy(String orderBy);
@@ -116,12 +116,6 @@ public interface ExpressionList<T> {
*/
Query<T> asDraft();
/**
* Deprecated in favour of setIncludeSoftDeletes().
*/
@Deprecated
Query<T> includeSoftDeletes();
/**
* Execute the query including soft deleted rows.
*/
@@ -147,6 +141,13 @@ public interface ExpressionList<T> {
*/
int update();
/**
* Execute the query iterating over the results.
*
* @see Query#findIterate()
*/
QueryIterator<T> findIterate();
/**
* Execute the query process the beans one at a time.
*
@@ -164,17 +165,17 @@ public interface ExpressionList<T> {
/**
* Execute the query returning a list.
*
*
* @see Query#findList()
*/
List<T> findList();
/**
* Execute the query returning the list of Id's.
*
*
* @see Query#findIds()
*/
List<Object> findIds();
<A> List<A> findIds();
/**
* Return the count of entities this query should return.
@@ -182,26 +183,60 @@ public interface ExpressionList<T> {
* This is the number of 'top level' or 'root level' entities.
* </p>
*/
int findCount();
/**
* Deprecated in favor of findCount().
*
* @deprecated
*/
int findRowCount();
/**
* Execute the query returning a set.
*
*
* @see Query#findSet()
*/
Set<T> findSet();
/**
* Execute the query returning a map.
*
*
* @see Query#findMap()
*/
Map<?, T> findMap();
<K> Map<K, T> findMap();
/**
* Return a typed map specifying the key property and type.
* Execute the query returning a list of values for a single property.
*
* <h3>Example 1:</h3>
* <pre>{@code
*
* List<String> names =
* Ebean.find(Customer.class)
* .select("name")
* .orderBy().asc("name")
* .findSingleAttributeList();
*
* }</pre>
*
* <h3>Example 2:</h3>
* <pre>{@code
*
* List<String> names =
* Ebean.find(Customer.class)
* .setDistinct(true)
* .select("name")
* .where().eq("status", Customer.Status.NEW)
* .orderBy().asc("name")
* .setMaxRows(100)
* .findSingleAttributeList();
*
* }</pre>
*
* @return the list of values for the selected property
*/
<K> Map<K, T> findMap(String keyProperty, Class<K> keyType);
<A> List<A> findSingleAttributeList();
/**
* Execute the query returning a single bean or null (if no matching
@@ -225,9 +260,16 @@ public interface ExpressionList<T> {
* execution status (isDone etc) and get the value (with or without a
* timeout).
* </p>
*
*
* @return a Future object for the row count query
*/
FutureRowCount<T> findFutureCount();
/**
* Deprecated in favor of findFutureCount().
*
* @deprecated
*/
FutureRowCount<T> findFutureRowCount();
/**
@@ -237,7 +279,7 @@ public interface ExpressionList<T> {
* execution status (isDone etc) and get the value (with or without a
* timeout).
* </p>
*
*
* @return a Future object for the list of Id's
*/
FutureIds<T> findFutureIds();
@@ -249,7 +291,7 @@ public interface ExpressionList<T> {
* 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
*/
FutureList<T> findFutureList();
@@ -312,7 +354,7 @@ public interface ExpressionList<T> {
/**
* Specify specific properties to fetch on the main/root bean (aka partial
* object).
*
*
* @see Query#select(String)
*/
Query<T> select(String properties);
@@ -337,28 +379,28 @@ public interface ExpressionList<T> {
/**
* Set the first row to fetch.
*
*
* @see Query#setFirstRow(int)
*/
Query<T> setFirstRow(int firstRow);
/**
* Set the maximum number of rows to fetch.
*
*
* @see Query#setMaxRows(int)
*/
Query<T> setMaxRows(int maxRows);
/**
* Set the name of the property which values become the key of a map.
*
*
* @see Query#setMapKey(String)
*/
Query<T> setMapKey(String mapKey);
/**
* Set to true to use the query for executing this query.
*
*
* @see Query#setUseCache(boolean)
*/
Query<T> setUseCache(boolean useCache);
@@ -619,7 +661,7 @@ public interface ExpressionList<T> {
* To get control over the options you can create an ExampleExpression and set
* those options such as case insensitive etc.
* </p>
*
*
* <pre>{@code
*
* // create an example bean and set the properties
@@ -627,26 +669,26 @@ public interface ExpressionList<T> {
* Customer example = new Customer();
* example.setName("Rob%");
* example.setNotes("%something%");
*
*
* List&lt;Customer&gt; list = Ebean.find(Customer.class).where()
* // pass the bean into the where() clause
* .exampleLike(example)
* // you can add other expressions to the same query
* .gt("id", 2).findList();
*
*
* }</pre>
*
*
* Similarly you can create an ExampleExpression
*
*
* <pre>{@code
*
* Customer example = new Customer();
* example.setName("Rob%");
* example.setNotes("%something%");
*
*
* // create a ExampleExpression with more control
* ExampleExpression qbe = new ExampleExpression(example, true, LikeType.EQUAL_TO).includeZeros();
*
*
* List<Customer> list = Ebean.find(Customer.class).where().add(qbe).findList();
*
* }</pre>
@@ -748,7 +790,7 @@ public interface ExpressionList<T> {
* Exists expression
*/
ExpressionList<T> exists(Query<?> subQuery);
/**
* Not exists expression
*/
@@ -775,7 +817,7 @@ public interface ExpressionList<T> {
* Expression where all the property names in the map are equal to the
* corresponding value.
* </p>
*
*
* @param propertyMap
* a map keyed by property names.
*/
@@ -925,7 +967,7 @@ public interface ExpressionList<T> {
* This is exactly the same as conjunction();
* </p>
* <p>
* Use endJunction() to end the AND junction.
* Use endAnd() or endJunction() to end the AND junction.
* </p>
* <p>
* Note that a where() clause defaults to an AND junction so
@@ -943,11 +985,11 @@ public interface ExpressionList<T> {
* .and() // nested and
* .startsWith("name", "r")
* .eq("anniversary", onAfter)
* .endJunction() // end AND junction
* .endAnd()
* .and()
* .eq("status", Customer.Status.ACTIVE)
* .gt("id", 0)
* .endJunction() // end AND junction
* .endAnd()
* .orderBy().asc("name")
* .findList();
* }</pre>
@@ -959,7 +1001,7 @@ public interface ExpressionList<T> {
* This is exactly the same as disjunction();
*
* <p>
* Use endJunction() to end the OR junction.
* Use endOr() or endJunction() to end the OR junction.
* </p>
*
* <pre>{@code
@@ -973,11 +1015,11 @@ public interface ExpressionList<T> {
* .and()
* .startsWith("name", "r")
* .eq("anniversary", onAfter)
* .endJunction() // end AND junction
* .endAnd()
* .and()
* .eq("status", Customer.Status.ACTIVE)
* .gt("id", 0)
* .endJunction() // end AND junction
* .endAnd()
* .orderBy().asc("name")
* .findList();
*
@@ -988,7 +1030,7 @@ public interface ExpressionList<T> {
/**
* Return a list of expressions that will be wrapped by NOT.
* <p>
* Use endJunction() to end expressions being added to the
* Use endNot() or endJunction() to end expressions being added to the
* NOT expression list.
* </p>
*
@@ -998,7 +1040,7 @@ public interface ExpressionList<T> {
* .not()
* .gt("id", 1)
* .eq("anniversary", onAfter)
* .endJunction() // end the not expressions
* .endNot()
*
* }</pre>
*
@@ -1012,7 +1054,7 @@ public interface ExpressionList<T> {
* .not()
* .gt("id", 1)
* .eq("anniversary", onAfter)
* .endJunction() // end the not expressions
* .endNot()
* .orderBy()
* .asc("name")
* .findList();
@@ -1085,4 +1127,19 @@ public interface ExpressionList<T> {
*/
ExpressionList<T> endJunction();
/**
* End a AND junction - synonym for endJunction().
*/
ExpressionList<T> endAnd();
/**
* End a AND junction - synonym for endJunction().
*/
ExpressionList<T> endOr();
/**
* End a NOT junction - synonym for endJunction().
*/
ExpressionList<T> endNot();
}
@@ -29,8 +29,7 @@ import java.io.Serializable;
* // 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
* Example: Using a "query join" instead of a "fetch join" we instead use 2 SQL queries
* </p>
*
* <pre>{@code
@@ -117,7 +116,7 @@ import java.io.Serializable;
* <pre>{@code
* List<Order> list = Ebean.find(Order.class)
* .fetch("customer","name", new FetchConfig().lazy(5))
* .fetch("customer.contacts",&quotcontactName, phone, email&quot)
* .fetch("customer.contacts","contactName, phone, email")
* .fetch("customer.shippingAddress")
* .where().eq("status",Order.Status.NEW)
* .findList();
@@ -125,12 +124,7 @@ import java.io.Serializable;
* // 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 (?,?,?,?,?)
* // .. use a batch size of 5 to load the customers
*
* }</pre>
*
@@ -9,8 +9,6 @@ import java.util.concurrent.Future;
* 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>> {
@@ -19,16 +17,4 @@ public interface FutureIds<T> extends Future<List<Object>> {
*/
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();
}
+21 -11
View File
@@ -59,11 +59,11 @@ package com.avaje.ebean;
* .and()
* .startsWith("name", "r")
* .eq("anniversary", onAfter)
* .endJunction()
* .endAnd()
* .and()
* .eq("status", Customer.Status.ACTIVE)
* .gt("id", 0)
* .endJunction()
* .endAnd()
* .order().asc("name");
*
* q.findList();
@@ -84,39 +84,41 @@ public interface Junction<T> extends Expression, ExpressionList<T> {
/**
* AND group.
*/
AND(" and ", ""),
AND(" and ", "", false),
/**
* OR group.
*/
OR(" or ", ""),
OR(" or ", "", false),
/**
* NOT group.
*/
NOT(" and ", "not "),
NOT(" and ", "not ", false),
/**
* Text search AND group.
*/
MUST("must", ""),
MUST("must", "", true),
/**
* Text search NOT group.
*/
MUST_NOT("must_not", ""),
MUST_NOT("must_not", "", true),
/**
* Text search OR group.
*/
SHOULD("should", "");
SHOULD("should", "", true);
String prefix;
String literal;
private String prefix;
private String literal;
private boolean text;
Type(String literal, String prefix) {
Type(String literal, String prefix, boolean text) {
this.literal = literal;
this.prefix = prefix;
this.text = text;
}
/**
@@ -132,6 +134,14 @@ public interface Junction<T> extends Expression, ExpressionList<T> {
public String prefix() {
return prefix;
}
/**
* Return true if this is a text type.
*/
public boolean isText() {
return text;
}
}
}
+24 -17
View File
@@ -495,7 +495,7 @@ public abstract class Model {
/**
* Return typically a different EbeanServer to the default.
* <p>
* This is equivilent to {@link Ebean#getServer(String)}
* This is equivalent to {@link Ebean#getServer(String)}
*
* @param server
* The name of the EbeanServer. If this is null then the default EbeanServer is
@@ -598,7 +598,7 @@ public abstract class Model {
* <p>
* Equivalent to {@link Query#findIds()}
*/
public List<Object> findIds() {
public <A> List<A> findIds() {
return query().findIds();
}
@@ -660,36 +660,43 @@ public abstract class Model {
* <p>
* Equivalent to {@link Query#findMap()}
*/
public Map<?, T> findMap() {
public <K> Map<K, T> findMap() {
return query().findMap();
}
/**
* Executes the query and returns the results as a map of the objects specifying the map key
* property.
* <p>
* Equivalent to {@link Query#findMap(String, Class)}
*/
public <K> Map<K, T> findMap(String keyProperty, Class<K> keyType) {
return query().findMap(keyProperty, keyType);
}
/**
* Executes a find row count query in a background thread.
* <p>
* Equivalent to {@link Query#findFutureRowCount()}
* Equivalent to {@link Query#findFutureCount()}
*/
public FutureRowCount<T> findFutureCount() {
return query().findFutureCount();
}
/**
* Deprecated in favor of findFutureCount().
* <p>
* Equivalent to {@link Query#findFutureCount()}
*/
public FutureRowCount<T> findFutureRowCount() {
return query().findFutureRowCount();
return query().findFutureCount();
}
/**
* Returns the total number of entities for this type. *
* <p>
* Equivalent to {@link Query#findRowCount()}
* Equivalent to {@link Query#findCount()}
*/
public int findCount() {
return query().findCount();
}
/**
* Deprecated in favor of findCount().
* @deprecated
*/
public int findRowCount() {
return query().findRowCount();
return query().findCount();
}
/**
+10 -2
View File
@@ -148,6 +148,13 @@ public final class OrderBy<T> implements Serializable {
return copy;
}
/**
* Add to the order by by parsing a raw expression.
*/
public void add(String rawExpression) {
parse(rawExpression);
}
/**
* Add a property to the order by.
*/
@@ -206,8 +213,9 @@ public final class OrderBy<T> implements Serializable {
* order by clause and replace.
* </p>
*/
public void clear() {
public OrderBy<T> clear() {
list.clear();
return this;
}
/**
@@ -400,6 +408,6 @@ public final class OrderBy<T> implements Serializable {
}
private boolean isEmptyString(String s) {
return s == null || s.length() == 0;
return s == null || s.isEmpty();
}
}
@@ -110,6 +110,13 @@ public interface PagedList<T> {
* wrapped in the unchecked PersistenceException (which might be preferrable).
* </p>
*/
void loadCount();
/**
* Deprecated in favor of loadCount().
*
* @deprecated
*/
void loadRowCount();
/**
@@ -138,6 +145,13 @@ public interface PagedList<T> {
*
* }</pre>
*/
Future<Integer> getFutureCount();
/**
* Deprecated in favor of getFutureCount().
*
* @deprecated
*/
Future<Integer> getFutureRowCount();
/**
@@ -170,6 +184,13 @@ public interface PagedList<T> {
*
* }</pre>
*/
int getTotalCount();
/**
* Deprecated in favor of getTotalCount().
*
* @deprecated
*/
int getTotalRowCount();
/**
@@ -78,6 +78,6 @@ class PrimaryServer {
* Return true if the string is null or empty.
*/
private static boolean isEmpty(String value) {
return value == null || value.trim().length() == 0;
return value == null || value.trim().isEmpty();
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,67 @@
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>
* <p>
* Note that findIterate (and findEach and findEachWhile) uses a "per graph"
* persistence context scope and adjusts jdbc fetch buffer size for large
* queries. As such it is better to use findList for small queries.
* </p>
* <p>
* Remember that with {@link QueryIterator} you must call {@link QueryIterator#close()}
* when you have finished iterating the results (typically in a finally block).
* </p>
*
* <pre>{@code
*
* Query<Customer> query = server.find(Customer.class)
* .where().gt("id", 0)
* .orderBy("id")
* .setMaxRows(2);
*
* QueryIterator<Customer> it = query.findIterate();
* try {
* while (it.hasNext()) {
* Customer customer = it.next();
* // do something with customer ...
* }
* } finally {
* // close the underlying resources
* it.close();
* }
*
* }</pre>
*
* @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();
}
+12 -12
View File
@@ -404,7 +404,7 @@ public final class RawSql implements Serializable {
this.dbColumnMap = new LinkedHashMap<String, Column>();
for (int i = 0; i < columns.size(); i++) {
Column c = columns.get(i);
dbColumnMap.put(c.getDbColumn(), c);
dbColumnMap.put(c.getDbColumnKey(), c);
}
}
@@ -500,8 +500,7 @@ public final class RawSql implements Serializable {
} else {
Column column = dbColumnMap.get(dbColumn);
if (column == null) {
String msg = "DB Column [" + dbColumn + "] not found in mapping. Expecting one of ["
+ dbColumnMap.keySet() + "]";
String msg = "DB Column [" + dbColumn + "] not found in mapping. Expecting one of [" + dbColumnMap.keySet() + "]";
throw new IllegalArgumentException(msg);
}
column.setPropertyName(propertyName);
@@ -607,9 +606,9 @@ public final class RawSql implements Serializable {
}
}
private static String derivePropertyName(String dbAlias, String dbColumn) {
protected static String derivePropertyName(String dbAlias, String dbColumn) {
if (dbAlias != null) {
return dbAlias;
return CamelCaseHelper.toCamelFromUnderscore(dbAlias);
}
int dotPos = dbColumn.indexOf('.');
if (dotPos > -1) {
@@ -657,6 +656,14 @@ public final class RawSql implements Serializable {
return indexPos;
}
/**
* Return the DB column alias if specified otherwise DB column.
* This is used as the key for mapping a column to a logical property.
*/
public String getDbColumnKey() {
return (dbAlias != null) ? dbAlias : dbColumn;
}
/**
* Return the DB column name including table alias (if it has one).
*/
@@ -664,13 +671,6 @@ public final class RawSql implements Serializable {
return dbColumn;
}
/**
* Return the DB column alias (if it has one).
*/
public String getDbAlias() {
return dbAlias;
}
/**
* Return the bean property this column is mapped to.
*/
@@ -2,8 +2,6 @@ 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.
+3 -4
View File
@@ -26,7 +26,7 @@ package com.avaje.ebean;
*
* int modifiedCount = Ebean.execute(update);
*
* String msg = &quot;There where &quot; + modifiedCount + &quot;rows updated&quot;
* String msg = &quot;There were &quot; + modifiedCount + &quot; rows updated&quot;
* </pre>
*
* @see Update
@@ -117,8 +117,7 @@ public interface SqlUpdate {
SqlUpdate setParameter(int position, Object value);
/**
* Set a null parameter via its index position. Exactly the same as
* {@link #setNull(int, int)}.
* Set a null parameter via its index position.
*/
SqlUpdate setNull(int position, int jdbcType);
@@ -143,4 +142,4 @@ public interface SqlUpdate {
*/
SqlUpdate setNullParameter(String name, int jdbcType);
}
}
+120 -6
View File
@@ -3,6 +3,7 @@ package com.avaje.ebean;
import com.avaje.ebean.annotation.DocStoreMode;
import com.avaje.ebean.config.DocStoreConfig;
import com.avaje.ebean.config.PersistBatch;
import com.avaje.ebean.config.ServerConfig;
import javax.persistence.PersistenceException;
import javax.persistence.RollbackException;
@@ -53,13 +54,52 @@ public interface Transaction extends Closeable {
*/
void setReadOnly(boolean readOnly);
/**
* Commits the transaction at this point with the expectation that another
* commit (or rollback or end) will occur later to complete the transaction.
* <p>
* This is similar to commit() but leaves the transaction "Active".
* </p>
* <h3>Functions/h3>
* <ul>
* <li>Flush the JDBC batch buffer</li>
* <li>Call commit on the underlying JDBC connection</li>
* <li>Trigger any registered TransactionCallbacks</li>
* <li>Perform post-commit processing updating L2 cache, ElasticSearch etc</li>
* </ul>
*/
void commitAndContinue() throws RollbackException;
/**
* Commit the transaction.
* <p>
* This performs commit and completes the transaction closing underlying resources and
* marking the transaction as "In active".
* </p>
* <h3>Functions/h3>
* <ul>
* <li>Flush the JDBC batch buffer</li>
* <li>Call commit on the underlying JDBC connection</li>
* <li>Trigger any registered TransactionCallbacks</li>
* <li>Perform post-commit processing updating L2 cache, ElasticSearch etc</li>
* <li>Close any underlying resources, closing the underlying JDBC connection</li>
* <li>Mark the transaction as "Inactive"</li>
* </ul>
*/
void commit() throws RollbackException;
/**
* Rollback the transaction.
* <p>
* This performs rollback, closes underlying resources and marks the transaction as "In active".
* </p>
* <h3>Functions/h3>
* <ul>
* <li>Call rollback on the underlying JDBC connection</li>
* <li>Trigger any registered TransactionCallbacks</li>
* <li>Close any underlying resources, closing the underlying JDBC connection</li>
* <li>Mark the transaction as "Inactive"</li>
* </ul>
*/
void rollback() throws PersistenceException;
@@ -73,6 +113,16 @@ public interface Transaction extends Closeable {
*/
void rollback(Throwable e) throws PersistenceException;
/**
* Mark the transaction for rollback only.
*/
void setRollbackOnly();
/**
* Return true if the transaction is marked as rollback only.
*/
boolean isRollbackOnly();
/**
* If the transaction is active then perform rollback. Otherwise do nothing.
*/
@@ -125,13 +175,78 @@ public interface Transaction extends Closeable {
* Set to true when you want all loaded properties to be included in the update
* (rather than just the changed properties).
* <p>
* You might set this when using JDBC batch in order to get multiple updates
* with slightly different sets of changed properties into the same statement
* and hence better JDBC batch performance.
* You might set this when using JDBC batch in order to get multiple updates
* with slightly different sets of changed properties into the same statement
* and hence better JDBC batch performance.
* </p>
*/
void setUpdateAllLoadedProperties(boolean updateAllLoadedProperties);
/**
* Set if the L2 cache should be skipped for "find by id" and "find by natural key" queries.
* <p>
* By default {@link ServerConfig#isSkipCacheAfterWrite()} is true and that means that for
* "find by id" and "find by natural key" queries which normally hit L2 bean cache automatically
* - will not do so after a persist/write on the transaction.
* </p>
* <p>
* This method provides explicit control over whether "find by id" and "find by natural key"
* will skip the L2 bean cache or not (regardless of whether the transaction is considered "read only").
* </p>
* <p>
* Refer to {@link ServerConfig#setSkipCacheAfterWrite(boolean)} for configuring the default behavior
* for using the L2 bean cache in transactions spanning multiple query/persist requests.
* </p>
*
* <pre>{@code
*
* // assume Customer has L2 bean caching enabled ...
*
* Transaction transaction = Ebean.beginTransaction();
* try {
*
* // this uses L2 bean cache as the transaction
* // ... is considered "query only" at this point
* Customer.find.byId(42);
*
* // transaction no longer "query only" once
* // ... a bean has been saved etc
* Ebean.save(someBean);
*
* // will NOT use L2 bean cache as the transaction
* // ... is no longer considered "query only"
* Customer.find.byId(55);
*
*
*
* // explicit control - please use L2 bean cache
*
* transaction.setSkipCache(false);
* Customer.find.byId(77); // hit the l2 bean cache
*
*
* // explicit control - please don't use L2 bean cache
*
* transaction.setSkipCache(true);
* Customer.find.byId(99); // skips l2 bean cache
*
*
* } finally {
* transaction.end();
* }
*
* }</pre>
*
* @see ServerConfig#isSkipCacheAfterWrite()
*/
void setSkipCache(boolean skipCache);
/**
* Return true if the L2 cache should be skipped. More accurately if true then find by id
* and find by natural key queries should NOT automatically use the L2 bean cache.
*/
boolean isSkipCache();
/**
* Turn on or off statement batching. Statement batching can be transparent
* for drivers and databases that support getGeneratedKeys. Otherwise you may
@@ -351,9 +466,8 @@ public interface Transaction extends Closeable {
/**
* 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}.
* impact on any internals of ebean and are solely meant as a convenient
* method push user information (although somewhat replaced by TransactionCallback).
*/
void putUserObject(String name, Object value);
+39 -22
View File
@@ -16,7 +16,7 @@ import java.util.ArrayList;
* This object is used internally with the enhancement of a method with
* Transactional annotation.
* </p>
*
*
* @see TxCallable
* @see TxRunnable
* @see Ebean#execute(TxScope, TxCallable)
@@ -44,27 +44,6 @@ public final class TxScope {
ArrayList<Class<? extends Throwable>> noRollbackFor;
/**
* Return true if PersistBatch has been set.
*/
public boolean isBatchSet() {
return batch != null && batch != PersistBatch.INHERIT;
}
/**
* Return true if batch on cascade has been set.
*/
public boolean isBatchOnCascadeSet() {
return batchOnCascade != null && batchOnCascade != PersistBatch.INHERIT;
}
/**
* Return true if batch size has been set.
*/
public boolean isBatchSizeSet() {
return batchSize > 0;
}
/**
* Helper method to create a TxScope with REQUIRES.
*/
@@ -130,6 +109,44 @@ public final class TxScope {
+ "] rollbackFor[" + rollbackFor + "] noRollbackFor[" + noRollbackFor + "]";
}
/**
* Return true if PersistBatch has been set.
*/
public boolean isBatchSet() {
return batch != null && batch != PersistBatch.INHERIT;
}
/**
* Return true if batch on cascade has been set.
*/
public boolean isBatchOnCascadeSet() {
return batchOnCascade != null && batchOnCascade != PersistBatch.INHERIT;
}
/**
* Return true if batch size has been set.
*/
public boolean isBatchSizeSet() {
return batchSize > 0;
}
/**
* Check for batchSize being set without batch mode and use this to imply PersistBatch.ALL.
*/
public void checkBatchMode() {
if (batchSize > 0 && notSet(batch) && notSet(batchOnCascade)) {
// Use setting the batchSize as implying PersistBatch.ALL for @Transactional
batch = PersistBatch.ALL;
}
}
/**
* Return true if the mode is considered not set.
*/
private boolean notSet(PersistBatch batchMode) {
return batchMode == null || batchMode == PersistBatch.INHERIT;
}
/**
* Return the transaction type.
*/
@@ -31,6 +31,11 @@ public interface BeanCollection<E> extends Serializable {
ALL
}
/**
* Set the disableLazyLoad state.
*/
void setDisableLazyLoad(boolean disableLazyLoad);
/**
* Load bean from another collection.
*/
@@ -39,6 +39,8 @@ public final class EntityBeanIntercept implements Serializable {
private transient BeanLoader beanLoader;
private transient PreGetterCallback preGetterCallback;
private String ebeanServerName;
/**
@@ -186,6 +188,21 @@ public final class EntityBeanIntercept implements Serializable {
return embeddedOwnerIndex;
}
/**
* Clear the getter callback.
*/
public void clearGetterCallback() {
this.preGetterCallback = null;
}
/**
* Register the callback to be triggered when getter is called.
* This is used primarily to automatically flush the JDBC batch.
*/
public void registerGetterCallback(PreGetterCallback getterCallback) {
this.preGetterCallback = getterCallback;
}
/**
* Set the embedded beans owning bean.
*/
@@ -325,6 +342,13 @@ public final class EntityBeanIntercept implements Serializable {
return state == STATE_LOADED;
}
/**
* Set the bean into NEW state.
*/
public void setNew() {
this.state = STATE_NEW;
}
/**
* Set the loaded state to true.
* <p>
@@ -832,19 +856,31 @@ public final class EntityBeanIntercept implements Serializable {
public void initialisedMany(int propertyIndex) {
loadedProps[propertyIndex] = true;
}
private final void preGetterCallback() {
if (preGetterCallback != null) {
preGetterCallback.preGetterTrigger();
}
}
/**
* Called prior to Id property getter.
*/
public void preGetId() {
preGetterCallback();
}
/**
* Method that is called prior to a getter method on the actual entity.
*/
public void preGetter(int propertyIndex) {
preGetterCallback();
if (state == STATE_NEW || disableLazyLoad) {
return;
}
if (!isLoadedProperty(propertyIndex)) {
loadBean(propertyIndex);
}
if (nodeUsageCollector != null) {
nodeUsageCollector.addUsed(getProperty(propertyIndex));
}
@@ -0,0 +1,13 @@
package com.avaje.ebean.bean;
/**
* A callback that can be registered to fire on getter method calls.
* It's primary purpose is to automatically flush JDBC batch buffer.
*/
public interface PreGetterCallback {
/**
* Trigger the callback.
*/
void preGetterTrigger();
}
@@ -5,6 +5,15 @@ package com.avaje.ebean.cache;
*/
public interface ServerCacheManager {
/**
* Return true if the L2 caching is local.
* <p>
* Local L2 caching means that the cache updates should occur in foreground
* rather than background processing.
* </p>
*/
boolean isLocalL2Caching();
/**
* Return true if there is an active bean cache for this type of bean.
*/
@@ -20,6 +20,8 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
protected boolean readOnly;
protected boolean disableLazyLoad;
/**
* The EbeanServer this is associated with. (used for lazy fetch).
*/
@@ -84,6 +86,11 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
this.filterMany = filterMany;
}
@Override
public void setDisableLazyLoad(boolean disableLazyLoad) {
this.disableLazyLoad = disableLazyLoad;
}
protected void lazyLoadCollection(boolean onlyIds) {
if (loader == null) {
loader = (BeanCollectionLoader) Ebean.getServer(ebeanServerName);
@@ -102,7 +102,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
private void initClear() {
synchronized (this) {
if (list == null) {
if (modifyListening) {
if (!disableLazyLoad && modifyListening) {
lazyLoadCollection(true);
} else {
list = new ArrayList<E>();
@@ -114,7 +114,11 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
private void init() {
synchronized (this) {
if (list == null) {
lazyLoadCollection(false);
if (disableLazyLoad) {
list = new ArrayList<E>();
} else {
lazyLoadCollection(false);
}
}
}
}
@@ -274,7 +274,7 @@ public abstract class AbstractNamingConvention implements NamingConvention {
* Checks string is null or empty .
*/
protected boolean isEmpty(String s) {
return s == null || s.trim().length() == 0;
return s == null || s.trim().isEmpty();
}
/**
@@ -83,7 +83,6 @@ public class DocStoreConfig {
if (systemValue != null) {
return systemValue;
}
return url;
}
@@ -100,6 +99,10 @@ public class DocStoreConfig {
* Return true if Ebean should generate mapping files on server startup.
*/
public boolean isGenerateMapping() {
String systemValue = System.getProperty("ebean.docstore.generateMapping");
if (systemValue != null) {
return Boolean.parseBoolean(systemValue);
}
return generateMapping;
}
@@ -114,6 +117,10 @@ public class DocStoreConfig {
* Return true if the document store should recreate mapped indexes.
*/
public boolean isDropCreate() {
String systemValue = System.getProperty("ebean.docstore.dropCreate");
if (systemValue != null) {
return Boolean.parseBoolean(systemValue);
}
return dropCreate;
}
@@ -129,6 +136,10 @@ public class DocStoreConfig {
* This is only used if dropCreate is false.
*/
public boolean isCreate() {
String systemValue = System.getProperty("ebean.docstore.create");
if (systemValue != null) {
return Boolean.parseBoolean(systemValue);
}
return create;
}
@@ -14,7 +14,6 @@ import com.avaje.ebean.event.BeanPostLoad;
import com.avaje.ebean.event.BeanQueryAdapter;
import com.avaje.ebean.event.BulkTableEventListener;
import com.avaje.ebean.event.ServerConfigStartup;
import com.avaje.ebean.event.TransactionEventListener;
import com.avaje.ebean.event.changelog.ChangeLogListener;
import com.avaje.ebean.event.changelog.ChangeLogPrepare;
import com.avaje.ebean.event.changelog.ChangeLogRegister;
@@ -47,23 +46,16 @@ import java.util.ServiceLoader;
* </p>
*
* <pre>{@code
*
* ServerConfig c = new ServerConfig();
* c.setName("ordh2");
* c.setName("db");
*
* // read the ebean.properties and load
* // those settings into this serverConfig object
* c.loadFromProperties();
*
* // generate DDL and run it
* c.setDdlGenerate(true);
* c.setDdlRun(true);
*
* // add any classes found in the app.data package
* c.addPackage("app.data");
*
* // add the names of Jars that contain entities
* c.addJar("myJarContainingEntities.jar");
* c.addJar("someOtherJarContainingEntities.jar");
* c.addPackage("com.myapp.domain");
*
* // register as the 'Default' server
* c.setDefaultServer(true);
@@ -128,17 +120,6 @@ public class ServerConfig {
*/
private List<String> packages = new ArrayList<String>();
/**
* The names of Jar files that are searched for entities and other interesting
* classes. Only used when classes is empty/not explicitly specified.
*/
private List<String> searchJars = new ArrayList<String>();
/**
* Class name of a classPathReader implementation.
*/
private String classPathReaderClassName;
/**
* Configuration for the ElasticSearch integration.
*/
@@ -181,6 +162,17 @@ public class ServerConfig {
*/
private int databaseSequenceBatchSize = 20;
/**
* JDBC fetchSize hint when using findList. Defaults to 0 leaving it up to the JDBC driver.
*/
private int jdbcFetchSizeFindList;
/**
* JDBC fetchSize hint when using findEach/findEachWhile. Defaults to 100. Note that this does
* not apply to MySql as that gets special treatment (forward only etc).
*/
private int jdbcFetchSizeFindEach = 100;
/**
* Suffix appended to the base table to derive the view that contains the union
* of the base table and the history table in order to support asOf queries.
@@ -205,9 +197,11 @@ public class ServerConfig {
private PersistBatch persistBatch = PersistBatch.NONE;
/**
* Use for per request batch mode.
* Use for cascade persist JDBC batch mode. INHERIT means use the platform default
* which is ALL except for SQL Server where it is NONE (as getGeneratedKeys isn't
* supported on SQL Server with JDBC batch).
*/
private PersistBatch persistBatchOnCascade = PersistBatch.NONE;
private PersistBatch persistBatchOnCascade = PersistBatch.INHERIT;
private int persistBatchSize = 20;
@@ -238,6 +232,11 @@ public class ServerConfig {
private String ddlSeedSql;
/**
* When true L2 bean cache use is skipped after a write has occurred on a transaction.
*/
private boolean skipCacheAfterWrite = true;
private boolean useJtaTransactionManager;
/**
@@ -320,7 +319,7 @@ public class ServerConfig {
/**
* Setting to indicate if UUID should be stored as binary(16) or varchar(40) or native DB type (for H2 and Postgres).
*/
private DbUuid dbUuid = DbUuid.AUTO;
private DbUuid dbUuid = DbUuid.AUTO_VARCHAR;
private List<IdGenerator> idGenerators = new ArrayList<IdGenerator>();
@@ -331,7 +330,6 @@ public class ServerConfig {
private List<BeanQueryAdapter> queryAdapters = new ArrayList<BeanQueryAdapter>();
private List<BulkTableEventListener> bulkTableEventListeners = new ArrayList<BulkTableEventListener>();
private List<ServerConfigStartup> configStartupListeners = new ArrayList<ServerConfigStartup>();
private List<TransactionEventListener> transactionEventListeners = new ArrayList<TransactionEventListener>();
/**
* By default inserts are included in the change log.
@@ -379,19 +377,13 @@ public class ServerConfig {
private boolean transactionRollbackOnChecked = true;
private boolean registerJmxMBeans = true;
// configuration for the background executor service (thread pool)
private int backgroundExecutorSchedulePoolSize = 1;
private int backgroundExecutorCorePoolSize = 1;
private int backgroundExecutorMaxPoolSize = 8;
private int backgroundExecutorIdleSecs = 60;
private int backgroundExecutorShutdownSecs = 30;
// defaults for the L2 bean caching
private int cacheWarmingDelay = 30;
private int cacheMaxSize = 10000;
private int cacheMaxIdleTime = 600;
private int cacheMaxTimeToLive = 60 * 60 * 6;
@@ -409,7 +401,7 @@ public class ServerConfig {
private boolean expressionEqualsWithNullAsNoop;
/**
* Set to true to use native ILIKE expression (if support by datasbase platform / like Postgres).
* Set to true to use native ILIKE expression (if support by database platform / like Postgres).
*/
private boolean expressionNativeIlike;
@@ -732,6 +724,34 @@ public class ServerConfig {
this.databaseSequenceBatchSize = databaseSequenceBatchSize;
}
/**
* Return the default JDBC fetchSize hint for findList queries.
*/
public int getJdbcFetchSizeFindList() {
return jdbcFetchSizeFindList;
}
/**
* Set the default JDBC fetchSize hint for findList queries.
*/
public void setJdbcFetchSizeFindList(int jdbcFetchSizeFindList) {
this.jdbcFetchSizeFindList = jdbcFetchSizeFindList;
}
/**
* Return the default JDBC fetchSize hint for findEach/findEachWhile queries.
*/
public int getJdbcFetchSizeFindEach() {
return jdbcFetchSizeFindEach;
}
/**
* Set the default JDBC fetchSize hint for findEach/findEachWhile queries.
*/
public void setJdbcFetchSizeFindEach(int jdbcFetchSizeFindEach) {
this.jdbcFetchSizeFindEach = jdbcFetchSizeFindEach;
}
/**
* Return the ChangeLogPrepare.
* <p>
@@ -1014,20 +1034,6 @@ public class ServerConfig {
this.transactionRollbackOnChecked = transactionRollbackOnChecked;
}
/**
* Return true if the server should register JMX MBeans.
*/
public boolean isRegisterJmxMBeans() {
return registerJmxMBeans;
}
/**
* Set if the server should register JMX MBeans.
*/
public void setRegisterJmxMBeans(boolean registerJmxMBeans) {
this.registerJmxMBeans = registerJmxMBeans;
}
/**
* Return the Background executor schedule pool size. Defaults to 1.
*/
@@ -1042,48 +1048,6 @@ public class ServerConfig {
this.backgroundExecutorSchedulePoolSize = backgroundExecutorSchedulePoolSize;
}
/**
* Return the Background executor core pool size.
*/
public int getBackgroundExecutorCorePoolSize() {
return backgroundExecutorCorePoolSize;
}
/**
* Set the Background executor core pool size.
*/
public void setBackgroundExecutorCorePoolSize(int backgroundExecutorCorePoolSize) {
this.backgroundExecutorCorePoolSize = backgroundExecutorCorePoolSize;
}
/**
* Return the Background executor max pool size.
*/
public int getBackgroundExecutorMaxPoolSize() {
return backgroundExecutorMaxPoolSize;
}
/**
* Set the Background executor max pool size.
*/
public void setBackgroundExecutorMaxPoolSize(int backgroundExecutorMaxPoolSize) {
this.backgroundExecutorMaxPoolSize = backgroundExecutorMaxPoolSize;
}
/**
* Return the Background executor idle seconds.
*/
public int getBackgroundExecutorIdleSecs() {
return backgroundExecutorIdleSecs;
}
/**
* Set the Background executor idle seconds.
*/
public void setBackgroundExecutorIdleSecs(int backgroundExecutorIdleSecs) {
this.backgroundExecutorIdleSecs = backgroundExecutorIdleSecs;
}
/**
* Return the Background executor shutdown seconds. This is the time allowed for the pool to shutdown nicely
* before it is forced shutdown.
@@ -1100,20 +1064,6 @@ public class ServerConfig {
this.backgroundExecutorShutdownSecs = backgroundExecutorShutdownSecs;
}
/**
* Return the cache warming delay in seconds.
*/
public int getCacheWarmingDelay() {
return cacheWarmingDelay;
}
/**
* Set the cache warming delay in seconds.
*/
public void setCacheWarmingDelay(int cacheWarmingDelay) {
this.cacheWarmingDelay = cacheWarmingDelay;
}
/**
* Return the L2 cache default max size.
*/
@@ -1790,67 +1740,6 @@ public class ServerConfig {
this.packages = packages;
}
/**
* Add the name of a Jar to search for entities via class path search.
* <p>
* This is only used if classes have not been explicitly specified.
* </p>
* <p>
* If you are using ebean.properties you can specify jars to search by setting
* a ebean.search.jars property.
* </p>
*
* <pre>{@code
* # EBean will search through classes for entities, but will not search jar files
* # unless you tell it to do so, for performance reasons. Set this value to a
* # comma-delimited list of jar files you want ebean to search.
* ebean.search.jars=example.jar
* }</pre>
*/
public void addJar(String jarName) {
if (searchJars == null) {
searchJars = new ArrayList<String>();
}
searchJars.add(jarName);
}
/**
* Return packages to search for entities via class path search.
* <p>
* This is only used if classes have not been explicitly specified.
* </p>
*/
public List<String> getJars() {
return searchJars;
}
/**
* Set the names of Jars to search for entities via class path search.
* <p>
* This is only used if classes have not been explicitly specified.
* </p>
*/
public void setJars(List<String> searchJars) {
this.searchJars = searchJars;
}
/**
* Return the class name of a classPathReader implementation.
*/
public String getClassPathReaderClassName() {
return classPathReaderClassName;
}
/**
* Set the class name of a classPathReader implementation.
* <p>
* Refer to server.util.ClassPathReader, this should really by a plugin but doing this for now
* to be relatively compatible with current implementation.
*/
public void setClassPathReaderClassName(String classPathReaderClassName) {
this.classPathReaderClassName = classPathReaderClassName;
}
/**
* Set the list of classes (entities, listeners, scalarTypes etc) that should
* be used for this server.
@@ -1874,6 +1763,66 @@ public class ServerConfig {
return classes;
}
/**
* Return true if L2 bean cache should be skipped once writes have occurred on a transaction.
* <p>
* This defaults to true and means that for "find by id" and "find by natural key"
* queries that normally hit L2 bean cache automatically will not do so after a write/persist
* on the transaction.
* </p>
*
* <pre>{@code
*
* // assume Customer has L2 bean caching enabled ...
*
* Transaction transaction = Ebean.beginTransaction();
* try {
*
* // this uses L2 bean cache as the transaction
* // ... is considered "query only" at this point
* Customer.find.byId(42);
*
* // transaction no longer "query only" once
* // ... a bean has been saved etc
* Ebean.save(someBean);
*
* // will NOT use L2 bean cache as the transaction
* // ... is no longer considered "query only"
* Customer.find.byId(55);
*
*
*
* // explicit control - please use L2 bean cache
*
* transaction.setSkipCache(false);
* Customer.find.byId(77); // hit the l2 bean cache
*
*
* // explicit control - please don't use L2 bean cache
*
* transaction.setSkipCache(true);
* Customer.find.byId(99); // skips l2 bean cache
*
*
* } finally {
* transaction.end();
* }
*
* }</pre>
*
* @see com.avaje.ebean.Transaction#setSkipCache(boolean)
*/
public boolean isSkipCacheAfterWrite() {
return skipCacheAfterWrite;
}
/**
* Set to false when we still want to hit the cache after a write has occurred on a transaction.
*/
public void setSkipCacheAfterWrite(boolean skipCacheAfterWrite) {
this.skipCacheAfterWrite = skipCacheAfterWrite;
}
/**
* Return true to only update changed properties.
*/
@@ -2101,35 +2050,6 @@ public class ServerConfig {
this.persistControllers = persistControllers;
}
/**
* Register a TransactionEventListener instance
* <p>
* Note alternatively you can use {@link #setTransactionEventListeners(List)}
* to set all the TransactionEventListener instances.
* </p>
*/
public void add(TransactionEventListener listener) {
transactionEventListeners.add(listener);
}
/**
* Return the TransactionEventListener instances.
*/
public List<TransactionEventListener> getTransactionEventListeners() {
return transactionEventListeners;
}
/**
* Register all the TransactionEventListener instances.
* <p>
* Note alternatively you can use {@link #add(TransactionEventListener)} to
* add TransactionEventListener instances one at a time.
* </p>
*/
public void setTransactionEventListeners(List<TransactionEventListener> transactionEventListeners) {
this.transactionEventListeners = transactionEventListeners;
}
/**
* Register a BeanPersistListener instance.
* <p>
@@ -2372,6 +2292,8 @@ public class ServerConfig {
autoCommitMode = p.getBoolean("autoCommitMode", autoCommitMode);
useJtaTransactionManager = p.getBoolean("useJtaTransactionManager", useJtaTransactionManager);
backgroundExecutorSchedulePoolSize = p.getInt("backgroundExecutorSchedulePoolSize", backgroundExecutorSchedulePoolSize);
backgroundExecutorShutdownSecs = p.getInt("backgroundExecutorShutdownSecs", backgroundExecutorShutdownSecs);
disableClasspathSearch = p.getBoolean("disableClasspathSearch", disableClasspathSearch);
currentUserProvider = createInstance(p, CurrentUserProvider.class, "currentUserProvider", currentUserProvider);
databasePlatform = createInstance(p, DatabasePlatform.class, "databasePlatform", databasePlatform);
@@ -2381,13 +2303,6 @@ public class ServerConfig {
dbEncrypt = createInstance(p, DbEncrypt.class, "dbEncrypt", dbEncrypt);
serverCachePlugin = createInstance(p, ServerCachePlugin.class, "serverCachePlugin", serverCachePlugin);
serverCacheManager = createInstance(p, ServerCacheManager.class, "serverCacheManager", serverCacheManager);
cacheWarmingDelay = p.getInt("cacheWarmingDelay", cacheWarmingDelay);
classPathReaderClassName = p.get("classpathreader");
String jarsProp = p.get("search.jars", p.get("jars", null));
if (jarsProp != null) {
searchJars = getSearchJarsPackages(jarsProp);
}
if (packages != null) {
String packagesProp = p.get("search.packages", p.get("packages", null));
@@ -2397,6 +2312,7 @@ public class ServerConfig {
collectQueryStatsByNode = p.getBoolean("collectQueryStatsByNode", collectQueryStatsByNode);
collectQueryOrigins = p.getBoolean("collectQueryOrigins", collectQueryOrigins);
skipCacheAfterWrite = p.getBoolean("skipCacheAfterWrite", skipCacheAfterWrite);
updateAllPropertiesInBatch = p.getBoolean("updateAllPropertiesInBatch", updateAllPropertiesInBatch);
updateChangesOnly = p.getBoolean("updateChangesOnly", updateChangesOnly);
@@ -2424,6 +2340,8 @@ public class ServerConfig {
asOfSysPeriod = p.get("asOfSysPeriod", asOfSysPeriod);
historyTableSuffix = p.get("historyTableSuffix", historyTableSuffix);
dataSourceJndiName = p.get("dataSourceJndiName", dataSourceJndiName);
jdbcFetchSizeFindEach = p.getInt("jdbcFetchSizeFindEach", jdbcFetchSizeFindEach);
jdbcFetchSizeFindList = p.getInt("jdbcFetchSizeFindList", jdbcFetchSizeFindList);
databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize);
databaseBooleanTrue = p.get("databaseBooleanTrue", databaseBooleanTrue);
databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse);
@@ -2479,7 +2397,7 @@ public class ServerConfig {
String[] split = classNames.split("[ ,;]");
for (int i = 0; i < split.length; i++) {
String cn = split[i].trim();
if (cn.length() > 0 && !"class".equalsIgnoreCase(cn)) {
if (!cn.isEmpty() && !"class".equalsIgnoreCase(cn)) {
try {
classes.add(Class.forName(cn));
} catch (ClassNotFoundException e) {
@@ -2508,13 +2426,14 @@ public class ServerConfig {
/**
* Return the PersistBatch mode to use for 'batchOnCascade' taking into account if the database
* platform supports getGeneratedKeys in batch mode.
* <p>
* Used to effectively turn off batchOnCascade for SQL Server - still allows explicit batch mode.
* </p>
*/
public PersistBatch appliedPersistBatchOnCascade() {
return databasePlatform.isDisallowBatchOnCascade() ? PersistBatch.NONE : persistBatchOnCascade;
if (persistBatchOnCascade == PersistBatch.INHERIT) {
// use the platform default (ALL except SQL Server which has NONE)
return databasePlatform.getPersistBatchOnCascade();
}
return persistBatchOnCascade;
}
/**
@@ -2590,18 +2509,45 @@ public class ServerConfig {
public enum DbUuid {
/**
* Store using native UUID in H2 and Postgres.
* Store using native UUID in H2 and Postgres and otherwise fallback to VARCHAR(40).
*/
AUTO,
AUTO_VARCHAR(true, false),
/**
* Store using DB VARCHAR.
* Store using native UUID in H2 and Postgres and otherwise fallback to BINARY(16).
*/
VARCHAR,
AUTO_BINARY(true, true),
/**
* Store using DB BINARY.
* Store using DB VARCHAR(40).
*/
BINARY
VARCHAR(false, false),
/**
* Store using DB BINARY(16).
*/
BINARY(false, true);
boolean nativeType;
boolean binary;
DbUuid(boolean nativeType, boolean binary) {
this.nativeType = nativeType;
this.binary = binary;
}
/**
* Return true if native UUID type is preferred.
*/
public boolean useNativeType() {
return nativeType;
}
/**
* Return true if BINARY(16) storage is preferred over VARCHAR(40).
*/
public boolean useBinary() {
return binary;
}
}
}
@@ -146,6 +146,6 @@ public final class TableName {
* @return true, if is valid
*/
public boolean isValid() {
return name != null && name.length() > 0;
return name != null && !name.isEmpty();
}
}
@@ -2,6 +2,7 @@ package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.Query;
import com.avaje.ebean.config.PersistBatch;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlHandler;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl;
@@ -14,7 +15,6 @@ import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Properties;
/**
* Database platform specific settings.
@@ -33,12 +33,6 @@ public class DatabasePlatform {
*/
ROLLBACK,
/**
* Just close the transaction. Valid at READ_COMMITTED isolation and preferred on some Databases
* as a performance optimisation.
*/
CLOSE,
/**
* Commit the transaction
*/
@@ -155,11 +149,9 @@ public class DatabasePlatform {
protected boolean forwardOnlyHintOnFindIterate;
/**
* Flag set for SQL Server due to lack of support of getGeneratedKeys in
* batch mode (meaning for batch inserts you should explicitly turn off
* getGeneratedKeys - joy).
* By default we use JDBC batch when cascading (except for SQL Server).
*/
protected boolean disallowBatchOnCascade;
protected PersistBatch persistBatchOnCascade = PersistBatch.ALL;
protected PlatformDdl platformDdl;
@@ -183,8 +175,11 @@ public class DatabasePlatform {
public DatabasePlatform() {
}
public void configure(Properties properties) {
// by default do nothing
/**
* Configure UUID Storage etc based on ServerConfig settings.
*/
public void configure(ServerConfig serverConfig) {
dbTypeMap.config(nativeUuidType, serverConfig.getDbUuid());
}
/**
@@ -492,7 +487,7 @@ public class DatabasePlatform {
*/
public String convertQuotedIdentifiers(String dbName) {
// Ignore null values e.g. schema name or catalog
if (dbName != null && dbName.length() > 0) {
if (dbName != null && !dbName.isEmpty()) {
if (dbName.charAt(0) == BACK_TICK) {
if (dbName.charAt(dbName.length() - 1) == BACK_TICK) {
@@ -542,14 +537,10 @@ public class DatabasePlatform {
}
/**
* Return true if the persistBatchOnCascade setting should be ignored.
* <p>
* This is primarily for SQL Server which does not support getGeneratedKeys with jdbc batch mode
* so can't really be transparently used.
* </p>
* Return the platform default JDBC batch mode for persist cascade.
*/
public boolean isDisallowBatchOnCascade() {
return disallowBatchOnCascade;
public PersistBatch getPersistBatchOnCascade() {
return persistBatchOnCascade;
}
/**
@@ -6,11 +6,13 @@ package com.avaje.ebean.config.dbplatform;
public interface DbHistorySupport {
/**
* Return true if the 'As of' predicate is part of the from clause
* (more standard sql2011). So true for Oracle total recall and false
* for Postgres and MySql (where we use views and history tables).
* Return true if the implementation is SQL2011 standards based.
* <p>
* Non standards based means we need to add additional predicates into the
* JOIN ON clause and add an additional predicate for the base table.
* </p>
*/
boolean isBindWithFromClause();
boolean isStandardsBased();
/**
* Return the number of columns bound in a 'As Of' predicate.
@@ -5,11 +5,8 @@ package com.avaje.ebean.config.dbplatform;
*/
public abstract class DbStandardHistorySupport implements DbHistorySupport {
/**
* Return true as with sql2011 the 'as of timestamp' clause included in from or join clause.
*/
@Override
public boolean isBindWithFromClause() {
public boolean isStandardsBased() {
return true;
}
@@ -152,4 +152,10 @@ public class DbType {
return sb.toString();
}
/**
* Create a copy of the type with a new default length.
*/
public DbType withLength(int defaultLength) {
return new DbType(name, defaultLength);
}
}
@@ -1,5 +1,7 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.config.ServerConfig;
import java.sql.Types;
import java.util.HashMap;
import java.util.Map;
@@ -9,6 +11,8 @@ import java.util.Map;
*/
public class DbTypeMap {
private static final DbType UUID_NATIVE = new DbType("uuid", false);
private static final DbType UUID_PLACEHOLDER = new DbType("uuidPlaceholder");
private static final DbType JSON_CLOB_PLACEHOLDER = new DbType("jsonClobPlaceholder");
private static final DbType JSON_BLOB_PLACEHOLDER = new DbType("jsonBlobPlaceholder");
private static final DbType JSON_VARCHAR_PLACEHOLDER = new DbType("jsonVarcharPlaceholder");
@@ -66,7 +70,7 @@ public class DbTypeMap {
/**
* Return the DbTypeMap with standard (not platform specific) types.
*
* <p>
* This has some extended JSON types (JSON, JSONB, JSONVarchar, JSONClob, JSONBlob).
* These types get translated to specific database platform types during DDL generation.
*/
@@ -104,8 +108,6 @@ public class DbTypeMap {
put(Types.BLOB, new DbType("blob"));
put(Types.CLOB, new DbType("clob"));
// DB native UUID support (H2 and Postgres)
put(DbType.UUID, new DbType("uuid"));
put(Types.ARRAY, new DbType("array"));
if (logicalTypes) {
@@ -116,6 +118,7 @@ public class DbTypeMap {
put(DbType.JSONClob, new DbType("jsonclob"));
put(DbType.JSONBlob, new DbType("jsonblob"));
put(DbType.JSONVarchar, new DbType("jsonvarchar", 1000));
put(DbType.UUID, UUID_NATIVE);
} else {
put(DbType.JSON, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSON
@@ -123,6 +126,7 @@ public class DbTypeMap {
put(DbType.JSONClob, JSON_CLOB_PLACEHOLDER);
put(DbType.JSONBlob, JSON_BLOB_PLACEHOLDER);
put(DbType.JSONVarchar, JSON_VARCHAR_PLACEHOLDER);
put(DbType.UUID, UUID_PLACEHOLDER);
}
put(Types.LONGVARBINARY, new DbType("longvarbinary"));
@@ -133,7 +137,6 @@ public class DbTypeMap {
put(Types.DATE, new DbType("date"));
put(Types.TIME, new DbType("time"));
put(Types.TIMESTAMP, new DbType("timestamp"));
}
/**
@@ -191,4 +194,17 @@ public class DbTypeMap {
public DbType get(int jdbcType) {
return typeMap.get(jdbcType);
}
/**
* Map the UUID appropriately based on native DB support and ServerConfig.DbUuid.
*/
public void config(boolean nativeUuidType, ServerConfig.DbUuid dbUuid) {
if (nativeUuidType && dbUuid.useNativeType()) {
put(DbType.UUID, UUID_NATIVE);
} else if (dbUuid.useBinary()) {
put(DbType.UUID, get(Types.BINARY).withLength(16));
} else {
put(DbType.UUID, get(Types.VARCHAR).withLength(40));
}
}
}
@@ -9,11 +9,8 @@ package com.avaje.ebean.config.dbplatform;
*/
public abstract class DbViewHistorySupport implements DbHistorySupport {
/**
* Return false for view based implementations where we append extra 'as of' predicates to the end.
*/
@Override
public boolean isBindWithFromClause() {
public boolean isStandardsBased() {
return false;
}
@@ -9,9 +9,7 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* H2 database trigger used to populate history tables to support the @History feature.
@@ -54,7 +52,6 @@ public class H2HistoryTrigger implements Trigger {
insertSql.append("insert into ").append(tableName).append(HISTORY_SUFFIX).append(" (");
int count = 0;
List<String> columns = new ArrayList<String>();
while (rs.next()) {
if (++count > 1) {
insertSql.append(",");
@@ -66,7 +63,6 @@ public class H2HistoryTrigger implements Trigger {
this.effectEndPosition = count - 1;
}
insertSql.append(columnName);
columns.add(columnName);
}
insertSql.append(") values (");
for (int i = 0; i < count; i++) {
@@ -1,9 +1,11 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.H2Ddl;
import javax.sql.DataSource;
import java.util.Properties;
/**
* H2 specific platform.
@@ -19,9 +21,7 @@ public class H2Platform extends DatabasePlatform {
this.nativeUuidType = true;
this.dbDefaultValue.setNow("now()");
// only support getGeneratedKeys with non-batch JDBC
// so generally use SEQUENCE instead of IDENTITY for H2
this.dbIdentity.setIdType(IdType.SEQUENCE);
this.dbIdentity.setIdType(IdType.IDENTITY);
this.dbIdentity.setSupportsGetGeneratedKeys(true);
this.dbIdentity.setSupportsSequence(true);
this.dbIdentity.setSupportsIdentity(true);
@@ -34,6 +34,18 @@ public class H2Platform extends DatabasePlatform {
// so no changes to dbTypeMap required
}
@Override
public void configure(ServerConfig serverConfig) {
super.configure(serverConfig);
Properties properties = serverConfig.getProperties();
if (properties != null) {
String idType = properties.getProperty("ebean.h2.idtype");
if (idType != null) {
this.dbIdentity.setIdType(IdType.valueOf(idType));
}
}
}
/**
* Return a H2 specific sequence IdGenerator that supports batch fetching
* sequence values.
@@ -1,5 +1,7 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.config.PersistBatch;
import java.sql.Types;
/**
@@ -18,6 +20,7 @@ public class MsSqlServer2000Platform extends DatabasePlatform {
public MsSqlServer2000Platform() {
super();
this.name = "mssqlserver2000";
this.persistBatchOnCascade = PersistBatch.NONE;
this.dbIdentity.setIdType(IdType.IDENTITY);
this.dbIdentity.setSupportsGetGeneratedKeys(false);
this.dbIdentity.setSelectLastInsertedIdTemplate("select @@IDENTITY as X");
@@ -1,5 +1,6 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.config.PersistBatch;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.MsSqlServerDdl;
import java.sql.Types;
@@ -21,7 +22,7 @@ public class MsSqlServer2005Platform extends DatabasePlatform {
this.name = "mssqlserver2005";
// effectively disable persistBatchOnCascade mode for SQL Server
// due to lack of support for getGeneratedKeys in batch mode
this.disallowBatchOnCascade = true;
this.persistBatchOnCascade = PersistBatch.NONE;
this.idInExpandedForm = true;
this.selectCountWithAlias = true;
this.sqlLimiter = new MsSqlServer2005SqlLimiter();
@@ -64,12 +64,15 @@ public class PostgresPlatform extends DatabasePlatform {
}
@Override
public void configure(Properties properties) {
super.configure(properties);
String tsType = properties.getProperty("ebean.postgres.timestamp");
if (tsType != null) {
// set timestamp type to "timestamp" without time zone
dbTypeMap.put(Types.TIMESTAMP, new DbType(tsType));
public void configure(ServerConfig serverConfig) {
super.configure(serverConfig);
Properties properties = serverConfig.getProperties();
if (properties != null) {
String tsType = properties.getProperty("ebean.postgres.timestamp");
if (tsType != null) {
// set timestamp type to "timestamp" without time zone
dbTypeMap.put(Types.TIMESTAMP, new DbType(tsType));
}
}
}
@@ -114,7 +114,7 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
public Object nextId(Transaction t) {
synchronized (monitor) {
if (idList.size() == 0) {
if (idList.isEmpty()) {
loadMoreIds(batchSize, t);
}
Long nextId = idList.remove(0);
@@ -193,7 +193,7 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
while (rset.next()) {
newIds.add(rset.getLong(1));
}
if (newIds.size() == 0) {
if (newIds.isEmpty()) {
throw new PersistenceException("Always expecting more than 1 row from " + sql);
}
@@ -164,9 +164,6 @@ public class DbMigration {
* </p>
*/
public void addPlatform(DbPlatformName platform, String prefix) {
if (!prefix.endsWith("-")) {
prefix += "-";
}
platforms.add(new Pair(getPlatform(platform), prefix));
}
@@ -204,13 +201,20 @@ public class DbMigration {
// use this flag to stop other plugins like full DDL generation
if (!online) {
DbOffline.setRunningMigration();
DbOffline.setGenerateMigration();
if (databasePlatform == null && !platforms.isEmpty()) {
// for multiple platform generation set the general platform
// to H2 so that it runs offline without DB connection
setPlatform(platforms.get(0).platform);
}
}
setDefaults();
try {
Request request = createRequest();
generateExtraDdl(request);
if (platforms.isEmpty()) {
generateExtraDdl(request.migrationDir, databasePlatform);
}
String pendingVersion = generatePendingDrop();
if (pendingVersion != null) {
@@ -234,15 +238,15 @@ public class DbMigration {
* migration runner.
* </p>
*/
private void generateExtraDdl(Request request) throws IOException {
private void generateExtraDdl(File migrationDir, DatabasePlatform dbPlatform) throws IOException {
if (databasePlatform != null) {
if (dbPlatform != null) {
ExtraDdl extraDdl = ExtraDdlXmlReader.read("/extra-ddl.xml");
if (extraDdl != null) {
List<DdlScript> ddlScript = extraDdl.getDdlScript();
for (DdlScript script : ddlScript) {
if (ExtraDdlXmlReader.matchPlatform(databasePlatform.getName(), script.getPlatforms())) {
writeExtraDdl(request, script);
if (ExtraDdlXmlReader.matchPlatform(dbPlatform.getName(), script.getPlatforms())) {
writeExtraDdl(migrationDir, script);
}
}
}
@@ -252,13 +256,13 @@ public class DbMigration {
/**
* Write (or override) the "repeatable" migration script.
*/
private void writeExtraDdl(Request request, DdlScript script) throws IOException {
private void writeExtraDdl(File migrationDir, DdlScript script) throws IOException {
String fullName = repeatableMigrationName(script.getName());
logger.info("writing repeatable script {}", fullName);
File file = new File(request.migrationDir, fullName);
File file = new File(migrationDir, fullName);
FileWriter writer = new FileWriter(file);
writer.write(script.getValue());
writer.flush();
@@ -363,14 +367,16 @@ public class DbMigration {
logger.warn("migration already exists, not generating DDL");
} else {
if (databasePlatform != null) {
if (!platforms.isEmpty()) {
writeExtraPlatformDdl(fullVersion, request.currentModel, dbMigration, request.migrationDir);
} else if (databasePlatform != null) {
// writer needs the current model to provide table/column details for
// history ddl generation (triggers, history tables etc)
DdlWrite write = new DdlWrite(new MConfiguration(), request.current);
PlatformDdlWriter writer = createDdlWriter(databasePlatform, "");
writer.processMigration(dbMigration, write, request.migrationDir, fullVersion);
}
writeExtraPlatformDdl(fullVersion, request.currentModel, dbMigration, request.migrationDir);
}
}
@@ -426,7 +432,10 @@ public class DbMigration {
for (Pair pair : platforms) {
DdlWrite platformBuffer = new DdlWrite(new MConfiguration(), currentModel.read());
PlatformDdlWriter platformWriter = createDdlWriter(pair);
platformWriter.processMigration(dbMigration, platformBuffer, writePath, fullVersion);
File subPath = platformWriter.subPath(writePath, pair.prefix);
platformWriter.processMigration(dbMigration, platformBuffer, subPath, fullVersion);
generateExtraDdl(subPath, pair.platform);
}
}
@@ -14,7 +14,7 @@ public class DbOffline {
private static final String KEY = "ebean.dboffline";
private static boolean runningMigration;
private static boolean generateMigration;
/**
* Set the platform to use when creating the next EbeanServer instance.
@@ -55,23 +55,23 @@ public class DbOffline {
* Return true if the migration is running. This typically means don't run the
* plugins like full DDL generation.
*/
public static boolean isRunningMigration() {
return runningMigration;
public static boolean isGenerateMigration() {
return generateMigration;
}
/**
* Called when the migration is running is order to stop other plugins
* like the full DDL generation from executing.
*/
public static void setRunningMigration() {
runningMigration = true;
public static void setGenerateMigration() {
generateMigration = true;
}
/**
* Reset the offline platform and runningMigration flag.
*/
public static void reset() {
runningMigration = false;
generateMigration = false;
System.clearProperty(KEY);
logger.debug("reset");
}
@@ -96,7 +96,13 @@ public class DdlGenerator {
Transaction transaction = server.createTransaction();
Connection connection = transaction.getConnection();
try {
if (expectErrors) {
connection.setAutoCommit(true);
}
int count = runner.runAll(content, connection);
if (expectErrors) {
connection.setAutoCommit(false);
}
transaction.commit();
return count;
@@ -583,6 +583,12 @@ public class BaseTableDdl implements TableDdl {
}
}
for (Column column : columns) {
if (hasValue(column.getReferences())) {
writeForeignKey(writer, tableName, column);
}
}
// add a bit of whitespace
writer.apply().end();
}
@@ -831,9 +837,10 @@ public class BaseTableDdl implements TableDdl {
protected void alterTableAddColumn(DdlBuffer buffer, String tableName, Column column, boolean onHistoryTable) throws IOException {
String convertedType = platformDdl.convert(column.getType(), false);
buffer.append("alter table ").append(tableName)
.append(" add column ").append(column.getName())
.append(" ").append(column.getType());
.append(" ").append(convertedType);
if (!onHistoryTable) {
if (isTrue(column.isNotnull())) {
@@ -26,6 +26,8 @@ import java.util.List;
*/
public class PlatformDdl {
protected final DatabasePlatform platform;
protected PlatformHistoryDdl historyDdl = new NoHistorySupportDdl();
/**
@@ -98,6 +100,7 @@ public class PlatformDdl {
protected final DbDefaultValue dbDefaultValue;
public PlatformDdl(DatabasePlatform platform) {
this.platform = platform;
this.dbIdentity = platform.getDbIdentity();
this.dbDefaultValue = platform.getDbDefaultValue();
this.typeConverter = new PlatformTypeConverter(platform.getDbTypeMap());
@@ -107,6 +110,7 @@ public class PlatformDdl {
* Set configuration options.
*/
public void configure(ServerConfig serverConfig) {
platform.configure(serverConfig);
historyDdl.configure(serverConfig, this);
naming = serverConfig.getConstraintNaming();
}
@@ -11,7 +11,6 @@ import com.avaje.ebean.dbmigration.model.visitor.VisitAllUsing;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import java.io.IOException;
import java.util.List;
/**
* Reads EbeanServer bean descriptors to build the current model.
@@ -24,6 +23,8 @@ public class CurrentModel {
private final DbConstraintNaming.MaxLength maxLength;
private final boolean platformTypes;
private ModelContainer model;
private ChangeSet changeSet;
@@ -31,32 +32,31 @@ public class CurrentModel {
private DdlWrite write;
/**
* Construct with a given EbeanServer instance.
* Construct with a given EbeanServer instance for DDL create all generation, not migration.
*/
public CurrentModel(SpiEbeanServer server) {
this(server, server.getServerConfig().getConstraintNaming());
this(server, server.getServerConfig().getConstraintNaming(), true);
}
/**
* Construct with a given EbeanServer, platformDdl and constraintNaming convention.
* <p>
* Note the EbeanServer is just used to read the BeanDescriptors and platformDdl supplies
* the platform specific handling on
* Note the EbeanServer is just used to read the BeanDescriptors and platformDdl supplies
* the platform specific handling on
* </p>
*/
public CurrentModel(SpiEbeanServer server, DbConstraintNaming constraintNaming) {
this(server, constraintNaming, false);
}
private CurrentModel(SpiEbeanServer server, DbConstraintNaming constraintNaming, boolean platformTypes) {
this.server = server;
this.constraintNaming = constraintNaming;
this.maxLength = maxLength(server, constraintNaming);
this.platformTypes = platformTypes;
}
public CurrentModel(SpiEbeanServer server, DbConstraintNaming constraintNaming, int maxConstraintLength) {
this.server = server;
this.constraintNaming = constraintNaming;
this.maxLength = new DefaultConstraintMaxLength(maxConstraintLength);
}
private DbConstraintNaming.MaxLength maxLength(SpiEbeanServer server, DbConstraintNaming naming) {
private static DbConstraintNaming.MaxLength maxLength(SpiEbeanServer server, DbConstraintNaming naming) {
if (naming.getMaxLength() != null) {
return naming.getMaxLength();
@@ -73,7 +73,7 @@ public class CurrentModel {
if (model == null) {
model = new ModelContainer();
ModelBuildContext context = new ModelBuildContext(model, constraintNaming, maxLength);
ModelBuildContext context = new ModelBuildContext(model, constraintNaming, maxLength, platformTypes);
ModelBuildBeanVisitor visitor = new ModelBuildBeanVisitor(context);
VisitAllUsing visit = new VisitAllUsing(visitor, server);
visit.visitAllBeans();
@@ -104,7 +104,7 @@ public class MTable {
/**
* Compound unique constraints.
*/
private List<MCompoundUniqueConstraint> compoundUniqueConstraints = new ArrayList<MCompoundUniqueConstraint>();
private List<MCompoundUniqueConstraint> uniqueConstraints = new ArrayList<MCompoundUniqueConstraint>();
/**
* Compound foreign keys.
@@ -216,7 +216,7 @@ public class MTable {
createTable.getForeignKey().add(compoundKey.createForeignKey());
}
for (MCompoundUniqueConstraint constraint : compoundUniqueConstraints) {
for (MCompoundUniqueConstraint constraint : uniqueConstraints) {
UniqueConstraint uq = new UniqueConstraint();
uq.setName(constraint.getName());
String[] columns = constraint.getColumns();
@@ -270,17 +270,15 @@ public class MTable {
}
// compare existing columns (look for dropped columns)
int columnPosition = 0;
for (MColumn existingColumn : allColumns()) {
MColumn newColumn = newColumnMap.get(existingColumn.getName());
if (newColumn == null) {
diffDropColumn(modelDiff, existingColumn, columnPosition, newTable);
diffDropColumn(modelDiff, existingColumn);
} else if (newColumn.isDraftOnly() && !draft) {
// effectively a drop column (draft only column on a non-draft table)
logger.trace("... drop column {} from table {} as now draftOnly", newColumn.getName(), name);
diffDropColumn(modelDiff, existingColumn, columnPosition, newTable);
diffDropColumn(modelDiff, existingColumn);
}
columnPosition++;
}
if (addColumn != null) {
@@ -404,8 +402,8 @@ public class MTable {
return columns;
}
public List<MCompoundUniqueConstraint> getCompoundUniqueConstraints() {
return compoundUniqueConstraints;
public List<MCompoundUniqueConstraint> getUniqueConstraints() {
return uniqueConstraints;
}
public List<MCompoundForeignKey> getCompoundKeys() {
@@ -476,21 +474,21 @@ public class MTable {
}
/**
* Add a compound unique constraint.
* Add a unique constraint.
*/
public void addCompoundUniqueConstraint(String[] columns, boolean oneToOne, String constraintName) {
compoundUniqueConstraints.add(new MCompoundUniqueConstraint(columns, oneToOne, constraintName));
public void addUniqueConstraint(String[] columns, boolean oneToOne, String constraintName) {
uniqueConstraints.add(new MCompoundUniqueConstraint(columns, oneToOne, constraintName));
}
/**
* Add a compound unique constraint.
* Add a unique constraint.
*/
public void addCompoundUniqueConstraint(List<MColumn> columns, boolean oneToOne, String constraintName) {
public void addUniqueConstraint(List<MColumn> columns, boolean oneToOne, String constraintName) {
String[] cols = new String[columns.size()];
for (int i = 0; i < columns.size(); i++) {
cols[i] = columns.get(i).getName();
}
addCompoundUniqueConstraint(cols, oneToOne, constraintName);
addUniqueConstraint(cols, oneToOne, constraintName);
}
/**
@@ -540,7 +538,7 @@ public class MTable {
/**
* Add a 'drop column' to the diff.
*/
private void diffDropColumn(ModelDiff modelDiff, MColumn existingColumn, int columnPosition, MTable newTable) {
private void diffDropColumn(ModelDiff modelDiff, MColumn existingColumn) {
DropColumn dropColumn = new DropColumn();
dropColumn.setTableName(name);
@@ -9,6 +9,8 @@ import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
import com.avaje.ebean.dbmigration.migration.ChangeSet;
import com.avaje.ebean.dbmigration.migration.ChangeSetType;
import com.avaje.ebean.dbmigration.migration.Migration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileWriter;
@@ -21,6 +23,8 @@ import java.util.List;
*/
public class PlatformDdlWriter {
private static final Logger logger = LoggerFactory.getLogger(PlatformDdlWriter.class);
private final ServerConfig serverConfig;
private final DatabasePlatform platform;
@@ -67,7 +71,7 @@ public class PlatformDdlWriter {
protected void writePlatformDdl(DdlWrite write, File resourcePath, String fullVersion) throws IOException {
if (!write.isApplyEmpty()) {
FileWriter applyWriter = createWriter(resourcePath, fullVersion, "", config.getApplySuffix());
FileWriter applyWriter = createWriter(resourcePath, fullVersion, config.getApplySuffix());
try {
writeApplyDdl(applyWriter, write);
applyWriter.flush();
@@ -77,28 +81,12 @@ public class PlatformDdlWriter {
}
}
protected FileWriter createWriter(File path, String fullVersion, String subPath, String suffix) throws IOException {
protected FileWriter createWriter(File path, String fullVersion, String suffix) throws IOException {
String fileName = fullVersion;
if (!platformPrefix.isEmpty()) {
fileName += "-"+platformPrefix;
}
if (subPath != null && !subPath.isEmpty()) {
path = subPath(path, subPath);
}
fileName += suffix;
File applyFile = new File(path, fileName);
File applyFile = new File(path, fullVersion + suffix);
return new FileWriter(applyFile);
}
protected File subPath(File path, String suffix) {
File subPath = new File(path, suffix);
if (!subPath.exists()) {
subPath.mkdirs();
}
return subPath;
}
/**
* Write the 'Apply' DDL buffers to the writer.
*/
@@ -127,4 +115,17 @@ public class PlatformDdlWriter {
return platform.createDdlHandler(serverConfig);
}
/**
* Return a sub directory (for multi-platform ddl generation).
*/
public File subPath(File path, String suffix) {
File subPath = new File(path, suffix);
if (!subPath.exists()) {
if (!subPath.mkdirs()) {
logger.error("failed to create directories for " + subPath.getAbsolutePath());
}
}
return subPath;
}
}
@@ -29,10 +29,13 @@ public class ModelBuildContext {
private final DbConstraintNaming.MaxLength maxLength;
public ModelBuildContext(ModelContainer model, DbConstraintNaming naming, DbConstraintNaming.MaxLength maxLength) {
private final boolean platformTypes;
public ModelBuildContext(ModelContainer model, DbConstraintNaming naming, DbConstraintNaming.MaxLength maxLength, boolean platformTypes) {
this.model = model;
this.constraintNaming = naming;
this.maxLength = maxLength;
this.platformTypes = platformTypes;
}
/**
@@ -132,7 +135,7 @@ public class ModelBuildContext {
}
// can be the logical JSON types (JSON, JSONB, JSONClob, JSONBlob, JSONVarchar)
int dbType = p.getDbType();
int dbType = p.getDbType(platformTypes);
if (dbType == 0) {
throw new RuntimeException("No scalarType defined for " + p.getFullBeanName());
}
@@ -85,6 +85,11 @@ public class ModelBuildIntersectionTable {
String tableName = intersectionTableJoin.getTable();
MTable table = new MTable(tableName);
if (!manyProp.isExcludedFromHistory()) {
if (localDesc.isHistorySupport()) {
table.setWithHistory(true);
}
}
table.setPkName(ctx.primaryKeyName(tableName));
TableJoinColumn[] columns = intersectionTableJoin.columns();
@@ -10,7 +10,7 @@ import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
import com.avaje.ebeaninternal.server.deploy.CompoundUniqueConstraint;
import com.avaje.ebeaninternal.server.deploy.IndexDefinition;
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
import com.avaje.ebeaninternal.server.deploy.TableJoinColumn;
import com.avaje.ebeaninternal.server.deploy.id.ImportedId;
@@ -45,30 +45,30 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
this.ctx = ctx;
this.table = table;
this.beanDescriptor = beanDescriptor;
addCompoundUniqueConstraint(beanDescriptor.getCompoundUniqueConstraints());
addIndexes(beanDescriptor.getIndexDefinitions());
}
/**
* Add unique constraints defined via JPA UniqueConstraint annotations.
*/
private void addCompoundUniqueConstraint(CompoundUniqueConstraint[] constraints) {
private void addIndexes(IndexDefinition[] indexes) {
if (constraints != null) {
for (int i = 0; i < constraints.length; i++) {
CompoundUniqueConstraint constraint = constraints[i];
String[] columns = constraint.getColumns();
if (indexes != null) {
for (int i = 0; i < indexes.length; i++) {
IndexDefinition index = indexes[i];
String[] columns = index.getColumns();
indexSet.add(columns);
if (constraint.isUnique()) {
String uqName = constraint.getName();
if (index.isUnique()) {
String uqName = index.getName();
if (uqName == null || uqName.trim().isEmpty()) {
uqName = determineUniqueConstraintName(columns);
}
table.addCompoundUniqueConstraint(columns, false, uqName);
table.addUniqueConstraint(columns, false, uqName);
} else {
// 'just' an index (not a unique constraint)
String idxName = constraint.getName();
String idxName = index.getName();
if (idxName == null || idxName.trim().isEmpty()) {
idxName = determineIndexName(columns);
}
@@ -216,7 +216,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
} else {
String uqName = determineUniqueConstraintName(p.getName());
table.addCompoundUniqueConstraint(modelColumns, true, uqName);
table.addUniqueConstraint(modelColumns, true, uqName);
indexSetAdd(modelColumns);
}
}
@@ -260,15 +260,6 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
col.setCheckConstraintName(determineCheckConstraintName(col.getName()));
}
String indexName = p.getIndexName();
if (indexName != null) {
// single column non-unique index
if (indexName.trim().isEmpty()) {
indexName = determineIndexName(col.getName());
}
ctx.addIndex(indexName, table.getName(), p.getDbColumn());
}
lastColumn = col;
table.addColumn(col);
}
@@ -1,7 +1,5 @@
package com.avaje.ebean.event;
import java.util.Set;
import com.avaje.ebean.config.ServerConfig;
/**
@@ -1,7 +1,5 @@
package com.avaje.ebean.event;
import java.util.Set;
/**
* Used to enhance or override the default bean persistence mechanism.
* <p>
@@ -1,18 +0,0 @@
package com.avaje.ebean.event;
import com.avaje.ebean.Transaction;
/**
* Used to get notified about commit or rollback of a transaction
*/
public interface TransactionEventListener {
/**
* Called after the transaction has been committed
*/
void postTransactionCommit(Transaction tx);
/**
* Called after the transaction has been rolled back
*/
void postTransactionRollback(Transaction tx, Throwable cause);
}
@@ -1,18 +0,0 @@
package com.avaje.ebean.event;
import com.avaje.ebean.Transaction;
/**
* A no operation implementation of TransactionEventListener. Objects extending
* this need to only override the methods they want to.
*/
public abstract class TransactionEventListenerAdapter implements TransactionEventListener {
public void postTransactionCommit(Transaction tx) {
// do nothing by default
}
public void postTransactionRollback(Transaction tx, Throwable cause) {
// do nothing by default
}
}
@@ -80,7 +80,7 @@ public class BeanChange {
* Set the bean id (for JSON tools).
*/
public void setId(Object id) {
this.id = this.id;
this.id = id;
}
/**
@@ -109,7 +109,7 @@ public class PathProperties implements FetchPath {
String path = entry.getKey();
String props = entry.getValue().getPropertiesAsString();
if (path == null || path.length() == 0) {
if (path == null || path.isEmpty()) {
query.select(props);
} else {
query.fetch(path, props);
@@ -108,7 +108,7 @@ class PathPropertiesParser {
private void addCurrentProperty() {
String w = currentWord();
if (w.length() > 0) {
if (!w.isEmpty()) {
currentPathProps.addProperty(w);
}
}
@@ -23,7 +23,7 @@ public final class TimeStringParser implements StringParser {
*/
@SuppressWarnings("deprecation")
public Object parse(String value) {
if (value == null || value.trim().length() == 0) {
if (value == null || value.trim().isEmpty()) {
return null;
}
@@ -12,9 +12,12 @@ public class CamelCaseHelper {
*/
public static String toCamelFromUnderscore(String underscore) {
StringBuilder result = new StringBuilder();
String[] vals = underscore.split("_");
if (vals.length == 1) {
return underscore;
}
StringBuilder result = new StringBuilder();
for (int i = 0; i < vals.length; i++) {
String lower = vals[i].toLowerCase();
if (i > 0) {
@@ -123,7 +123,7 @@ public class StringHelper {
String listDelimiter, String nameValueSeparator) {
HashMap<String, String> params = new HashMap<String, String>();
if ((allNameValuePairs == null) || (allNameValuePairs.length() == 0)) {
if ((allNameValuePairs == null) || (allNameValuePairs.isEmpty())) {
return params;
}
// trim off any leading listDelimiter...
@@ -155,7 +155,7 @@ public class StringHelper {
* Return true if the value is null or an empty string.
*/
public static boolean isNull(String value) {
return value == null || value.trim().length() == 0;
return value == null || value.trim().isEmpty();
}
/**
@@ -189,7 +189,7 @@ public class StringHelper {
// there is a key without a value?
String key = allNameValuePairs.substring(pos, delimPos);
key = key.trim();
if (key.length() > 0) {
if (!key.isEmpty()) {
map.put(key, null);
}
return getKeyValue(map, delimPos + 1, allNameValuePairs, listDelimiter,
@@ -251,7 +251,7 @@ public class StringHelper {
if (endPos == -1) {
if (startPos <= str.length()) {
String lastValue = str.substring(startPos, str.length());
if (keepEmpties || lastValue.length() != 0) {
if (keepEmpties || !lastValue.isEmpty()) {
list.add(lastValue);
}
}
@@ -260,7 +260,7 @@ public class StringHelper {
} else {
// get the delimited value... add it..
String value = str.substring(startPos, endPos);
if (keepEmpties || value.length() != 0) {
if (keepEmpties || !value.isEmpty()) {
list.add(value);
}
// recursively search as we are not at the end yet...
@@ -398,7 +398,7 @@ public class StringHelper {
int additionalSize, int startPos, int endPos) {
if (source == null) {
return source;
return null;
}
char match0 = match.charAt(0);
@@ -132,15 +132,11 @@ public class ManyWhereJoins implements Serializable {
formulaProperties.append(propertyName);
}
public boolean isHasMany() {
return formulaWithJoin || !joins.isEmpty();
}
/**
* Return true if the findRowCount query just needs the id property in the select clause.
* Return true if the query select includes a formula with join.
*/
public boolean isSelectId() {
return !formulaWithJoin;
public boolean isFormulaWithJoin() {
return formulaWithJoin;
}
/**
@@ -181,6 +181,15 @@ public class ScopeTrans implements Thread.UncaughtExceptionHandler {
return e;
}
/**
* Mark the underlying transaction as rollback only.
*/
public void setRollbackOnly() {
if (transaction != null) {
transaction.setRollbackOnly();
}
}
/**
* An Exception was caught and may or may not cause a rollback to occur.
* Returns the exception and this should be thrown by the calling code.
@@ -29,9 +29,13 @@ public class ScopedTransaction implements SpiTransaction {
public ScopedTransaction(ScopeTrans scopeTrans) {
this.scopeTrans = scopeTrans;
this.transaction =scopeTrans.getTransaction();
this.transaction = scopeTrans.getTransaction();
}
@Override
public void commitAndContinue() throws RollbackException {
transaction.commitAndContinue();
}
@Override
public void commit() throws RollbackException {
@@ -49,6 +53,21 @@ public class ScopedTransaction implements SpiTransaction {
scopeTrans.rollback(e);
}
@Override
public void rollbackIfActive() {
transaction.rollbackIfActive();
}
@Override
public void setRollbackOnly() {
scopeTrans.setRollbackOnly();
}
@Override
public boolean isRollbackOnly() {
return transaction.isRollbackOnly();
}
@Override
public void end() throws PersistenceException {
try {
@@ -105,6 +124,16 @@ public class ScopedTransaction implements SpiTransaction {
transaction.logSummary(msg);
}
@Override
public void setSkipCache(boolean skipCache) {
transaction.setSkipCache(skipCache);
}
@Override
public boolean isSkipCache() {
return transaction.isSkipCache();
}
@Override
public void addBeanChange(BeanChange beanChange) {
transaction.addBeanChange(beanChange);
@@ -145,7 +145,7 @@ public interface SpiEbeanServer extends EbeanServer, BeanLoader, BeanCollectionL
* the query has finished (if executing in a background thread).
* </p>
*/
<T> List<Object> findIdsWithCopy(Query<T> query, Transaction t);
<A> List<A> findIdsWithCopy(Query<?> query, Transaction t);
/**
* Execute the findRowCount query but without copying the query.
@@ -13,13 +13,23 @@ import java.io.IOException;
*/
public interface SpiExpression extends Expression {
/**
/**
* Simplify nested expressions if possible.
*/
void simplify();
/**
* Write the expression as an elastic search expression.
*/
void writeDocQuery(DocQueryContext context) throws IOException;
/**
* Process "Many" properties populating ManyWhereJoins.
/**
* Return the nested path for this expression.
*/
String nestedPath(BeanDescriptor<?> desc);
/**
* Process "Many" properties populating ManyWhereJoins.
* <p>
* Predicates on Many properties require an extra independent join clause.
* </p>
@@ -89,4 +99,8 @@ public interface SpiExpression extends Expression {
*/
SpiExpression copyForPlanKey();
/**
* Return the bind Id value if this is a "equal to" expression for the id property.
*/
Object getIdEqualTo(String idName);
}
@@ -0,0 +1,6 @@
package com.avaje.ebeaninternal.api;
public interface SpiNamedParam {
Object getValue();
}
@@ -78,6 +78,11 @@ public interface SpiQuery<T> extends Query<T> {
*/
ID_LIST,
/**
* Find single attribute.
*/
ATTRIBUTE,
/**
* Find rowCount.
*/
@@ -133,6 +138,11 @@ public interface SpiQuery<T> extends Query<T> {
}
}
/**
* Check for a single "equal to" expression for the Id.
*/
void checkIdEqualTo();
/**
* Return true if AutoTune should be attempted on this query.
*/
@@ -218,34 +228,29 @@ public interface SpiQuery<T> extends Query<T> {
Timestamp getAsOf();
/**
* Add a table alias for a @History entity involved in a 'As Of' query.
* Return true if the base table is using history.
*/
void addAsOfTableAlias(String tableAlias);
boolean isAsOfBaseTable();
/**
* Return the list of table alias involved in a 'As Of' query that have @History support.
* Set when the base table is using history.
*/
List<String> getAsOfTableAlias();
void setAsOfBaseTable();
/**
* Increment the counter of tables used in 'As Of' query.
*/
void incrementAsOfTableCount();
/**
* Return the table alias used for the base table.
*/
int getAsOfTableCount();
void addSoftDeletePredicate(String softDeletePredicate);
List<String> getSoftDeletePredicates();
/**
* Set the list of Id's that is being populated.
* <p>
* This is a mutating list of id's and we are setting this so that other
* threads have access to the id's before the id query has finished.
* </p>
*/
void setIdList(List<Object> ids);
/**
* Return the list of Id's that is currently being fetched by a background
* thread.
*/
List<Object> getIdList();
/**
* Return a copy of the query.
*/
@@ -291,6 +296,16 @@ public interface SpiQuery<T> extends Query<T> {
*/
void setLoadDescription(String loadMode, String loadDescription);
/**
* Check that the named parameters have had their values set.
*/
void checkNamedParameters();
/**
* Create a named parameter placeholder.
*/
SpiNamedParam createNamedParameter(String parameterName);
/**
* Return the joins required to support predicates on the many properties.
*/
@@ -301,6 +316,11 @@ public interface SpiQuery<T> extends Query<T> {
*/
NaturalKeyBindParam getNaturalKeyBindParam();
/**
* Prepare the query for docstore execution with nested paths.
*/
void prepareDocNested();
/**
* Set the query to be a delete query.
*/
@@ -311,6 +331,24 @@ public interface SpiQuery<T> extends Query<T> {
*/
void setSelectId();
/**
* Mark the query as selecting a single attribute.
*/
void setSingleAttribute();
/**
* Return true if this is singleAttribute query.
*/
boolean isSingleAttribute();
/**
* Return true if the query should include the Id property.
* <p>
* distinct and single attribute queries exclude the Id property.
* </p>
*/
boolean isWithId();
/**
* Set a filter to a join path.
*/
@@ -475,12 +513,6 @@ public interface SpiQuery<T> extends Query<T> {
*/
OrderBy<T> getOrderBy();
/**
* Return additional where clause. This should be added to any where clause
* that was part of the original query.
*/
String getAdditionalWhere();
/**
* Can return null if no expressions where added to the where clause.
*/
@@ -496,12 +528,6 @@ public interface SpiQuery<T> extends Query<T> {
*/
SpiExpressionList<T> getTextExpression();
/**
* Return additional having clause. Where raw String expressions are added
* to having clause rather than Expression objects.
*/
String getAdditionalHaving();
/**
* Returns true if either firstRow or maxRows has been set.
*/
@@ -544,12 +570,6 @@ public interface SpiQuery<T> extends Query<T> {
*/
BindParams getBindParams();
/**
* Get the orm query as a String. Only available if the query was built from
* a string.
*/
String getQuery();
/**
* Replace the query detail. This is used by the AutoTune feature to as a
* fast way to set the query properties and joins.
@@ -566,6 +586,11 @@ public interface SpiQuery<T> extends Query<T> {
*/
boolean tuneFetchProperties(OrmQueryDetail detail);
/**
* If this is a RawSql based entity set the default RawSql if not set.
*/
void setDefaultRawSqlIfRequired();
/**
* Set to true if this query has been tuned by autoTune.
*/
@@ -576,9 +601,15 @@ public interface SpiQuery<T> extends Query<T> {
*/
OrmQueryDetail getDetail();
TableJoin getIncludeTableJoin();
/**
* Return the extra join for a M2M lazy load.
*/
TableJoin getM2mIncludeJoin();
void setIncludeTableJoin(TableJoin includeTableJoin);
/**
* Set the extra join for a M2M lazy load.
*/
void setM2MIncludeJoin(TableJoin includeTableJoin);
/**
* Return the property used to specify keys for a map.
@@ -622,16 +653,16 @@ public interface SpiQuery<T> extends Query<T> {
*/
void setDefaultSelectClause();
/**
* Return the where clause from a parsed string query.
*/
String getRawWhereClause();
/**
* Set the generated sql for debug purposes.
*/
void setGeneratedSql(String generatedSql);
/**
* Set the JDBC fetchSize buffer hint if not explicitly set.
*/
void setDefaultFetchBuffer(int fetchSize);
/**
* Return the hint for Statement.setFetchSize().
*/
@@ -688,4 +719,8 @@ public interface SpiQuery<T> extends Query<T> {
*/
OrmUpdateProperties getUpdateProperties();
/**
* Simplify nested expression lists where possible.
*/
void simplifyExpressions();
}
@@ -220,6 +220,12 @@ public interface SpiTransaction extends Transaction {
*/
Connection getInternalConnection();
/**
* Rollback if the transaction is active. This provides an internal
* mechanism for rollback failures occur on commit().
*/
void rollbackIfActive();
/**
* Return true if the manyToMany intersection should be persisted for this particular relationship direction.
*/
@@ -40,7 +40,7 @@ public class ExtraDdlXmlReader {
* @param platforms The platforms (comma delimited) this script should run for
*/
public static boolean matchPlatform(String platformName, String platforms) {
if (platforms == null || platforms.trim().length() == 0) {
if (platforms == null || platforms.trim().isEmpty()) {
return true;
}
String[] names = platforms.split("[,;]");
@@ -45,9 +45,8 @@ public class ProfileOriginNodeUsage {
if (path != null) {
ElPropertyValue elGetValue = rootDesc.getElGetValue(path);
if (elGetValue == null) {
desc = null;
logger.warn("AutoTune: Can't find join for path[" + path + "] for " + rootDesc.getName());
return;
} else {
BeanProperty beanProperty = elGetValue.getBeanProperty();
if (beanProperty instanceof BeanPropertyAssoc<?>) {
@@ -4,7 +4,6 @@ import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@@ -1,7 +1,6 @@
package com.avaje.ebeaninternal.server.cache;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.EbeanServer;
import com.avaje.ebean.cache.ServerCache;
import com.avaje.ebean.cache.ServerCacheOptions;
import com.avaje.ebean.cache.ServerCacheStatistics;
@@ -20,10 +20,13 @@ public class DefaultServerCacheManager implements ServerCacheManager {
private final DefaultCacheHolder collectionIdsCache;
private final boolean localL2Caching;
/**
* Create with a cache factory and default cache options.
*/
public DefaultServerCacheManager(ServerCacheFactory cacheFactory, ServerCacheOptions defaultBeanOptions, ServerCacheOptions defaultQueryOptions) {
public DefaultServerCacheManager(boolean localL2Caching, ServerCacheFactory cacheFactory, ServerCacheOptions defaultBeanOptions, ServerCacheOptions defaultQueryOptions) {
this.localL2Caching = localL2Caching;
this.beanCache = new DefaultCacheHolder(cacheFactory, defaultBeanOptions);
this.queryCache = new DefaultCacheHolder(cacheFactory, defaultQueryOptions);
this.naturalKeyCache = new DefaultCacheHolder(cacheFactory, defaultBeanOptions);
@@ -34,7 +37,11 @@ public class DefaultServerCacheManager implements ServerCacheManager {
* Construct when l2 cache is disabled.
*/
public DefaultServerCacheManager() {
this(new DefaultServerCacheFactory(), new ServerCacheOptions(), new ServerCacheOptions());
this(true, new DefaultServerCacheFactory(), new ServerCacheOptions(), new ServerCacheOptions());
}
public boolean isLocalL2Caching() {
return localL2Caching;
}
/**
@@ -49,7 +56,9 @@ public class DefaultServerCacheManager implements ServerCacheManager {
queryCache.clearCache(beanName);
}
/**
* Clear all caches.
*/
public void clearAll() {
beanCache.clearAll();
queryCache.clearAll();
@@ -57,7 +66,6 @@ public class DefaultServerCacheManager implements ServerCacheManager {
collectionIdsCache.clearAll();
}
public ServerCache getCollectionIdsCache(Class<?> beanType, String propertyName) {
return collectionIdsCache.getCache(beanType.getName() + "." + propertyName, ServerCacheType.COLLECTION_IDS);
}
@@ -87,5 +95,4 @@ public class DefaultServerCacheManager implements ServerCacheManager {
return beanCache.isCaching(beanType.getName());
}
}
@@ -68,11 +68,11 @@ public abstract class BeanRequest {
public void rollbackTransIfRequired() {
if (createdTransaction) {
try {
transaction.rollback();
transaction.rollbackIfActive();
} catch (Exception e) {
// Just log this and carry on. A previous exception has been
// thrown and if this rollback throws exception it likely means
// that the connection is broken (and the datasource and db will cleanup)
// that the connection is broken (and the dataSource and db will cleanup)
log.error("Error trying to rollback a transaction (after a prior exception thrown)", e);
}
}
@@ -10,7 +10,7 @@ public class CacheOptions {
/**
* Instance when no caching is used.
*/
public static CacheOptions NO_CACHING = new CacheOptions();
public static final CacheOptions NO_CACHING = new CacheOptions();
private final boolean enableBeanCache;
private final boolean enableQueryCache;
@@ -1,35 +1,25 @@
package com.avaje.ebeaninternal.server.core;
import java.util.concurrent.TimeUnit;
import com.avaje.ebeaninternal.api.SpiBackgroundExecutor;
import com.avaje.ebeaninternal.server.lib.DaemonExecutorService;
import com.avaje.ebeaninternal.server.lib.DaemonScheduleThreadPool;
import com.avaje.ebeaninternal.server.lib.DaemonThreadPool;
import java.util.concurrent.TimeUnit;
/**
* The default implementation of the BackgroundExecutor.
*/
public class DefaultBackgroundExecutor implements SpiBackgroundExecutor {
private final DaemonThreadPool pool;
private final DaemonScheduleThreadPool schedulePool;
private final DaemonExecutorService pool;
/**
* Construct the default implementation of BackgroundExecutor.
*
* @param corePoolSize
* the core size of the thread pool.
* @param maximumPoolSize
* the maximum pool size before jobs are queued
* @param keepAliveSecs
* the time in seconds idle threads are keep alive
* @param shutdownWaitSeconds
* the time in seconds allowed for the pool to shutdown nicely.
* After this the pool is forced to shutdown.
*/
public DefaultBackgroundExecutor(int schedulePoolSize, int corePoolSize, int maximumPoolSize, long keepAliveSecs,int shutdownWaitSeconds, String namePrefix) {
this.pool = new DaemonThreadPool(corePoolSize, maximumPoolSize, keepAliveSecs, shutdownWaitSeconds, namePrefix);
public DefaultBackgroundExecutor(int schedulePoolSize, int shutdownWaitSeconds, String namePrefix) {
this.pool = new DaemonExecutorService(shutdownWaitSeconds, namePrefix);
this.schedulePool = new DaemonScheduleThreadPool(schedulePoolSize, shutdownWaitSeconds, namePrefix+"-periodic-");
}
@@ -281,7 +281,7 @@ public class DefaultBeanLoader {
}
}
SpiQuery<?> query = (SpiQuery<?>) server.createQuery(desc.getBeanType());
SpiQuery<?> query = server.createQuery(desc.getBeanType());
query.setLazyLoadProperty(ebi.getLazyLoadProperty());
if (draft) {
query.asDraft();
@@ -14,14 +14,14 @@ import java.util.Set;
*/
public class DefaultBeanState implements BeanState {
private final EntityBean entityBean;
private final EntityBeanIntercept intercept;
public DefaultBeanState(EntityBean entityBean){
this.entityBean = entityBean;
this.intercept = entityBean._ebean_getIntercept();
}
private final EntityBean entityBean;
private final EntityBeanIntercept intercept;
public DefaultBeanState(EntityBean entityBean) {
this.entityBean = entityBean;
this.intercept = entityBean._ebean_getIntercept();
}
public void setPropertyLoaded(String propertyName, boolean loaded) {
intercept.setPropertyLoaded(propertyName, loaded);
@@ -31,52 +31,62 @@ public class DefaultBeanState implements BeanState {
return intercept.isReference();
}
public boolean isNew() {
return intercept.isNew();
}
public boolean isNewOrDirty() {
return intercept.isNewOrDirty();
}
public boolean isDirty() {
return intercept.isDirty();
}
public Set<String> getLoadedProps() {
return intercept.getLoadedPropertyNames();
}
public Set<String> getChangedProps() {
return intercept.getDirtyPropertyNames();
public boolean isNew() {
return intercept.isNew();
}
public Map<String,ValuePair> getDirtyValues() {
public boolean isNewOrDirty() {
return intercept.isNewOrDirty();
}
public boolean isDirty() {
return intercept.isDirty();
}
public Set<String> getLoadedProps() {
return intercept.getLoadedPropertyNames();
}
public Set<String> getChangedProps() {
return intercept.getDirtyPropertyNames();
}
public Map<String, ValuePair> getDirtyValues() {
return intercept.getDirtyValues();
}
public boolean isReadOnly() {
return intercept.isReadOnly();
}
public void setReadOnly(boolean readOnly){
intercept.setReadOnly(readOnly);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
entityBean.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
entityBean.removePropertyChangeListener(listener);
}
public void setLoaded() {
intercept.setLoaded();
}
public boolean isReadOnly() {
return intercept.isReadOnly();
}
public void setReadOnly(boolean readOnly) {
intercept.setReadOnly(readOnly);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
entityBean.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
entityBean.removePropertyChangeListener(listener);
}
public void setLoaded() {
intercept.setLoaded();
}
@Override
public void setDisableLazyLoad(boolean disableLazyLoading) {
intercept.setDisableLazyLoad(disableLazyLoading);
}
@Override
public boolean isDisableLazyLoad() {
return intercept.isDisableLazyLoad();
}
@Override
public void resetForInsert() {
intercept.setNew();
}
}
@@ -17,6 +17,8 @@ import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.server.cache.DefaultServerCachePlugin;
import com.avaje.ebeaninternal.server.cache.DefaultServerCacheManager;
import com.avaje.ebeaninternal.server.cluster.ClusterManager;
import com.avaje.ebeaninternal.server.core.bootup.BootupClassPathSearch;
import com.avaje.ebeaninternal.server.core.bootup.BootupClasses;
import com.avaje.ebeaninternal.server.lib.ShutdownManager;
import org.avaje.datasource.DataSourceAlertFactory;
import org.avaje.datasource.DataSourceConfig;
@@ -76,14 +78,10 @@ public class DefaultContainer implements SpiContainer {
private SpiBackgroundExecutor createBackgroundExecutor(ServerConfig serverConfig) {
String namePrefix = "ebean-" + serverConfig.getName();
int schedulePoolSize = serverConfig.getBackgroundExecutorSchedulePoolSize();
int corePoolSize = serverConfig.getBackgroundExecutorCorePoolSize();
int maxPoolSize = serverConfig.getBackgroundExecutorMaxPoolSize();
int idleSecs = serverConfig.getBackgroundExecutorIdleSecs();
int shutdownSecs = serverConfig.getBackgroundExecutorShutdownSecs();
return new DefaultBackgroundExecutor(schedulePoolSize, corePoolSize, maxPoolSize, idleSecs, shutdownSecs, namePrefix);
return new DefaultBackgroundExecutor(schedulePoolSize, shutdownSecs, namePrefix);
}
/**
@@ -120,22 +118,20 @@ public class DefaultContainer implements SpiContainer {
// generate and run DDL if required
// if there are any other tasks requiring action in their plugins, do them as well
if (!DbOffline.isRunningMigration()) {
if (!DbOffline.isGenerateMigration()) {
server.executePlugins(online);
}
// initialise prior to registering with clusterManager
server.initialise();
if (online) {
if (clusterManager.isClustering()) {
// register the server once it has been created
clusterManager.registerServer(server);
// initialise prior to registering with clusterManager
server.initialise();
if (online) {
if (clusterManager.isClustering()) {
// register the server once it has been created
clusterManager.registerServer(server);
}
}
// start any services after registering with clusterManager
server.start();
}
// start any services after registering with clusterManager
server.start();
DbOffline.reset();
return server;
}
@@ -168,6 +164,7 @@ public class DefaultContainer implements SpiContainer {
queryOptions.setMaxIdleSecs(serverConfig.getQueryCacheMaxIdleTime());
queryOptions.setMaxSecsToLive(serverConfig.getQueryCacheMaxTimeToLive());
boolean localL2Caching = false;
ServerCachePlugin plugin = serverConfig.getServerCachePlugin();
if (plugin == null) {
ServiceLoader<ServerCachePlugin> cacheFactories = ServiceLoader.load(ServerCachePlugin.class);
@@ -177,13 +174,14 @@ public class DefaultContainer implements SpiContainer {
plugin = iterator.next();
logger.debug("using ServerCacheFactory {}", plugin.getClass());
} else {
// use the built in default
// use the built in default l2 caching which is local cache based
localL2Caching = true;
plugin = new DefaultServerCachePlugin();
}
}
ServerCacheFactory factory = plugin.create(serverConfig, executor);
return new DefaultServerCacheManager(factory, beanOptions, queryOptions);
return new DefaultServerCacheManager(localL2Caching, factory, beanOptions, queryOptions);
}
/**
@@ -192,20 +190,19 @@ public class DefaultContainer implements SpiContainer {
*/
private BootupClasses getBootupClasses(ServerConfig serverConfig) {
BootupClasses bootupClasses = getBootupClasses1(serverConfig);
bootupClasses.addIdGenerators(serverConfig.getIdGenerators());
bootupClasses.addPersistControllers(serverConfig.getPersistControllers());
bootupClasses.addPostLoaders(serverConfig.getPostLoaders());
bootupClasses.addFindControllers(serverConfig.getFindControllers());
bootupClasses.addTransactionEventListeners(serverConfig.getTransactionEventListeners());
bootupClasses.addPersistListeners(serverConfig.getPersistListeners());
bootupClasses.addQueryAdapters(serverConfig.getQueryAdapters());
bootupClasses.addServerConfigStartup(serverConfig.getServerConfigStartupListeners());
bootupClasses.addChangeLogInstances(serverConfig);
BootupClasses bootup = getBootupClasses1(serverConfig);
bootup.addIdGenerators(serverConfig.getIdGenerators());
bootup.addPersistControllers(serverConfig.getPersistControllers());
bootup.addPostLoaders(serverConfig.getPostLoaders());
bootup.addFindControllers(serverConfig.getFindControllers());
bootup.addPersistListeners(serverConfig.getPersistListeners());
bootup.addQueryAdapters(serverConfig.getQueryAdapters());
bootup.addServerConfigStartup(serverConfig.getServerConfigStartupListeners());
bootup.addChangeLogInstances(serverConfig);
// run any ServerConfigStartup instances
bootupClasses.runServerConfigStartup(serverConfig);
return bootupClasses;
bootup.runServerConfigStartup(serverConfig);
return bootup;
}
/**
@@ -214,7 +211,7 @@ public class DefaultContainer implements SpiContainer {
private BootupClasses getBootupClasses1(ServerConfig serverConfig) {
List<Class<?>> entityClasses = serverConfig.getClasses();
if (serverConfig.isDisableClasspathSearch() || (entityClasses != null && entityClasses.size() > 0)) {
if (serverConfig.isDisableClasspathSearch() || (entityClasses != null && !entityClasses.isEmpty())) {
// use classes we explicitly added via configuration
return new BootupClasses(entityClasses);
}
@@ -240,7 +237,7 @@ public class DefaultContainer implements SpiContainer {
if (dbPlatform == null) {
DatabasePlatformFactory factory = new DatabasePlatformFactory();
DatabasePlatform db = factory.create(config);
db.configure(config.getProperties());
db.configure(config);
config.setDatabasePlatform(db);
logger.info("DatabasePlatform name:" + config.getName() + " platform:" + db.getName());
}
@@ -40,6 +40,7 @@ import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
import com.avaje.ebeaninternal.server.el.ElFilter;
import com.avaje.ebeaninternal.server.grammer.EqlParser;
import com.avaje.ebeaninternal.server.lib.ShutdownManager;
import com.avaje.ebeaninternal.server.query.CQuery;
import com.avaje.ebeaninternal.server.query.CQueryEngine;
@@ -70,10 +71,8 @@ import javax.persistence.NonUniqueResultException;
import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceException;
import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -557,7 +556,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
InheritInfo inheritInfo = desc.getInheritInfo();
if (inheritInfo == null) {
return (T)desc.contextRef(pc, null, id);
return (T)desc.contextRef(pc, null, false, id);
}
BeanProperty idProp = desc.getIdProperty();
@@ -683,6 +682,9 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
if (txScope == null) {
// create a TxScope with default settings
txScope = new TxScope();
} else {
// check for implied batch mode via setting batchSize
txScope.checkBatchMode();
}
SpiTransaction suspended = null;
@@ -836,7 +838,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
if (sortByClause == null) {
throw new NullPointerException("sortByClause is null");
}
if (list.size() == 0) {
if (list.isEmpty()) {
// don't need to sort an empty list
return;
}
@@ -884,6 +886,32 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
return createQuery(beanType);
}
@Override
public <T> Query<T> createNamedQuery(Class<T> beanType, String namedQuery) {
BeanDescriptor<T> desc = getBeanDescriptor(beanType);
if (desc == null) {
throw new PersistenceException(beanType.getName() + " is NOT an Entity Bean registered with this server?");
}
String named = desc.getNamedQuery(namedQuery);
if (named != null) {
return createQuery(beanType, named);
}
RawSql rawSql = desc.getNamedRawSql(namedQuery);
if (rawSql != null) {
DefaultOrmQuery<T> query = createQuery(beanType);
query.setRawSql(rawSql);
return query;
}
throw new PersistenceException("No named query called " + namedQuery + " for bean:" + beanType.getName());
}
@Override
public <T> Query<T> createQuery(Class<T> beanType, String eql) {
DefaultOrmQuery<T> query = createQuery(beanType);
EqlParser.parse(eql, query);
return query;
}
public <T> DefaultOrmQuery<T> createQuery(Class<T> beanType) {
BeanDescriptor<T> desc = getBeanDescriptor(beanType);
if (desc == null) {
@@ -936,12 +964,14 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
SpiQuery<T> spiQuery = (SpiQuery<T>) query;
spiQuery.setType(type);
spiQuery.checkNamedParameters();
return createQueryRequest(spiQuery, t);
}
private <T> SpiOrmQueryRequest<T> createQueryRequest(SpiQuery<T> query, Transaction t) {
query.setDefaultRawSqlIfRequired();
if (query.isAutoTunable() && !autoTuneService.tuneQuery(query)) {
// use deployment FetchType.LAZY/EAGER annotations
// to define the 'default' select clause
@@ -991,7 +1021,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
}
if (!query.isUseBeanCache()) {
if (!query.isUseBeanCache() || (t != null && t.isSkipCache())) {
return null;
}
@@ -1041,26 +1071,31 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
}
public <T> T findUnique(Query<T> query, Transaction t) {
Object id = query.getId();
if (id != null) {
// actually a find by Id query
return findId(query, t);
}
public <T> T findUnique(Query<T> query, Transaction transaction) {
SpiQuery<T> spiQuery = (SpiQuery<T>) query;
BeanDescriptor<T> desc = spiQuery.getBeanDescriptor();
id = desc.cacheNaturalKeyIdLookup(spiQuery);
spiQuery.checkIdEqualTo();
Object id = spiQuery.getId();
if (id != null) {
T bean = findIdCheckPersistenceContextAndCache(t, spiQuery, id);
if (bean != null) {
return bean;
// actually a find by Id query
return findId(query, transaction);
}
SpiTransaction t = (SpiTransaction) transaction;
if (t == null) {
t = getCurrentServerTransaction();
}
if (t == null || !t.isSkipCache()) {
id = spiQuery.getBeanDescriptor().cacheNaturalKeyIdLookup(spiQuery);
if (id != null) {
T bean = findIdCheckPersistenceContextAndCache(t, spiQuery, id);
if (bean != null) {
return bean;
}
}
}
// a query that is expected to return either 0 or 1 rows
// a query that is expected to return either 0 or 1 beans
List<T> list = findList(query, t);
return extractUnique(list);
}
@@ -1097,30 +1132,52 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public <T> Map<?, T> findMap(Query<T> query, Transaction t) {
public <K, T> Map<K, T> findMap(Query<T> query, Transaction t) {
SpiOrmQueryRequest request = createQueryRequest(Type.MAP, query, t);
Object result = request.getFromQueryCache();
if (result != null) {
return (Map<?, T>) result;
return (Map<K, T>) result;
}
try {
request.initTransIfRequired();
return (Map<?, T>) request.findMap();
return (Map<K, T>) request.findMap();
} finally {
request.endTransIfRequired();
}
}
public <T> int findRowCount(Query<T> query, Transaction t) {
@Override
@SuppressWarnings("unchecked")
public <A> List<A> findSingleAttributeList(Query<?> query, Transaction t) {
SpiOrmQueryRequest request = createQueryRequest(Type.ATTRIBUTE, query, t);
Object result = request.getFromQueryCache();
if (result != null) {
return (List<A>) result;
}
try {
request.initTransIfRequired();
return (List<A>) request.findSingleAttributeList();
} finally {
request.endTransIfRequired();
}
}
public <T> int findCount(Query<T> query, Transaction t) {
SpiQuery<T> copy = ((SpiQuery<T>) query).copy();
return findRowCountWithCopy(copy, t);
}
public <T> int findRowCount(Query<T> query, Transaction t) {
return findCount(query, t);
}
public <T> int findRowCountWithCopy(Query<T> query, Transaction t) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ROWCOUNT, query, t);
@@ -1133,16 +1190,14 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
}
public <T> List<Object> findIds(Query<T> query, Transaction t) {
public <A> List<A> findIds(Query<?> query, Transaction t) {
SpiQuery<T> copy = ((SpiQuery<T>) query).copy();
return findIdsWithCopy(copy, t);
return findIdsWithCopy(((SpiQuery<?>) query).copy(), t);
}
public <T> List<Object> findIdsWithCopy(Query<T> query, Transaction t) {
public <A> List<A> findIdsWithCopy(Query<?> query, Transaction t) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ID_LIST, query, t);
SpiOrmQueryRequest<?> request = createQueryRequest(Type.ID_LIST, query, t);
try {
request.initTransIfRequired();
return request.findIds();
@@ -1176,7 +1231,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
}
public <T> FutureRowCount<T> findFutureRowCount(Query<T> q, Transaction t) {
public <T> FutureRowCount<T> findFutureCount(Query<T> q, Transaction t) {
SpiQuery<T> copy = ((SpiQuery<T>) q).copy();
copy.setFutureFetch(true);
@@ -1191,17 +1246,15 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
return queryFuture;
}
public <T> FutureRowCount<T> findFutureRowCount(Query<T> q, Transaction t) {
return findFutureCount(q, t);
}
public <T> FutureIds<T> findFutureIds(Query<T> query, Transaction t) {
SpiQuery<T> copy = ((SpiQuery<T>) query).copy();
copy.setFutureFetch(true);
// this is the list we will put the id's in ... create it now so
// it is available for other threads to read while the id query
// is still executing (we don't need to wait for it to finish)
List<Object> idList = Collections.synchronizedList(new ArrayList<Object>());
copy.setIdList(idList);
Transaction newTxn = createTransaction();
CallableQueryIds<T> call = new CallableQueryIds<T>(this, copy, newTxn);
@@ -1249,6 +1302,19 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
return new LimitOffsetPagedList<T>(this, spiQuery);
}
public <T> QueryIterator<T> findIterate(Query<T> query, Transaction t) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
try {
request.initTransIfRequired();
return request.findIterate();
} catch (RuntimeException ex) {
request.endTransIfRequired();
throw ex;
}
}
public <T> void findEach(Query<T> query, QueryEachConsumer<T> consumer, Transaction t) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
@@ -22,6 +22,7 @@ import com.avaje.ebeaninternal.server.changelog.DefaultChangeLogListener;
import com.avaje.ebeaninternal.server.changelog.DefaultChangeLogPrepare;
import com.avaje.ebeaninternal.server.changelog.DefaultChangeLogRegister;
import com.avaje.ebeaninternal.server.cluster.ClusterManager;
import com.avaje.ebeaninternal.server.core.bootup.BootupClasses;
import com.avaje.ebeaninternal.server.core.timezone.CloneDataTimeZone;
import com.avaje.ebeaninternal.server.core.timezone.DataTimeZone;
import com.avaje.ebeaninternal.server.core.timezone.NoDataTimeZone;
@@ -136,7 +137,7 @@ public class InternalConfiguration {
this.dataTimeZone = initDataTimeZone();
this.binder = getBinder(typeManager, databasePlatform, dataTimeZone);
this.cQueryEngine = new CQueryEngine(databasePlatform, binder, asOfTableMapping, serverConfig.getAsOfSysPeriod(), draftTableMap);
this.cQueryEngine = new CQueryEngine(serverConfig, databasePlatform, binder, asOfTableMapping, draftTableMap);
}
/**
@@ -234,7 +235,7 @@ public class InternalConfiguration {
if (historySupport == null) {
return new Binder(typeManager, 0, false, jsonHandler, dataTimeZone);
}
return new Binder(typeManager, historySupport.getBindCount(), historySupport.isBindWithFromClause(), jsonHandler, dataTimeZone);
return new Binder(typeManager, historySupport.getBindCount(), historySupport.isStandardsBased(), jsonHandler, dataTimeZone);
}
/**
@@ -337,15 +338,16 @@ public class InternalConfiguration {
*/
public TransactionManager createTransactionManager(DocStoreUpdateProcessor indexUpdateProcessor) {
boolean localL2 = cacheManager.isLocalL2Caching();
if (serverConfig.isExplicitTransactionBeginMode()) {
return new ExplicitTransactionManager(serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager, this.getBootupClasses());
return new ExplicitTransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager);
}
if (isAutoCommitMode()) {
return new AutoCommitTransactionManager(serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager, this.getBootupClasses());
return new AutoCommitTransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager);
}
return new TransactionManager(serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager, this.getBootupClasses());
return new TransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager);
}
/**
@@ -1,8 +1,8 @@
package com.avaje.ebeaninternal.server.core;
import com.avaje.ebean.QueryIterator;
import com.avaje.ebean.Version;
import com.avaje.ebean.bean.BeanCollection;
import com.avaje.ebeaninternal.api.BeanIdList;
import java.util.List;
@@ -21,6 +21,14 @@ public interface OrmQueryEngine {
*/
<T> BeanCollection<T> findMany(OrmQueryRequest<T> request);
/**
* Execute the findSingleAttributeList query.
*/
<A> List<A> findSingleAttributeList(OrmQueryRequest<?> request);
/**
* Execute the findVersions query.
*/
<T> List<Version<T>> findVersions(OrmQueryRequest<T> request);
/**
@@ -36,7 +44,7 @@ public interface OrmQueryEngine {
/**
* Execute the find id's query.
*/
<T> BeanIdList findIds(OrmQueryRequest<T> request);
<A> List<A> findIds(OrmQueryRequest<?> request);
/**
* Execute the query as a delete statement.
@@ -3,6 +3,7 @@ package com.avaje.ebeaninternal.server.core;
import com.avaje.ebean.PersistenceContextScope;
import com.avaje.ebean.QueryEachConsumer;
import com.avaje.ebean.QueryEachWhileConsumer;
import com.avaje.ebean.QueryIterator;
import com.avaje.ebean.RawSql;
import com.avaje.ebean.Version;
import com.avaje.ebean.bean.BeanCollection;
@@ -12,7 +13,6 @@ import com.avaje.ebean.event.BeanFindController;
import com.avaje.ebean.event.BeanQueryAdapter;
import com.avaje.ebean.event.BeanQueryRequest;
import com.avaje.ebean.text.json.JsonReadOptions;
import com.avaje.ebeaninternal.api.BeanIdList;
import com.avaje.ebeaninternal.api.CQueryPlanKey;
import com.avaje.ebeaninternal.api.HashQuery;
import com.avaje.ebeaninternal.api.LoadContext;
@@ -304,9 +304,8 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
return queryEngine.findRowCount(this);
}
public List<Object> findIds() {
BeanIdList idList = queryEngine.findIds(this);
return idList.getIdList();
public <A> List<A> findIds() {
return queryEngine.findIds(this);
}
public void findEach(QueryEachConsumer<T> consumer) {
@@ -373,6 +372,14 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
return (Map<?, ?>) queryEngine.findMany(this);
}
/**
* Execute the findSingleAttributeList query.
*/
@Override
public <A> List<A> findSingleAttributeList() {
return queryEngine.findSingleAttributeList(this);
}
/**
* Return a bean specific finder if one has been set.
*/
@@ -513,4 +520,18 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
public boolean isAuditReads() {
return !query.isDisableReadAudit() && beanDescriptor.isReadAuditing();
}
/**
* Return the base table alias for this query.
*/
public String getBaseTableAlias() {
return query.getAlias() == null ? beanDescriptor.getBaseTableAlias() : query.getAlias();
}
/**
* Set the JDBC buffer fetchSize hint if not set explicitly.
*/
public void setDefaultFetchBuffer(int fetchSize) {
query.setDefaultFetchBuffer(fetchSize);
}
}
@@ -1,6 +1,7 @@
package com.avaje.ebeaninternal.server.core;
import com.avaje.ebean.ValuePair;
import com.avaje.ebean.bean.PreGetterCallback;
import com.avaje.ebeaninternal.api.ConcurrencyMode;
import com.avaje.ebean.annotation.DocStoreMode;
import com.avaje.ebean.bean.EntityBean;
@@ -36,7 +37,7 @@ import java.util.Set;
/**
* PersistRequest for insert update or delete of a bean.
*/
public final class PersistRequestBean<T> extends PersistRequest implements BeanPersistRequest<T>, DocStoreUpdate {
public final class PersistRequestBean<T> extends PersistRequest implements BeanPersistRequest<T>, DocStoreUpdate, PreGetterCallback {
private final BeanManager<T> beanManager;
@@ -137,6 +138,11 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
private long version;
/**
* Flag set when request is added to JDBC batch registered as a "getter callback" to automatically flush batch.
*/
private boolean getterCallback;
public PersistRequestBean(SpiEbeanServer server, T bean, Object parentBean, BeanManager<T> mgr, SpiTransaction t,
PersistExecute persistExecute, PersistRequest.Type type, boolean saveRecurse, boolean publish) {
@@ -239,8 +245,17 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
*/
public void setBatched() {
batched = true;
if (type == Type.INSERT || type == Type.UPDATE) {
// used to trigger automatic jdbc batch flush
intercept.registerGetterCallback(this);
getterCallback = true;
}
}
@Override
public void preGetterTrigger() {
transaction.flushBatch();
}
public void setSkipBatchForTopLevel() {
skipBatchForTopLevel = true;
@@ -548,7 +563,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
* Create and return a new reference bean matching this beans Id value.
*/
public T createReference() {
return beanDescriptor.createReference(Boolean.FALSE, getBeanId(), null);
return beanDescriptor.createReference(Boolean.FALSE, false, getBeanId(), null);
}
/**
@@ -621,6 +636,9 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
@Override
public int executeNow() {
if (getterCallback) {
intercept.clearGetterCallback();
}
switch (type) {
case INSERT:
persistExecute.executeInsertBean(this);
@@ -803,7 +821,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
}
/**
* Add the bean to the TransactionEvent. This will be used by TransactionManager to synch Cache,
* Add the bean to the TransactionEvent. This will be used by TransactionManager to sync Cache,
* Cluster and text indexes.
*/
private void addEvent() {
@@ -1,60 +0,0 @@
package com.avaje.ebeaninternal.server.core;
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();
}
@@ -219,7 +219,7 @@ public final class RelationalQueryRequest {
int maxRows = query.getMaxRows();
if (firstRow > 0 || maxRows > 0) {
return ebeanServer.getDatabasePlatform().getBasicSqlLimiter()
.limit(query.getQuery(), firstRow, maxRows);
.limit(sql, firstRow, maxRows);
}
return sql;
}
@@ -2,6 +2,7 @@ package com.avaje.ebeaninternal.server.core;
import com.avaje.ebean.QueryEachConsumer;
import com.avaje.ebean.QueryEachWhileConsumer;
import com.avaje.ebean.QueryIterator;
import com.avaje.ebean.Version;
import com.avaje.ebean.bean.BeanCollection;
import com.avaje.ebeaninternal.api.SpiQuery;
@@ -70,7 +71,7 @@ public interface SpiOrmQueryRequest<T> extends DocQueryRequest<T> {
/**
* Execute the find ids query.
*/
List<Object> findIds();
<A> List<A> findIds();
/**
* Execute the find returning a QueryIterator and visitor pattern.
@@ -107,6 +108,11 @@ public interface SpiOrmQueryRequest<T> extends DocQueryRequest<T> {
*/
Map<?, ?> findMap();
/**
* Execute the findSingleAttributeList query.
*/
<A> List<A> findSingleAttributeList();
/**
* Try to get the query result from the query cache.
*/
@@ -41,7 +41,7 @@ final class TransWrapper {
void rollbackIfCreated() {
if (wasCreated){
transaction.rollback();
transaction.rollbackIfActive();
}
}
@@ -1,6 +1,7 @@
package com.avaje.ebeaninternal.server.core;
package com.avaje.ebeaninternal.server.core.bootup;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebeaninternal.server.core.ClassPathScanners;
import org.avaje.classpath.scanner.ClassPathScanner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -10,10 +11,12 @@ import java.util.*;
/**
* Searches for interesting classes such as Entities, Embedded and ScalarTypes.
*/
class BootupClassPathSearch {
public class BootupClassPathSearch {
private static final Logger logger = LoggerFactory.getLogger(BootupClassPathSearch.class);
private static final String EBEAN_MF = "META-INF/ebean.mf";
private final List<String> packages;
private final List<ClassPathScanner> scanners;
@@ -28,7 +31,11 @@ class BootupClassPathSearch {
}
private BootupClassPathSearch(ServerConfig serverConfig) {
this.packages = serverConfig.getPackages();
// find packages defined in META-INF/ebean.mf resources
Set<String> mfPackages = ManifestReader.readManifests(serverConfig.getClassLoadConfig().getClassLoader(), EBEAN_MF);
this.packages = DistillPackages.distill(serverConfig.getPackages(), mfPackages);
this.scanners = ClassPathScanners.find(serverConfig);
}
@@ -42,7 +49,7 @@ class BootupClassPathSearch {
long st = System.currentTimeMillis();
for (ClassPathScanner finder : this.scanners) {
if (packages != null && packages.size() > 0) {
if (packages != null && !packages.isEmpty()) {
for (String packageName : packages) {
finder.scanForClasses(packageName, bc);
}
@@ -1,4 +1,4 @@
package com.avaje.ebeaninternal.server.core;
package com.avaje.ebeaninternal.server.core.bootup;
import com.avaje.ebean.config.CompoundType;
import com.avaje.ebean.config.IdGenerator;
@@ -10,14 +10,12 @@ import com.avaje.ebean.event.BeanPersistListener;
import com.avaje.ebean.event.BeanPostLoad;
import com.avaje.ebean.event.BeanQueryAdapter;
import com.avaje.ebean.event.ServerConfigStartup;
import com.avaje.ebean.event.TransactionEventListener;
import com.avaje.ebean.event.changelog.ChangeLogListener;
import com.avaje.ebean.event.changelog.ChangeLogPrepare;
import com.avaje.ebean.event.changelog.ChangeLogRegister;
import com.avaje.ebean.event.readaudit.ReadAuditLogger;
import com.avaje.ebean.event.readaudit.ReadAuditPrepare;
import com.avaje.ebeaninternal.server.type.ScalarType;
import com.avaje.ebeaninternal.server.util.ClassPathSearchMatcher;
import org.avaje.classpath.scanner.ClassFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -35,7 +33,7 @@ import java.util.List;
* Interesting classes for a EbeanServer such as Embeddable, Entity,
* ScalarTypes, Finders, Listeners and Controllers.
*/
public class BootupClasses implements ClassPathSearchMatcher, ClassFilter {
public class BootupClasses implements ClassFilter {
private static final Logger logger = LoggerFactory.getLogger(BootupClasses.class);
@@ -55,8 +53,6 @@ public class BootupClasses implements ClassPathSearchMatcher, ClassFilter {
private final List<Class<?>> beanPostLoadList = new ArrayList<Class<?>>();
private final List<Class<?>> transactionEventListenerList = new ArrayList<Class<?>>();
private final List<Class<?>> beanFindControllerList = new ArrayList<Class<?>>();
private final List<Class<?>> beanQueryAdapterList = new ArrayList<Class<?>>();
@@ -71,7 +67,6 @@ public class BootupClasses implements ClassPathSearchMatcher, ClassFilter {
private final List<BeanPostLoad> beanPostLoadInstances = new ArrayList<BeanPostLoad>();
private final List<BeanPersistListener> persistListenerInstances = new ArrayList<BeanPersistListener>();
private final List<BeanQueryAdapter> queryAdapterInstances = new ArrayList<BeanQueryAdapter>();
private final List<TransactionEventListener> transactionEventListenerInstances = new ArrayList<TransactionEventListener>();
private Class<?> changeLogPrepareClass;
private Class<?> changeLogListenerClass;
@@ -182,19 +177,6 @@ public class BootupClasses implements ClassPathSearchMatcher, ClassFilter {
}
}
/**
* Add TransactionEventListeners instances.
*/
public void addTransactionEventListeners(List<TransactionEventListener> transactionEventListeners) {
if (transactionEventListeners != null) {
for (TransactionEventListener c : transactionEventListeners) {
this.transactionEventListenerInstances.add(c);
// don't automatically instantiate
this.transactionEventListenerList.remove(c.getClass());
}
}
}
public void addPersistListeners(List<BeanPersistListener> listenerInstances) {
if (listenerInstances != null) {
for (BeanPersistListener l : listenerInstances) {
@@ -352,14 +334,6 @@ public class BootupClasses implements ClassPathSearchMatcher, ClassFilter {
return idGeneratorInstances;
}
public List<TransactionEventListener> getTransactionEventListeners() {
// add class registered TransactionEventListener to the already created instances
for (Class<?> cls : transactionEventListenerList) {
createAdd(cls, transactionEventListenerInstances);
}
return transactionEventListenerInstances;
}
/**
* Return the list of Embeddable classes.
*/
@@ -441,11 +415,6 @@ public class BootupClasses implements ClassPathSearchMatcher, ClassFilter {
interesting = true;
}
if (TransactionEventListener.class.isAssignableFrom(cls)) {
transactionEventListenerList.add(cls);
interesting = true;
}
if (ScalarType.class.isAssignableFrom(cls)) {
scalarTypeList.add(cls);
interesting = true;
@@ -0,0 +1,48 @@
package com.avaje.ebeaninternal.server.core.bootup;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.TreeSet;
/**
* Distill packages into distinct top level packages for searching.
*/
class DistillPackages {
/**
* Distill the list of packages into distinct top level packages.
*/
static List<String> distill(Collection<String> packages, Collection<String> mfPackages) {
// sort into natural order
TreeSet<String> treeSet = new TreeSet<String>();
treeSet.addAll(packages);
treeSet.addAll(mfPackages);
List<String> distilled = new ArrayList<String>();
// build the distilled list
for (String pack : treeSet) {
if (notAlreadyContained(distilled, pack)) {
distilled.add(pack);
}
}
return distilled;
}
/**
* Return true if the package is not already contained in the distilled list.
*/
private static boolean notAlreadyContained(List<String> distilled, String pack) {
for (int i = 0; i < distilled.size(); i++) {
if (pack.startsWith(distilled.get(i))) {
return false;
}
}
return true;
}
}
@@ -0,0 +1,84 @@
package com.avaje.ebeaninternal.server.core.bootup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
/**
* Reads all the META-INF/ebean.mf resources with the package locations of entity beans.
*/
class ManifestReader {
private static final Logger logger = LoggerFactory.getLogger(ManifestReader.class);
private final Set<String> packageSet = new HashSet<String>();
/**
* Read the packages from ebean.mf manifest files found as resources.
*/
static Set<String> readManifests(ClassLoader classLoader, String resourcePath) {
return new ManifestReader().read(classLoader, resourcePath);
}
/**
* Read all the specific manifest files and return the set of packages containing type query beans.
*/
private Set<String> read(ClassLoader classLoader, String resourcePath) {
try {
Enumeration<URL> resources = classLoader.getResources(resourcePath);
while (resources.hasMoreElements()) {
InputStream is = resources.nextElement().openStream();
try {
read(new Manifest(is));
} finally {
close(is);
}
}
} catch (IOException e) {
logger.warn("Error reading META-INF/ebean.mf manifest resources", e);
}
return packageSet;
}
private void close(InputStream is) {
try {
is.close();
} catch (IOException e) {
logger.warn("Error closing manifest InputStream", e);
}
}
/**
* Read the packages from the manifest.
*/
private void read(Manifest manifest) throws IOException {
Attributes attributes = manifest.getMainAttributes();
String packages = attributes.getValue("packages");
if (packages != null) {
add(packages);
}
}
/**
* Collect each individual package splitting by delimiters.
*/
private void add(String packages) {
String[] split = packages.split(",|;| ");
for (int i = 0; i <split.length; i++) {
String pkg = split[i].trim();
if (!pkg.isEmpty()) {
packageSet.add(pkg);
}
}
}
}
@@ -1,7 +1,6 @@
package com.avaje.ebeaninternal.server.deploy;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.bean.EntityBeanIntercept;
import com.avaje.ebean.bean.PersistenceContext;
import com.avaje.ebeaninternal.server.query.SqlJoinType;
@@ -21,6 +20,7 @@ abstract class AssocOneHelp {
this.property = property;
this.target = property.targetDescriptor;
}
/**
* Effectively skip reading (the jdbc resultSet as already in the persistence context etc).
*/
@@ -45,9 +45,11 @@ abstract class AssocOneHelp {
return existing;
}
Object ref = target.contextRef(pc, ctx.isReadOnly(), id);
EntityBeanIntercept ebi = ((EntityBean) ref)._ebean_getIntercept();
ctx.register(property.name, ebi);
boolean disableLazyLoading = ctx.isDisableLazyLoading();
Object ref = target.contextRef(pc, ctx.isReadOnly(), disableLazyLoading, id);
if (!disableLazyLoading) {
ctx.register(property.name, ((EntityBean) ref)._ebean_getIntercept());
}
return ref;
}
@@ -1,7 +1,6 @@
package com.avaje.ebeaninternal.server.deploy;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.bean.EntityBeanIntercept;
import com.avaje.ebean.bean.PersistenceContext;
import com.avaje.ebeaninternal.server.query.SqlJoinType;
@@ -53,9 +52,11 @@ class AssocOneHelpRefInherit extends AssocOneHelp {
}
// for inheritance hierarchy create the correct type for this row...
Object ref = desc.contextRef(pc, ctx.isReadOnly(), id);
EntityBeanIntercept ebi = ((EntityBean) ref)._ebean_getIntercept();
ctx.register(property.name, ebi);
boolean disableLazyLoading = ctx.isDisableLazyLoading();
Object ref = desc.contextRef(pc, ctx.isReadOnly(), disableLazyLoading, id);
if (disableLazyLoading) {
ctx.register(property.name, ((EntityBean) ref)._ebean_getIntercept());
}
return ref;
}
@@ -10,56 +10,69 @@ import javax.persistence.CascadeType;
*/
public class BeanCascadeInfo {
/**
* should delete cascade.
*/
boolean delete;
/**
* Should save cascade.
*/
boolean save;
private boolean delete;
public void setTypes(CascadeType[] types) {
for (int i = 0; i < types.length; i++) {
setType(types[i]);
}
private boolean save;
private boolean refresh;
public void setTypes(CascadeType[] types) {
for (int i = 0; i < types.length; i++) {
setType(types[i]);
}
private void setType(CascadeType type) {
if (type.equals(CascadeType.ALL)){
save = true;
delete = true;
}
if (type.equals(CascadeType.REMOVE)){
delete = true;
}
if (type.equals(CascadeType.PERSIST)){
save = true;
}
if (type.equals(CascadeType.MERGE)){
save = true;
}
}
/**
* Return true if delete should cascade.
*/
public boolean isDelete() {
return delete;
}
/**
* Set to true if delete should cascade.
*/
public void setDelete(boolean delete) {
this.delete = delete;
}
/**
* Return true if save should cascade.
*/
public boolean isSave() {
return save;
}
private void setType(CascadeType type) {
switch (type) {
case ALL:
save = true;
delete = true;
refresh = true;
break;
case REMOVE:
delete = true;
break;
case REFRESH:
refresh = true;
break;
case PERSIST:
save = true;
break;
case MERGE:
save = true;
break;
default:
throw new IllegalStateException("Unexpected CascadeType " + type);
}
}
/**
* Return true if refresh should cascade.
*/
public boolean isRefresh() {
return refresh;
}
/**
* Return true if delete should cascade.
*/
public boolean isDelete() {
return delete;
}
/**
* Set to true if delete should cascade.
*/
public void setDelete(boolean delete) {
this.delete = delete;
}
/**
* Return true if save should cascade.
*/
public boolean isSave() {
return save;
}
/**
* Set cascade save and delete settings.

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