Compare commits

...
Author SHA1 Message Date
Robin Bygrave b4c7cf529d [maven-release-plugin] prepare release avaje-ebeanorm-6.1.1 2015-07-20 20:08:42 +12:00
Robin Bygrave ba5c67f936 #346 - ENH: Add @Nullable annotation on find by id and findUnique() methods 2015-07-20 20:06:55 +12:00
Robin Bygrave 2bd7995ca1 Bump pom to 6.1.1-SNAPSHOT 2015-07-20 12:55:33 +12:00
Robin Bygrave cc8c860709 Internal DefaultOrmQuery cleanup : timeout can default to 0 (rather than -1) 2015-07-20 12:51:24 +12:00
Robin Bygrave 7d25e31289 No effective change - unused imports 2015-07-20 12:48:08 +12:00
Robin Bygrave 936e56835c Internal SpiQuery : remove unused lazyLoadForParentsIds 2015-07-20 12:47:09 +12:00
Robin Bygrave 0d848e9311 Internal SpiQuery : remove unused context additions 2015-07-20 12:44:26 +12:00
Robin Bygrave b794b6c77e Internal SpiQuery : remove unused convertWhereNaturalKeyToId() 2015-07-20 12:40:08 +12:00
Robin Bygrave f45d240682 #345 - Expose Query.getId() and Query.getBeanType() methods ... (previously on SpiQuery) 2015-07-20 12:24:56 +12:00
Robin Bygrave 1a6f68edd3 No effective change - javadoc 2015-07-20 11:55:24 +12:00
Robin Bygrave 81683c5d2a No effective change - javadoc 2015-07-20 11:50:38 +12:00
Robin Bygrave 2b535d59b8 No effective change - javadoc 2015-07-20 11:41:23 +12:00
Robin Bygrave ae0bbaaaf8 #344 - Remove deprecated annotation @ColumnHstore ... migrate to @DbHstore 2015-07-20 11:38:40 +12:00
Robin Bygrave aaca20f9c3 #343 - Remove deprecated interface BeanFinder<T> ... migrate to BeanFindController 2015-07-20 11:34:05 +12:00
Robin Bygrave 245cbb0ea1 #342 - Remove deprecated method - JsonContext createJsonContext() ... migrate to json() 2015-07-20 11:27:00 +12:00
Robin Bygrave dbe984c668 #341 - Remove deprecated method - insert(Collection<?> beans); ... migrate to insertAll() 2015-07-20 11:22:16 +12:00
Robin Bygrave 89088f9480 #340 - Remove deprecated method - update(Collection<?> beans) ... migrate to updateAll() 2015-07-20 11:18:51 +12:00
Robin Bygrave 80253c4e07 #339 - Remove deprecated method - save(Collection<?> beans, Transaction transaction) ... migrate to saveAll() 2015-07-20 11:15:10 +12:00
Robin Bygrave f96ce11c73 #338 - Remove deprecated method - save(Iterator<?> it, Transaction transaction) ... please change to iterate yourself and save. 2015-07-20 11:11:45 +12:00
Robin Bygrave b8f8cb5ae7 #337 - Remove deprecated method - delete(Class<?> beanType, Collection<?> ids) ... migrate to deleteAll() 2015-07-20 11:07:52 +12:00
Robin Bygrave b8a2aac95a #336 - Remove deprecated method - delete(Iterator<?> it, Transaction transaction) 2015-07-20 10:59:52 +12:00
Robin Bygrave 7b090a6346 #335 - Remove deprecated method - delete(Collection<?> beans) ... migrate to deleteAll() 2015-07-20 10:54:18 +12:00
Robin Bygrave b10c68489f #334 - Remove deprecated method - delete(Iterator<?> it) ... change to iterate yourself and delete() 2015-07-20 10:47:51 +12:00
Robin Bygrave 2dbb2d9911 #333 - Remove deprecated method - save(Iterator<?> it) ... change to iterate yourself and save() 2015-07-20 10:43:37 +12:00
Robin Bygrave b3b4c72a77 #332 - Remove deprecated method - save(Collection<?> beans) ... migrate to saveAll(beans) 2015-07-20 10:39:15 +12:00
Robin Bygrave 1c040e4583 No effective change - code format 2015-07-20 10:24:10 +12:00
Robin Bygrave 9677e585b6 #331 - Remove deprecated method - EbeanServer.findVisit() ... in favor of findEachWhile() or findEach() 2015-07-20 10:22:50 +12:00
Robin Bygrave c53806224f [maven-release-plugin] prepare for next development iteration 2015-07-20 09:53:59 +12:00
Robin Bygrave 6fd5927c64 [maven-release-plugin] prepare release avaje-ebeanorm-5.1.1 2015-07-20 09:53:35 +12:00
Robin Bygrave 920635c6df #326 - API Addition - saveAll(), deleteAll() etc 2015-07-20 09:51:36 +12:00
Robin Bygrave fb1c29b57c Bump pom to 5.1.1-SNAPSHOT 2015-07-20 09:46:31 +12:00
Robin Bygrave 89bed8be67 #326 - API Addition - saveAll(), deleteAll() etc 2015-07-20 09:42:05 +12:00
Robin Bygrave 776e48a501 [maven-release-plugin] prepare for next development iteration 2015-07-20 09:06:01 +12:00
Robin Bygrave 0666a72df7 [maven-release-plugin] prepare release avaje-ebeanorm-4.9.1 2015-07-20 09:05:34 +12:00
Robin Bygrave 55000a3515 No effective change - rename parameter ctx -> parser 2015-07-20 09:01:54 +12:00
Robin Bygrave 8307e259ba bump pom to 4.9.1-SNAPSHOT 2015-07-20 08:50:54 +12:00
Robin Bygrave 95b7574d04 No effective change - format 2015-07-20 08:49:31 +12:00
Robin Bygrave f6466d3211 #280 - ENH: Add ServerConfig.setJsonInclude(...) ALL, NON_NULL, NON_EMPTY 2015-07-20 08:45:46 +12:00
Robin Bygrave 160e4d7dd1 #318 - JSON - toBean error at Transient (with support for #327, #328, #329) 2015-07-19 21:41:20 +12:00
Robin Bygrave a00980c61f #329 - JSON - Remove @Deprecated from JsonWriteOptions ... to support ObjectMapper which can be used for serialize/deserialize of @Transient properties 2015-07-19 21:38:27 +12:00
Robin Bygrave 72d2fcb59e #330 - JSON - Add ebean @JsonIgnore ... with serialize() default false and deserialize() default false 2015-07-19 21:37:37 +12:00
Robin Bygrave 0f503b2a2f No effective change - format code 2015-07-19 09:35:27 +12:00
Robin Bygrave a79e2e786a #324 - on effective change, sync internal name from primaryServer to defaultServer 2015-07-19 09:20:03 +12:00
Robin Bygrave c9ffa2673f #324 - ENH: Add Ebean.getDefaultServer() 2015-07-18 07:46:53 +12:00
Robin Bygrave 0e0fa37f0d #324 - ENH: Add Ebean.getDefaultServer() 2015-07-18 07:46:42 +12:00
Robin Bygrave f7bbd5b3bb No effective change - code format (fix variable names) 2015-07-18 07:35:19 +12:00
Robin Bygrave ba614cd287 No effective change - code format 2015-07-18 07:34:56 +12:00
Robin Bygrave 7d028f3318 [maven-release-plugin] prepare for next development iteration 2015-07-14 23:28:55 +12:00
Robin Bygrave 21b04c244b [maven-release-plugin] prepare release avaje-ebeanorm-4.8.1 2015-07-14 23:28:32 +12:00
Robin Bygrave 957c2def43 bump pom to 4.8.1-SNAPSHOT 2015-07-14 23:24:34 +12:00
Robin Bygrave 35f9cd3821 Bump pom to 4.8.1-SNAPSHOT 2015-07-14 23:18:51 +12:00
Robin Bygrave e95d3304bf #322 - RawSql fetch object with inheritance 2015-07-14 23:09:38 +12:00
rbygrave 0f7c9da5d2 #319 - Beans loaded without an @Id value ... return in NEW state rather than LOADED state (also refer to #317) 2015-07-09 22:18:03 +12:00
rbygrave b4008da70c #317 - RawSql getting error - Caused by: java.sql.SQLException: Column Index out of range, 0 < 1. 2015-07-09 21:44:45 +12:00
rbygrave 34a0f16c74 No effective change - bump mysql-connector-java test dependency version 2015-07-07 23:07:10 +12:00
Rob Bygrave a880109201 Merge pull request #316 from castovoid/master
Resolve NullPointerException on JtaTransacionManager constructor
2015-06-30 21:17:27 +12:00
Rob Bygrave 0607151ac8 Merge pull request #315 from ossd/patch-1
Update ScalarTypeEnumStandard.java
2015-06-30 21:15:47 +12:00
Leone Parise 5c4ad4c01c Resolve NullPointerException on JtaTransacionManager 2015-06-30 01:01:35 -03:00
ossd 3564504e00 Update ScalarTypeEnumStandard.java
Using toString() to calculate the Enum length is wrong. If you overwrite the Enum's toString() the length may be shorter. In this situation, the ddl script will create a to small varchar field for the value and you get an exception on save
2015-06-29 22:36:24 +02:00
rbygrave 49babef495 #314 - ServerCache API - change from int to long for ServerCacheStatistics (hitCount, missCount) and ServerCache remove putIfAbsent() method 2015-06-30 00:56:11 +12:00
rbygrave 9e3362d004 No effective change - tidy 2015-06-26 23:05:40 +12:00
Rob Bygrave 3f0dcdb6d1 Update README.md 2015-06-25 00:12:16 +12:00
rbygrave 481116251d [maven-release-plugin] prepare for next development iteration 2015-06-24 23:50:22 +12:00
rbygrave d490966025 [maven-release-plugin] prepare release avaje-ebeanorm-4.7.3 2015-06-24 23:50:02 +12:00
rbygrave 5bc0b01a6c #308 - Deprecate BeanFinder ... preference now to use BeanFindController 2015-06-24 23:42:35 +12:00
rbygrave 2bd14db8f7 #308 - Add BeanFindController 2015-06-24 23:36:34 +12:00
rbygrave 17a0933860 #308 - Add BeanFindController 2015-06-24 23:12:34 +12:00
rbygrave 5bb8384567 No effective change - format only 2015-06-24 22:44:08 +12:00
rbygrave 29a6bbb6e6 #312 - Ability to remove deregister BeanPersistListeners removed 2015-06-24 22:32:12 +12:00
rbygrave 46a1324f58 [maven-release-plugin] prepare for next development iteration 2015-06-22 00:22:45 +12:00
rbygrave 8f7199b586 [maven-release-plugin] prepare release avaje-ebeanorm-4.7.2 2015-06-22 00:22:23 +12:00
rbygrave d2c3142de4 WIP on Finder 2015-06-22 00:20:01 +12:00
rbygrave 721a50219d #307 - Add back support for JsonValueAdapter and JsonReadOptions into 4.x 2015-06-21 01:46:23 +12:00
Rob Bygrave f0b8270e5e Update README.md 2015-06-18 00:11:04 +12:00
rbygrave 92232c2afb [maven-release-plugin] prepare for next development iteration 2015-06-17 23:18:58 +12:00
rbygrave 5e68b1a25e [maven-release-plugin] prepare release avaje-ebeanorm-4.7.1 2015-06-17 23:18:36 +12:00
rbygrave 041324d177 #310 - Child bean with @Id long id = 0 ... when cascade saved from parent ... tries to update instead of insert resulting in OptimisticLockingException 2015-06-17 23:16:02 +12:00
rbygrave 7d02a42276 #309 - ScalarTypeConverters for Java8 time datatypes not working 2015-06-17 21:13:48 +12:00
rbygrave 2a900165f0 #305 - ENH: Add EbeanServerFactory.createWithContextClassLoader() to support OSGi 2015-06-03 20:47:58 +12:00
rbygrave e7c40e9552 No effective change - update javadoc on annotations 2015-06-01 12:26:59 +12:00
rbygrave 0d92807308 No effective change - change test code to use Long as @Version on BasicDomain 2015-06-01 12:14:20 +12:00
rbygrave 16f7de30c6 No effective change - format code 2015-06-01 12:11:53 +12:00
rbygrave 3d250b0eca No effective change - format code, tidy 2015-05-30 21:42:50 +12:00
rbygrave 8403adac90 #298 - JndiDataSourceLookup assumes java: prefix 2015-05-30 20:54:51 +12:00
rbygrave c006aa3f48 No effective change - inline String messages 2015-05-30 20:54:12 +12:00
rbygrave dcb7054248 #303 - Change beginTransaction() to use REQUIRED scope by default 2015-05-30 20:10:56 +12:00
rbygrave 12833bc918 Bump pom version to 4.7.1-SNAPSHOT 2015-05-30 19:43:15 +12:00
rbygrave 71d805bc17 #302 - Postgres specific - Rename @ColumnHstore to @DbHstore (deprecate @ColumnHstore ) 2015-05-30 19:41:54 +12:00
rbygrave ab8704e2c9 Bump version in README 2015-05-29 21:52:43 +12:00
rbygrave 327e2baae7 No effective change - format only 2015-05-29 21:52:00 +12:00
rbygrave 6e89c551d5 [maven-release-plugin] prepare for next development iteration 2015-05-29 21:17:29 +12:00
rbygrave 0a3941227f [maven-release-plugin] prepare release avaje-ebeanorm-4.6.3 2015-05-29 21:17:08 +12:00
rbygrave 0013cb1a76 #301 - MySQL specific issue - java.sql.SQLException: Streaming result set com.mysql.jdbc.RowDataDynamic@3ef4415f is still active. No statements may be issued when any streaming result sets a re open and in use on a given connection. Ensure that you have called .close() on any active streaming result sets before attempting more queries 2015-05-29 21:13:30 +12:00
rbygrave 8fe91f66c0 #300 - Stateless update with deleteMissingChildren and JDBC batched inserts on those children ... can delete newly inserted child 2015-05-29 20:51:23 +12:00
rbygrave 053fdf4abb No effective change - format and tidy 2015-05-29 20:49:55 +12:00
rbygrave 24be907dc5 No effective change - improved logging when PooledConnection.close() throws exception 2015-05-29 20:39:54 +12:00
rbygrave 6aa915b420 Fix test for cross database use 2015-05-29 20:38:38 +12:00
rbygrave 40d87af5b1 Fix test for cross database use 2015-05-29 20:38:07 +12:00
rbygrave 75082fe0c0 Fix test for cross database use 2015-05-29 20:37:12 +12:00
rbygrave 7d43f5a3d7 Fix test for cross database use 2015-05-29 20:36:51 +12:00
rbygrave 99203a35a2 No effective change - reformat and tidy 2015-05-29 00:40:47 +12:00
rbygrave 67f427b83e #299 - ENH: Add support for mapping Jackson JsonNode as JSON content to DB including Postgres JSON and JSON types 2015-05-28 22:54:32 +12:00
rbygrave f5a2cf8ff9 #297 - ENH: Add support for mapping Map<String,Object> as JSON content to DB including Postgres JSON and JSON types. 2015-05-28 00:02:57 +12:00
rbygrave 4e1cda691f No effective change - reformat and tidy 2015-05-19 01:35:27 +12:00
rbygrave 64b01324d1 No effective change - reformat and tidy 2015-05-19 01:25:51 +12:00
rbygrave 3cba238073 No effective change - reformat and tidy 2015-05-18 23:23:11 +12:00
rbygrave b5b4a4639f No effective change - reformat and tidy 2015-05-18 22:17:28 +12:00
rbygrave 2d0a179c3b No effective change - reformat and tidy 2015-05-15 00:09:19 +12:00
rbygrave 40f7a0088d No effective change - add tests for ConvertInetAddressesTest and DefaultTypeFactoryTest 2015-05-14 23:22:19 +12:00
rbygrave 6a02a8d69f No effective change - code format and tidy 2015-05-14 22:42:37 +12:00
rbygrave ed18cbcabf No effective change - add test for ConvertInetAddresses 2015-05-14 21:57:38 +12:00
Rob Bygrave 3ce4f2fb35 Merge pull request #294 from andersha/add_distinct_db2
add distinct to db2
2015-05-14 21:35:59 +12:00
Anders H. Abrahamsen 962a27f838 add distinct to db2 2015-05-13 15:52:50 +02:00
rbygrave 2b583cf707 Update README.md 2015-05-13 23:09:49 +12:00
rbygrave ef9ade4f5c [maven-release-plugin] prepare for next development iteration 2015-05-13 22:56:09 +12:00
303 changed files with 13803 additions and 10138 deletions
+1
View File
@@ -1,5 +1,6 @@
*.autofetch
*.sql
*.orig
.classpath
.project
.settings/
+12 -5
View File
@@ -1,9 +1,10 @@
[![Stories in Ready](https://badge.waffle.io/ebean-orm/avaje-ebeanorm.png?label=ready&title=Ready)](https://waffle.io/ebean-orm/avaje-ebeanorm)
* [![Maven Central : avaje-ebeanorm](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm) - avaje-ebeanorm
* [![Maven Central : avaje-ebeanorm-agent](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-agent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-agent) - avaje-ebeanorm-agent
* [![Maven Central : avaje-ebeanorm-agent](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-mavenenhancer/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-mavenenhancer) - avaje-ebeanorm-mavenenhancer
Ebean ORM
==============
Project Website
----------------
[http://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Website")
@@ -12,5 +13,11 @@ Maven Dependency
<dependency>
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm</artifactId>
<version>4.5.5</version>
<version>4.7.3</version>
</dependency>
[Maven central - avaje-ebeanorm](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.avaje.ebeanorm%22%20AND%20a%3A%22avaje-ebeanorm%22 "maven central ebeanorm")
[Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cavaje-ebeanorm "maven central ebeanorm")
+28 -13
View File
@@ -9,7 +9,7 @@
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm</artifactId>
<version>4.6.2</version>
<version>6.1.1</version>
<packaging>jar</packaging>
<name>avaje-ebeanorm</name>
@@ -43,6 +43,12 @@
<dependencies>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>13.0</version>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
@@ -55,12 +61,21 @@
<version>1.7.7</version>
</dependency>
<!-- provided scope for JsonNode support -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.3</version>
<scope>provided</scope>
</dependency>
<!-- Jackson core used internally by Ebean -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.4.3</version>
<version>2.5.3</version>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
@@ -68,6 +83,7 @@
<scope>provided</scope>
</dependency>
<!-- provided scope to read validation annotations Size etc -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
@@ -89,6 +105,14 @@
<scope>provided</scope>
</dependency>
<!-- Provided scope for Postgres JSON/JSONB support -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4-1201-jdbc41</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp</groupId>
<artifactId>okhttp</artifactId>
@@ -124,13 +148,6 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>8.4-701.jdbc4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
@@ -141,7 +158,7 @@
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.27</version>
<version>5.1.36</version>
<scope>test</scope>
</dependency>
@@ -254,8 +271,6 @@
<configuration>
<doctitle>Ebean 4</doctitle>
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
<!-- <excludePackageNames>com.avaje.ebeaninternal.*:com.avaje.ebean.util</excludePackageNames> -->
<!--<additionalparam>-Xdoclint:none</additionalparam>-->
<source>1.8</source>
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
<excludePackageNames>com.avaje.ebeaninternal.*:com.avaje.ebean.util</excludePackageNames>
+100 -110
View File
@@ -2,7 +2,6 @@ package com.avaje.ebean;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -10,6 +9,7 @@ import java.util.concurrent.ConcurrentHashMap;
import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceException;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -101,7 +101,7 @@ import com.avaje.ebean.text.json.JsonContext;
* specific database.
* </p>
*
* <pre> {@code
* <pre>{@code
*
* // Get access to the Human Resources EbeanServer/Database
* EbeanServer hrDb = Ebean.getServer("hr");
@@ -146,9 +146,9 @@ public final class Ebean {
private final Object monitor = new Object();
/**
* The 'default/primary' EbeanServer.
* The 'default' EbeanServer.
*/
private EbeanServer primaryServer;
private EbeanServer defaultServer;
private ServerManager() {
@@ -162,10 +162,10 @@ public final class Ebean {
} else {
// look to see if there is a default server defined
String primaryName = PrimaryServer.getPrimaryServerName();
logger.debug("primaryName:" + primaryName);
if (primaryName != null && primaryName.trim().length() > 0) {
primaryServer = getWithCreate(primaryName.trim());
String defaultName = PrimaryServer.getDefaultServerName();
logger.debug("defaultName:" + defaultName);
if (defaultName != null && defaultName.trim().length() > 0) {
defaultServer = getWithCreate(defaultName.trim());
}
}
} catch (RuntimeException e) {
@@ -174,19 +174,19 @@ public final class Ebean {
}
}
private EbeanServer getPrimaryServer() {
if (primaryServer == null) {
private EbeanServer getDefaultServer() {
if (defaultServer == null) {
String msg = "The default EbeanServer has not been defined?";
msg += " This is normally set via the ebean.datasource.default property.";
msg += " Otherwise it should be registered programatically via registerServer()";
throw new PersistenceException(msg);
}
return primaryServer;
return defaultServer;
}
private EbeanServer get(String name) {
if (name == null || name.length() == 0) {
return primaryServer;
return defaultServer;
}
// non-synchronized read
EbeanServer server = concMap.get(name);
@@ -221,12 +221,12 @@ public final class Ebean {
registerWithName(server.getName(), server, isPrimaryServer);
}
private void registerWithName(String name, EbeanServer server, boolean isPrimaryServer) {
private void registerWithName(String name, EbeanServer server, boolean isDefaultServer) {
synchronized (monitor) {
concMap.put(name, server);
syncMap.put(name, server);
if (isPrimaryServer) {
primaryServer = server;
if (isDefaultServer) {
defaultServer = server;
}
}
}
@@ -254,12 +254,22 @@ public final class Ebean {
* }</pre>
*
* @param name
* the name of the server, use null for the 'default server'
* the name of the server, can use null for the 'default server'
*/
public static EbeanServer getServer(String name) {
return serverMgr.get(name);
}
/**
* Returns the default EbeanServer.
* <p>
* This is equivalent to <code>Ebean.getServer(null);</code>
* </p>
*/
public static EbeanServer getDefaultServer() {
return serverMgr.getDefaultServer();
}
/**
* Return the ExpressionFactory from the default server.
* <p>
@@ -278,23 +288,23 @@ public final class Ebean {
* </p>
*/
public static ExpressionFactory getExpressionFactory() {
return serverMgr.getPrimaryServer().getExpressionFactory();
return serverMgr.getDefaultServer().getExpressionFactory();
}
/**
* Register the server with this Ebean singleton. Specify if the registered
* server is the primary/default server.
*/
public static void register(EbeanServer server, boolean isPrimaryServer) {
serverMgr.register(server, isPrimaryServer);
public static void register(EbeanServer server, boolean defaultServer) {
serverMgr.register(server, defaultServer);
}
/**
* Backdoor for registering a mock implementation of EbeanServer as the default server.
*/
protected static EbeanServer mock(String name, EbeanServer server, boolean isPrimaryServer) {
EbeanServer originalPrimaryServer = serverMgr.primaryServer;
serverMgr.registerWithName(name, server, isPrimaryServer);
protected static EbeanServer mock(String name, EbeanServer server, boolean defaultServer) {
EbeanServer originalPrimaryServer = serverMgr.defaultServer;
serverMgr.registerWithName(name, server, defaultServer);
return originalPrimaryServer;
}
@@ -311,11 +321,14 @@ public final class Ebean {
* </p>
*/
public static Object nextId(Class<?> beanType) {
return serverMgr.getPrimaryServer().nextId(beanType);
return serverMgr.getDefaultServer().nextId(beanType);
}
/**
* Start a new explicit transaction.
* Start a transaction with 'REQUIRED' semantics.
* <p>
* With REQUIRED semantics if an active transaction already exists that transaction will be used.
* </p>
* <p>
* The transaction is stored in a ThreadLocal variable and typically you only
* need to use the returned Transaction <em>IF</em> you wish to do things like
@@ -356,7 +369,7 @@ public final class Ebean {
* </p>
*/
public static Transaction beginTransaction() {
return serverMgr.getPrimaryServer().beginTransaction();
return serverMgr.getDefaultServer().beginTransaction();
}
/**
@@ -367,7 +380,7 @@ public final class Ebean {
*
*/
public static Transaction beginTransaction(TxIsolation isolation) {
return serverMgr.getPrimaryServer().beginTransaction(isolation);
return serverMgr.getDefaultServer().beginTransaction(isolation);
}
/**
@@ -422,7 +435,7 @@ public final class Ebean {
* }</pre>
*/
public static Transaction beginTransaction(TxScope scope){
return serverMgr.getPrimaryServer().beginTransaction(scope);
return serverMgr.getDefaultServer().beginTransaction(scope);
}
/**
@@ -430,7 +443,7 @@ public final class Ebean {
* in scope.
*/
public static Transaction currentTransaction() {
return serverMgr.getPrimaryServer().currentTransaction();
return serverMgr.getDefaultServer().currentTransaction();
}
/**
@@ -443,21 +456,21 @@ public final class Ebean {
* @throws PersistenceException if there is no currently active transaction
*/
public static void register(TransactionCallback transactionCallback) throws PersistenceException {
serverMgr.getPrimaryServer().register(transactionCallback);
serverMgr.getDefaultServer().register(transactionCallback);
}
/**
* Commit the current transaction.
*/
public static void commitTransaction() {
serverMgr.getPrimaryServer().commitTransaction();
serverMgr.getDefaultServer().commitTransaction();
}
/**
* Rollback the current transaction.
*/
public static void rollbackTransaction() {
serverMgr.getPrimaryServer().rollbackTransaction();
serverMgr.getDefaultServer().rollbackTransaction();
}
/**
@@ -486,7 +499,7 @@ public final class Ebean {
* }</pre>
*/
public static void endTransaction() {
serverMgr.getPrimaryServer().endTransaction();
serverMgr.getDefaultServer().endTransaction();
}
/**
@@ -497,7 +510,7 @@ public final class Ebean {
* </p>
*/
public static Map<String, ValuePair> diff(Object a, Object b) {
return serverMgr.getPrimaryServer().diff(a, b);
return serverMgr.getDefaultServer().diff(a, b);
}
/**
@@ -520,7 +533,6 @@ public final class Ebean {
* public class Order { ...
*
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
* @JoinColumn(name="order_id")
* List<OrderDetail> details;
* ...
* }
@@ -534,7 +546,7 @@ public final class Ebean {
* </p>
*/
public static void save(Object bean) throws OptimisticLockException {
serverMgr.getPrimaryServer().save(bean);
serverMgr.getDefaultServer().save(bean);
}
/**
@@ -542,14 +554,14 @@ public final class Ebean {
* want to explicitly insert it.
*/
public static void insert(Object bean) {
serverMgr.getPrimaryServer().insert(bean);
serverMgr.getDefaultServer().insert(bean);
}
/**
* Insert a collection of beans.
*/
public static void insert(Collection<?> beans) {
serverMgr.getPrimaryServer().insert(beans);
public static void insertAll(Collection<?> beans) {
serverMgr.getDefaultServer().insertAll(beans);
}
/**
@@ -573,7 +585,7 @@ public final class Ebean {
* }</pre>
*/
public static void markAsDirty(Object bean) throws OptimisticLockException {
serverMgr.getPrimaryServer().markAsDirty(bean);
serverMgr.getDefaultServer().markAsDirty(bean);
}
/**
@@ -613,28 +625,21 @@ public final class Ebean {
* @see ServerConfig#setUpdateChangesOnly(boolean)
*/
public static void update(Object bean) throws OptimisticLockException {
serverMgr.getPrimaryServer().update(bean);
serverMgr.getDefaultServer().update(bean);
}
/**
* Update the beans in the collection.
*/
public static void update(Collection<?> beans) throws OptimisticLockException {
serverMgr.getPrimaryServer().update(beans);
}
/**
* Save all the beans from an Iterator.
*/
public static int save(Iterator<?> iterator) throws OptimisticLockException {
return serverMgr.getPrimaryServer().save(iterator);
public static void updateAll(Collection<?> beans) throws OptimisticLockException {
serverMgr.getDefaultServer().updateAll(beans);
}
/**
* Save all the beans from a Collection.
*/
public static int save(Collection<?> beans) throws OptimisticLockException {
return serverMgr.getPrimaryServer().save(beans);
public static int saveAll(Collection<?> beans) throws OptimisticLockException {
return serverMgr.getDefaultServer().saveAll(beans);
}
/**
@@ -648,7 +653,7 @@ public final class Ebean {
* @return the number of associations deleted (from the intersection table).
*/
public static int deleteManyToManyAssociations(Object ownerBean, String propertyName) {
return serverMgr.getPrimaryServer().deleteManyToManyAssociations(ownerBean, propertyName);
return serverMgr.getDefaultServer().deleteManyToManyAssociations(ownerBean, propertyName);
}
/**
@@ -666,7 +671,7 @@ public final class Ebean {
* </p>
*/
public static void saveManyToManyAssociations(Object ownerBean, String propertyName) {
serverMgr.getPrimaryServer().saveManyToManyAssociations(ownerBean, propertyName);
serverMgr.getDefaultServer().saveManyToManyAssociations(ownerBean, propertyName);
}
/**
@@ -686,7 +691,7 @@ public final class Ebean {
* the property we want to save
*/
public static void saveAssociation(Object ownerBean, String propertyName) {
serverMgr.getPrimaryServer().saveAssociation(ownerBean, propertyName);
serverMgr.getDefaultServer().saveAssociation(ownerBean, propertyName);
}
/**
@@ -697,35 +702,28 @@ public final class Ebean {
* </p>
*/
public static void delete(Object bean) throws OptimisticLockException {
serverMgr.getPrimaryServer().delete(bean);
serverMgr.getDefaultServer().delete(bean);
}
/**
* Delete the bean given its type and id.
*/
public static int delete(Class<?> beanType, Object id) {
return serverMgr.getPrimaryServer().delete(beanType, id);
return serverMgr.getDefaultServer().delete(beanType, id);
}
/**
* Delete several beans given their type and id values.
*/
public static void delete(Class<?> beanType, Collection<?> ids) {
serverMgr.getPrimaryServer().delete(beanType, ids);
public static void deleteAll(Class<?> beanType, Collection<?> ids) {
serverMgr.getDefaultServer().deleteAll(beanType, ids);
}
/**
* Delete all the beans from an Iterator.
* Delete all the beans in the Collection.
*/
public static int delete(Iterator<?> it) throws OptimisticLockException {
return serverMgr.getPrimaryServer().delete(it);
}
/**
* Delete all the beans from a Collection.
*/
public static int delete(Collection<?> c) throws OptimisticLockException {
return delete(c.iterator());
public static int deleteAll(Collection<?> beans) throws OptimisticLockException {
return serverMgr.getDefaultServer().deleteAll(beans);
}
/**
@@ -736,7 +734,7 @@ public final class Ebean {
* </p>
*/
public static void refresh(Object bean) {
serverMgr.getPrimaryServer().refresh(bean);
serverMgr.getDefaultServer().refresh(bean);
}
/**
@@ -757,7 +755,7 @@ public final class Ebean {
* the property name of the List Set or Map to refresh.
*/
public static void refreshMany(Object bean, String manyPropertyName) {
serverMgr.getPrimaryServer().refreshMany(bean, manyPropertyName);
serverMgr.getDefaultServer().refreshMany(bean, manyPropertyName);
}
/**
@@ -785,7 +783,7 @@ public final class Ebean {
* the id value
*/
public static <T> T getReference(Class<T> beanType, Object id) {
return serverMgr.getPrimaryServer().getReference(beanType, id);
return serverMgr.getDefaultServer().getReference(beanType, id);
}
/**
@@ -831,7 +829,7 @@ public final class Ebean {
* the properties to sort the list by
*/
public static <T> void sort(List<T> list, String sortByClause) {
serverMgr.getPrimaryServer().sort(list, sortByClause);
serverMgr.getDefaultServer().sort(list, sortByClause);
}
/**
@@ -880,8 +878,9 @@ public final class Ebean {
* @param id
* the id value
*/
@Nullable
public static <T> T find(Class<T> beanType, Object id) {
return serverMgr.getPrimaryServer().find(beanType, id);
return serverMgr.getDefaultServer().find(beanType, id);
}
/**
@@ -893,7 +892,7 @@ public final class Ebean {
* </p>
*/
public static SqlQuery createSqlQuery(String sql) {
return serverMgr.getPrimaryServer().createSqlQuery(sql);
return serverMgr.getDefaultServer().createSqlQuery(sql);
}
/**
@@ -906,7 +905,7 @@ public final class Ebean {
* the name of the query
*/
public static SqlQuery createNamedSqlQuery(String namedQuery) {
return serverMgr.getPrimaryServer().createNamedSqlQuery(namedQuery);
return serverMgr.getDefaultServer().createNamedSqlQuery(namedQuery);
}
/**
@@ -924,7 +923,7 @@ public final class Ebean {
* </p>
*/
public static SqlUpdate createSqlUpdate(String sql) {
return serverMgr.getPrimaryServer().createSqlUpdate(sql);
return serverMgr.getDefaultServer().createSqlUpdate(sql);
}
/**
@@ -933,7 +932,7 @@ public final class Ebean {
* @see CallableSql
*/
public static CallableSql createCallableSql(String sql) {
return serverMgr.getPrimaryServer().createCallableSql(sql);
return serverMgr.getDefaultServer().createCallableSql(sql);
}
/**
@@ -956,7 +955,7 @@ public final class Ebean {
* }</pre>
*/
public static SqlUpdate createNamedSqlUpdate(String namedQuery) {
return serverMgr.getPrimaryServer().createNamedSqlUpdate(namedQuery);
return serverMgr.getDefaultServer().createNamedSqlUpdate(namedQuery);
}
/**
@@ -984,7 +983,7 @@ public final class Ebean {
*/
public static <T> Query<T> createNamedQuery(Class<T> beanType, String namedQuery) {
return serverMgr.getPrimaryServer().createNamedQuery(beanType, namedQuery);
return serverMgr.getDefaultServer().createNamedQuery(beanType, namedQuery);
}
/**
@@ -1012,7 +1011,7 @@ public final class Ebean {
* the object query
*/
public static <T> Query<T> createQuery(Class<T> beanType, String query) {
return serverMgr.getPrimaryServer().createQuery(beanType, query);
return serverMgr.getDefaultServer().createQuery(beanType, query);
}
/**
@@ -1071,7 +1070,7 @@ public final class Ebean {
*/
public static <T> Update<T> createNamedUpdate(Class<T> beanType, String namedUpdate) {
return serverMgr.getPrimaryServer().createNamedUpdate(beanType, namedUpdate);
return serverMgr.getDefaultServer().createNamedUpdate(beanType, namedUpdate);
}
/**
@@ -1105,7 +1104,7 @@ public final class Ebean {
*/
public static <T> Update<T> createUpdate(Class<T> beanType, String ormUpdate) {
return serverMgr.getPrimaryServer().createUpdate(beanType, ormUpdate);
return serverMgr.getDefaultServer().createUpdate(beanType, ormUpdate);
}
/**
@@ -1113,7 +1112,7 @@ public final class Ebean {
*/
public static <T> CsvReader<T> createCsvReader(Class<T> beanType) {
return serverMgr.getPrimaryServer().createCsvReader(beanType);
return serverMgr.getDefaultServer().createCsvReader(beanType);
}
/**
@@ -1170,7 +1169,7 @@ public final class Ebean {
*/
public static <T> Query<T> createQuery(Class<T> beanType) {
return serverMgr.getPrimaryServer().createQuery(beanType);
return serverMgr.getDefaultServer().createQuery(beanType);
}
/**
@@ -1187,7 +1186,7 @@ public final class Ebean {
*/
public static <T> Query<T> find(Class<T> beanType) {
return serverMgr.getPrimaryServer().find(beanType);
return serverMgr.getDefaultServer().find(beanType);
}
/**
@@ -1201,7 +1200,7 @@ public final class Ebean {
* </p>
*/
public static <T> Filter<T> filter(Class<T> beanType) {
return serverMgr.getPrimaryServer().filter(beanType);
return serverMgr.getDefaultServer().filter(beanType);
}
/**
@@ -1248,7 +1247,7 @@ public final class Ebean {
* @see Ebean#execute(CallableSql)
*/
public static int execute(SqlUpdate sqlUpdate) {
return serverMgr.getPrimaryServer().execute(sqlUpdate);
return serverMgr.getDefaultServer().execute(sqlUpdate);
}
/**
@@ -1277,7 +1276,7 @@ public final class Ebean {
* @see Ebean#execute(SqlUpdate)
*/
public static int execute(CallableSql callableSql) {
return serverMgr.getPrimaryServer().execute(callableSql);
return serverMgr.getDefaultServer().execute(callableSql);
}
/**
@@ -1302,7 +1301,7 @@ public final class Ebean {
* }</pre>
*/
public static void execute(TxScope scope, TxRunnable r) {
serverMgr.getPrimaryServer().execute(scope, r);
serverMgr.getDefaultServer().execute(scope, r);
}
/**
@@ -1330,7 +1329,7 @@ public final class Ebean {
* }</pre>
*/
public static void execute(TxRunnable r) {
serverMgr.getPrimaryServer().execute(r);
serverMgr.getDefaultServer().execute(r);
}
/**
@@ -1357,7 +1356,7 @@ public final class Ebean {
*
*/
public static <T> T execute(TxScope scope, TxCallable<T> c) {
return serverMgr.getPrimaryServer().execute(scope, c);
return serverMgr.getDefaultServer().execute(scope, c);
}
/**
@@ -1391,7 +1390,7 @@ public final class Ebean {
* }</pre>
*/
public static <T> T execute(TxCallable<T> c) {
return serverMgr.getPrimaryServer().execute(c);
return serverMgr.getDefaultServer().execute(c);
}
/**
@@ -1428,10 +1427,9 @@ public final class Ebean {
* @param deletes
* true if rows on the table where deleted
*/
public static void externalModification(String tableName, boolean inserts, boolean updates,
boolean deletes) {
public static void externalModification(String tableName, boolean inserts, boolean updates, boolean deletes) {
serverMgr.getPrimaryServer().externalModification(tableName, inserts, updates, deletes);
serverMgr.getDefaultServer().externalModification(tableName, inserts, updates, deletes);
}
/**
@@ -1441,7 +1439,7 @@ public final class Ebean {
* </p>
*/
public static BeanState getBeanState(Object bean) {
return serverMgr.getPrimaryServer().getBeanState(bean);
return serverMgr.getDefaultServer().getBeanState(bean);
}
/**
@@ -1449,7 +1447,7 @@ public final class Ebean {
*
*/
public static ServerCacheManager getServerCacheManager() {
return serverMgr.getPrimaryServer().getServerCacheManager();
return serverMgr.getDefaultServer().getServerCacheManager();
}
/**
@@ -1457,7 +1455,7 @@ public final class Ebean {
* queries.
*/
public static BackgroundExecutor getBackgroundExecutor() {
return serverMgr.getPrimaryServer().getBackgroundExecutor();
return serverMgr.getDefaultServer().getBackgroundExecutor();
}
/**
@@ -1468,7 +1466,7 @@ public final class Ebean {
* </p>
*/
public static void runCacheWarming() {
serverMgr.getPrimaryServer().runCacheWarming();
serverMgr.getDefaultServer().runCacheWarming();
}
/**
@@ -1480,22 +1478,14 @@ public final class Ebean {
*/
public static void runCacheWarming(Class<?> beanType) {
serverMgr.getPrimaryServer().runCacheWarming(beanType);
serverMgr.getDefaultServer().runCacheWarming(beanType);
}
/**
* Return the JsonContext for reading/writing JSON.
*/
public static JsonContext json() {
return serverMgr.getPrimaryServer().json();
}
/**
* Return the JsonContext for reading/writing JSON.
* @deprecated Please use #json instead.
*/
public static JsonContext createJsonContext() {
return json();
return serverMgr.getDefaultServer().json();
}
}
+38 -71
View File
@@ -1,7 +1,6 @@
package com.avaje.ebean;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -15,6 +14,7 @@ import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.meta.MetaInfoManager;
import com.avaje.ebean.text.csv.CsvReader;
import com.avaje.ebean.text.json.JsonContext;
import org.jetbrains.annotations.Nullable;
/**
* Provides the API for fetching and saving beans to a particular DataSource.
@@ -509,7 +509,10 @@ public interface EbeanServer {
Transaction createTransaction(TxIsolation isolation);
/**
* Start a new explicit transaction putting it into a ThreadLocal.
* Start a transaction with 'REQUIRED' semantics.
* <p>
* With REQUIRED semantics if an active transaction already exists that transaction will be used.
* </p>
* <p>
* The transaction is stored in a ThreadLocal variable and typically you only
* need to use the returned Transaction <em>IF</em> you wish to do things like
@@ -901,19 +904,6 @@ public interface EbeanServer {
*/
<T> void findEachWhile(Query<T> query, QueryEachWhileConsumer<T> consumer, Transaction transaction);
/**
* Deprecated in favor of #findEachWhile which is functionally exactly the same
* but has a much better name.
* <p>
* Execute the query visiting the results. This is similar to findIterate in
* that not all the result beans need to be held in memory at the same time
* and as such is go for processing large queries.
* </p>
*
* @deprecated
*/
<T> void findVisit(Query<T> query, QueryResultVisitor<T> visitor, Transaction transaction);
/**
* Execute a query returning a list of beans.
* <p>
@@ -1106,6 +1096,7 @@ public interface EbeanServer {
*
* @see Query#findUnique()
*/
@Nullable
<T> T findUnique(Query<T> query, Transaction transaction);
/**
@@ -1182,6 +1173,7 @@ public interface EbeanServer {
*
* @see SqlQuery#findUnique()
*/
@Nullable
SqlRow findUnique(SqlQuery query, Transaction transaction);
/**
@@ -1219,15 +1211,10 @@ public interface EbeanServer {
*/
void save(Object bean) throws OptimisticLockException;
/**
* Save all the beans in the iterator.
*/
int save(Iterator<?> it) throws OptimisticLockException;
/**
* Save all the beans in the collection.
*/
int save(Collection<?> beans) throws OptimisticLockException;
int saveAll(Collection<?> beans) throws OptimisticLockException;
/**
* Delete the bean.
@@ -1238,15 +1225,10 @@ public interface EbeanServer {
*/
void delete(Object bean) throws OptimisticLockException;
/**
* Delete all the beans from an Iterator.
*/
int delete(Iterator<?> it) throws OptimisticLockException;
/**
* Delete all the beans in the collection.
*/
int delete(Collection<?> c) throws OptimisticLockException;
int deleteAll(Collection<?> beans) throws OptimisticLockException;
/**
* Delete the bean given its type and id.
@@ -1261,13 +1243,18 @@ public interface EbeanServer {
/**
* Delete several beans given their type and id values.
*/
void delete(Class<?> beanType, Collection<?> ids);
void deleteAll(Class<?> beanType, Collection<?> ids);
/**
* Delete several beans given their type and id values with an explicit
* transaction.
*/
void delete(Class<?> beanType, Collection<?> ids, Transaction transaction);
void deleteAll(Class<?> beanType, Collection<?> ids, Transaction transaction);
/**
* Delete the bean with an explicit transaction.
*/
void delete(Object bean, Transaction transaction) throws OptimisticLockException;
/**
* Execute a Sql Update Delete or Insert statement. This returns the number of
@@ -1325,7 +1312,7 @@ public interface EbeanServer {
* Execute a ORM insert update or delete statement with an explicit
* transaction.
*/
int execute(Update<?> update, Transaction t);
int execute(Update<?> update, Transaction transaction);
/**
* For making calls to stored procedures.
@@ -1397,27 +1384,22 @@ public interface EbeanServer {
* the type of entity bean to find
* @param beanType
* the type of entity bean to find
* @param uid
* @param id
* the bean id value
* @param transaction
* the transaction to use (can be null)
*/
<T> T find(Class<T> beanType, Object uid, Transaction transaction);
<T> T find(Class<T> beanType, Object id, Transaction transaction);
/**
* Insert or update a bean with an explicit transaction.
*/
void save(Object bean, Transaction transaction) throws OptimisticLockException;
/**
* Save all the beans in the iterator with an explicit transaction.
*/
int save(Iterator<?> it, Transaction transaction) throws OptimisticLockException;
/**
* Save all the beans in the collection with an explicit transaction.
*/
int save(Collection<?> beans, Transaction transaction) throws OptimisticLockException;
int saveAll(Collection<?> beans, Transaction transaction) throws OptimisticLockException;
/**
* Marks the entity bean as dirty.
@@ -1482,7 +1464,7 @@ public interface EbeanServer {
/**
* Update a bean additionally specifying a transaction.
*/
void update(Object bean, Transaction t) throws OptimisticLockException;
void update(Object bean, Transaction transaction) throws OptimisticLockException;
/**
* Update a bean additionally specifying a transaction and the deleteMissingChildren setting.
@@ -1502,13 +1484,13 @@ public interface EbeanServer {
* Update a collection of beans. If there is no current transaction one is created and used to
* update all the beans in the collection.
*/
void update(Collection<?> beans) throws OptimisticLockException;
void updateAll(Collection<?> beans) throws OptimisticLockException;
/**
* Update a collection of beans with an explicit transaction.
*/
void update(Collection<?> beans, Transaction transaction) throws OptimisticLockException;
void updateAll(Collection<?> beans, Transaction transaction) throws OptimisticLockException;
/**
* Insert the bean.
* <p>
@@ -1522,18 +1504,18 @@ public interface EbeanServer {
/**
* Insert the bean with a transaction.
*/
void insert(Object bean, Transaction t);
void insert(Object bean, Transaction transaction);
/**
* Insert a collection of beans. If there is no current transaction one is created and used to
* insert all the beans in the collection.
*/
void insert(Collection<?> beans);
void insertAll(Collection<?> beans);
/**
* Insert a collection of beans with an explicit transaction.
*/
void insert(Collection<?> beans, Transaction t);
void insertAll(Collection<?> beans, Transaction transaction);
/**
* Delete the associations (from the intersection table) of a ManyToMany given
@@ -1542,7 +1524,7 @@ public interface EbeanServer {
* Typically these deletions occur automatically when persisting a ManyToMany
* collection and this provides a way to invoke those deletions directly.
* </p>
*
*
* @return the number of associations deleted (from the intersection table).
*/
int deleteManyToManyAssociations(Object ownerBean, String propertyName);
@@ -1557,10 +1539,10 @@ public interface EbeanServer {
* Typically these deletions occur automatically when persisting a ManyToMany
* collection and this provides a way to invoke those deletions directly.
* </p>
*
*
* @return the number of associations deleted (from the intersection table).
*/
int deleteManyToManyAssociations(Object ownerBean, String propertyName, Transaction t);
int deleteManyToManyAssociations(Object ownerBean, String propertyName, Transaction transaction);
/**
* Save the associations of a ManyToMany given the owner bean and the
@@ -1582,7 +1564,7 @@ public interface EbeanServer {
* way to invoke those insertions directly.
* </p>
*/
void saveManyToManyAssociations(Object ownerBean, String propertyName, Transaction t);
void saveManyToManyAssociations(Object ownerBean, String propertyName, Transaction transaction);
/**
* Save the associated collection or bean given the property name.
@@ -1619,27 +1601,18 @@ public interface EbeanServer {
* @param propertyName
* the property we want to save
*/
void saveAssociation(Object ownerBean, String propertyName, Transaction t);
void saveAssociation(Object ownerBean, String propertyName, Transaction transaction);
/**
* Delete the bean with an explicit transaction.
*/
void delete(Object bean, Transaction t) throws OptimisticLockException;
/**
* Delete all the beans from an iterator.
*/
int delete(Iterator<?> it, Transaction t) throws OptimisticLockException;
/**
* Execute explicitly passing a transaction.
*/
int execute(SqlUpdate updSql, Transaction t);
int execute(SqlUpdate updSql, Transaction transaction);
/**
* Execute explicitly passing a transaction.
*/
int execute(CallableSql callableSql, Transaction t);
int execute(CallableSql callableSql, Transaction transaction);
/**
* Execute a TxRunnable in a Transaction with an explicit scope.
@@ -1662,7 +1635,7 @@ public interface EbeanServer {
*
* }</pre>
*/
void execute(TxScope scope, TxRunnable r);
void execute(TxScope scope, TxRunnable runnable);
/**
* Execute a TxRunnable in a Transaction with the default scope.
@@ -1688,7 +1661,7 @@ public interface EbeanServer {
*
* }</pre>
*/
void execute(TxRunnable r);
void execute(TxRunnable runnable);
/**
* Execute a TxCallable in a Transaction with an explicit scope.
@@ -1712,7 +1685,7 @@ public interface EbeanServer {
*
* }</pre>
*/
<T> T execute(TxScope scope, TxCallable<T> c);
<T> T execute(TxScope scope, TxCallable<T> callable);
/**
* Execute a TxCallable in a Transaction with the default scope.
@@ -1744,7 +1717,7 @@ public interface EbeanServer {
*
* }</pre>
*/
<T> T execute(TxCallable<T> c);
<T> T execute(TxCallable<T> callable);
/**
* Return the manager of the server cache ("L2" cache).
@@ -1774,12 +1747,6 @@ public interface EbeanServer {
*/
void runCacheWarming(Class<?> beanType);
/**
* Return the JsonContext for reading/writing JSON.
* @deprecated Please use #json instead.
*/
JsonContext createJsonContext();
/**
* Return the JsonContext for reading/writing JSON.
* <p>
@@ -3,6 +3,7 @@ package com.avaje.ebean;
import com.avaje.ebean.common.SpiContainer;
import com.avaje.ebean.config.ContainerConfig;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebeaninternal.server.lib.ShutdownManager;
import javax.persistence.PersistenceException;
import java.lang.reflect.Constructor;
@@ -75,6 +76,32 @@ public class EbeanServerFactory {
return server;
}
/**
* Create using the ServerConfig additionally specifying a classLoader to use as the context class loader.
*/
public static synchronized EbeanServer createWithContextClassLoader(ServerConfig config, ClassLoader classLoader) {
ClassLoader currentContextLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);
try {
return EbeanServerFactory.create(config);
} finally {
// set the currentContextLoader back
Thread.currentThread().setContextClassLoader(currentContextLoader);
}
}
/**
* Shutdown gracefully all EbeanServers cleaning up any resources as required.
* <p>
* This is typically invoked via JVM shutdown hook and not explicitly called.
* </p>
*/
public static synchronized void shutdown() {
ShutdownManager.shutdown();
}
private static EbeanServer createInternal(ServerConfig config) {
@@ -1,6 +1,7 @@
package com.avaje.ebean;
import com.avaje.ebean.text.PathProperties;
import org.jetbrains.annotations.Nullable;
import java.io.Serializable;
import java.util.Collection;
@@ -116,14 +117,6 @@ public interface ExpressionList<T> extends Serializable {
*/
void findEachWhile(QueryEachWhileConsumer<T> consumer);
/**
* Deprecated in favor of #findEachWhile which is functionally exactly the same
* but has a much better name.
*
* @deprecated
*/
void findVisit(QueryResultVisitor<T> visitor);
/**
* Execute the query returning a list.
*
@@ -170,6 +163,7 @@ public interface ExpressionList<T> extends Serializable {
*
* @see Query#findUnique()
*/
@Nullable
T findUnique();
/**
+36 -36
View File
@@ -22,57 +22,57 @@ import java.io.Serializable;
* efficient loaded as 2 SQL queries.
* </p>
*
* <pre class="code">
* <pre>{@code
* // Normal fetch join results in a single SQL query
* List&lt;Order&gt; list = Ebean.find(Order.class).fetch(&quot;details&quot;).findList();
* List<Order> list = Ebean.find(Order.class).fetch("details").findList();
*
* // Find Orders join details using a single SQL query
* </pre>
* }</pre>
* <p>
* Example: Using a "query join" instead of a "fetch join" we instead use 2 SQL
* queries
* </p>
*
* <pre class="code">
* <pre>{@code
* // This will use 2 SQL queries to build this object graph
* List&lt;Order&gt; list =
* List<Order> list =
* Ebean.find(Order.class)
* .fetch(&quot;details&quot;, new FetchConfig().query())
* .fetch("details", new FetchConfig().query())
* .findList();
*
* // query 1) find order
* // query 2) find orderDetails where order.id in (?,?...) // first 100 order id's
* </pre>
* }</pre>
* <p>
* Example: Using 2 "query joins"
* </p>
*
* <pre class="code">
* <pre>{@code
* // This will use 3 SQL queries to build this object graph
* List&lt;Order&gt; list =
* List<Order> list =
* Ebean.find(Order.class)
* .fetch(&quot;details&quot;, new FetchConfig().query())
* .fetch(&quot;customer&quot;, new FetchConfig().queryFirst(5))
* .fetch("details", new FetchConfig().query())
* .fetch("customer", new FetchConfig().queryFirst(5))
* .findList();
*
* // query 1) find order
* // query 2) find orderDetails where order.id in (?,?...) // first 100 order id's
* // query 3) find customer where id in (?,?,?,?,?) // first 5 customers
* </pre>
* }</pre>
* <p>
* Example: Using "query joins" and partial objects
* </p>
*
* <pre class="code">
* <pre>{@code
* // This will use 3 SQL queries to build this object graph
* List&lt;Order&gt; list =
* List<Order> list =
* Ebean.find(Order.class)
* .select(&quot;status, shipDate&quot;)
* .fetch(&quot;details&quot;, &quot;quantity, price&quot;, new FetchConfig().query())
* .fetch(&quot;details.product&quot;, &quot;sku, name&quot;)
* .fetch(&quot;customer&quot;, &quot;name&quot;, new FetchConfig().queryFirst(5))
* .fetch(&quot;customer.contacts&quot;)
* .fetch(&quot;customer.shippingAddress&quot;)
* .select("status, shipDate")
* .fetch("details", "quantity, price", new FetchConfig().query())
* .fetch("details.product", "sku, name")
* .fetch("customer", "name", new FetchConfig().queryFirst(5))
* .fetch("customer.contacts")
* .fetch("customer.shippingAddress")
* .findList();
*
* // query 1) find order (status, shipDate)
@@ -81,22 +81,22 @@ import java.io.Serializable;
* // query 3) find customer (name) fetch contacts (*) fetch shippingAddress (*)
* // where id in (?,?,?,?,?)
*
* // Note: the fetch of &quot;details.product&quot; is automatically included into the
* // fetch of &quot;details&quot;
* // Note: the fetch of "details.product" is automatically included into the
* // fetch of "details"
* //
* // Note: the fetch of &quot;customer.contacts&quot; and &quot;customer.shippingAddress&quot;
* // are automatically included in the fetch of &quot;customer&quot;
* </pre>
* // Note: the fetch of "customer.contacts" and "customer.shippingAddress"
* // are automatically included in the fetch of "customer"
* }</pre>
* <p>
* You can use query() and lazy together on a single join. The query is executed
* immediately and the lazy defines the batch size to use for further lazy
* loading (if lazy loading is invoked).
* </p>
*
* <pre class="code">
* List&lt;Order&gt; list =
* <pre>{@code
* List<Order> list =
* Ebean.find(Order.class)
* .fetch(&quot;customer&quot;, new FetchConfig().query(10).lazy(5))
* .fetch("customer", new FetchConfig().query(10).lazy(5))
* .findList();
*
* // query 1) find order
@@ -104,7 +104,7 @@ import java.io.Serializable;
* // .. then if lazy loading of customers is invoked
* // .. use a batch size of 5 to load the customers
*
* </pre>
* }</pre>
*
* <p>
* Example of controlling the lazy loading query:
@@ -114,12 +114,12 @@ import java.io.Serializable;
* case.
* </p>
*
* <pre class="code">
* List&lt;Order&gt; list = Ebean.find(Order.class)
* .fetch(&quot;customer&quot;,&quot;name&quot;, new FetchConfig().lazy(5))
* .fetch(&quot;customer.contacts&quot;,&quotcontactName, phone, email&quot)
* .fetch(&quot;customer.shippingAddress&quot;)
* .where().eq(&quot;status&quot;,Order.Status.NEW)
* <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.shippingAddress")
* .where().eq("status",Order.Status.NEW)
* .findList();
*
* // query 1) find order where status = Order.Status.NEW
@@ -132,7 +132,7 @@ import java.io.Serializable;
* fetch customer.shippingAddress (*)
* where id in (?,?,?,?,?)
*
* </pre>
* }</pre>
*
* @author mario
* @author rbygrave
+8 -8
View File
@@ -2,14 +2,13 @@ package com.avaje.ebean;
import com.avaje.ebean.text.PathProperties;
import com.avaje.ebean.util.ClassUtil;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import org.jetbrains.annotations.Nullable;
import javax.persistence.MappedSuperclass;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
/**
* A MappedSuperclass base class that provides convenience methods for inserting, updating and
@@ -152,7 +151,7 @@ public abstract class Model {
* }</pre>
*/
public static EbeanServer db() {
return Ebean.getServer(null);
return Ebean.getDefaultServer();
}
/**
@@ -451,8 +450,8 @@ public abstract class Model {
* Construct passing the class literal type of the entity type.
*/
protected Find(String serverName, Class<T> type) {
this.type = type;
this.serverName = serverName;
this.type = type;
}
/**
@@ -514,6 +513,7 @@ public abstract class Model {
* <p>
* Equivalent to {@link EbeanServer#find(Class, Object)}
*/
@Nullable
public T byId(I id) {
return db().find(type, id);
}
@@ -34,7 +34,7 @@ class PrimaryServer {
/**
* Return the default server name.
*/
static synchronized String getPrimaryServerName() {
static synchronized String getDefaultServerName() {
getProperties();
return defaultServerName;
}
+17 -16
View File
@@ -1,6 +1,7 @@
package com.avaje.ebean;
import com.avaje.ebean.text.PathProperties;
import org.jetbrains.annotations.Nullable;
import java.io.Serializable;
import java.util.List;
@@ -483,7 +484,7 @@ public interface Query<T> extends Serializable {
*
* }</pre>
*/
Query<T> fetch(String path, FetchConfig joinConfig);
Query<T> fetch(String path, FetchConfig fetchConfig);
/**
* Apply the path properties replacing the select and fetch clauses.
@@ -520,19 +521,7 @@ public interface Query<T> extends Serializable {
*/
QueryIterator<T> findIterate();
/**
* This is deprecated in favor of #findEachWhile.
* <p>
* This is functionally exactly the same as #findEachWhile. It is
* replaced by findEachWhile because the method name is much better.
* </p>
*
* @param visitor
* the visitor used to process the queried beans.
*
* @deprecated
*/
void findVisit(QueryResultVisitor<T> visitor);
/**
* Execute the query processing the beans one at a time.
@@ -716,6 +705,7 @@ public interface Query<T> extends Serializable {
* ...
* }</pre>
*/
@Nullable
T findUnique();
/**
@@ -878,6 +868,11 @@ public interface Query<T> extends Serializable {
*/
Query<T> setId(Object id);
/**
* Return the Id value.
*/
Object getId();
/**
* Add additional clause(s) to the where clause.
* <p>
@@ -1123,8 +1118,8 @@ public interface Query<T> extends Serializable {
/**
* Set the first row to return for this query.
*
* @param firstRow
*
* @param firstRow the first row to include in the query result.
*/
Query<T> setFirstRow(int firstRow);
@@ -1235,4 +1230,10 @@ public interface Query<T> extends Serializable {
* Set root table alias.
*/
Query<T> alias(String alias);
/**
* Return the type of beans being queried.
*/
Class<T> getBeanType();
}
@@ -1,49 +0,0 @@
package com.avaje.ebean;
/**
* Used to process a query result one bean at a time via a callback to this
* visitor.
* <p>
* If you wish to stop further processing return false from the accept method.
* </p>
* <p>
* Unlike findList() and findSet() using a QueryResultVisitor does not require
* all the beans in the query result to be held in memory at once. This makes
* QueryResultVisitor useful for processing large queries.
* </p>
*
* <pre class="code">
*
* Query&lt;Customer&gt; query = server.find(Customer.class)
* .fetch(&quot;contacts&quot;, new FetchConfig().query(2))
* .where().gt(&quot;id&quot;, 0)
* .orderBy(&quot;id&quot;)
* .setMaxRows(2);
*
* query.findVisit(new QueryResultVisitor&lt;Customer&gt;() {
*
* public boolean accept(Customer customer) {
* // do something with customer
* System.out.println(&quot;-- visit &quot; + customer);
* return true;
* }
* });
* </pre>
*
* @author rbygrave
*
* @param <T>
* the type of entity bean being queried.
*/
public interface QueryResultVisitor<T> {
/**
* Process the bean and return true if you want to continue processing more
* beans. Return false if you want to stop processing further.
*
* @param bean
* the entity bean to process
* @return true to continue processing or false to stop.
*/
boolean accept(T bean);
}
@@ -480,6 +480,13 @@ public final class RawSql implements Serializable {
this.queryHashCode = hc;
}
/**
* Return true if the property is mapped.
*/
public boolean contains(String property) {
return this.propertyColumnMap.containsKey(property);
}
/**
* Creates an immutable copy of this ColumnMapping.
*
@@ -55,4 +55,4 @@ public @interface CacheStrategy {
*/
String warmingQuery() default "";
};
}
@@ -44,4 +44,12 @@ public @interface CacheTuning {
* </p>
*/
int maxSecsToLive() default 0;
};
/**
* The frequency (in seconds) that cache trimming should occur.
* <p>
* This is a hint for cache implementations that use background cache trimming.
* </p>
*/
int trimFrequency() default 0;
}
@@ -1,15 +0,0 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ColumnHstore {
}
@@ -18,14 +18,17 @@ import java.lang.annotation.Target;
* timestamp value after the insert has occurred. You need to fetch the entity
* back to get the inserted timestamp if you want to used it.
* </p>
*
* <pre class="code">
* &#064;Column(insertable = false, updateable = false)
* Timestamp cretimestamp;
* </pre>
*
* <h3>Example:</h3>
* <pre>{@code
*
* @CreatedTimestamp
* Timestamp whenCreated;
*
* }</pre>
*/
@Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface CreatedTimestamp {
};
}
@@ -0,0 +1,26 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Used for mapping a Map<String,String> type property to Postgres HSTORE data type.
* <p>
* The Map property should have keys and values of type String.
* </p>
*
* <h3>Example:</h3>
* <pre>{@code
*
* @DbHstore
* Map<String, String> tags;
*
* }</pre>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface DbHstore {
}
@@ -0,0 +1,44 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specify a property holding JSON content.
* <p>
* By default the content will be stored in a DB Clob except on Postgres where DB JSON type is used.
* </p>
* <h3>Example:</h3>
* <pre>{@code
*
* // Store as JSON on Postgres or Clob on other databases
* @DbJson
* Map<String,Object> content;
*
* }</pre>
*
* <h3>Example with JSONB storage</h3>
* <pre>{@code
*
* // Store as JSONB on Postgres or Clob on other databases
* @DbJson(storage = DbJsonType.JSONB)
* Map<String,Object> content;
*
* }</pre>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface DbJson {
/**
* Specify the database type used to store the JSON content.
*/
DbJsonType storage() default DbJsonType.JSON;
/**
* For VARCHAR storage specify the column length (defaults to 3000).
*/
int length() default 0;
}
@@ -0,0 +1,39 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specify a property holding JSON content.
* <p>
* The content will be stored on Postgres using it's JSONB type and as Clob for other databases.
* </p>
* <p>
* This is equivalent to using <code>@DbJson(storage = DbJsonType.JSONB)</code>
* </p>
*
* <h3>Example:</h3>
* <pre>{@code
*
* // Store as JSONB on Postgres or Clob on other databases
* @DbJsonB
* Map<String,Object> content;
*
* }</pre>
*
* <h3>Equivalent to:</h3>
* <pre>{@code
*
* // Store as JSONB on Postgres or Clob on other databases
* @DbJson(storage = DbJsonType.JSONB)
* Map<String,Object> content;
*
* }</pre>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface DbJsonB {
}
@@ -0,0 +1,32 @@
package com.avaje.ebean.annotation;
/**
* Specify the DB storage type used to store JSON content.
*/
public enum DbJsonType {
/**
* Store as JSON on Postgres and for other databases store as CLOB.
*/
JSON,
/**
* Store as JSONB on Postgres and for other databases store as CLOB.
*/
JSONB,
/**
* Store as database VARCHAR.
*/
VARCHAR,
/**
* Store as database CLOB.
*/
CLOB,
/**
* Store as database BLOB.
*/
BLOB
}
@@ -28,4 +28,4 @@ public @interface EmbeddedColumns {
*/
String columns() default "";
};
}
@@ -21,4 +21,4 @@ public @interface Encrypted {
* Used to specify the DB column length.
*/
int dbLength() default 0;
};
}
@@ -87,4 +87,4 @@ public @interface EnumMapping {
* The length of DB column if mapping to string values.
*/
int length() default 0;
};
}
@@ -8,19 +8,21 @@ import java.lang.annotation.Target;
/**
* Enables you to specify a value to use to persist for an enum value.
*
* <pre class="code">
* <pre>{@code
*
* public enum Status {
* &#064;EnumValue(&quot;N&quot;)
*
* @EnumValue("N")
* NEW,
*
* &#064;EnumValue(&quot;A&quot;)
* @EnumValue("A")
* ACTIVE,
*
* &#064;EnumValue(&quot;I&quot;)
* @EnumValue("I")
* INACTIVE,
* }
*
* </pre>
* }</pre>
* <p>
* This is an alternative to using the JPA standard approach or Ebean's
* {@link EnumMapping} annotation.
@@ -43,4 +45,4 @@ public @interface EnumValue {
* </p>
*/
String value();
};
}
@@ -12,17 +12,17 @@ import java.lang.annotation.Target;
@Target(ElementType.FIELD)
public @interface Expose {
/**
* If {@code true}, the field marked with this annotation is written out in the JSON while
* serializing. If {@code false}, the field marked with this annotation is skipped from the
* serialized output. Defaults to {@code true}.
*/
public boolean serialize() default true;
/**
* If {@code true}, the field marked with this annotation is written out in the JSON while
* serializing. If {@code false}, the field marked with this annotation is skipped from the
* serialized output. Defaults to {@code true}.
*/
boolean serialize() default true;
/**
* If {@code true}, the field marked with this annotation is deserialized from the JSON.
* If {@code false}, the field marked with this annotation is skipped during deserialization.
* Defaults to {@code true}.
*/
public boolean deserialize() default true;
/**
* If {@code true}, the field marked with this annotation is deserialized from the JSON.
* If {@code false}, the field marked with this annotation is skipped during deserialization.
* Defaults to {@code true}.
*/
boolean deserialize() default true;
}
@@ -39,30 +39,31 @@ import com.avaje.ebean.Query;
* queries - it needs to be explicitly included.
* </p>
*
* <pre class="code">
* <pre>{@code
*
* // find by Id
* Order o1 = Ebean.find(Order.class)
* .select(&quot;id, totalAmount&quot;)
* .select("id, totalAmount")
* .setId(1).findUnique();
*
* // find list ... using totalAmount in the where clause
* List&lt;Order&gt; list = Ebean.find(Order.class)
* .select(&quot;id, totalAmount&quot;)
* List<Order> list = Ebean.find(Order.class)
* .select("id, totalAmount")
* .where()
* .eq(&quot;status&quot;, Order.Status.NEW)
* .gt(&quot;totalAmount&quot;, 10)
* .eq("status", Order.Status.NEW)
* .gt("totalAmount", 10)
* .findList();
*
* // as a join from customer
* List&lt;Customer&gt; l0 = Ebean.find(Customer.class)
* .select(&quot;id, name&quot;)
* .join(&quot;orders&quot;, &quot;status, totalAmount&quot;)
* List<Customer> l0 = Ebean.find(Customer.class)
* .select("id, name")
* .fetch("orders", "status, totalAmount")
* .where()
* .gt(&quot;id&quot;, 0)
* .gt(&quot;orders.totalAmount&quot;, 10)
* .gt("id", 0)
* .gt("orders.totalAmount", 10)
* .findList();
*
* </pre>
* }</pre>
*/
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@@ -94,10 +95,12 @@ public @interface Formula {
* user.
* </p>
*
* <pre class="code">
* <pre>{@code
*
* join (select user_id, count(*) as topic_count from f_topic group by user_id) as _tc on _tc.user_id = ${ta}.id
* </pre>
*
* }</pre>
*/
String join() default "";
};
}
@@ -14,11 +14,11 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
public @interface Index {
/**
* Name of the index
*
* @return index name
*/
String value() default "";
/**
* Name of the index
*
* @return index name
*/
String value() default "";
}
@@ -0,0 +1,32 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Similar to Jackson JsonIgnore but provides the option to just ignore serialize or deserialize.
* <p>
* This provides the same features as Expose but from the opposite perspective which is probably
* more common and more familiar to Jackson users.
* </p>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface JsonIgnore {
/**
* If {@code true}, the field marked with this annotation is written out in the JSON while
* serializing. If {@code false}, the field marked with this annotation is skipped from the
* serialized output. Defaults to {@code false}.
*/
boolean serialize() default false;
/**
* If {@code true}, the field marked with this annotation is deserialized from the JSON.
* If {@code false}, the field marked with this annotation is skipped during deserialization.
* Defaults to {@code false}.
*/
boolean deserialize() default false;
}
@@ -34,4 +34,4 @@ public @interface NamedUpdate {
*/
boolean notifyCache() default true;
};
}
@@ -17,4 +17,4 @@ public @interface NamedUpdates {
*/
NamedUpdate[] value();
};
}
@@ -31,4 +31,4 @@ public @interface PrivateOwned {
*/
boolean cascadeRemove() default true;
};
}
@@ -21,4 +21,4 @@ public @interface Sql {
*/
SqlSelect[] select() default { @SqlSelect };
};
}
@@ -295,4 +295,4 @@ public @interface SqlSelect {
* Set this to true to have debug output when Ebean parses the sql-select.
*/
boolean debug() default false;
};
}
@@ -125,4 +125,4 @@ public @interface Transactional {
*/
Class<? extends Throwable>[] noRollbackFor() default {};
};
}
@@ -31,4 +31,4 @@ public @interface UpdateMode {
*/
boolean updateChangesOnly() default true;
};
}
@@ -13,4 +13,4 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
public @interface UpdatedTimestamp {
};
}
@@ -9,26 +9,29 @@ import java.lang.annotation.Target;
* Add an Literal to add to the where clause when a many property (List, Set or
* Map) is loaded or refreshed.
*
* <pre class="code">
* <pre>{@code
*
* // on a OneToMany property...
*
* &#064;OneToMany
* &#064;Where(clause = &quot;deleted='y'&quot;)
* List&lt;Topic&gt; topics;
* </pre>
* @OneToMany
* @Where(clause = "deleted='y'")
* List<Topic> topics;
*
* }</pre>
*
* <p>
* Note that you can include "${ta}" as a place holder for the table alias if
* you need to include the table alias in the clause.
* </p>
*
* <pre class="code">
* <pre>{@code
* // ... including the ${ta} table alias placeholder...
*
* &#064;OneToMany
* &#064;Where(clause = &quot;${ta}.deleted='y'&quot;)
* List&lt;Topic&gt; topics;
* </pre>
* @OneToMany
* @Where(clause = "${ta}.deleted='y'")
* List<Topic> topics;
*
* }</pre>
*
* <p>
* This will be added to the where clause when lazy loading the OneToMany
@@ -48,4 +51,4 @@ public @interface Where {
*/
String clause();
};
}
-6
View File
@@ -48,12 +48,6 @@ public interface ServerCache {
*/
Object put(Object id, Object value);
/**
* Put the value in the cache but only if a matching value is not already in
* the cache.
*/
Object putIfAbsent(Object id, Object value);
/**
* Remove a entry from the cache given its id.
*/
+24 -5
View File
@@ -10,6 +10,7 @@ public class ServerCacheOptions {
private int maxSize;
private int maxIdleSecs;
private int maxSecsToLive;
private int trimFrequency;
/**
* Construct with no set options.
@@ -25,15 +26,17 @@ public class ServerCacheOptions {
this.maxSize = cacheTuning.maxSize();
this.maxIdleSecs = cacheTuning.maxIdleSecs();
this.maxSecsToLive = cacheTuning.maxSecsToLive();
this.trimFrequency = cacheTuning.trimFrequency();
}
/**
* Create merging default options with the deployment specified ones.
*/
public ServerCacheOptions(ServerCacheOptions d) {
this.maxSize = d.getMaxSize();
this.maxIdleSecs = d.getMaxIdleSecs();
this.maxSecsToLive = d.getMaxIdleSecs();
public ServerCacheOptions(ServerCacheOptions defaults) {
this.maxSize = defaults.getMaxSize();
this.maxIdleSecs = defaults.getMaxIdleSecs();
this.maxSecsToLive = defaults.getMaxIdleSecs();
this.trimFrequency = defaults.getTrimFrequency();
}
/**
@@ -50,6 +53,9 @@ public class ServerCacheOptions {
if (maxSecsToLive == 0) {
maxSecsToLive = defaults.getMaxSecsToLive();
}
if (trimFrequency == 0) {
trimFrequency = defaults.getTrimFrequency();
}
}
/**
@@ -61,7 +67,7 @@ public class ServerCacheOptions {
copy.maxSize = maxSize;
copy.maxIdleSecs = maxIdleSecs;
copy.maxSecsToLive = maxSecsToLive;
copy.trimFrequency = trimFrequency;
return copy;
}
@@ -107,4 +113,17 @@ public class ServerCacheOptions {
this.maxSecsToLive = maxSecsToLive;
}
/**
* Return the trim frequency in seconds.
*/
public int getTrimFrequency() {
return trimFrequency;
}
/**
* Set the trim frequency in seconds.
*/
public void setTrimFrequency(int trimFrequency) {
this.trimFrequency = trimFrequency;
}
}
+175 -23
View File
@@ -5,9 +5,9 @@ package com.avaje.ebean.cache;
* <p>
* These can be monitored to review the effectiveness of a particular cache.
* </p>
*
* @author rbygrave
*
* <p>
* Depending on the cache implementation not all the statistics may be collected.
* </p>
*/
public class ServerCacheStatistics {
@@ -17,21 +17,63 @@ public class ServerCacheStatistics {
protected int size;
protected int hitCount;
protected long hitCount;
protected int missCount;
protected long missCount;
protected long insertCount;
protected long updateCount;
protected long removeCount;
protected long clearCount;
protected long evictionRunCount;
protected long evictionRunMicros;
protected long evictByIdle;
protected long evictByTTL;
protected long evictByLRU;
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(cacheName);
sb.append(" maxSize:").append(maxSize);
sb.append(" size:").append(size);
sb.append(" hitRatio:").append(getHitRatio());
sb.append(" hitCount:").append(hitCount);
sb.append(" missCount:").append(missCount);
sb.append(" maxSize:").append(maxSize);
sb.append(" hit:").append(hitCount);
sb.append(" miss:").append(missCount);
sb.append(" insert:").append(insertCount);
sb.append(" update:").append(updateCount);
sb.append(" remove:").append(removeCount);
sb.append(" clear:").append(clearCount);
sb.append(" evictByIdle:").append(evictByIdle);
sb.append(" evictByTTL:").append(evictByTTL);
sb.append(" evictByLRU:").append(evictByLRU);
sb.append(" evictionRunCount:").append(evictionRunCount);
sb.append(" evictionRunMicros:").append(evictionRunMicros);
return sb.toString();
}
/**
* Returns an int from 0 to 100 (percentage) for the hit ratio.
* <p>
* A hit ratio of 100 means every get request against the cache hits an entry.
* </p>
*/
public int getHitRatio() {
long totalCount = hitCount + missCount;
if (totalCount == 0) {
return 0;
} else {
return (int)(hitCount * 100 / totalCount);
}
}
/**
* Return the name of the cache.
*/
@@ -49,28 +91,28 @@ public class ServerCacheStatistics {
/**
* Return the hit count. The number of successful gets.
*/
public int getHitCount() {
public long getHitCount() {
return hitCount;
}
/**
* Set the hit count.
*/
public void setHitCount(int hitCount) {
public void setHitCount(long hitCount) {
this.hitCount = hitCount;
}
/**
* Return the miss count. The number of gets that returned null.
*/
public int getMissCount() {
public long getMissCount() {
return missCount;
}
/**
* Set the miss count.
*/
public void setMissCount(int missCount) {
public void setMissCount(long missCount) {
this.missCount = missCount;
}
@@ -107,18 +149,128 @@ public class ServerCacheStatistics {
}
/**
* Returns an int from 0 to 100 (percentage) for the hit ratio.
* <p>
* A hit ratio of 100 means every get request against the cache hits an entry.
* </p>
* Set the put insert count.
*/
public int getHitRatio() {
int totalCount = hitCount + missCount;
if (totalCount == 0) {
return 0;
} else {
return hitCount * 100 / totalCount;
}
public void setInsertCount(long insertCount) {
this.insertCount = insertCount;
}
/**
* Return the put insert count.
*/
public long getInsertCount() {
return insertCount;
}
/**
* Set the put update count.
*/
public void setUpdateCount(long updateCount) {
this.updateCount = updateCount;
}
/**
* Return the put update count.
*/
public long getUpdateCount() {
return updateCount;
}
/**
* Set the remove count.
*/
public void setRemoveCount(long removeCount) {
this.removeCount = removeCount;
}
/**
* Return the remove count.
*/
public long getRemoveCount() {
return removeCount;
}
/**
* Set the clear count.
*/
public void setClearCount(long clearCount) {
this.clearCount = clearCount;
}
/**
* Return the clear count.
*/
public long getClearCount() {
return clearCount;
}
/**
* Set the eviction run count.
*/
public void setEvictionRunCount(long evictCount) {
this.evictionRunCount = evictCount;
}
/**
* Return the eviction run count.
*/
public long getEvictionRunCount() {
return evictionRunCount;
}
/**
* Set the eviction run time in micros.
*/
public void setEvictionRunMicros(long evictionRunMicros) {
this.evictionRunMicros = evictionRunMicros;
}
/**
* Return the eviction run time in micros.
*/
public long getEvictionRunMicros() {
return evictionRunMicros;
}
/**
* Set the count of entries evicted due to idle time.
*/
public void setEvictByIdle(long evictByIdle) {
this.evictByIdle = evictByIdle;
}
/**
* Return the count of entries evicted due to idle time.
*/
public long getEvictByIdle() {
return evictByIdle;
}
/**
* Set the count of entries evicted due to time to live.
*/
public void setEvictByTTL(long evictByTTL) {
this.evictByTTL = evictByTTL;
}
/**
* Return the count of entries evicted due to time to live.
*/
public long getEvictByTTL() {
return evictByTTL;
}
/**
* Set the count of entries evicted due to time least recently used.
*/
public void setEvictByLRU(long evictByLRU) {
this.evictByLRU = evictByLRU;
}
/**
* Return the count of entries evicted due to time least recently used.
*/
public long getEvictByLRU() {
return evictByLRU;
}
}
@@ -26,4 +26,22 @@ public abstract class JsonConfig {
ISO8601
}
public enum Include {
/**
* Include all values including null and empty collections.
*/
ALL,
/**
* Exclude null values (include empty collections).
*/
NON_NULL,
/**
* Exclude null values and empty collections.
*/
NON_EMPTY
}
}
@@ -123,6 +123,12 @@ public class ServerConfig {
*/
private JsonConfig.DateTime jsonDateTime = JsonConfig.DateTime.MILLIS;
/**
* For writing JSON specify if null values or empty collections should be exluded.
* By default all values are included.
*/
private JsonConfig.Include jsonInclude = JsonConfig.Include.ALL;
/**
* The database platform name. Used to imply a DatabasePlatform to use.
*/
@@ -231,6 +237,7 @@ public class ServerConfig {
private boolean uuidStoreAsBinary;
private List<BeanFindController> findControllers = new ArrayList<BeanFindController>();
private List<BeanPersistController> persistControllers = new ArrayList<BeanPersistController>();
private List<BeanPersistListener> persistListeners = new ArrayList<BeanPersistListener>();
private List<BeanQueryAdapter> queryAdapters = new ArrayList<BeanQueryAdapter>();
@@ -291,6 +298,7 @@ public class ServerConfig {
private int queryCacheMaxSize = 1000;
private int queryCacheMaxIdleTime = 600;
private int queryCacheMaxTimeToLive = 60*60*6;
private Object objectMapper;
/**
* Construct a Server Configuration for programmatically creating an EbeanServer.
@@ -302,7 +310,7 @@ public class ServerConfig {
/**
* Return the Jackson JsonFactory to use.
* <p>
* If not set a default implmentation will be used.
* If not set a default implementation will be used.
*/
public JsonFactory getJsonFactory() {
return jsonFactory;
@@ -311,7 +319,7 @@ public class ServerConfig {
/**
* Set the Jackson JsonFactory to use.
* <p>
* If not set a default implmentation will be used.
* If not set a default implementation will be used.
*/
public void setJsonFactory(JsonFactory jsonFactory) {
this.jsonFactory = jsonFactory;
@@ -331,6 +339,23 @@ public class ServerConfig {
this.jsonDateTime = jsonDateTime;
}
/**
* Return the JSON include mode used when writing JSON.
*/
public JsonConfig.Include getJsonInclude() {
return jsonInclude;
}
/**
* Set the JSON include mode used when writing JSON.
* <p>
* Set to NON_NULL or NON_EMPTY to suppress nulls or null & empty collections respectively.
* </p>
*/
public void setJsonInclude(JsonConfig.Include jsonInclude) {
this.jsonInclude = jsonInclude;
}
/**
* Return the name of the EbeanServer.
*/
@@ -1539,6 +1564,14 @@ public class ServerConfig {
persistControllers.add(beanPersistController);
}
public List<BeanFindController> getFindControllers() {
return findControllers;
}
public void setFindControllers(List<BeanFindController> findControllers) {
this.findControllers = findControllers;
}
/**
* Return the BeanPersistController instances.
*/
@@ -1774,7 +1807,7 @@ public class ServerConfig {
int batchSize = p.getInt("batch.size", persistBatchSize);
persistBatchSize = p.getInt("persistBatchSize", batchSize);
persistenceContextScope = PersistenceContextScope.valueOf(p.get("persistenceContextScope","TRANSACTION"));
persistenceContextScope = PersistenceContextScope.valueOf(p.get("persistenceContextScope", "TRANSACTION"));
dataSourceJndiName = p.get("dataSourceJndiName", dataSourceJndiName);
databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize);
@@ -1787,6 +1820,7 @@ public class ServerConfig {
lazyLoadBatchSize = p.getInt("lazyLoadBatchSize", lazyLoadBatchSize);
queryBatchSize = p.getInt("queryBatchSize", queryBatchSize);
jsonInclude = p.getEnum(JsonConfig.Include.class, "jsonInclude", jsonInclude);
String jsonDateTimeFormat = p.get("jsonDateTime", null);
if (jsonDateTimeFormat != null) {
jsonDateTime = JsonConfig.DateTime.valueOf(jsonDateTimeFormat);
@@ -1818,8 +1852,7 @@ public class ServerConfig {
String classNames = properties.get("classes", null);
if (classNames == null) {
return null;
return classes;
}
List<Class<?>> classes = new ArrayList<Class<?>>();
@@ -1864,4 +1897,12 @@ public class ServerConfig {
return databasePlatform.isDisallowBatchOnCascade() ? PersistBatch.NONE : persistBatchOnCascade;
}
public Object getObjectMapper() {
return objectMapper;
}
public void setObjectMapper(Object objectMapper) {
this.objectMapper = objectMapper;
}
}
@@ -39,6 +39,12 @@ public class DatabasePlatform {
COMMIT
}
/**
* Set to true for MySql, no other jdbc drivers need this workaround.
*/
protected boolean useExtraTransactionOnIterateSecondaryQueries;
/**
* The behaviour used when ending a read only transaction at read committed isolation level.
*/
@@ -153,6 +159,17 @@ public class DatabasePlatform {
return name;
}
/**
* Return true if the JDBC driver does not allow additional queries to execute
* when a resultSet is being 'streamed' as is the case with findEach() etc.
* <p>
* Honestly, this is a workaround for a stupid MySql JDBC driver limitation.
* </p>
*/
public boolean useExtraTransactionOnIterateSecondaryQueries() {
return useExtraTransactionOnIterateSecondaryQueries;
}
/**
* Return a DB Sequence based IdGenerator.
*
@@ -7,6 +7,9 @@ public class Db2SqlLimiter implements SqlLimiter {
StringBuilder sb = new StringBuilder(512);
sb.append("select ");
if (request.isDistinct()) {
sb.append("distinct ");
}
sb.append(request.getDbSql());
int maxRows = request.getMaxRows();
@@ -8,6 +8,36 @@ package com.avaje.ebean.config.dbplatform;
*/
public class DbType {
/**
* Type to map Map content to Postgres HSTORE.
*/
public static final int HSTORE = 5000;
/**
* Type to map JSON content to Clob or Postgres JSON type.
*/
public static final int JSON = 5001;
/**
* Type to map JSON content to Clob or Postgres JSONB type.
*/
public static final int JSONB = 5002;
/**
* Type to map JSON content to VARCHAR.
*/
public static final int JSONVarchar = 5003;
/**
* Type to map JSON content to Clob.
*/
public static final int JSONClob = 5004;
/**
* Type to map JSON content to Blob.
*/
public static final int JSONBlob = 5005;
/**
* The data type name (VARCHAR, INTEGER ...)
*/
@@ -36,6 +36,13 @@ public class DbTypeMap {
put(Types.BLOB, new DbType("blob"));
put(Types.CLOB, new DbType("clob"));
put(DbType.JSON, new DbType("clob")); // Postgres maps this to JSON
put(DbType.JSONB, new DbType("clob")); // Postgres maps this to JSONB
put(DbType.JSONClob, new DbType("clob"));
put(DbType.JSONBlob, new DbType("blob"));
put(DbType.JSONVarchar, new DbType("varchar", 1000));
put(Types.LONGVARBINARY, new DbType("longvarbinary"));
put(Types.LONGVARCHAR, new DbType("lonvarchar"));
put(Types.VARBINARY, new DbType("varbinary", 255));
@@ -20,6 +20,7 @@ public class MySqlPlatform extends DatabasePlatform {
public MySqlPlatform() {
super();
this.name = "mysql";
this.useExtraTransactionOnIterateSecondaryQueries = true;
this.likeClause = "like ? escape''";
this.selectCountWithAlias = true;
this.dbEncrypt = new MySqlDbEncrypt();
@@ -13,11 +13,6 @@ import java.sql.Types;
*/
public class PostgresPlatform extends DatabasePlatform {
/**
* Unique jdbc type id defined for hstore type.
*/
public static final int TYPE_HSTORE = 4001;
public PostgresPlatform() {
super();
this.name = "postgres";
@@ -43,8 +38,10 @@ public class PostgresPlatform extends DatabasePlatform {
this.openQuote = "\"";
this.closeQuote = "\"";
dbTypeMap.put(TYPE_HSTORE, new DbType("hstore"));
dbTypeMap.put(DbType.HSTORE, new DbType("hstore"));
dbTypeMap.put(DbType.JSON, new DbType("json"));
dbTypeMap.put(DbType.JSONB, new DbType("jsonb"));
dbTypeMap.put(Types.INTEGER, new DbType("integer", false));
dbTypeMap.put(Types.DOUBLE, new DbType("float"));
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
@@ -15,12 +15,32 @@ import com.avaje.ebean.bean.BeanCollection;
* com.avaje.ebean.meta and finders in com.avaje.ebean.server.meta.
* </p>
*/
public interface BeanFinder<T> {
public interface BeanFindController {
/**
* Return true if this BeanPersistController should be registered for events
* on this entity type.
*/
boolean isRegisterFor(Class<?> cls);
/**
* Return true if this controller should intercept and process this find request.
*
* Return false to allow the default behavior to process the request.
*/
boolean isInterceptFind(BeanQueryRequest<?> request);
/**
* Find a bean using its id or unique predicate.
*/
T find(BeanQueryRequest<T> request);
<T> T find(BeanQueryRequest<T> request);
/**
* Return true if this controller should intercept and process this findMany request.
*
* Return false to allow the default behavior to process the request.
*/
boolean isInterceptFindMany(BeanQueryRequest<?> request);
/**
* Return a List, Set or Map for the given find request.
@@ -29,6 +49,6 @@ public interface BeanFinder<T> {
* get the return type right.
* </p>
*/
BeanCollection<T> findMany(BeanQueryRequest<T> request);
<T> BeanCollection<T> findMany(BeanQueryRequest<T> request);
}
@@ -35,14 +35,29 @@ public class EJson {
public static void write(Object object, JsonGenerator jsonGenerator) throws IOException {
EJsonWriter.write(object, jsonGenerator);
}
/**
* Parse the json and return as a Map additionally specifying if the returned map should
* be modify aware meaning that it can detect when it has been modified.
*/
public static Map<String,Object> parseObject(String json, boolean modifyAware) throws IOException {
return EJsonReader.parseObject(json, modifyAware);
}
/**
* Parse the json and return as a Map.
*/
public static Map<String,Object> parseObject(String json) throws IOException {
return EJsonReader.parseObject(json);
}
/**
* Parse the json and return as a Map taking a reader.
*/
public static Map<String,Object> parseObject(Reader reader, boolean modifyAware) throws IOException {
return EJsonReader.parseObject(reader, modifyAware);
}
/**
* Parse the json and return as a Map taking a reader.
*/
@@ -9,6 +9,10 @@ import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import com.avaje.ebeaninternal.server.type.ModifyAwareFlag;
import com.avaje.ebeaninternal.server.type.ModifyAwareList;
import com.avaje.ebeaninternal.server.type.ModifyAwareMap;
import com.avaje.ebeaninternal.server.type.ModifyAwareOwner;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
@@ -16,7 +20,12 @@ import com.fasterxml.jackson.core.JsonToken;
class EJsonReader {
static JsonFactory json = new JsonFactory();
@SuppressWarnings("unchecked")
static Map<String, Object> parseObject(String json, boolean modifyAware) throws IOException {
return (Map<String, Object>) parse(json, modifyAware);
}
@SuppressWarnings("unchecked")
static Map<String, Object> parseObject(String json) throws IOException {
return (Map<String, Object>) parse(json);
@@ -26,7 +35,12 @@ class EJsonReader {
static Map<String, Object> parseObject(Reader reader) throws IOException {
return (Map<String, Object>) parse(reader);
}
@SuppressWarnings("unchecked")
static Map<String, Object> parseObject(Reader reader, boolean modifyAware) throws IOException {
return (Map<String, Object>) parse(reader, modifyAware);
}
@SuppressWarnings("unchecked")
static Map<String, Object> parseObject(JsonParser parser) throws IOException {
return (Map<String, Object>) parse(parser);
@@ -34,7 +48,7 @@ class EJsonReader {
@SuppressWarnings("unchecked")
static Map<String, Object> parseObject(JsonParser parser, JsonToken token) throws IOException {
return (Map<String, Object>)parse(parser, token);
return (Map<String, Object>)parse(parser, token, false);
}
@SuppressWarnings("unchecked")
@@ -56,40 +70,58 @@ class EJsonReader {
return parse(new StringReader(json));
}
static Object parse(String json, boolean modifyAware) throws IOException {
return parse(new StringReader(json), modifyAware);
}
static Object parse(Reader reader) throws IOException {
return parse(json.createParser(reader));
}
static Object parse(JsonParser parser) throws IOException {
return parse(parser, null);
static Object parse(Reader reader, boolean modifyAware) throws IOException {
return parse(json.createParser(reader), modifyAware);
}
static Object parse(JsonParser parser, JsonToken token) throws IOException {
return new EJsonReader(parser).parseJson(token);
static Object parse(JsonParser parser) throws IOException {
return parse(parser, null, false);
}
static Object parse(JsonParser parser, boolean modifyAware) throws IOException {
return parse(parser, null, modifyAware);
}
static Object parse(JsonParser parser, JsonToken token, boolean modifyAware) throws IOException {
return new EJsonReader(parser, modifyAware).parseJson(token);
}
private final JsonParser parser;
private final boolean modifyAware;
private final ModifyAwareFlag modifyAwareOwner;
private int depth;
private Stack stack;
private Context currentContext;
EJsonReader(JsonParser parser) {
EJsonReader(JsonParser parser, boolean modifyAware) {
this.parser = parser;
this.modifyAware = modifyAware;
this.modifyAwareOwner = (modifyAware) ? new ModifyAwareFlag() : null;
}
private void startArray() {
depth++;
stack.push(currentContext);
currentContext = new ArrayContext();
currentContext = modifyAware ? new ArrayContext(modifyAwareOwner) : new ArrayContext();
}
private void startObject() {
depth++;
stack.push(currentContext);
currentContext = new ObjectContext();
currentContext = modifyAware ? new ObjectContext(modifyAwareOwner) : new ObjectContext();
}
private void endArray() {
@@ -105,6 +137,9 @@ class EJsonReader {
if (!stack.isEmpty()) {
currentContext = stack.pop(currentContext);
}
if (modifyAwareOwner != null) {
modifyAwareOwner.resetMarkedDirty();
}
}
private void setValue(Object value) {
@@ -235,10 +270,18 @@ class EJsonReader {
private static class ObjectContext extends Context {
private final Map<String, Object> map = new LinkedHashMap<String, Object>();
private final Map<String, Object> map;
private String key;
ObjectContext() {
map = new LinkedHashMap<String, Object>();
}
ObjectContext(ModifyAwareOwner owner) {
map = new ModifyAwareMap<String, Object>(owner, new LinkedHashMap<String, Object>());
}
public void popContext(Context temp) {
setValue(temp.getValue());
}
@@ -262,7 +305,15 @@ class EJsonReader {
private static class ArrayContext extends Context {
private final List<Object> values = new ArrayList<Object>();
private final List<Object> values;
ArrayContext() {
values = new ArrayList<Object>();
}
ArrayContext(ModifyAwareOwner owner) {
values = new ModifyAwareList<Object>(owner, new ArrayList<Object>());
}
public void popContext(Context temp) {
values.add(temp.getValue());
@@ -21,6 +21,13 @@ public interface JsonContext {
*/
<T> T toBean(Class<T> rootType, String json) throws JsonIOException;
/**
* Convert json string input into a Bean of a specific type additionally using JsonReadOptions.
*
* @throws JsonIOException When IOException occurs
*/
<T> T toBean(Class<T> rootType, String json, JsonReadOptions options) throws JsonIOException;
/**
* Convert json reader input into a Bean of a specific type.
*
@@ -28,6 +35,13 @@ public interface JsonContext {
*/
<T> T toBean(Class<T> rootType, Reader json) throws JsonIOException;
/**
* Convert json reader input into a Bean of a specific type additionally using JsonReadOptions.
*
* @throws JsonIOException When IOException occurs
*/
<T> T toBean(Class<T> rootType, Reader json, JsonReadOptions options) throws JsonIOException;
/**
* Convert json parser input into a Bean of a specific type.
*
@@ -35,6 +49,13 @@ public interface JsonContext {
*/
<T> T toBean(Class<T> cls, JsonParser parser) throws JsonIOException;
/**
* Convert json parser input into a Bean of a specific type additionally using JsonReadOptions..
*
* @throws JsonIOException When IOException occurs
*/
<T> T toBean(Class<T> cls, JsonParser parser, JsonReadOptions options) throws JsonIOException;
/**
* Convert json string input into a list of beans of a specific type.
*
@@ -42,6 +63,13 @@ public interface JsonContext {
*/
<T> List<T> toList(Class<T> rootType, String json) throws JsonIOException;
/**
* Convert json string input into a list of beans of a specific type additionally using JsonReadOptions.
*
* @throws JsonIOException When IOException occurs
*/
<T> List<T> toList(Class<T> rootType, String json, JsonReadOptions options) throws JsonIOException;
/**
* Convert json reader input into a list of beans of a specific type.
*
@@ -49,12 +77,26 @@ public interface JsonContext {
*/
<T> List<T> toList(Class<T> rootType, Reader json) throws JsonIOException;
/**
* Convert json reader input into a list of beans of a specific type additionally using JsonReadOptions.
*
* @throws JsonIOException When IOException occurs
*/
<T> List<T> toList(Class<T> rootType, Reader json, JsonReadOptions options) throws JsonIOException;
/**
* Convert json parser input into a list of beans of a specific type.
*
* @throws JsonIOException When IOException occurs
*/
<T> List<T> toList(Class<T> cls, JsonParser src) throws JsonIOException;
<T> List<T> toList(Class<T> cls, JsonParser json) throws JsonIOException;
/**
* Convert json parser input into a list of beans of a specific type additionally using JsonReadOptions.
*
* @throws JsonIOException When IOException occurs
*/
<T> List<T> toList(Class<T> cls, JsonParser json, JsonReadOptions options) throws JsonIOException;
/**
* Use the genericType to determine if this should be converted into a List or
@@ -121,8 +163,6 @@ public interface JsonContext {
/**
* Deprecated in favour of using PathProperties by itself.
* Write json to the JsonGenerator using the JsonWriteOptions.
*
* @deprecated
*/
void toJson(Object value, JsonGenerator generator, JsonWriteOptions options) throws JsonIOException;
@@ -131,7 +171,6 @@ public interface JsonContext {
* With additional options.
*
* @throws JsonIOException When IOException occurs
* @deprecated
*/
void toJson(Object value, Writer writer, JsonWriteOptions options) throws JsonIOException;
@@ -140,7 +179,6 @@ public interface JsonContext {
* Convert a bean or collection to json string.
*
* @throws JsonIOException When IOException occurs
* @deprecated
*/
String toJson(Object value, JsonWriteOptions options) throws JsonIOException;
@@ -0,0 +1,30 @@
package com.avaje.ebean.text.json;
import java.util.Map;
/**
* Provides for custom handling of json content as it is read.
* <p>
* This visit method is called after all the known properties of the bean have
* been processed. Any JSON elements that could not be mapped to known bean
* properties are available in the unmapped Map.
* </p>
*
* @param <T> The type of entity bean
*/
public interface JsonReadBeanVisitor<T> {
/**
* Visit the bean that has just been processed.
* <p>
* This provides a method of customising the bean and processing any custom
* JSON content.
* </p>
*
* @param bean the bean being processed
* @param unmapped Map of any JSON elements that didn't map to known bean properties
*/
void visit(T bean, Map<String, Object> unmapped);
}
@@ -0,0 +1,62 @@
package com.avaje.ebean.text.json;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Provides the ability to customise the reading of JSON content.
* <p>
* You can register JsonReadBeanVisitors to customise the processing of the
* beans as they are processed and handle any custom JSON elements that
* could not be mapped to bean properties.
* </p>
*/
public class JsonReadOptions {
protected Map<String, JsonReadBeanVisitor<?>> visitorMap;
protected Object objectMapper;
/**
* Default constructor.
*/
public JsonReadOptions() {
this.visitorMap = new LinkedHashMap<String, JsonReadBeanVisitor<?>>();
}
/**
* Return the map of JsonReadBeanVisitor's.
*/
public Map<String, JsonReadBeanVisitor<?>> getVisitorMap() {
return visitorMap;
}
/**
* Register a JsonReadBeanVisitor for the root level.
*/
public JsonReadOptions addRootVisitor(JsonReadBeanVisitor<?> visitor) {
return addVisitor(null, visitor);
}
/**
* Register a JsonReadBeanVisitor for a given path.
*/
public JsonReadOptions addVisitor(String path, JsonReadBeanVisitor<?> visitor) {
visitorMap.put(path, visitor);
return this;
}
/**
* Return the Jackson ObjectMapper to use (if not wanted to use the objectMapper set on the ServerConfig).
*/
public Object getObjectMapper() {
return objectMapper;
}
/**
* Set the Jackson ObjectMapper to use (if not wanted to use the objectMapper set on the ServerConfig).
*/
public void setObjectMapper(Object objectMapper) {
this.objectMapper = objectMapper;
}
}
@@ -1,21 +1,23 @@
package com.avaje.ebean.text.json;
import com.avaje.ebean.config.JsonConfig;
import com.avaje.ebean.text.PathProperties;
/**
* Deprecated in favour of just using PathProperties.
*
* Provides options for customising the JSON write process.
* <p>
* You can explicitly state which properties to include in the JSON output for
* the root level and each path.
* </p>
* @deprecated
*/
public class JsonWriteOptions {
protected PathProperties pathProperties;
protected Object objectMapper;
protected JsonConfig.Include include;
/**
* Parse and return a PathProperties from nested string format like
* (a,b,c(d,e),f(g)) where "c" is a path containing "d" and "e" and "f" is a
@@ -51,4 +53,35 @@ public class JsonWriteOptions {
return pathProperties;
}
/**
* Return the include mode for this request.
*/
public JsonConfig.Include getInclude() {
return include;
}
/**
* Set the include mode for this request.
*/
public void setInclude(JsonConfig.Include include) {
this.include = include;
}
/**
* Return the jackson object mapper to use.
* <p/>
* If null the ObjectMapper from serverConfig will be used.
*/
public Object getObjectMapper() {
return objectMapper;
}
/**
* Set the jackson object mapper to use.
* <p/>
* If null the ObjectMapper from serverConfig will be used.
*/
public void setObjectMapper(Object objectMapper) {
this.objectMapper = objectMapper;
}
}
@@ -6,88 +6,101 @@ import org.slf4j.LoggerFactory;
/**
* Helper to find classes taking into account the context class loader.
*
* @author rbygrave
*/
public class ClassUtil {
private static final Logger logger = LoggerFactory.getLogger(ClassUtil.class);
private static boolean preferContext = true;
private static final Logger logger = LoggerFactory.getLogger(ClassUtil.class);
/**
* Load a class taking into account a context class loader (if present).
*/
public static Class<?> forName(String name) throws ClassNotFoundException {
return forName(name, null);
}
/**
* Load a class taking into account a context class loader (if present).
*/
public static Class<?> forName(String name, Class<?> caller) throws ClassNotFoundException {
if (caller == null){
caller = ClassUtil.class;
}
ClassLoadContext ctx = ClassLoadContext.of(caller, preferContext);
return ctx.forName(name);
}
private static boolean preferContext = true;
public static ClassLoader getClassLoader(Class<?> caller, boolean preferContext) {
if (caller == null){
caller = ClassUtil.class;
}
ClassLoadContext ctx = ClassLoadContext.of(caller, preferContext);
ClassLoader classLoader = ctx.getDefault(preferContext);
if (ctx.isAmbiguous()){
logger.info("Ambigous ClassLoader (Context vs Caller) chosen "+classLoader);
}
return classLoader;
}
/**
* Load a class taking into account a context class loader (if present).
*/
public static Class<?> forName(String name) throws ClassNotFoundException {
return forName(name, null);
}
/**
* Return true if the given class is present.
*/
public static boolean isPresent(String className) {
return isPresent(className, null);
}
/**
* Return true if the given class is present.
*/
public static boolean isPresent(String className, Class<?> caller) {
try {
forName(className, caller);
return true;
} catch (Throwable ex) {
// Class or one of its dependencies is not present...
return false;
}
}
/**
* Load a class taking into account a context class loader (if present).
*/
public static Class<?> forName(String name, Class<?> caller) throws ClassNotFoundException {
/**
* Return a new instance of the class using the default constructor.
*/
public static Object newInstance(String className) {
return newInstance(className,null);
if (caller == null) {
caller = ClassUtil.class;
}
/**
* Return a new instance of the class using the default constructor.
*/
public static Object newInstance(String className, Class<?> caller) {
try {
Class<?> cls = forName(className, caller);
return cls.newInstance();
} catch (Exception e){
String msg = "Error constructing "+className;
throw new IllegalArgumentException(msg, e);
}
ClassLoadContext ctx = ClassLoadContext.of(caller, preferContext);
return ctx.forName(name);
}
public static ClassLoader getClassLoader(Class<?> caller, boolean preferContext) {
if (caller == null) {
caller = ClassUtil.class;
}
ClassLoadContext ctx = ClassLoadContext.of(caller, preferContext);
ClassLoader classLoader = ctx.getDefault(preferContext);
if (ctx.isAmbiguous()) {
logger.info("Ambigous ClassLoader (Context vs Caller) chosen " + classLoader);
}
return classLoader;
}
/**
* Return true if Jackson annotations like JsonIgnore are present.
*/
public static boolean isJacksonAnnotationsPresent() {
return isPresent("com.fasterxml.jackson.annotation.JsonIgnore", null);
}
/**
* Return true if Jackson ObjectMapper is present.
*/
public static boolean isJacksonObjectMapperPresent() {
return isPresent("com.fasterxml.jackson.databind.ObjectMapper", null);
}
/**
* Return true if the given class is present.
*/
public static boolean isPresent(String className) {
return isPresent(className, null);
}
/**
* Return true if the given class is present.
*/
public static boolean isPresent(String className, Class<?> caller) {
try {
forName(className, caller);
return true;
} catch (Throwable ex) {
// Class or one of its dependencies is not present...
return false;
}
}
/**
* Return a new instance of the class using the default constructor.
*/
public static Object newInstance(String className) {
return newInstance(className, null);
}
/**
* Return a new instance of the class using the default constructor.
*/
public static Object newInstance(String className, Class<?> caller) {
try {
Class<?> cls = forName(className, caller);
return cls.newInstance();
} catch (Exception e) {
String msg = "Error constructing " + className;
throw new IllegalArgumentException(msg, e);
}
}
}
@@ -11,16 +11,16 @@ import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
*/
public interface LoadBeanBuffer {
public int getBatchSize();
int getBatchSize();
public List<EntityBeanIntercept> getBatch();
List<EntityBeanIntercept> getBatch();
public BeanDescriptor<?> getBeanDescriptor();
BeanDescriptor<?> getBeanDescriptor();
public PersistenceContext getPersistenceContext();
PersistenceContext getPersistenceContext();
public String getFullPath();
String getFullPath();
public void configureQuery(SpiQuery<?> query, String lazyLoadProperty);
void configureQuery(SpiQuery<?> query, String lazyLoadProperty);
}
@@ -14,13 +14,13 @@ public interface LoadContext {
/**
* Return the minimum batch size when using QueryIterator with query joins.
*/
public int getSecondaryQueriesMinBatchSize(OrmQueryRequest<?> parentRequest, int defaultQueryBatch);
int getSecondaryQueriesMinBatchSize(OrmQueryRequest<?> parentRequest, int defaultQueryBatch);
/**
* Execute any secondary (+query) queries if there are any defined.
* @param parentRequest the originating query request
*/
public void executeSecondaryQueries(OrmQueryRequest<?> parentRequest);
void executeSecondaryQueries(OrmQueryRequest<?> parentRequest);
/**
* Register any secondary queries (+query or +lazy) with their
@@ -30,17 +30,17 @@ public interface LoadContext {
* defined query for +query and +lazy execution.
* </p>
*/
public void registerSecondaryQueries(SpiQuery<?> query);
void registerSecondaryQueries(SpiQuery<?> query);
/**
* Return the node for a given path which is used by autofetch profiling.
*/
public ObjectGraphNode getObjectGraphNode(String path);
ObjectGraphNode getObjectGraphNode(String path);
/**
* Return the persistence context used by this query and future lazy loading.
*/
public PersistenceContext getPersistenceContext();
PersistenceContext getPersistenceContext();
/**
* Set the persistence context used by this query and future lazy loading.
@@ -48,16 +48,16 @@ public interface LoadContext {
* Used by query iterator when processing large result sets.
* </p>
*/
public void resetPersistenceContext(PersistenceContext persistenceContext);
void resetPersistenceContext(PersistenceContext persistenceContext);
/**
* Register a Bean for lazy loading.
*/
public void register(String path, EntityBeanIntercept ebi);
void register(String path, EntityBeanIntercept ebi);
/**
* Register a collection for lazy loading.
*/
public void register(String path, BeanCollection<?> bc);
void register(String path, BeanCollection<?> bc);
}
@@ -13,20 +13,20 @@ import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
*/
public interface LoadManyBuffer {
public int getBatchSize();
int getBatchSize();
public List<BeanCollection<?>> getBatch();
List<BeanCollection<?>> getBatch();
public BeanPropertyAssocMany<?> getBeanProperty();
BeanPropertyAssocMany<?> getBeanProperty();
public ObjectGraphNode getObjectGraphNode();
ObjectGraphNode getObjectGraphNode();
public BeanDescriptor<?> getBeanDescriptor();
BeanDescriptor<?> getBeanDescriptor();
public PersistenceContext getPersistenceContext();
PersistenceContext getPersistenceContext();
public String getFullPath();
String getFullPath();
public void configureQuery(SpiQuery<?> query);
void configureQuery(SpiQuery<?> query);
}
@@ -48,4 +48,11 @@ public abstract class LoadRequest {
return transaction;
}
/**
* Return true if the parent query is a findIterate() type query.
* So one of - findIterate(), findEach(), findEachWhile() or findVisit().
*/
public boolean isParentFindIterate() {
return parentRequest != null && parentRequest.getQuery().getType() == SpiQuery.Type.ITERATE;
}
}
@@ -14,5 +14,5 @@ public interface LoadSecondaryQuery {
/**
* Execute the secondary query with a given batch size.
*/
public void loadSecondaryQuery(OrmQueryRequest<?> parentRequest);
void loadSecondaryQuery(OrmQueryRequest<?> parentRequest);
}
@@ -10,5 +10,5 @@ public interface SpiBackgroundExecutor extends BackgroundExecutor {
/**
* Shutdown any associated thread pools.
*/
public void shutdown();
void shutdown();
}
@@ -4,7 +4,7 @@ import com.avaje.ebean.CallableSql;
public interface SpiCallableSql extends CallableSql {
public BindParams getBindParams();
BindParams getBindParams();
public TransactionEventTable getTransactionEventTable();
TransactionEventTable getTransactionEventTable();
}
@@ -9,6 +9,7 @@ import com.avaje.ebean.config.dbplatform.DatabasePlatform;
* author: Richard Vowles - http://gplus.to/RichardVowles
*/
public interface SpiEbeanPlugin {
/**
* initializes the plugin.
*
@@ -16,7 +17,10 @@ public interface SpiEbeanPlugin {
* @param dbPlatform - the database we are using - this is available from the server, but it is provided for convenience
* @param serverConfig - the configured server information. It allows access to pre-collected information (but not the collector PropertySource, yet)
*/
public void setup(SpiEbeanServer server, DatabasePlatform dbPlatform, ServerConfig serverConfig);
void setup(SpiEbeanServer server, DatabasePlatform dbPlatform, ServerConfig serverConfig);
public void execute(boolean online);
/**
* Execute the plugin (generate DDL for example).
*/
void execute(boolean online);
}
@@ -26,22 +26,22 @@ public interface SpiEbeanServer extends EbeanServer, BeanLoader, BeanCollectionL
/**
* For internal use, shutdown of the server invoked by JVM Shutdown.
*/
public void shutdownManaged();
void shutdownManaged();
/**
* Return true if query origins should be collected.
*/
public boolean isCollectQueryOrigins();
boolean isCollectQueryOrigins();
/**
* Return the server configuration.
*/
public ServerConfig getServerConfig();
ServerConfig getServerConfig();
/**
* Return the DatabasePlatform for this server.
*/
public DatabasePlatform getDatabasePlatform();
DatabasePlatform getDatabasePlatform();
/**
* Return a JDBC driver specific handler for batching.
@@ -49,7 +49,7 @@ public interface SpiEbeanServer extends EbeanServer, BeanLoader, BeanCollectionL
* Required for Oracle specific batch handling.
* </p>
*/
public PstmtBatch getPstmtBatch();
PstmtBatch getPstmtBatch();
/**
* Create an object to represent the current CallStack.
@@ -58,47 +58,47 @@ public interface SpiEbeanServer extends EbeanServer, BeanLoader, BeanCollectionL
* graph costing.
* </p>
*/
public CallStack createCallStack();
CallStack createCallStack();
/**
* Return the PersistenceContextScope to use defined at query or server level.
*/
public PersistenceContextScope getPersistenceContextScope(SpiQuery<?> query);
PersistenceContextScope getPersistenceContextScope(SpiQuery<?> query);
/**
* Return the DDL generator.
*/
public DdlGenerator getDdlGenerator();
DdlGenerator getDdlGenerator();
/**
* Return the AutoFetchListener.
*/
public AutoFetchManager getAutoFetchManager();
AutoFetchManager getAutoFetchManager();
/**
* Clear the query execution statistics.
*/
public void clearQueryStatistics();
void clearQueryStatistics();
/**
* Return all the descriptors.
*/
public List<BeanDescriptor<?>> getBeanDescriptors();
List<BeanDescriptor<?>> getBeanDescriptors();
/**
* Return the BeanDescriptor for a given type of bean.
*/
public <T> BeanDescriptor<T> getBeanDescriptor(Class<T> type);
<T> BeanDescriptor<T> getBeanDescriptor(Class<T> type);
/**
* Return BeanDescriptor using it's unique id.
*/
public BeanDescriptor<?> getBeanDescriptorById(String descriptorId);
BeanDescriptor<?> getBeanDescriptorById(String descriptorId);
/**
* Return BeanDescriptors mapped to this table.
*/
public List<BeanDescriptor<?>> getBeanDescriptors(String tableName);
List<BeanDescriptor<?>> getBeanDescriptors(String tableName);
/**
* Process committed changes from another framework.
@@ -108,7 +108,7 @@ public interface SpiEbeanServer extends EbeanServer, BeanLoader, BeanCollectionL
* this to maintain its cache and text indexes appropriately.
* </p>
*/
public void externalModification(TransactionEventTable event);
void externalModification(TransactionEventTable event);
/**
* Create a ServerTransaction.
@@ -116,44 +116,44 @@ public interface SpiEbeanServer extends EbeanServer, BeanLoader, BeanCollectionL
* To specify to use the default transaction isolation use a value of -1.
* </p>
*/
public SpiTransaction createServerTransaction(boolean isExplicit, int isolationLevel);
SpiTransaction createServerTransaction(boolean isExplicit, int isolationLevel);
/**
* Return the current transaction or null if there is no current transaction.
*/
public SpiTransaction getCurrentServerTransaction();
SpiTransaction getCurrentServerTransaction();
/**
* Create a ScopeTrans for a method for the given scope definition.
*/
public ScopeTrans createScopeTrans(TxScope txScope);
ScopeTrans createScopeTrans(TxScope txScope);
/**
* Create a ServerTransaction for query purposes.
*/
public SpiTransaction createQueryTransaction();
SpiTransaction createQueryTransaction();
/**
* An event from another server in the cluster used to notify local
* BeanListeners of remote inserts updates and deletes.
*/
public void remoteTransactionEvent(RemoteTransactionEvent event);
void remoteTransactionEvent(RemoteTransactionEvent event);
/**
* Create a query request object.
*/
public <T> SpiOrmQueryRequest<T> createQueryRequest(BeanDescriptor<T> desc, SpiQuery<T> q,
<T> SpiOrmQueryRequest<T> createQueryRequest(BeanDescriptor<T> desc, SpiQuery<T> q,
Transaction t);
/**
* Compile a query.
*/
public <T> CQuery<T> compileQuery(Query<T> query, Transaction t);
<T> CQuery<T> compileQuery(Query<T> query, Transaction t);
/**
* Return the queryEngine for this server.
*/
public CQueryEngine getQueryEngine();
CQueryEngine getQueryEngine();
/**
* Execute the findId's query but without copying the query.
@@ -162,37 +162,37 @@ public interface SpiEbeanServer extends EbeanServer, BeanLoader, BeanCollectionL
* the query has finished (if executing in a background thread).
* </p>
*/
public <T> List<Object> findIdsWithCopy(Query<T> query, Transaction t);
<T> List<Object> findIdsWithCopy(Query<T> query, Transaction t);
/**
* Execute the findRowCount query but without copying the query.
*/
public <T> int findRowCountWithCopy(Query<T> query, Transaction t);
<T> int findRowCountWithCopy(Query<T> query, Transaction t);
/**
* Load a batch of Associated One Beans.
*/
public void loadBean(LoadBeanRequest loadRequest);
void loadBean(LoadBeanRequest loadRequest);
/**
* Lazy load a batch of Many's.
*/
public void loadMany(LoadManyRequest loadRequest);
void loadMany(LoadManyRequest loadRequest);
/**
* Return the default batch size for lazy loading.
*/
public int getLazyLoadBatchSize();
int getLazyLoadBatchSize();
/**
* Return true if the type is known as an Entity or Xml type or a List Set or
* Map of known bean types.
*/
public boolean isSupportedType(java.lang.reflect.Type genericType);
boolean isSupportedType(java.lang.reflect.Type genericType);
/**
* Collect query statistics by ObjectGraphNode. Used for Lazy loading reporting.
*/
public void collectQueryStats(ObjectGraphNode objectGraphNode, long loadedBeanCount, long timeMicros);
void collectQueryStats(ObjectGraphNode objectGraphNode, long loadedBeanCount, long timeMicros);
}
@@ -16,7 +16,7 @@ public interface SpiExpression extends Expression {
* Predicates on Many properties require an extra independent join clause.
* </p>
*/
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins whereManyJoins);
void containsMany(BeanDescriptor<?> desc, ManyWhereJoins whereManyJoins);
/**
* Calculate a hash value used to identify a query for AutoFetch tuning.
@@ -25,7 +25,7 @@ public interface SpiExpression extends Expression {
* from an AutoFetch perspective and get different tuning.
* </p>
*/
public void queryAutoFetchHash(HashQueryPlanBuilder builder);
void queryAutoFetchHash(HashQueryPlanBuilder builder);
/**
* Calculate a hash value for the expression.
@@ -36,12 +36,12 @@ public interface SpiExpression extends Expression {
* case the query execution plan can be reused.
* </p>
*/
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder);
void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder);
/**
* Return the hash value for the values that will be bound.
*/
public int queryBindHash();
int queryBindHash();
/**
* Add some sql to the query.
@@ -56,7 +56,7 @@ public interface SpiExpression extends Expression {
* @param request
* the associated request.
*/
public void addSql(SpiExpressionRequest request);
void addSql(SpiExpressionRequest request);
/**
* Add the parameter values to be set against query. For each ? place holder
@@ -65,5 +65,5 @@ public interface SpiExpression extends Expression {
* @param request
* the associated request.
*/
public void addBindValues(SpiExpressionRequest request);
void addBindValues(SpiExpressionRequest request);
}
@@ -7,6 +7,6 @@ public interface SpiExpressionFactory extends ExpressionFactory {
/**
* Create another expression factory with a given sub path.
*/
public ExpressionFactory createExpressionFactory();
ExpressionFactory createExpressionFactory();
}
@@ -16,17 +16,17 @@ public interface SpiExpressionList<T> extends ExpressionList<T> {
/**
* Return the underlying list of expressions.
*/
public List<SpiExpression> getUnderlyingList();
List<SpiExpression> getUnderlyingList();
/**
* Return a copy of the ExpressionList with the path trimmed for filterMany() expressions.
*/
public SpiExpressionList<?> trimPath(int prefixTrim);
SpiExpressionList<?> trimPath(int prefixTrim);
/**
* Restore the ExpressionFactory after deserialisation.
*/
public void setExpressionFactory(ExpressionFactory expr);
void setExpressionFactory(ExpressionFactory expr);
/**
* Process "Many" properties populating ManyWhereJoins.
@@ -34,12 +34,12 @@ public interface SpiExpressionList<T> extends ExpressionList<T> {
* Predicates on Many properties require an extra independent join clause.
* </p>
*/
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoins);
void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoins);
/**
* Return true if this list is empty.
*/
public boolean isEmpty();
boolean isEmpty();
/**
* Concatenate the expression sql into a String.
@@ -48,7 +48,7 @@ public interface SpiExpressionList<T> extends ExpressionList<T> {
* with bind parameters.
* </p>
*/
public String buildSql(SpiExpressionRequest request);
String buildSql(SpiExpressionRequest request);
/**
* Combine the expression bind values into a list.
@@ -59,12 +59,12 @@ public interface SpiExpressionList<T> extends ExpressionList<T> {
*
* @return the list of all the bind values in order.
*/
public ArrayList<Object> buildBindValues(SpiExpressionRequest request);
ArrayList<Object> buildBindValues(SpiExpressionRequest request);
/**
* Calculate a hash based on the expressions but excluding the actual bind
* values.
*/
public void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder);
void queryPlanHash(BeanQueryRequest<?> request, HashQueryPlanBuilder builder);
}
@@ -13,45 +13,45 @@ public interface SpiExpressionRequest {
/**
* Parse the logical property name to the deployment name.
*/
public String parseDeploy(String logicalProp);
String parseDeploy(String logicalProp);
/**
* Return the bean descriptor for the root type.
*/
public BeanDescriptor<?> getBeanDescriptor();
BeanDescriptor<?> getBeanDescriptor();
/**
* Return the associated QueryRequest.
*/
public SpiOrmQueryRequest<?> getQueryRequest();
SpiOrmQueryRequest<?> getQueryRequest();
/**
* Append to the expression sql.
*/
public SpiExpressionRequest append(String sql);
SpiExpressionRequest append(String sql);
/**
* Add a bind value to this request.
*/
public void addBindValue(Object bindValue);
void addBindValue(Object bindValue);
/**
* Return the accumulated expression sql for all expressions in this request.
*/
public String getSql();
String getSql();
/**
* Return the ordered list of bind values for all expressions in this request.
*/
public ArrayList<Object> getBindValues();
ArrayList<Object> getBindValues();
/**
* Increments the parameter index and returns that value.
*/
public int nextParameter();
int nextParameter();
/**
* Append a DB Like clause.
*/
public void appendLike();
void appendLike();
}
File diff suppressed because it is too large Load Diff
@@ -10,68 +10,68 @@ import com.avaje.ebean.SqlQueryListener;
*/
public interface SpiSqlQuery extends SqlQuery {
/**
* Return the named or positioned parameters.
*/
public BindParams getBindParams();
/**
* Return the named or positioned parameters.
*/
BindParams getBindParams();
/**
* return the query.
*/
public String getQuery();
/**
* return the query.
*/
String getQuery();
/**
* Return the queryListener.
*/
public SqlQueryListener getListener();
/**
* Return the first row to fetch.
*/
public int getFirstRow();
/**
* Return the maximum number of rows to fetch.
*/
public int getMaxRows();
/**
* Return the number of rows after which background fetching occurs.
*/
public int getBackgroundFetchAfter();
/**
* Return the key property for maps.
*/
public String getMapKey();
/**
* Return the query timeout.
*/
public int getTimeout();
/**
* Return the queryListener.
*/
SqlQueryListener getListener();
/**
* Return the hint for Statement.setFetchSize().
*/
public int getBufferFetchSizeHint();
/**
* Return the first row to fetch.
*/
int getFirstRow();
/**
* Return true if this is a future fetch type query.
*/
public boolean isFutureFetch();
/**
* Return the maximum number of rows to fetch.
*/
int getMaxRows();
/**
* Set to true if this is a future fetch type query.
*/
public void setFutureFetch(boolean futureFetch);
/**
* Return the number of rows after which background fetching occurs.
*/
int getBackgroundFetchAfter();
/**
* Set the PreparedStatement for the purposes of supporting cancel.
*/
public void setPreparedStatement(PreparedStatement pstmt);
/**
* Return true if the query has been cancelled.
*/
public boolean isCancelled();
/**
* Return the key property for maps.
*/
String getMapKey();
/**
* Return the query timeout.
*/
int getTimeout();
/**
* Return the hint for Statement.setFetchSize().
*/
int getBufferFetchSizeHint();
/**
* Return true if this is a future fetch type query.
*/
boolean isFutureFetch();
/**
* Set to true if this is a future fetch type query.
*/
void setFutureFetch(boolean futureFetch);
/**
* Set the PreparedStatement for the purposes of supporting cancel.
*/
void setPreparedStatement(PreparedStatement pstmt);
/**
* Return true if the query has been cancelled.
*/
boolean isCancelled();
}
@@ -4,7 +4,7 @@ import com.avaje.ebean.SqlUpdate;
public interface SpiSqlUpdate extends SqlUpdate {
public BindParams getBindParams();
BindParams getBindParams();
public void setGeneratedSql(String sql);
void setGeneratedSql(String sql);
}
@@ -20,45 +20,45 @@ public interface SpiTransaction extends Transaction {
/**
* End the transaction when had query only use.
*/
public void endQueryOnly();
void endQueryOnly();
/**
* Return the string prefix with the transactin id and label used in logging.
*/
public String getLogPrefix();
String getLogPrefix();
/**
* Return true if generated SQL and Bind values should be logged to the
* transaction log.
*/
public boolean isLogSql();
boolean isLogSql();
/**
* Return true if summary level events should be logged to the transaction
* log.
*/
public boolean isLogSummary();
boolean isLogSummary();
/**
* Log a message to the SQL logger.
*/
public void logSql(String msg);
void logSql(String msg);
/**
* Log a message to the SUMMARY logger.
*/
public void logSummary(String msg);
void logSummary(String msg);
/**
* Register a "Derived Relationship" (that requires an additional update).
*/
public void registerDerivedRelationship(DerivedRelationshipData assocBean);
void registerDerivedRelationship(DerivedRelationshipData assocBean);
/**
* Return the list of "Derived Relationships" that must be maintained after
* insert.
*/
public List<DerivedRelationshipData> getDerivedRelationship(Object bean);
List<DerivedRelationshipData> getDerivedRelationship(Object bean);
/**
* Add a deleting bean to the registered list.
@@ -66,22 +66,22 @@ public interface SpiTransaction extends Transaction {
* This is to handle bi-directional relationships where both sides Cascade.
* </p>
*/
public void registerDeleteBean(Integer hash);
void registerDeleteBean(Integer hash);
/**
* Unregister the hash of the bean.
*/
public void unregisterDeleteBean(Integer hash);
void unregisterDeleteBean(Integer hash);
/**
* Return true if this is a bean that has already been saved/deleted.
*/
public boolean isRegisteredDeleteBean(Integer hash);
boolean isRegisteredDeleteBean(Integer hash);
/**
* Unregister the persisted bean.
*/
public void unregisterBean(Object bean);
void unregisterBean(Object bean);
/**
* Return true if this is a bean that has already been persisted in the
@@ -91,13 +91,13 @@ public interface SpiTransaction extends Transaction {
* This will register the bean if it is not already.
* </p>
*/
public boolean isRegisteredBean(Object bean);
boolean isRegisteredBean(Object bean);
/**
* Returns a String used to identify the transaction. This id is used for
* Transaction logging.
*/
public String getId();
String getId();
/**
* Return the batchSize specifically set for this transaction or 0.
@@ -105,7 +105,7 @@ public interface SpiTransaction extends Transaction {
* Returning 0 implies to use the system wide default batch size.
* </p>
*/
public int getBatchSize();
int getBatchSize();
/**
* Modify and return the current 'depth' of the transaction.
@@ -119,18 +119,18 @@ public interface SpiTransaction extends Transaction {
* executed first during save.
* </p>
*/
public int depth(int diff);
int depth(int diff);
/**
* Return the current depth.
*/
public int depth();
int depth();
/**
* Return true if this transaction was created explicitly via
* <code>Ebean.beginTransaction()</code>.
*/
public boolean isExplicit();
boolean isExplicit();
/**
* Get the object that holds the event details.
@@ -140,29 +140,29 @@ public interface SpiTransaction extends Transaction {
* around the cluster (if you have a cluster).
* </p>
*/
public TransactionEvent getEvent();
TransactionEvent getEvent();
/**
* Whether persistCascade is on for save and delete.
*/
public boolean isPersistCascade();
boolean isPersistCascade();
/**
* Return true if this request should be batched. Conversely returns false
* if this request should be executed immediately.
*/
public boolean isBatchThisRequest(PersistRequest.Type type);
boolean isBatchThisRequest(PersistRequest.Type type);
/**
* Return the queue used to batch up persist requests.
*/
public BatchControl getBatchControl();
BatchControl getBatchControl();
/**
* Set the queue used to batch up persist requests. There should only be one
* PersistQueue set per transaction.
*/
public void setBatchControl(BatchControl control);
void setBatchControl(BatchControl control);
/**
* Return the persistence context associated with this transaction.
@@ -172,7 +172,7 @@ public interface SpiTransaction extends Transaction {
* behaviour.
* </p>
*/
public PersistenceContext getPersistenceContext();
PersistenceContext getPersistenceContext();
/**
* Set the persistence context to this transaction.
@@ -185,47 +185,46 @@ public interface SpiTransaction extends Transaction {
* PersistenceContext with multiple transactions.
* </p>
*/
public void setPersistenceContext(PersistenceContext context);
void setPersistenceContext(PersistenceContext context);
/**
* Return the underlying Connection for internal use.
* <p>
* If the connection is made public from Transaction and the user code calls
* If the connection is made from Transaction and the user code calls
* that method we can no longer trust the query only status of a
* Transaction.
* </p>
*/
public Connection getInternalConnection();
Connection getInternalConnection();
/**
* Return true if the manyToMany intersection should be persisted for this particular relationship direction.
*/
public boolean isSaveAssocManyIntersection(String intersectionTable, String beanName);
boolean isSaveAssocManyIntersection(String intersectionTable, String beanName);
/**
* Return true if batch mode got escalated for this request (and associated cascades).
*/
public boolean checkBatchEscalationOnCascade(PersistRequestBean<?> request);
boolean checkBatchEscalationOnCascade(PersistRequestBean<?> request);
/**
* If batch mode was turned on for the request then flush the batch.
*/
public void flushBatchOnCascade();
void flushBatchOnCascade();
/**
* Mark the transaction explicitly as not being query only.
*/
public void markNotQueryOnly();
void markNotQueryOnly();
/**
* Potentially escalate batch mode on saving or deleting a collection.
*/
public void checkBatchEscalationOnCollection();
void checkBatchEscalationOnCollection();
/**
* Flush batch if we escalated batch mode on saving or deleting a collection.
*/
public void flushBatchOnCollection();
void flushBatchOnCollection();
}
@@ -2,5 +2,5 @@ package com.avaje.ebeaninternal.api;
public interface SpiTransactionScopeManager {
public void replace(SpiTransaction t);
void replace(SpiTransaction t);
}
@@ -11,66 +11,66 @@ public interface SpiUpdate<T> extends Update<T> {
* The type of the update request.
*/
enum OrmUpdateType {
INSERT{
INSERT {
public String toString() {
return "Insert";
}
},
UPDATE{
UPDATE {
public String toString() {
return "Update";
}
},
DELETE{
},
DELETE {
public String toString() {
return "Delete";
}
},
UNKNOWN{
UNKNOWN {
public String toString() {
return "Unknown";
}
};
}
}
/**
* Return the type of bean being updated.
*/
public Class<?> getBeanType();
Class<?> getBeanType();
/**
* Return the type of this - insert, update or delete.
*/
public OrmUpdateType getOrmUpdateType();
OrmUpdateType getOrmUpdateType();
/**
* Return the name of the table being modified.
*/
public String getBaseTable();
String getBaseTable();
/**
* Return the update statement. This could be either sql or an orm update with bean types and property names.
*/
public String getUpdateStatement();
String getUpdateStatement();
/**
* Return the timeout in seconds.
*/
public int getTimeout();
int getTimeout();
/**
* Return true if the cache should be notified to invalidate objects.
*/
public boolean isNotifyCache();
boolean isNotifyCache();
/**
* Return the bind parameters.
*/
public BindParams getBindParams();
BindParams getBindParams();
/**
* Set the generated sql used.
*/
public void setGeneratedSql(String sql);
void setGeneratedSql(String sql);
}
@@ -16,8 +16,6 @@ import com.avaje.ebeaninternal.server.persist.dmlbind.Bindable;
* <p>
* The plans are cached by the BeanDescriptors.
* </>
*
* @author rbygrave
*/
public interface SpiUpdatePlan {
@@ -28,48 +26,42 @@ public interface SpiUpdatePlan {
* deployment.
* </p>
*/
public boolean isEmptySetClause();
boolean isEmptySetClause();
/**
* Bind given the request and bean. The bean could be the oldValues bean
* when binding a update or delete where clause with ALL concurrency mode.
*/
public void bindSet(DmlHandler bind, EntityBean bean) throws SQLException;
void bindSet(DmlHandler bind, EntityBean bean) throws SQLException;
/**
* Return the time this plan was created.
*/
public long getTimeCreated();
long getTimeCreated();
/**
* Return the time this plan was last used.
*/
public Long getTimeLastUsed();
Long getTimeLastUsed();
/**
* Return the hash key for this plan.
*/
public Integer getKey();
Integer getKey();
/**
* Return the concurrency mode for this plan.
*/
public ConcurrencyMode getMode();
ConcurrencyMode getMode();
/**
* Return the update SQL statement.
*/
public String getSql();
String getSql();
/**
* Return the set of bindable update properties.
*/
public Bindable getSet();
// /**
// * Return the properties that where changed and should be included in the
// * update statement.
// */
// public Set<String> getProperties();
Bindable getSet();
}
@@ -65,10 +65,10 @@ public class TransactionEvent implements Serializable {
}
/**
* For BeanListeners the requests they are interested in.
* Return the list of PersistRequestBean's for this transaction.
*/
public TransactionEventBeans getEventBeans() {
return eventBeans;
public List<PersistRequestBean<?>> getPersistRequestBeans() {
return (eventBeans == null) ? null : eventBeans.getRequests();
}
public TransactionEventTable getEventTables() {
@@ -1,22 +1,18 @@
package com.avaje.ebeaninternal.server.cache;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
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;
import com.avaje.ebeaninternal.server.util.LongAdder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
* The default cache implementation.
@@ -27,375 +23,392 @@ import org.slf4j.LoggerFactory;
*/
public class DefaultServerCache implements ServerCache {
private static final Logger logger = LoggerFactory.getLogger(DefaultServerCache.class);
protected static final Logger logger = LoggerFactory.getLogger(DefaultServerCache.class);
private static final CacheEntryComparator comparator = new CacheEntryComparator();
private final ConcurrentHashMap<Object, CacheEntry> map = new ConcurrentHashMap<Object, CacheEntry>();
private final AtomicInteger missCount = new AtomicInteger();
private final AtomicInteger removedHitCount = new AtomicInteger();
private final Object monitor = new Object();
private final String name;
private int maxSize;
private long trimFrequency;
private int maxIdleSecs;
private int maxSecsToLive;
public DefaultServerCache(String name, ServerCacheOptions options) {
this(name, options.getMaxSize(), options.getMaxIdleSecs(), options.getMaxSecsToLive());
}
public DefaultServerCache(String name, int maxSize, int maxIdleSecs, int maxSecsToLive) {
this.name = name;
this.maxSize = maxSize;
this.maxIdleSecs = maxIdleSecs;
this.maxSecsToLive = maxSecsToLive;
this.trimFrequency = 60;
}
public void init(EbeanServer server) {
TrimTask trim = new TrimTask();
BackgroundExecutor executor = server.getBackgroundExecutor();
executor.executePeriodically(trim, trimFrequency, TimeUnit.SECONDS);
}
public ServerCacheStatistics getStatistics(boolean reset) {
ServerCacheStatistics s = new ServerCacheStatistics();
s.setCacheName(name);
s.setMaxSize(maxSize);
// these counters won't necessarily be consistent with
// respect to each other as activity can occur while
// they are being calculated
int mc = reset ? missCount.getAndSet(0) : missCount.get();
int hc = getHitCount(reset);
int size = size();
s.setSize(size);
s.setHitCount(hc);
s.setMissCount(mc);
return s;
}
public int getHitRatio() {
int mc = missCount.get();
int hc = getHitCount(false);
int totalCount = hc + mc;
if (totalCount == 0){
return 0;
} else {
return hc * 100 / totalCount;
}
}
private int getHitCount(boolean reset) {
int hc = reset ? removedHitCount.getAndSet(0) : removedHitCount.get();
for (CacheEntry cacheEntry : map.values()) {
hc += cacheEntry.getHitCount(reset);
}
return hc;
}
/**
* Compare by last access time (for LRU eviction).
*/
public static final CompareByLastAccess BY_LAST_ACCESS = new CompareByLastAccess();
public ServerCacheOptions getOptions() {
synchronized (monitor) {
ServerCacheOptions o = new ServerCacheOptions();
o.setMaxIdleSecs(maxIdleSecs);
o.setMaxSize(maxSize);
o.setMaxSecsToLive(maxSecsToLive);
return o;
}
}
public void setOptions(ServerCacheOptions o) {
synchronized (monitor) {
maxIdleSecs = o.getMaxIdleSecs();
maxSize = o.getMaxSize();
maxSecsToLive = o.getMaxSecsToLive();
}
}
/**
* Return the max cache size.
*/
public int getMaxSize() {
return maxSize;
}
/**
* The underlying map (ConcurrentHashMap or similar)
*/
protected final Map<Object, CacheEntry> map;
/**
* Set the max cache size.
*/
public void setMaxSize(int maxSize) {
synchronized (monitor) {
this.maxSize = maxSize;
}
}
// LongAdder is a highly concurrent low latency counter (back ported from Java8)
protected final LongAdder missCount = new LongAdder();
protected final LongAdder hitCount = new LongAdder();
protected final LongAdder insertCount = new LongAdder();
protected final LongAdder updateCount = new LongAdder();
protected final LongAdder removeCount = new LongAdder();
protected final LongAdder clearCount = new LongAdder();
/**
* Return the max idle time.
*/
public long getMaxIdleSecs() {
return maxIdleSecs;
}
protected final LongAdder evictByIdle = new LongAdder();
protected final LongAdder evictByTTL = new LongAdder();
protected final LongAdder evictByLRU = new LongAdder();
protected final LongAdder evictCount = new LongAdder();
protected final LongAdder evictMicros = new LongAdder();
/**
* Set the max idle time.
*/
public void setMaxIdleSecs(int maxIdleSecs) {
synchronized (monitor) {
this.maxIdleSecs = maxIdleSecs;
}
}
protected final Object monitor = new Object();
/**
* Return the maximum time to live.
*/
public long getMaxSecsToLive() {
return maxSecsToLive;
}
protected final String name;
/**
* Set the maximum time to live.
*/
public void setMaxSecsToLive(int maxSecsToLive) {
synchronized (monitor) {
this.maxSecsToLive = maxSecsToLive;
}
}
/**
* Return the name of the cache.
*/
public String getName() {
return name;
}
protected int maxSize;
/**
* Clear the cache.
*/
public void clear() {
map.clear();
}
protected int trimFrequency;
/**
* Return a value from the cache.
*/
public Object get(Object key) {
CacheEntry entry = map.get(key);
if (entry == null){
missCount.incrementAndGet();
return null;
} else {
// get value incrementing last
// access time and hitCount
return entry.getValue();
}
}
protected int maxIdleSecs;
/**
* Put a value into the cache.
*/
public Object put(Object key, Object value) {
// put new entry with create time
CacheEntry entry = map.put(key, new CacheEntry(key, value));
if (entry == null){
return null;
} else {
int removedHits = entry.getHitCount(true);
removedHitCount.addAndGet(removedHits);
return entry.getValue();
}
}
protected int maxSecsToLive;
/**
* Put a value into the cache but only if absent.
*/
public Object putIfAbsent(Object key, Object value) {
CacheEntry entry = map.putIfAbsent(key, new CacheEntry(key, value));
if (entry == null){
return null;
} else {
return entry.getValue();
}
}
/**
* Construct using a ConcurrentHashMap and cache options.
*/
public DefaultServerCache(String name, ServerCacheOptions options) {
this(name, new ConcurrentHashMap<Object, CacheEntry>(), options);
}
/**
* Remove an entry from the cache.
*/
public Object remove(Object key) {
CacheEntry entry = map.remove(key);
if (entry == null){
return null;
} else {
int removedHits = entry.getHitCount(true);
removedHitCount.addAndGet(removedHits);
return entry.getValue();
}
}
/**
* Construct passing in name, map and base eviction controls as ServerCacheOptions.
*/
public DefaultServerCache(String name, Map<Object, CacheEntry> map, ServerCacheOptions options) {
this(name, map, options.getMaxSize(), options.getMaxIdleSecs(), options.getMaxSecsToLive(), options.getTrimFrequency());
}
/**
* Return the number of elements in the cache.
*/
public int size() {
return map.size();
}
/**
* Construct passing in name, map and base eviction controls.
*/
public DefaultServerCache(String name, Map<Object, CacheEntry> map, int maxSize, int maxIdleSecs, int maxSecsToLive, int trimFrequency) {
this.name = name;
this.map = map;
this.maxSize = maxSize;
this.maxIdleSecs = maxIdleSecs;
this.maxSecsToLive = maxSecsToLive;
this.trimFrequency = trimFrequency;
}
/**
* The task used to periodically trim the cache.
*/
private class TrimTask implements Runnable {
@Override
public void init(EbeanServer server) {
public void run() {
EvictionRunnable trim = new EvictionRunnable();
long startTime = System.currentTimeMillis();
if (logger.isTraceEnabled()){
logger.trace("trimming cache " + name);
}
int trimmedByIdle = 0;
int trimmedByTTL = 0;
int trimmedByLRU = 0;
// default to trimming the cache every 60 seconds
long trimFreqSecs = (trimFrequency == 0) ? 60 : trimFrequency;
boolean trimMaxSize = maxSize > 0 && maxSize < size();
BackgroundExecutor executor = server.getBackgroundExecutor();
executor.executePeriodically(trim, trimFreqSecs, TimeUnit.SECONDS);
}
ArrayList<CacheEntry> activeList = new ArrayList<CacheEntry>();
@Override
public ServerCacheStatistics getStatistics(boolean reset) {
long idleExpire = System.currentTimeMillis() - (maxIdleSecs*1000);
long ttlExpire = System.currentTimeMillis() - (maxSecsToLive*1000);
ServerCacheStatistics cacheStats = new ServerCacheStatistics();
cacheStats.setCacheName(name);
cacheStats.setMaxSize(maxSize);
Iterator<CacheEntry> it = map.values().iterator();
while (it.hasNext()) {
CacheEntry cacheEntry = it.next();
if (maxIdleSecs > 0 && idleExpire > cacheEntry.getLastAccessTime()) {
it.remove();
trimmedByIdle++;
// these counters won't necessarily be consistent with
// respect to each other as activity can occur while
// they are being calculated here but they should be good enough
// and we don't want to reduce concurrent use to make them consistent
long clear = reset ? clearCount.sumThenReset() : clearCount.sum();
long remove = reset ? removeCount.sumThenReset() : removeCount.sum();
long update = reset ? updateCount.sumThenReset() : updateCount.sum();
long insert = reset ? insertCount.sumThenReset() : insertCount.sum();
long miss = reset ? missCount.sumThenReset() : missCount.sum();
long hit = reset ? hitCount.sumThenReset() : hitCount.sum();
} else if (maxSecsToLive > 0 && ttlExpire > cacheEntry.getCreateTime()) {
it.remove();
trimmedByTTL++;
long evict = reset ? evictCount.sumThenReset() : evictCount.sum();
long evictTime = reset ? evictMicros.sumThenReset() : evictMicros.sum();
long evictIdle = reset ? evictByIdle.sumThenReset() : evictByIdle.sum();
long evictTTL = reset ? evictByTTL.sumThenReset() : evictByTTL.sum();
long evictLRU = reset ? evictByLRU.sumThenReset() : evictByLRU.sum();
} else if (trimMaxSize) {
activeList.add(cacheEntry);
}
}
int size = size();
if (trimMaxSize) {
trimmedByLRU = activeList.size() - maxSize;
cacheStats.setSize(size);
cacheStats.setHitCount(hit);
cacheStats.setMissCount(miss);
cacheStats.setInsertCount(insert);
cacheStats.setUpdateCount(update);
cacheStats.setRemoveCount(remove);
cacheStats.setClearCount(clear);
if (trimmedByLRU > 0) {
// sort into last access time ascending
Collections.sort(activeList, comparator);
for (int i = maxSize; i < activeList.size(); i++) {
// remove if still in the cache
map.remove(activeList.get(i).getKey());
}
}
}
long exeTime = System.currentTimeMillis() - startTime;
if (logger.isDebugEnabled()){
logger.debug("Executed trim of cache " + name + " in ["+exeTime
+"]millis idle[" + trimmedByIdle + "] timeToLive["
+ trimmedByTTL + "] accessTime["
+ trimmedByLRU + "]");
}
cacheStats.setEvictionRunCount(evict);
cacheStats.setEvictionRunMicros(evictTime);
cacheStats.setEvictByIdle(evictIdle);
cacheStats.setEvictByTTL(evictTTL);
cacheStats.setEvictByLRU(evictLRU);
}
return cacheStats;
}
}
@Override
public int getHitRatio() {
/**
* Comparator for sorting by last access time.
*/
private static class CacheEntryComparator implements Comparator<CacheEntry>, Serializable {
long mc = missCount.sum();
long hc = hitCount.sum();
private static final long serialVersionUID = 1L;
long totalCount = hc + mc;
if (totalCount == 0) {
return 0;
} else {
return (int) (hc * 100 / totalCount);
}
}
public int compare(CacheEntry o1, CacheEntry o2) {
return o1.getLastAccessLong().compareTo(o2.getLastAccessLong());
}
}
/**
* Wraps the values to additionally hold createTime and lastAccessTime.
*/
public static class CacheEntry {
/**
* Return the options controlling the cache.
*/
@Override
public ServerCacheOptions getOptions() {
synchronized (monitor) {
ServerCacheOptions options = new ServerCacheOptions();
options.setMaxIdleSecs(maxIdleSecs);
options.setMaxSize(maxSize);
options.setMaxSecsToLive(maxSecsToLive);
options.setTrimFrequency(trimFrequency);
return options;
}
}
private final Object key;
private final Object value;
private final long createTime;
private final AtomicInteger hitCount = new AtomicInteger();
private Long lastAccessTime;
/**
* Set the options controlling the cache
*/
@Override
public void setOptions(ServerCacheOptions options) {
synchronized (monitor) {
maxIdleSecs = options.getMaxIdleSecs();
maxSize = options.getMaxSize();
maxSecsToLive = options.getMaxSecsToLive();
}
}
public CacheEntry(Object key, Object value) {
this.key = key;
this.value = value;
this.createTime = System.currentTimeMillis();
this.lastAccessTime = Long.valueOf(createTime);
}
/**
* Return the name of the cache.
*/
public String getName() {
return name;
}
public Object getKey() {
return key;
}
/**
* Clear the cache.
*/
@Override
public void clear() {
clearCount.increment();
map.clear();
}
public Object getValue() {
// object assignment is atomic
hitCount.incrementAndGet();
this.lastAccessTime = Long.valueOf(System.currentTimeMillis());
return value;
}
/**
* Return a value from the cache.
*/
@Override
public Object get(Object key) {
public long getCreateTime() {
return createTime;
}
CacheEntry entry = map.get(key);
if (entry == null) {
missCount.increment();
return null;
public long getLastAccessTime() {
return lastAccessTime.longValue();
}
} else {
// Important that hitCount.increment() MUST be low latency under concurrent
// use hence must use LongAdder or better here
hitCount.increment();
return entry.getValue();
}
}
public Long getLastAccessLong() {
return lastAccessTime;
}
/**
* Put a value into the cache.
*/
@Override
public Object put(Object key, Object value) {
CacheEntry entry = map.put(key, new CacheEntry(key, value));
if (entry == null) {
insertCount.increment();
return null;
} else {
updateCount.increment();
return entry.getValue();
}
}
public int getHitCount(boolean reset) {
if (reset){
return hitCount.getAndSet(0);
/**
* Remove an entry from the cache.
*/
@Override
public Object remove(Object key) {
CacheEntry entry = map.remove(key);
if (entry == null) {
return null;
} else {
removeCount.increment();
return entry.getValue();
}
}
/**
* Return the number of elements in the cache.
*/
@Override
public int size() {
return map.size();
}
/**
* Return the size to trim to based on the max size.
* <p>
* This returns 90% of the max size.
* </p>
*/
protected int getTrimSize() {
return (maxSize * 90 / 100);
}
/**
* Run the eviction based on Idle time, Time to live and LRU last access.
*/
public void runEviction() {
long trimForMaxSize;
if (maxSize == 0) {
trimForMaxSize = 0;
} else {
trimForMaxSize = size() - maxSize;
}
if (maxIdleSecs == 0 && maxSecsToLive == 0 && trimForMaxSize < 0) {
// nothing to trim on this cache
return;
}
long startNanos = System.nanoTime();
long trimmedByIdle = 0;
long trimmedByTTL = 0;
long trimmedByLRU = 0;
ArrayList<CacheEntry> activeList = new ArrayList<CacheEntry>();
long idleExpire = System.currentTimeMillis() - (maxIdleSecs * 1000);
long ttlExpire = System.currentTimeMillis() - (maxSecsToLive * 1000);
Iterator<CacheEntry> it = map.values().iterator();
while (it.hasNext()) {
CacheEntry cacheEntry = it.next();
if (maxIdleSecs > 0 && idleExpire > cacheEntry.getLastAccessTime()) {
it.remove();
trimmedByIdle++;
} else if (maxSecsToLive > 0 && ttlExpire > cacheEntry.getCreateTime()) {
it.remove();
trimmedByTTL++;
} else if (trimForMaxSize > 0) {
activeList.add(cacheEntry);
}
}
if (trimForMaxSize > 0) {
trimmedByLRU = activeList.size() - maxSize;
if (trimmedByLRU > 0) {
// sort into last access time ascending
Collections.sort(activeList, BY_LAST_ACCESS);
int trimSize = getTrimSize();
for (int i = trimSize; i < activeList.size(); i++) {
// remove if still in the cache
map.remove(activeList.get(i).getKey());
}
}
}
long exeNanos = System.nanoTime() - startNanos;
long exeMicros = TimeUnit.MICROSECONDS.convert(exeNanos, TimeUnit.NANOSECONDS);
// increment the eviction statistics
evictMicros.add(exeMicros);
evictCount.increment();
evictByIdle.add(trimmedByIdle);
evictByTTL.add(trimmedByTTL);
evictByLRU.add(trimmedByLRU);
if (logger.isDebugEnabled()) {
logger.debug("Executed trim of cache {} in [{}]millis idle[{}] timeToLive[{}] accessTime[{}]"
, name, exeMicros, trimmedByIdle, trimmedByTTL, trimmedByLRU);
}
}
/**
* Runnable that calls the eviction routine.
*/
public class EvictionRunnable implements Runnable {
@Override
public void run() {
runEviction();
}
}
/**
* Comparator for sorting by last access time.
*/
public static class CompareByLastAccess implements Comparator<CacheEntry>, Serializable {
private static final long serialVersionUID = 1L;
public int compare(CacheEntry entry1, CacheEntry entry2) {
return Long.compare(entry1.getLastAccessTime(), entry2.getLastAccessTime());
}
}
/**
* Wraps the value to additionally hold createTime and lastAccessTime and hit counter.
*/
public static class CacheEntry {
private final Object key;
private final Object value;
private final long createTime;
private long lastAccessTime;
public CacheEntry(Object key, Object value) {
this.key = key;
this.value = value;
this.createTime = System.currentTimeMillis();
this.lastAccessTime = createTime;
}
/**
* Return the entry key.
*/
public Object getKey() {
return key;
}
/**
* Return the entry value.
*/
public Object getValue() {
// long assignment should be atomic these days (Ref Cliff Click)
lastAccessTime = System.currentTimeMillis();
return value;
}
/**
* Return the time the entry was created.
*/
public long getCreateTime() {
return createTime;
}
/**
* Return the time the entry was last accessed.
*/
public long getLastAccessTime() {
return lastAccessTime;
}
}
} else {
return hitCount.get();
}
}
public int getHitCount() {
return hitCount.get();
}
}
}
@@ -9,18 +9,13 @@ import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.Table;
import com.avaje.ebean.event.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.avaje.ebean.config.CompoundType;
import com.avaje.ebean.config.ScalarTypeConverter;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.event.BeanFinder;
import com.avaje.ebean.event.BeanPersistController;
import com.avaje.ebean.event.BeanPersistListener;
import com.avaje.ebean.event.BeanQueryAdapter;
import com.avaje.ebean.event.ServerConfigStartup;
import com.avaje.ebean.event.TransactionEventListener;
import com.avaje.ebeaninternal.server.type.ScalarType;
import com.avaje.ebeaninternal.server.util.ClassPathSearchMatcher;
@@ -46,16 +41,15 @@ public class BootupClasses implements ClassPathSearchMatcher {
private ArrayList<Class<?>> transactionEventListenerList = new ArrayList<Class<?>>();
private ArrayList<Class<?>> beanFinderList = new ArrayList<Class<?>>();
private ArrayList<Class<?>> beanListenerList = new ArrayList<Class<?>>();
private ArrayList<Class<?>> beanFindControllerList = new ArrayList<Class<?>>();
private ArrayList<Class<?>> beanQueryAdapterList = new ArrayList<Class<?>>();
private ArrayList<Class<?>> beanListenerList = new ArrayList<Class<?>>();
private ArrayList<Class<?>> serverConfigStartupList = new ArrayList<Class<?>>();
private ArrayList<ServerConfigStartup> serverConfigStartupInstances = new ArrayList<ServerConfigStartup>();
private List<BeanFindController> findControllerInstances = new ArrayList<BeanFindController>();
private List<BeanPersistController> persistControllerInstances = new ArrayList<BeanPersistController>();
private List<BeanPersistListener> persistListenerInstances = new ArrayList<BeanPersistListener>();
private List<BeanQueryAdapter> queryAdapterInstances = new ArrayList<BeanQueryAdapter>();
@@ -112,6 +106,19 @@ public class BootupClasses implements ClassPathSearchMatcher {
}
}
/**
* Add BeanFindController instances.
*/
public void addFindControllers(List<BeanFindController> findControllers) {
if (findControllers != null) {
for (BeanFindController c : findControllers) {
this.findControllerInstances.add(c);
// don't automatically instantiate
this.beanFindControllerList.remove(c.getClass());
}
}
}
/**
* Add TransactionEventListeners instances.
*/
@@ -161,6 +168,22 @@ public class BootupClasses implements ClassPathSearchMatcher {
return queryAdapterInstances;
}
public List<BeanFindController> getBeanFindControllers() {
// add class registered BeanFindController to the
// list of created instances
for (Class<?> cls : beanFindControllerList) {
try {
BeanFindController newInstance = (BeanFindController) cls.newInstance();
findControllerInstances.add(newInstance);
} catch (Exception e) {
String msg = "Error creating BeanPersistController " + cls;
logger.error(msg, e);
}
}
return findControllerInstances;
}
public List<BeanPersistListener> getBeanPersistListeners() {
// add class registered BeanPersistController to the
// already created instances
@@ -212,63 +235,56 @@ public class BootupClasses implements ClassPathSearchMatcher {
/**
* Return the list of Embeddable classes.
*/
public ArrayList<Class<?>> getEmbeddables() {
public List<Class<?>> getEmbeddables() {
return embeddableList;
}
/**
* Return the list of entity classes.
*/
public ArrayList<Class<?>> getEntities() {
public List<Class<?>> getEntities() {
return entityList;
}
/**
* Return the list of ScalarTypes found.
*/
public ArrayList<Class<?>> getScalarTypes() {
public List<Class<?>> getScalarTypes() {
return scalarTypeList;
}
/**
* Return the list of ScalarConverters found.
*/
public ArrayList<Class<?>> getScalarConverters() {
public List<Class<?>> getScalarConverters() {
return scalarConverterList;
}
/**
* Return the list of ScalarConverters found.
*/
public ArrayList<Class<?>> getCompoundTypes() {
public List<Class<?>> getCompoundTypes() {
return compoundTypeList;
}
/**
* Return the list of BeanControllers found.
*/
public ArrayList<Class<?>> getBeanControllers() {
public List<Class<?>> getBeanControllers() {
return beanControllerList;
}
/**
* Return the list of TransactionEventListeners found
*/
public ArrayList<Class<?>> getTransactionEventListenerList() {
public List<Class<?>> getTransactionEventListenerList() {
return transactionEventListenerList;
}
/**
* Return the list of BeanFinders found.
*/
public ArrayList<Class<?>> getBeanFinders() {
return beanFinderList;
}
/**
* Return the list of BeanListeners found.
*/
public ArrayList<Class<?>> getBeanListeners() {
public List<Class<?>> getBeanListeners() {
return beanListenerList;
}
@@ -327,8 +343,8 @@ public class BootupClasses implements ClassPathSearchMatcher {
interesting = true;
}
if (BeanFinder.class.isAssignableFrom(cls)) {
beanFinderList.add(cls);
if (BeanFindController.class.isAssignableFrom(cls)) {
beanFindControllerList.add(cls);
interesting = true;
}
@@ -80,7 +80,9 @@ public class DatabasePlatformFactory {
if (dbName.equals("mysql")) {
return new MySqlPlatform();
}
if (dbName.equals("h2")) {
return new H2Platform();
}
if (dbName.equals("sqlite")) {
return new SQLitePlatform();
}
@@ -5,6 +5,7 @@ import java.util.List;
import javax.persistence.EntityNotFoundException;
import com.avaje.ebeaninternal.api.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -15,11 +16,6 @@ import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.bean.EntityBeanIntercept;
import com.avaje.ebean.bean.ObjectGraphNode;
import com.avaje.ebean.bean.PersistenceContext;
import com.avaje.ebeaninternal.api.LoadBeanBuffer;
import com.avaje.ebeaninternal.api.LoadBeanRequest;
import com.avaje.ebeaninternal.api.LoadManyRequest;
import com.avaje.ebeaninternal.api.LoadManyBuffer;
import com.avaje.ebeaninternal.api.SpiQuery;
import com.avaje.ebeaninternal.api.SpiQuery.Mode;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
@@ -36,8 +32,11 @@ public class DefaultBeanLoader {
private final DefaultServer server;
private final boolean onIterateUseExtraTxn;
protected DefaultBeanLoader(DefaultServer server) {
this.server = server;
this.onIterateUseExtraTxn = server.getDatabasePlatform().useExtraTransactionOnIterateSecondaryQueries();
}
/**
@@ -122,7 +121,7 @@ public class DefaultBeanLoader {
query.where().raw(ew);
}
query.setLazyLoadForParents(idList, many);
query.setLazyLoadForParents(many);
many.addWhereParentIdIn(query, idList);
query.setPersistenceContext(pc);
@@ -143,7 +142,17 @@ public class DefaultBeanLoader {
query.select(many.getTargetIdProperty());
}
server.findList(query, loadRequest.getTransaction());
if (onIterateUseExtraTxn && loadRequest.isParentFindIterate()) {
// MySql - we need a different transaction to execute the secondary query
SpiTransaction extraTxn = server.createQueryTransaction();
try {
server.findList(query, extraTxn);
} finally {
extraTxn.end();
}
} else {
server.findList(query, loadRequest.getTransaction());
}
// check for BeanCollection's that where never processed
// in the +query or +lazy load due to no rows (predicates)
@@ -332,7 +341,18 @@ public class DefaultBeanLoader {
query.where().idIn(idList);
}
List<?> list = server.findList(query, loadRequest.getTransaction());
List<?> list;
if (onIterateUseExtraTxn && loadRequest.isParentFindIterate()) {
// MySql - we need a different transaction to execute the secondary query
SpiTransaction extraTxn = server.createQueryTransaction();
try {
list = server.findList(query, extraTxn);
} finally {
extraTxn.end();
}
} else {
list = server.findList(query, loadRequest.getTransaction());
}
if (loadRequest.isLoadCache()) {
for (int i = 0; i < list.size(); i++) {
@@ -219,7 +219,16 @@ public class DefaultContainer implements SpiContainer {
ServerCacheFactory cacheFactory = serverConfig.getServerCacheFactory();
if (cacheFactory == null) {
cacheFactory = new DefaultServerCacheFactory();
ServiceLoader<ServerCacheFactory> cacheFactories = ServiceLoader.load(ServerCacheFactory.class);
Iterator<ServerCacheFactory> iterator = cacheFactories.iterator();
if (iterator.hasNext()) {
// use the cacheFactory (via classpath service loader)
cacheFactory = iterator.next();
logger.debug("using ServerCacheFactory {}", cacheFactory.getClass());
} else {
// use the built in default
cacheFactory = new DefaultServerCacheFactory();
}
}
return new DefaultServerCacheManager(cacheFactory, beanOptions, queryOptions);
@@ -233,6 +242,7 @@ public class DefaultContainer implements SpiContainer {
BootupClasses bootupClasses = getBootupClasses1(serverConfig);
bootupClasses.addPersistControllers(serverConfig.getPersistControllers());
bootupClasses.addFindControllers(serverConfig.getFindControllers());
bootupClasses.addTransactionEventListeners(serverConfig.getTransactionEventListeners());
bootupClasses.addPersistListeners(serverConfig.getPersistListeners());
bootupClasses.addQueryAdapters(serverConfig.getQueryAdapters());
@@ -300,8 +310,7 @@ public class DefaultContainer implements SpiContainer {
if (config.getDataSourceJndiName() != null) {
ds = jndiDataSourceFactory.lookup(config.getDataSourceJndiName());
if (ds == null) {
String m = "JNDI lookup for DataSource " + config.getDataSourceJndiName() + " returned null.";
throw new PersistenceException(m);
throw new PersistenceException("JNDI lookup for DataSource " + config.getDataSourceJndiName() + " returned null.");
} else {
return ds;
}
@@ -309,14 +318,13 @@ public class DefaultContainer implements SpiContainer {
DataSourceConfig dsConfig = config.getDataSourceConfig();
if (dsConfig == null) {
String m = "No DataSourceConfig definded for " + config.getName();
String m = "No DataSourceConfig defined for " + config.getName();
throw new PersistenceException(m);
}
if (dsConfig.isOffline()) {
if (config.getDatabasePlatformName() == null) {
String m = "You MUST specify a DatabasePlatformName on ServerConfig when offline";
throw new PersistenceException(m);
throw new PersistenceException("You MUST specify a DatabasePlatformName on ServerConfig when offline");
}
return null;
}
@@ -38,6 +38,7 @@ import org.slf4j.LoggerFactory;
import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@@ -198,19 +199,20 @@ public final class DefaultServer implements SpiEbeanServer {
this.beanLoader = new DefaultBeanLoader(this);
this.jsonContext = config.createJsonContext(this);
loadAndInitializePlugins(config);
// load normal plugins late and call setup on all
loadAndInitializePlugins(config.getServerConfig());
// Register with the JVM Shutdown hook
ShutdownManager.registerEbeanServer(this);
}
protected void loadAndInitializePlugins(InternalConfiguration config) {
protected void loadAndInitializePlugins(ServerConfig config) {
List<SpiEbeanPlugin> spiPlugins = new ArrayList<SpiEbeanPlugin>();
for (SpiEbeanPlugin plugin : ServiceLoader.load(SpiEbeanPlugin.class)) {
spiPlugins.add(plugin);
plugin.setup(this, this.getDatabasePlatform(), config.getServerConfig());
plugin.setup(this, this.getDatabasePlatform(), config);
if (plugin instanceof DdlGenerator) {
// backwards compatible
@@ -222,18 +224,24 @@ public final class DefaultServer implements SpiEbeanServer {
// ServiceLoader not finding ddlGenerator (typically OSGi)
ddlGenerator = new DdlGenerator();
spiPlugins.add(ddlGenerator);
ddlGenerator.setup(this, this.getDatabasePlatform(), config.getServerConfig());
ddlGenerator.setup(this, this.getDatabasePlatform(), config);
}
ebeanPlugins = Collections.unmodifiableList(spiPlugins);
}
/**
* Return the list of registered plugins.
*/
public List<SpiEbeanPlugin> getSpiEbeanPlugins() {
return ebeanPlugins;
}
/**
* Execute all the plugins with an online flag indicating the DB is up or not.
*/
public void executePlugins(boolean online) {
for(SpiEbeanPlugin plugin : ebeanPlugins) {
for (SpiEbeanPlugin plugin : ebeanPlugins) {
plugin.execute(online);
}
}
@@ -756,16 +764,16 @@ public final class DefaultServer implements SpiEbeanServer {
}
/**
* Start a transaction.
* Start a transaction with 'REQUIRED' semantics.
* <p>
* If a transaction already exists that transaction will be used.
* </p>
* <p>
* Note that the transaction is stored in a ThreadLocal variable.
* </p>
*/
public Transaction beginTransaction() {
// start an explicit transaction
SpiTransaction t = transactionManager.createTransaction(true, -1);
transactionScopeManager.set(t);
return t;
return beginTransaction(TxScope.required());
}
public Transaction beginTransaction(TxScope scope) {
@@ -1155,16 +1163,15 @@ public final class DefaultServer implements SpiEbeanServer {
public <T> T findUnique(Query<T> query, Transaction t) {
// actually a find by Id type of query...
// ... perhaps with joins and cache hints?
SpiQuery<T> q = (SpiQuery<T>) query;
Object id = q.getId();
// ... perhaps with joins and cache hints
Object id = query.getId();
if (id != null) {
return findId(query, t);
}
BeanDescriptor<T> desc = beanDescriptorManager.getBeanDescriptor(q.getBeanType());
BeanDescriptor<T> desc = beanDescriptorManager.getBeanDescriptor(query.getBeanType());
T bean = desc.cacheNaturalKeyLookup(q, (SpiTransaction)t);
T bean = desc.cacheNaturalKeyLookup((SpiQuery<T>)query, (SpiTransaction) t);
if (bean != null) {
return bean;
}
@@ -1316,18 +1323,9 @@ public final class DefaultServer implements SpiEbeanServer {
return new LimitOffsetPagedList<T>(this, (SpiQuery<T>)query, pageIndex, pageSize);
}
public <T> void findVisit(Query<T> query, QueryResultVisitor<T> visitor, Transaction t) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.LIST, query, t);
request.initTransIfRequired();
request.findVisit(visitor);
// no try finally - findVisit guarantee's cleanup of the transaction if required
}
public <T> void findEach(Query<T> query, QueryEachConsumer<T> consumer, Transaction t) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.LIST, query, t);
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
request.initTransIfRequired();
request.findEach(consumer);
@@ -1336,7 +1334,7 @@ public final class DefaultServer implements SpiEbeanServer {
public <T> void findEachWhile(Query<T> query, QueryEachWhileConsumer<T> consumer, Transaction t) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.LIST, query, t);
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
request.initTransIfRequired();
request.findEachWhile(consumer);
@@ -1345,7 +1343,7 @@ public final class DefaultServer implements SpiEbeanServer {
public <T> QueryIterator<T> findIterate(Query<T> query, Transaction t) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.LIST, query, t);
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
try {
request.initTransIfRequired();
@@ -1492,17 +1490,15 @@ public final class DefaultServer implements SpiEbeanServer {
persister.update(checkEntityBean(bean), t, deleteMissingChildren);
}
/**
* Update all beans in the collection.
*/
public void update(Collection<?> beans) {
update(beans, null);
@Override
public void updateAll(Collection<?> beans) throws OptimisticLockException {
updateAll(beans, null);
}
/**
* Update all beans in the collection with an explicit transaction.
*/
public void update(Collection<?> beans, Transaction t) {
public void updateAll(Collection<?> beans, Transaction t) {
if (beans == null || beans.isEmpty()) {
// Nothing to update?
@@ -1540,14 +1536,14 @@ public final class DefaultServer implements SpiEbeanServer {
/**
* Insert all beans in the collection.
*/
public void insert(Collection<?> beans) {
insert(beans, null);
public void insertAll(Collection<?> beans) {
insertAll(beans, null);
}
/**
* Insert all beans in the collection with a transaction.
*/
public void insert(Collection<?> beans, Transaction t) {
public void insertAll(Collection<?> beans, Transaction t) {
if (beans == null || beans.isEmpty()) {
// Nothing to insert?
@@ -1662,34 +1658,20 @@ public final class DefaultServer implements SpiEbeanServer {
}
}
/**
* Perform an update or insert on each bean in the iterator. Returns the
* number of beans that where saved.
*/
public int save(Iterator<?> it) {
return save(it, null);
@Override
public int saveAll(Collection<?> beans, Transaction transaction) throws OptimisticLockException {
return saveAllInternal(beans.iterator(), transaction);
}
/**
* Perform an update or insert on each bean in the collection. Returns the
* number of beans that where saved.
*/
public int save(Collection<?> c) {
return save(c.iterator(), null);
@Override
public int saveAll(Collection<?> beans) throws OptimisticLockException {
return saveAllInternal(beans.iterator(), null);
}
/**
* Perform an update or insert on each bean in the collection. Returns the
* number of beans that where saved.
*/
public int save(Collection<?> c, Transaction t) {
return save(c.iterator(), t);
}
/**
* Save all beans in the iterator with an explicit transaction.
*/
public int save(Iterator<?> it, Transaction t) {
public int saveAllInternal(Iterator<?> it, Transaction t) {
TransWrapper wrap = initTransIfRequired(t);
try {
@@ -1732,11 +1714,13 @@ public final class DefaultServer implements SpiEbeanServer {
}
}
public void delete(Class<?> beanType, Collection<?> ids) {
delete(beanType, ids, null);
@Override
public void deleteAll(Class<?> beanType, Collection<?> ids) {
deleteAll(beanType, ids, null);
}
public void delete(Class<?> beanType, Collection<?> ids, Transaction t) {
@Override
public void deleteAll(Class<?> beanType, Collection<?> ids, Transaction t) {
TransWrapper wrap = initTransIfRequired(t);
try {
@@ -1765,24 +1749,18 @@ public final class DefaultServer implements SpiEbeanServer {
persister.delete(checkEntityBean(bean), t);
}
/**
* Delete all the beans in the iterator.
*/
public int delete(Iterator<?> it) {
return delete(it, null);
}
/**
* Delete all the beans in the collection.
*/
public int delete(Collection<?> c) {
return delete(c.iterator(), null);
@Override
public int deleteAll(Collection<?> beans) {
return deleteAllInternal(beans.iterator(), null);
}
/**
* Delete all the beans in the iterator with an explicit transaction.
*/
public int delete(Iterator<?> it, Transaction t) {
private int deleteAllInternal(Iterator<?> it, Transaction t) {
TransWrapper wrap = initTransIfRequired(t);
@@ -1995,12 +1973,6 @@ public final class DefaultServer implements SpiEbeanServer {
// immutable thread safe so return shared instance
return jsonContext;
}
@Override
public JsonContext createJsonContext() {
return json();
}
@Override
public void collectQueryStats(ObjectGraphNode node, long loadedBeanCount, long timeMicros) {
@@ -182,7 +182,7 @@ public class InternalConfiguration {
}
public OrmQueryEngine createOrmQueryEngine() {
return new DefaultOrmQueryEngine(beanDescriptorManager, cQueryEngine);
return new DefaultOrmQueryEngine(cQueryEngine);
}
public Persister createPersister(SpiEbeanServer server) {
@@ -11,34 +11,27 @@ import javax.sql.DataSource;
*/
public class JndiDataSourceLookup {
private static final String DEFAULT_PREFIX = "java:comp/env/jdbc/";
public JndiDataSourceLookup() {
}
public JndiDataSourceLookup() {
}
/**
* Return the DataSource by JNDI lookup.
* <p>
* If name is null the 'default' dataSource is returned.
* </p>
*/
public DataSource lookup(String jndiName) {
/**
* Return the DataSource by JNDI lookup.
* <p>
* If name is null the 'default' dataSource is returned.
* </p>
*/
public DataSource lookup(String jndiName) {
try {
if (!jndiName.startsWith("java:")){
jndiName = DEFAULT_PREFIX + jndiName;
}
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup(jndiName);
if (ds == null) {
throw new PersistenceException("JNDI DataSource [" + jndiName + "] not found?");
}
return ds;
try {
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup(jndiName);
if (ds == null) {
throw new PersistenceException("JNDI DataSource [" + jndiName + "] not found?");
}
return ds;
} catch (NamingException ex) {
throw new PersistenceException(ex);
}
}
} catch (NamingException ex) {
throw new PersistenceException(ex);
}
}
}
@@ -9,7 +9,7 @@ import javax.persistence.PersistenceException;
import com.avaje.ebean.*;
import com.avaje.ebean.bean.BeanCollection;
import com.avaje.ebean.bean.PersistenceContext;
import com.avaje.ebean.event.BeanFinder;
import com.avaje.ebean.event.BeanFindController;
import com.avaje.ebean.event.BeanQueryRequest;
import com.avaje.ebeaninternal.api.BeanIdList;
import com.avaje.ebeaninternal.api.HashQuery;
@@ -40,7 +40,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
private final SpiQuery<T> query;
private final BeanFinder<T> finder;
private final BeanFindController finder;
private final Boolean readOnly;
@@ -259,19 +259,6 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
}
}
public void findVisit(QueryResultVisitor<T> visitor) {
QueryIterator<T> it = queryEngine.findIterate(this);
try {
while (it.hasNext()) {
if (!visitor.accept(it.next())) {
break;
}
}
} finally {
it.close();
}
}
public QueryIterator<T> findIterate() {
return queryEngine.findIterate(this);
}
@@ -315,7 +302,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
/**
* Return a bean specific finder if one has been set.
*/
public BeanFinder<T> getBeanFinder() {
public BeanFindController getBeanFinder() {
return finder;
}
@@ -1,115 +1,104 @@
package com.avaje.ebeaninternal.server.core;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.avaje.ebean.QueryEachConsumer;
import com.avaje.ebean.QueryEachWhileConsumer;
import com.avaje.ebean.QueryIterator;
import com.avaje.ebean.QueryResultVisitor;
import com.avaje.ebean.bean.BeanCollection;
import com.avaje.ebeaninternal.api.SpiQuery;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Defines the ORM query request api.
*/
public interface SpiOrmQueryRequest<T> {
/**
* Return the query.
*/
public SpiQuery<T> getQuery();
/**
* Return the query.
*/
SpiQuery<T> getQuery();
/**
* Return the associated BeanDescriptor.
*/
public BeanDescriptor<?> getBeanDescriptor();
/**
* Return the associated BeanDescriptor.
*/
BeanDescriptor<?> getBeanDescriptor();
/**
* This will create a local (readOnly) transaction if no current transaction
* exists.
* <p>
* A transaction may have been passed in explicitly or currently be active
* in the thread local. If not, then a readOnly transaction is created to
* execute this query.
* </p>
*/
public void initTransIfRequired();
/**
* This will create a local (readOnly) transaction if no current transaction
* exists.
* <p>
* A transaction may have been passed in explicitly or currently be active
* in the thread local. If not, then a readOnly transaction is created to
* execute this query.
* </p>
*/
void initTransIfRequired();
/**
* Will end a locally created transaction.
* <p>
* It ends the transaction by using a rollback() as the transaction is known
* to be readOnly.
* </p>
*/
public void endTransIfRequired();
/**
* Will end a locally created transaction.
* <p>
* It ends the transaction by using a rollback() as the transaction is known
* to be readOnly.
* </p>
*/
void endTransIfRequired();
/**
* Execute the query as findById.
*/
public Object findId();
/**
* Execute the query as findById.
*/
Object findId();
/**
* Execute the find row count query.
*/
public int findRowCount();
/**
* Execute the find row count query.
*/
int findRowCount();
/**
* Execute the find ids query.
*/
public List<Object> findIds();
/**
* Execute the find returning a QueryIterator and visitor pattern.
*/
public void findVisit(QueryResultVisitor<T> visitor);
/**
* Execute the find ids query.
*/
List<Object> findIds();
/**
* Execute the find returning a QueryIterator and visitor pattern.
*/
public void findEach(QueryEachConsumer<T> consumer);
void findEach(QueryEachConsumer<T> consumer);
/**
* Execute the find returning a QueryIterator and visitor pattern.
*/
public void findEachWhile(QueryEachWhileConsumer<T> consumer);
void findEachWhile(QueryEachWhileConsumer<T> consumer);
/**
* Execute the find returning a QueryIterator.
*/
public QueryIterator<T> findIterate();
/**
* Execute the query as findList.
*/
public List<T> findList();
* Execute the find returning a QueryIterator.
*/
QueryIterator<T> findIterate();
/**
* Execute the query as findSet.
*/
public Set<?> findSet();
/**
* Execute the query as findList.
*/
List<T> findList();
/**
* Execute the query as findMap.
*/
public Map<?, ?> findMap();
/**
* Execute the query as findSet.
*/
Set<?> findSet();
/**
* Try to get the object out of the persistence context.
*/
//public T getFromPersistenceContextOrCache();
/**
* Execute the query as findMap.
*/
Map<?, ?> findMap();
/**
* Try to get the query result from the query cache.
*/
public BeanCollection<T> getFromQueryCache();
/**
* Try to get the query result from the query cache.
*/
BeanCollection<T> getFromQueryCache();
/**
* Return the Database platform like clause.
*/
public String getDBLikeClause();
/**
* Return the Database platform like clause.
*/
String getDBLikeClause();
}
@@ -10,16 +10,12 @@ import com.avaje.ebean.bean.PersistenceContext;
import com.avaje.ebean.config.EncryptKey;
import com.avaje.ebean.config.dbplatform.IdGenerator;
import com.avaje.ebean.config.dbplatform.IdType;
import com.avaje.ebean.event.BeanFinder;
import com.avaje.ebean.event.BeanPersistController;
import com.avaje.ebean.event.BeanPersistListener;
import com.avaje.ebean.event.BeanQueryAdapter;
import com.avaje.ebean.event.*;
import com.avaje.ebean.meta.MetaBeanInfo;
import com.avaje.ebean.meta.MetaQueryPlanStatistic;
import com.avaje.ebeaninternal.api.*;
import com.avaje.ebeaninternal.api.TransactionEventTable.TableIUD;
import com.avaje.ebeaninternal.server.cache.CachedBeanData;
import com.avaje.ebeaninternal.server.cache.CachedManyIds;
import com.avaje.ebeaninternal.server.core.CacheOptions;
import com.avaje.ebeaninternal.server.core.DefaultSqlUpdate;
import com.avaje.ebeaninternal.server.core.InternString;
@@ -28,17 +24,18 @@ import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyLists;
import com.avaje.ebeaninternal.server.el.*;
import com.avaje.ebeaninternal.server.persist.DmlUtil;
import com.avaje.ebeaninternal.server.query.CQueryPlan;
import com.avaje.ebeaninternal.server.query.CQueryPlanStats.Snapshot;
import com.avaje.ebeaninternal.server.query.SplitName;
import com.avaje.ebeaninternal.server.querydefn.OrmQueryDetail;
import com.avaje.ebeaninternal.server.text.json.ReadJson;
import com.avaje.ebeaninternal.server.text.json.WriteJson;
import com.avaje.ebeaninternal.server.type.DataBind;
import com.avaje.ebeaninternal.server.type.TypeManager;
import com.avaje.ebeaninternal.util.SortByClause;
import com.avaje.ebeaninternal.util.SortByClause.Property;
import com.avaje.ebeaninternal.util.SortByClauseParser;
import com.fasterxml.jackson.core.JsonParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -153,7 +150,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
/**
* If set overrides the find implementation. Server side only.
*/
private final BeanFinder<T> beanFinder;
private final BeanFindController beanFinder;
/**
* The table joins for this bean.
@@ -634,7 +631,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
}
public boolean calculateUseCache(Boolean queryUseCache) {
return (queryUseCache != null) ? queryUseCache.booleanValue() : isBeanCaching();
return (queryUseCache != null) ? queryUseCache : isBeanCaching();
}
/**
@@ -1514,7 +1511,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
/**
* Return the beanFinder. Usually null unless overriding the finder.
*/
public BeanFinder<T> getBeanFinder() {
public BeanFindController getBeanFinder() {
return beanFinder;
}
@@ -1525,17 +1522,35 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
return queryAdapter;
}
/**
* De-register the BeanPersistListener.
*/
public void deregister(BeanPersistListener listener) {
// volatile read...
BeanPersistListener currentListener = persistListener;
if (currentListener != null) {
if (currentListener instanceof ChainedBeanPersistListener) {
// remove it from the existing chain
persistListener = ((ChainedBeanPersistListener) currentListener).deregister(listener);
} else if (currentListener.equals(listener)) {
persistListener = null;
}
}
}
/**
* De-register the BeanPersistController.
*/
public void deregister(BeanPersistController controller) {
// volatile read...
BeanPersistController c = persistController;
if (c != null) {
if (c instanceof ChainedBeanPersistController) {
BeanPersistController currentController = persistController;
if (currentController != null) {
if (currentController instanceof ChainedBeanPersistController) {
// remove it from the existing chain
persistController = ((ChainedBeanPersistController) c).deregister(controller);
} else if (c.equals(controller)) {
persistController = ((ChainedBeanPersistController) currentController).deregister(controller);
} else if (currentController.equals(controller)) {
persistController = null;
}
}
@@ -1549,16 +1564,16 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
if (newPersistListener.isRegisterFor(beanType)) {
// volatile read...
BeanPersistListener currListener = persistListener;
if (currListener == null) {
BeanPersistListener currentListener = persistListener;
if (currentListener == null) {
persistListener = newPersistListener;
} else {
if (currListener instanceof ChainedBeanPersistListener) {
if (currentListener instanceof ChainedBeanPersistListener) {
// add it to the existing chain
persistListener = ((ChainedBeanPersistListener) currListener).register(newPersistListener);
persistListener = ((ChainedBeanPersistListener) currentListener).register(newPersistListener);
} else {
// build new chain of the 2
persistListener = new ChainedBeanPersistListener(currListener, newPersistListener);
persistListener = new ChainedBeanPersistListener(currentListener, newPersistListener);
}
}
}
@@ -1571,16 +1586,16 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
if (newController.isRegisterFor(beanType)) {
// volatile read...
BeanPersistController c = persistController;
if (c == null) {
BeanPersistController currentController = persistController;
if (currentController == null) {
persistController = newController;
} else {
if (c instanceof ChainedBeanPersistController) {
if (currentController instanceof ChainedBeanPersistController) {
// add it to the existing chain
persistController = ((ChainedBeanPersistController) c).register(newController);
persistController = ((ChainedBeanPersistController) currentController).register(newController);
} else {
// build new chain of the 2
persistController = new ChainedBeanPersistController(c, newController);
persistController = new ChainedBeanPersistController(currentController, newController);
}
}
}
@@ -1714,7 +1729,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
// not using Id generator so just base on isLoaded()
return !ebi.isLoaded();
}
if (!hasIdProperty(ebi)) {
if (!hasIdValue(ebi.getOwner())) {
// No Id property means it must be an insert
return true;
}
@@ -1729,9 +1744,9 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
public boolean hasIdPropertyOnly(EntityBeanIntercept ebi) {
return ebi.hasIdOnly(idPropertyIndex);
}
public boolean hasIdProperty(EntityBeanIntercept ebi) {
return idPropertyIndex > -1 && ebi.isLoadedProperty(idPropertyIndex);
public boolean hasIdValue(EntityBean bean) {
return (idProperty != null && !DmlUtil.isNullOrZero(idProperty.getValue(bean)));
}
public boolean hasVersionProperty(EntityBeanIntercept ebi) {
@@ -1893,11 +1908,11 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
jsonHelp.jsonWriteProperties(writeJson, bean);
}
public T jsonRead(JsonParser parser, String path) throws IOException {
return jsonHelp.jsonRead(parser, path);
public T jsonRead(ReadJson jsonRead, String path) throws IOException {
return jsonHelp.jsonRead(jsonRead, path);
}
protected T jsonReadObject(JsonParser parser, String path) throws IOException {
return jsonHelp.jsonReadObject(parser, path);
protected T jsonReadObject(ReadJson jsonRead, String path) throws IOException {
return jsonHelp.jsonReadObject(jsonRead, path);
}
}
@@ -303,7 +303,7 @@ public final class BeanDescriptorCacheHelp<T> {
// try looking up into the bean cache using the id
T cacheBean = beanCacheGetInternal(id, query.isReadOnly());
if (cacheBean != null) {
setupContext(cacheBean, query, getPersistenceContext(t));
setupContext(cacheBean, getPersistenceContext(t));
}
return cacheBean;
}
@@ -320,7 +320,7 @@ public final class BeanDescriptorCacheHelp<T> {
}
private boolean isNaturalKeyCaching(Boolean queryUseCache) {
return naturalKeyCache != null && (queryUseCache == null || queryUseCache.booleanValue());
return naturalKeyCache != null && (queryUseCache == null || queryUseCache);
}
private boolean isNaturalKey(String propName) {
@@ -332,7 +332,7 @@ public final class BeanDescriptorCacheHelp<T> {
/**
* For a bean built from the cache this sets up its persistence context for future lazy loading etc.
*/
private void setupContext(Object bean, SpiQuery<T> query, PersistenceContext context) {
private void setupContext(Object bean, PersistenceContext context) {
if (context == null) {
context = new DefaultPersistenceContext();
}
@@ -408,7 +408,7 @@ public final class BeanDescriptorCacheHelp<T> {
public T beanCacheGet(SpiQuery<T> query, PersistenceContext context) {
T bean = beanCacheGetInternal(query.getId(), query.isReadOnly());
if (bean != null) {
setupContext(bean, query, context);
setupContext(bean, context);
}
return bean;
}
@@ -2,6 +2,7 @@ package com.avaje.ebeaninternal.server.deploy;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.text.json.EJson;
import com.avaje.ebeaninternal.server.text.json.ReadJson;
import com.avaje.ebeaninternal.server.text.json.WriteJson;
import com.avaje.ebeaninternal.server.text.json.WriteJson.WriteBean;
import com.fasterxml.jackson.core.JsonParseException;
@@ -9,6 +10,8 @@ import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
public class BeanDescriptorJsonHelp<T> {
@@ -50,8 +53,9 @@ public class BeanDescriptorJsonHelp<T> {
@SuppressWarnings("unchecked")
public T jsonRead(JsonParser parser, String path) throws IOException {
public T jsonRead(ReadJson jsonRead, String path) throws IOException {
JsonParser parser = jsonRead.getParser();
if (parser.getCurrentToken() == JsonToken.START_OBJECT) {
// start object token read by Jackson already
} else {
@@ -66,7 +70,7 @@ public class BeanDescriptorJsonHelp<T> {
}
if (desc.inheritInfo == null) {
return jsonReadObject(parser, path);
return jsonReadObject(jsonRead, path);
}
// check for the discriminator value to determine the correct sub type
@@ -83,8 +87,8 @@ public class BeanDescriptorJsonHelp<T> {
BeanProperty property = desc.getBeanProperty(propName);
if (property != null) {
EntityBean bean = desc.createEntityBean();
property.jsonRead(parser, bean);
return jsonReadProperties(parser, bean);
property.jsonRead(jsonRead, bean);
return jsonReadProperties(jsonRead, bean, path);
}
String msg = "Error reading inheritance discriminator, expected property ["+discColumn+"] but got [" + propName + "] ?";
throw new JsonParseException(msg, parser.getCurrentLocation());
@@ -95,29 +99,39 @@ public class BeanDescriptorJsonHelp<T> {
// determine the sub type for this particular json object
InheritInfo localInheritInfo = inheritInfo.readType(discValue);
BeanDescriptor<?> localDescriptor = localInheritInfo.getBeanDescriptor();
return (T) localDescriptor.jsonReadObject(parser, path);
return (T) localDescriptor.jsonReadObject(jsonRead, path);
}
protected T jsonReadObject(JsonParser parser, String path) throws IOException {
protected T jsonReadObject(ReadJson readJson, String path) throws IOException {
EntityBean bean = desc.createEntityBean();
return jsonReadProperties(parser, bean);
return jsonReadProperties(readJson, bean, path);
}
@SuppressWarnings("unchecked")
protected T jsonReadProperties(JsonParser parser, EntityBean bean) throws IOException {
protected T jsonReadProperties(ReadJson readJson, EntityBean bean, String path) throws IOException {
if (path != null) {
readJson.pushPath(path);
}
// unmapped properties, send to JsonReadBeanVisitor later
Map<String,Object> unmappedProperties = null;
do {
JsonParser parser = readJson.getParser();
JsonToken event = parser.nextToken();
if (JsonToken.FIELD_NAME == event) {
String key = parser.getCurrentName();
BeanProperty p = desc.getBeanProperty(key);
if (p != null) {
p.jsonRead(parser, bean);
p.jsonRead(readJson, bean);
} else {
// unknown property ... read and ignore
EJson.parse(parser);
// read an unmapped property
if (unmappedProperties == null) {
unmappedProperties = new LinkedHashMap<String, Object>();
}
unmappedProperties.put(key, EJson.parse(parser));
}
} else if (JsonToken.END_OBJECT == event) {
@@ -128,6 +142,13 @@ public class BeanDescriptorJsonHelp<T> {
}
} while (true);
// visit JsonReadBeanVisitor (if registered for this path)
readJson.beanVisitor(bean, unmappedProperties);
if (path != null) {
readJson.popPath();
}
return (T)bean;
}
@@ -14,7 +14,6 @@ import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.config.dbplatform.DbIdentity;
import com.avaje.ebean.config.dbplatform.IdGenerator;
import com.avaje.ebean.config.dbplatform.IdType;
import com.avaje.ebean.event.BeanFinder;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.api.TransactionEventTable;
import com.avaje.ebeaninternal.server.core.*;
@@ -161,8 +160,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
this.persistControllerManager = new PersistControllerManager(bootupClasses);
this.persistListenerManager = new PersistListenerManager(bootupClasses);
this.beanQueryAdapterManager = new BeanQueryAdapterManager(bootupClasses);
this.beanFinderManager = new DefaultBeanFinderManager();
this.beanFinderManager = new BeanFinderManager(bootupClasses);
this.reflectFactory = createReflectionFactory();
this.transientProperties = new TransientProperties();
@@ -407,7 +405,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
int qa = beanQueryAdapterManager.getRegisterCount();
int cc = persistControllerManager.getRegisterCount();
int lc = persistListenerManager.getRegisterCount();
int fc = beanFinderManager.createBeanFinders(bootupClasses.getBeanFinders());
int fc = beanFinderManager.getRegisterCount();
logger.debug("BeanPersistControllers[" + cc + "] BeanFinders[" + fc + "] BeanPersistListeners[" + lc + "] BeanQueryAdapters[" + qa + "]");
}
@@ -435,7 +433,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
*/
private void readEmbeddedDeployment() {
ArrayList<Class<?>> embeddedClasses = bootupClasses.getEmbeddables();
List<Class<?>> embeddedClasses = bootupClasses.getEmbeddables();
for (int i = 0; i < embeddedClasses.size(); i++) {
Class<?> cls = embeddedClasses.get(i);
if (logger.isTraceEnabled()) {
@@ -456,7 +454,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
*/
private void readEntityDeploymentInitial() {
ArrayList<Class<?>> entityClasses = bootupClasses.getEntities();
List<Class<?>> entityClasses = bootupClasses.getEntities();
for (Class<?> entityClass : entityClasses) {
DeployBeanInfo<?> info = createDeployBeanInfo(entityClass);
@@ -935,17 +933,10 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
private <T> void setBeanControllerFinderListener(DeployBeanDescriptor<T> descriptor) {
Class<T> beanType = descriptor.getBeanType();
persistControllerManager.addPersistControllers(descriptor);
persistListenerManager.addPersistListeners(descriptor);
beanQueryAdapterManager.addQueryAdapter(descriptor);
BeanFinder<T> beanFinder = beanFinderManager.getBeanFinder(beanType);
if (beanFinder != null) {
descriptor.setBeanFinder(beanFinder);
logger.debug("BeanFinder on[" + descriptor.getFullName() + "] " + beanFinder.getClass().getName());
}
beanFinderManager.addFindControllers(descriptor);
}
/**
@@ -1,26 +1,42 @@
package com.avaje.ebeaninternal.server.deploy;
import com.avaje.ebean.event.BeanFindController;
import com.avaje.ebeaninternal.server.core.BootupClasses;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import com.avaje.ebean.event.BeanFinder;
/**
* Factory for controlling the construction of BeanFinders.
* Default implementation for BeanFinderFactory.
*/
public interface BeanFinderManager {
/**
* Return the number of beans with a registered finder.
*/
public int getRegisterCount();
public class BeanFinderManager {
final Logger logger = LoggerFactory.getLogger(BeanFinderManager.class);
private final List<BeanFindController> list;
public BeanFinderManager(BootupClasses bootupClasses) {
list = bootupClasses.getBeanFindControllers();
}
public int getRegisterCount() {
return list.size();
}
/**
* Return the BeanPersistController for a given entity type.
*/
public void addFindControllers(DeployBeanDescriptor<?> deployDesc) {
for (int i = 0; i < list.size(); i++) {
BeanFindController c = list.get(i);
if (c.isRegisterFor(deployDesc.getBeanType())) {
logger.debug("BeanFindController on[" + deployDesc.getFullName() + "] " + c.getClass().getName());
deployDesc.setBeanFinder(c);
}
}
}
/**
* Create the appropriate BeanController.
*/
public int createBeanFinders(List<Class<?>> finderClassList);
/**
* Return the BeanController for a given entity type.
*/
public <T> BeanFinder<T> getBeanFinder(Class<T> entityType);
}
@@ -2,7 +2,6 @@ package com.avaje.ebeaninternal.server.deploy;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.avaje.ebean.EbeanServer;
@@ -141,11 +140,13 @@ public final class BeanListHelp<T> implements BeanCollectionHelp<T> {
list = (List<?>) collection;
}
ctx.writeStartArray(name);
for (int j = 0; j < list.size(); j++) {
targetDescriptor.jsonWrite(ctx, (EntityBean) list.get(j));
if (!list.isEmpty() || ctx.isIncludeEmpty()) {
ctx.writeStartArray(name);
for (int j = 0; j < list.size(); j++) {
targetDescriptor.jsonWrite(ctx, (EntityBean) list.get(j));
}
ctx.writeEndArray();
}
ctx.writeEndArray();
}
}
@@ -177,12 +177,14 @@ public final class BeanMapHelp<T> implements BeanCollectionHelp<T> {
map = (Map<?, ?>) collection;
}
ctx.writeStartArray(name);
for (Entry<?, ?> entry : map.entrySet()) {
//FIXME: json write map key ...
targetDescriptor.jsonWrite(ctx, (EntityBean) entry.getValue());
if (!map.isEmpty() || ctx.isIncludeEmpty()) {
ctx.writeStartArray(name);
for (Entry<?, ?> entry : map.entrySet()) {
//FIXME: json write map key ...
targetDescriptor.jsonWrite(ctx, (EntityBean) entry.getValue());
}
ctx.writeEndArray();
}
ctx.writeEndArray();
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -74,7 +74,7 @@ public abstract class BeanPropertyAssoc<T> extends BeanProperty {
* Construct the property.
*/
public BeanPropertyAssoc(BeanDescriptorMap owner, BeanDescriptor<?> descriptor, DeployBeanPropertyAssoc<T> deploy) {
super(owner, descriptor, deploy);
super(descriptor, deploy);
this.extraWhere = InternString.intern(deploy.getExtraWhere());
this.isOuterJoin = deploy.isOuterJoin();
this.beanTable = deploy.getBeanTable();
@@ -13,8 +13,8 @@ import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.el.ElPropertyChainBuilder;
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
import com.avaje.ebeaninternal.server.query.SqlBeanLoad;
import com.avaje.ebeaninternal.server.text.json.ReadJson;
import com.avaje.ebeaninternal.server.text.json.WriteJson;
import com.fasterxml.jackson.core.JsonParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -225,7 +225,8 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
return createElPropertyValue(propName, remainder, chain, propertyDeploy);
}
public void buildSelectExpressionChain(String prefix, List<String> selectChain) {
@Override
public void buildRawSqlSelectChain(String prefix, List<String> selectChain) {
// do not add to the selectChain at the top level of the Many bean
}
@@ -872,13 +873,20 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
if (help != null) {
help.jsonWrite(ctx, name, value, include != null);
} else {
ctx.toJson(name, (Collection<?>) value);
if (isTransient) {
ctx.writeValueUsingObjectMapper(name, value);
} else {
Collection<?> collection = (Collection<?>)value;
if (!collection.isEmpty() || ctx.isIncludeEmpty()) {
ctx.toJson(name, collection);
}
}
}
ctx.popParentBeanMany();
}
}
public void jsonRead(JsonParser parser, EntityBean parentBean) throws IOException {
jsonHelp.jsonRead(parser, parentBean);
public void jsonRead(ReadJson readJson, EntityBean parentBean) throws IOException {
jsonHelp.jsonRead(readJson, parentBean);
}
}
@@ -1,28 +1,49 @@
package com.avaje.ebeaninternal.server.deploy;
import java.io.IOException;
import com.avaje.ebean.bean.BeanCollection;
import com.avaje.ebean.bean.BeanCollectionAdd;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebeaninternal.api.ClassUtil;
import com.avaje.ebeaninternal.server.text.json.ReadJson;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import java.io.IOException;
/**
* Help BeanPropertyAssocMany with JSON processing.
*/
public class BeanPropertyAssocManyJsonHelp {
/**
* The associated many property.
*/
private final BeanPropertyAssocMany<?> many;
/**
* Helper used to read json for transient 'many' properties.
*/
private final BeanPropertyAssocManyJsonTransient jsonTransient;
/**
* Construct for the owning many property.
*/
public BeanPropertyAssocManyJsonHelp(BeanPropertyAssocMany<?> many) {
this.many = many;
this.jsonTransient = !ClassUtil.isJacksonObjectMapperPresent() ? null : new BeanPropertyAssocManyJsonTransient();
}
public void jsonRead(JsonParser parser, EntityBean parentBean) throws IOException {
/**
* Read the JSON for this property.
*/
public void jsonRead(ReadJson readJson, EntityBean parentBean) throws IOException {
if (!this.many.jsonDeserialize) {
return;
}
JsonParser parser = readJson.getParser();
JsonToken event = parser.nextToken();
if (JsonToken.VALUE_NULL == event) {
return;
@@ -31,10 +52,15 @@ public class BeanPropertyAssocManyJsonHelp {
throw new JsonParseException("Unexpected token " + event + " - expecting start_array ", parser.getCurrentLocation());
}
if (many.isTransient()) {
jsonReadTransientUsingObjectMapper(readJson, parentBean);
return;
}
BeanCollection<?> collection = many.createEmpty(parentBean);
BeanCollectionAdd add = many.getBeanCollectionAdd(collection, null);
do {
EntityBean detailBean = (EntityBean) many.targetDescriptor.jsonRead(parser, many.name);
EntityBean detailBean = (EntityBean) many.targetDescriptor.jsonRead(readJson, many.name);
if (detailBean == null) {
// read the entire array
break;
@@ -49,4 +75,15 @@ public class BeanPropertyAssocManyJsonHelp {
many.setValue(parentBean, collection);
}
/**
* Read a Transient property using Jackson ObjectMapper.
*/
private void jsonReadTransientUsingObjectMapper(ReadJson readJson, EntityBean parentBean) throws IOException {
if (jsonTransient == null) {
throw new IllegalStateException("Jackson ObjectMapper is required to read this Transient property "+many.getFullBeanName());
}
jsonTransient.jsonReadUsingObjectMapper(many, readJson, parentBean);
}
}

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