Compare commits

...
Author SHA1 Message Date
Robin Bygrave a49b99156b [maven-release-plugin] prepare release avaje-ebeanorm-6.2.2 2015-07-30 06:45:36 +12:00
Robin Bygrave 54f3dbf35a #361 - ENH: Add ServerConfig expressionEqualsWithNullAsNoop - Can eq ne gt ... methods in ExpressionList treat null value as 1=1 ? 2015-07-30 06:41:51 +12:00
Rob Bygrave 27847424b3 Merge pull request #362 from kdeng/master
Introduce a ClassPathSearchService to support multiple ClassPath search processes with customise search methods
2015-07-30 05:12:47 +12:00
Robin Bygrave a5e94f6ae2 #357 - batch insertAll has no effect when tx commited 2015-07-30 04:23:02 +12:00
Kefeng Deng 9f8b3799eb Merge branch 'master' of github.com:kdeng/avaje-ebeanorm 2015-07-29 21:11:17 +12:00
Kefeng Deng 7734919010 Merge branch 'master' of github.com:kdeng/avaje-ebeanorm 2015-07-29 21:10:45 +12:00
Robin Bygrave 19f40cb2e5 No effective change - format 2015-07-29 20:56:58 +12:00
Robin Bygrave 3d4bd15dac #360 ENH: Add query setDisableLazyLoading(true) ... for use when graph serialised via external library (and you don't want lazy loading to fire) 2015-07-29 20:31:25 +12:00
Kefeng Deng a3c81c3a31 Merge branch 'master' of github.com:kdeng/avaje-ebeanorm
# Conflicts:
#	src/main/java/com/avaje/ebeaninternal/server/core/BootupClassPathSearch.java
#	src/main/java/com/avaje/ebeaninternal/server/util/ClassPathSearch.java
2015-07-29 20:19:43 +12:00
Kefeng Deng 3549f88232 Introduced a service interface to allow multiple ClassPathSearchs with its own customized search way 2015-07-29 20:14:44 +12:00
Robin Bygrave 59d009bc94 No effective change - change to assertJ from hamcrest matchers 2015-07-29 15:54:31 +12:00
Robin Bygrave a6edafbf2d No effective change - add generics type on variable 2015-07-29 15:40:21 +12:00
Robin Bygrave 5fab66204c #359 - ENH: add BeanState.setDisableLazyLoad(boolean) 2015-07-29 15:36:11 +12:00
Kefeng Deng 2fa7c57357 Introduced a service interface to allow multiple ClassPathSearchs with its own customized search way 2015-07-28 21:31:49 +12:00
Robin Bygrave 890e924eb0 [maven-release-plugin] prepare for next development iteration 2015-07-27 23:03:50 +12:00
Robin Bygrave 1c6592a6ec [maven-release-plugin] prepare release avaje-ebeanorm-6.2.1 2015-07-27 23:03:27 +12:00
Robin Bygrave 554c5a7bfc No effective change - format 2015-07-27 23:02:33 +12:00
Robin Bygrave 7a32c50894 Bump pom to 6.2.1-SNAPSHOT 2015-07-27 23:00:12 +12:00
Robin Bygrave 3fa8f04a4c #358 - ENH: Add ServerConfig updateAllPropertiesInBatch with a default of true 2015-07-27 22:59:18 +12:00
Robin Bygrave 962d7f601d #356 - ENH: Change to Binder logging such that the value in the bind log is the converted/bound value 2015-07-27 20:59:40 +12:00
Robin Bygrave f2aa2b5b8b No effective change - format and tidy 2015-07-27 20:47:23 +12:00
Robin Bygrave 87b485cfa4 #355 - ENH: Add notIn(...) expressions. Just to make life easier in those cases 2015-07-27 20:39:34 +12:00
Robin Bygrave 5a55b5235d No effective change - tidy 2015-07-27 15:56:06 +12:00
Robin Bygrave 97adb76eac No effective change - remove unused methods 2015-07-27 15:54:20 +12:00
Robin Bygrave d0d5ab474d No effective change - remove unused import 2015-07-27 15:42:57 +12:00
Robin Bygrave d396f09b3a #296 - ENH: Add to transaction setUpdateAllLoadedProperties() - force update all properties api 2015-07-24 21:56:11 +12:00
Robin Bygrave 3baa5bca46 #352 - Remove deprecated API - ValuePair getValue1() getValue2() ... use getNewValue() getOldValue() 2015-07-24 20:15:13 +12:00
Robin Bygrave c00484026c #351 - ENH: Add diff to Version beans returned from findVersions() 2015-07-24 20:12:26 +12:00
Robin Bygrave 71798afadd #350 - ENH: Add @History findVersions() query - add default ordering to lower sys period desc 2015-07-24 16:52:58 +12:00
Robin Bygrave 1ec2f74df9 #350 - ENH: Add @History findVersions() query ... returning historic versions for a given bean using history view 2015-07-24 16:20:15 +12:00
Robin Bygrave 61a0651439 No effective change - code format 2015-07-24 12:33:35 +12:00
Robin Bygrave eae06059c9 #349 - ENH: Add @WhoCreated @WhoModified ... with CurrentUserProvider interface 2015-07-24 12:33:04 +12:00
Robin Bygrave a1ff9034b6 No effective change - format 2015-07-24 12:09:04 +12:00
Robin Bygrave 1085a8d608 #348 - ENH: Add @WhenCreated and @WhenModified ... as alias to existing @CreatedTimestamp and @UpdatedTimstamp 2015-07-24 10:50:35 +12:00
Robin Bygrave 3a547bf487 #347 - @History support with query.asOf(Timestamp) - javadoc update 2015-07-24 10:24:28 +12:00
Robin Bygrave 82489636d5 #347 - @History support with query.asOf(Timestamp) 2015-07-24 10:18:17 +12:00
Robin Bygrave 3cafb37a73 [maven-release-plugin] prepare for next development iteration 2015-07-20 20:09:05 +12:00
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 d2c3142de4 WIP on Finder 2015-06-22 00:20:01 +12:00
272 changed files with 9421 additions and 6450 deletions
+1
View File
@@ -1,5 +1,6 @@
*.autofetch
*.sql
*.orig
.classpath
.project
.settings/
+6 -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,7 +13,7 @@ Maven Dependency
<dependency>
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm</artifactId>
<version>4.7.1</version>
<version>4.7.3</version>
</dependency>
+12 -26
View File
@@ -9,7 +9,7 @@
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm</artifactId>
<version>4.7.2</version>
<version>6.2.2</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>
@@ -152,36 +158,16 @@
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.27</version>
<version>5.1.36</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-integration</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.9</version>
<groupId>org.avaje.composite</groupId>
<artifactId>avaje-composite-testing</artifactId>
<version>1.1</version>
<scope>test</scope>
<type>pom</type>
</dependency>
<dependency>
@@ -33,6 +33,11 @@ public interface BeanState {
*/
boolean isDirty();
/**
* This can be called with true to disable lazy loading on the bean.
*/
void setDisableLazyLoad(boolean disableLazyLoading);
/**
* For partially populated beans returns the properties that are loaded on the
* bean.
+96 -109
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,7 +321,7 @@ public final class Ebean {
* </p>
*/
public static Object nextId(Class<?> beanType) {
return serverMgr.getPrimaryServer().nextId(beanType);
return serverMgr.getDefaultServer().nextId(beanType);
}
/**
@@ -359,7 +369,7 @@ public final class Ebean {
* </p>
*/
public static Transaction beginTransaction() {
return serverMgr.getPrimaryServer().beginTransaction();
return serverMgr.getDefaultServer().beginTransaction();
}
/**
@@ -370,7 +380,7 @@ public final class Ebean {
*
*/
public static Transaction beginTransaction(TxIsolation isolation) {
return serverMgr.getPrimaryServer().beginTransaction(isolation);
return serverMgr.getDefaultServer().beginTransaction(isolation);
}
/**
@@ -425,7 +435,7 @@ public final class Ebean {
* }</pre>
*/
public static Transaction beginTransaction(TxScope scope){
return serverMgr.getPrimaryServer().beginTransaction(scope);
return serverMgr.getDefaultServer().beginTransaction(scope);
}
/**
@@ -433,7 +443,7 @@ public final class Ebean {
* in scope.
*/
public static Transaction currentTransaction() {
return serverMgr.getPrimaryServer().currentTransaction();
return serverMgr.getDefaultServer().currentTransaction();
}
/**
@@ -446,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();
}
/**
@@ -489,7 +499,7 @@ public final class Ebean {
* }</pre>
*/
public static void endTransaction() {
serverMgr.getPrimaryServer().endTransaction();
serverMgr.getDefaultServer().endTransaction();
}
/**
@@ -500,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);
}
/**
@@ -523,7 +533,6 @@ public final class Ebean {
* public class Order { ...
*
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
* @JoinColumn(name="order_id")
* List<OrderDetail> details;
* ...
* }
@@ -537,7 +546,7 @@ public final class Ebean {
* </p>
*/
public static void save(Object bean) throws OptimisticLockException {
serverMgr.getPrimaryServer().save(bean);
serverMgr.getDefaultServer().save(bean);
}
/**
@@ -545,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);
}
/**
@@ -576,7 +585,7 @@ public final class Ebean {
* }</pre>
*/
public static void markAsDirty(Object bean) throws OptimisticLockException {
serverMgr.getPrimaryServer().markAsDirty(bean);
serverMgr.getDefaultServer().markAsDirty(bean);
}
/**
@@ -616,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);
}
/**
@@ -651,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);
}
/**
@@ -669,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);
}
/**
@@ -689,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);
}
/**
@@ -700,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);
}
/**
@@ -739,7 +734,7 @@ public final class Ebean {
* </p>
*/
public static void refresh(Object bean) {
serverMgr.getPrimaryServer().refresh(bean);
serverMgr.getDefaultServer().refresh(bean);
}
/**
@@ -760,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);
}
/**
@@ -788,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);
}
/**
@@ -834,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);
}
/**
@@ -883,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);
}
/**
@@ -896,7 +892,7 @@ public final class Ebean {
* </p>
*/
public static SqlQuery createSqlQuery(String sql) {
return serverMgr.getPrimaryServer().createSqlQuery(sql);
return serverMgr.getDefaultServer().createSqlQuery(sql);
}
/**
@@ -909,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);
}
/**
@@ -927,7 +923,7 @@ public final class Ebean {
* </p>
*/
public static SqlUpdate createSqlUpdate(String sql) {
return serverMgr.getPrimaryServer().createSqlUpdate(sql);
return serverMgr.getDefaultServer().createSqlUpdate(sql);
}
/**
@@ -936,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);
}
/**
@@ -959,7 +955,7 @@ public final class Ebean {
* }</pre>
*/
public static SqlUpdate createNamedSqlUpdate(String namedQuery) {
return serverMgr.getPrimaryServer().createNamedSqlUpdate(namedQuery);
return serverMgr.getDefaultServer().createNamedSqlUpdate(namedQuery);
}
/**
@@ -987,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);
}
/**
@@ -1015,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);
}
/**
@@ -1074,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);
}
/**
@@ -1108,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);
}
/**
@@ -1116,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);
}
/**
@@ -1173,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);
}
/**
@@ -1190,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);
}
/**
@@ -1204,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);
}
/**
@@ -1251,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);
}
/**
@@ -1280,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);
}
/**
@@ -1305,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);
}
/**
@@ -1333,7 +1329,7 @@ public final class Ebean {
* }</pre>
*/
public static void execute(TxRunnable r) {
serverMgr.getPrimaryServer().execute(r);
serverMgr.getDefaultServer().execute(r);
}
/**
@@ -1360,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);
}
/**
@@ -1394,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);
}
/**
@@ -1431,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);
}
/**
@@ -1444,7 +1439,7 @@ public final class Ebean {
* </p>
*/
public static BeanState getBeanState(Object bean) {
return serverMgr.getPrimaryServer().getBeanState(bean);
return serverMgr.getDefaultServer().getBeanState(bean);
}
/**
@@ -1452,7 +1447,7 @@ public final class Ebean {
*
*/
public static ServerCacheManager getServerCacheManager() {
return serverMgr.getPrimaryServer().getServerCacheManager();
return serverMgr.getDefaultServer().getServerCacheManager();
}
/**
@@ -1460,7 +1455,7 @@ public final class Ebean {
* queries.
*/
public static BackgroundExecutor getBackgroundExecutor() {
return serverMgr.getPrimaryServer().getBackgroundExecutor();
return serverMgr.getDefaultServer().getBackgroundExecutor();
}
/**
@@ -1471,7 +1466,7 @@ public final class Ebean {
* </p>
*/
public static void runCacheWarming() {
serverMgr.getPrimaryServer().runCacheWarming();
serverMgr.getDefaultServer().runCacheWarming();
}
/**
@@ -1483,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();
}
}
+39 -66
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.
@@ -148,7 +148,7 @@ public interface EbeanServer {
* difference comparison.
* </p>
*/
Map<String, ValuePair> diff(Object a, Object b);
Map<String, ValuePair> diff(Object newBean, Object oldBean);
/**
* Create a new instance of T that is an EntityBean.
@@ -905,17 +905,13 @@ 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.
* Return versions of a @History entity bean.
* <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.
* Generally this query is expected to be a find by id or unique predicates query.
* It will execute the query against the history returning the versions of the bean.
* </p>
*
* @deprecated
*/
<T> void findVisit(Query<T> query, QueryResultVisitor<T> visitor, Transaction transaction);
<T> List<Version<T>> findVersions(Query<T> query, Transaction transaction);
/**
* Execute a query returning a list of beans.
@@ -1109,6 +1105,7 @@ public interface EbeanServer {
*
* @see Query#findUnique()
*/
@Nullable
<T> T findUnique(Query<T> query, Transaction transaction);
/**
@@ -1185,6 +1182,7 @@ public interface EbeanServer {
*
* @see SqlQuery#findUnique()
*/
@Nullable
SqlRow findUnique(SqlQuery query, Transaction transaction);
/**
@@ -1222,15 +1220,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.
@@ -1241,15 +1234,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.
@@ -1264,13 +1252,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
@@ -1328,7 +1321,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.
@@ -1400,27 +1393,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.
@@ -1485,7 +1473,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.
@@ -1505,13 +1493,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>
@@ -1525,18 +1513,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
@@ -1545,7 +1533,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);
@@ -1560,10 +1548,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
@@ -1585,7 +1573,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.
@@ -1622,27 +1610,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.
@@ -1665,7 +1644,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.
@@ -1691,7 +1670,7 @@ public interface EbeanServer {
*
* }</pre>
*/
void execute(TxRunnable r);
void execute(TxRunnable runnable);
/**
* Execute a TxCallable in a Transaction with an explicit scope.
@@ -1715,7 +1694,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.
@@ -1747,7 +1726,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).
@@ -1777,12 +1756,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>
@@ -169,7 +169,22 @@ public interface ExpressionFactory {
* In - property has a value in the collection of values.
*/
Expression in(String propertyName, Collection<?> values);
/**
* Not In - property has a value in the array of values.
*/
Expression notIn(String propertyName, Object[] values);
/**
* Not In - property has a value in the collection of values.
*/
Expression notIn(String propertyName, Collection<?> values);
/**
* Not In - using a subQuery.
*/
Expression notIn(String propertyName, Query<?> subQuery);
/**
* Exists expression
*/
@@ -1,8 +1,10 @@
package com.avaje.ebean;
import com.avaje.ebean.text.PathProperties;
import org.jetbrains.annotations.Nullable;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -94,6 +96,17 @@ public interface ExpressionList<T> extends Serializable {
*/
Query<T> apply(PathProperties pathProperties);
/**
* Perform an 'As of' query using history tables to return the object graph
* as of a time in the past.
* <p>
* To perform this query the DB must have underlying history tables.
* </p>
*
* @param asOf the date time in the past at which you want to view the data
*/
Query<T> asOf(Timestamp asOf);
/**
* Execute the query iterating over the results.
*
@@ -116,14 +129,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 +175,7 @@ public interface ExpressionList<T> extends Serializable {
*
* @see Query#findUnique()
*/
@Nullable
T findUnique();
/**
@@ -229,6 +235,15 @@ public interface ExpressionList<T> extends Serializable {
*/
PagedList<T> findPagedList(int pageIndex, int pageSize);
/**
* Return versions of a @History entity bean.
* <p>
* Generally this query is expected to be a find by id or unique predicates query.
* It will execute the query against the history returning the versions of the bean.
* </p>
*/
List<Version<T>> findVersions();
/**
* Add some filter predicate expressions to the many property.
*/
@@ -473,7 +488,22 @@ public interface ExpressionList<T> extends Serializable {
* In - property has a value in the collection of values.
*/
ExpressionList<T> in(String propertyName, Collection<?> values);
/**
* Not In - property has a value in the array of values.
*/
ExpressionList<T> notIn(String propertyName, Object... values);
/**
* Not In - property has a value in the collection of values.
*/
ExpressionList<T> notIn(String propertyName, Collection<?> values);
/**
* Not In - using a subQuery.
*/
ExpressionList<T> notIn(String propertyName, Query<?> subQuery);
/**
* Exists expression
*/
+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;
}
+45 -16
View File
@@ -1,8 +1,10 @@
package com.avaje.ebean;
import com.avaje.ebean.text.PathProperties;
import org.jetbrains.annotations.Nullable;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -284,6 +286,17 @@ public interface Query<T> extends Serializable {
*/
Query<T> setRawSql(RawSql rawSql);
/**
* Perform an 'As of' query using history tables to return the object graph
* as of a time in the past.
* <p>
* To perform this query the DB must have underlying history tables.
* </p>
*
* @param asOf the date time in the past at which you want to view the data
*/
Query<T> asOf(Timestamp asOf);
/**
* Cancel the query execution if supported by the underlying database and
* driver.
@@ -483,7 +496,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 +533,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,8 +717,18 @@ public interface Query<T> extends Serializable {
* ...
* }</pre>
*/
@Nullable
T findUnique();
/**
* Return versions of a @History entity bean.
* <p>
* Generally this query is expected to be a find by id or unique predicates query.
* It will execute the query against the history returning the versions of the bean.
* </p>
*/
List<Version<T>> findVersions();
/**
* Return the count of entities this query should return.
* <p>
@@ -878,6 +889,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 +1139,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 +1251,17 @@ 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();
/**
* Set true if you want to disable lazy loading.
* <p>
* That is, once the object graph is returned further lazy loading is disabled.
* </p>
*/
Query<T> setDisableLazyLoading(boolean disableLazyLoading);
}
@@ -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.
*
@@ -97,6 +97,17 @@ public interface Transaction extends Closeable {
*/
void setPersistCascade(boolean persistCascade);
/**
* Set to true when you want all loaded properties to be included in the update
* (rather than just the changed properties).
* <p>
* You might set this when using JDBC batch in order to get multiple updates
* with slightly different sets of changed properties into the same statement
* and hence better JDBC batch performance.
* </p>
*/
void setUpdateAllLoadedProperties(boolean updateAllLoadedProperties);
/**
* Turn on or off statement batching. Statement batching can be transparent
* for drivers and databases that support getGeneratedKeys. Otherwise you may
+18 -11
View File
@@ -5,10 +5,19 @@ package com.avaje.ebean;
*/
public class ValuePair {
private final Object newValue;
protected Object newValue;
private final Object oldValue;
protected Object oldValue;
/**
* Default constructor for JSON tools.
*/
public ValuePair() {
}
/**
* Construct with the pair of new and old values.
*/
public ValuePair(Object newValue, Object oldValue) {
this.newValue = newValue;
this.oldValue = oldValue;
@@ -27,21 +36,19 @@ public class ValuePair {
public Object getOldValue() {
return oldValue;
}
/**
* Return the new value.
* Set the new value.
*/
@Deprecated
public Object getValue1() {
return newValue;
public void setNewValue(Object newValue) {
this.newValue = newValue;
}
/**
* Return the old value.
* Set the old value.
*/
@Deprecated
public Object getValue2() {
return oldValue;
public void setOldValue(Object oldValue) {
this.oldValue = oldValue;
}
public String toString() {
+101
View File
@@ -0,0 +1,101 @@
package com.avaje.ebean;
import java.sql.Timestamp;
import java.util.Map;
/**
* Wraps a version of a @History bean.
*/
public class Version<T> {
/**
* The version of the bean.
*/
protected T bean;
/**
* The effective start date time of this version.
*/
protected Timestamp start;
/**
* The effective end date time of this version.
*/
protected Timestamp end;
/**
* The map of changed properties.
*/
protected Map<String, ValuePair> diff;
/**
* Construct with bean and an effective date time range.
*/
public Version(T bean, Timestamp start, Timestamp end) {
this.bean = bean;
this.start = start;
this.end = end;
}
/**
* Default constructor - useful for JSON tools such as Jackson.
*/
public Version() {
}
/**
* Return the bean instance for this version.
*/
public T getBean() {
return bean;
}
/**
* Set the bean instance for this version.
*/
public void setBean(T bean) {
this.bean = bean;
}
/**
* Return the effective start date time of this version.
*/
public Timestamp getStart() {
return start;
}
/**
* Set the effective start date time of this version.
*/
public void setStart(Timestamp start) {
this.start = start;
}
/**
* Return the effective end date time of this version.
*/
public Timestamp getEnd() {
return end;
}
/**
* Set the effective end date time of this version.
*/
public void setEnd(Timestamp end) {
this.end = end;
}
/**
* Set the map of differences from this bean to the prior version.
*/
public void setDiff(Map<String, ValuePair> diff) {
this.diff = diff;
}
/**
* Return the map of differences from this bean to the prior version.
*/
public Map<String, ValuePair> getDiff() {
return diff;
}
}
@@ -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,17 +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;
/**
* Deprecated - please use @DbHstore instead.
* @see DbHstore
*/
@Deprecated
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ColumnHstore {
}
@@ -0,0 +1,19 @@
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;
/**
* Marks an entity bean as having history support.
* <p>
* In Postgres for example this means there is an associated history table which is
* typically automatically populated via database triggers.
* </p>
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface History {
}
@@ -0,0 +1,25 @@
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;
/**
* Marks a property as being excluded from history.
* <p>
* This means the property values are not maintained in the history table. Typically this
* would be placed on relatively large properties (Clobs, Blobs, large varchar columns etc)
* that are considered not interesting enough to maintain history on excluding them reduces
* underlying database costs.
* </p>
* <p>
* When placed on a ManyToMany this means that the intersection table does not have history
* support.
* </p>
*/
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface HistoryExclude {
}
@@ -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;
}
@@ -0,0 +1,38 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* For a timestamp property that is set to the datetime when the entity is
* created/inserted.
* <p>
* This is effectively an alias for @CreatedTimestamp and added to hint
* towards a better naming convention (WhenCreated, WhenModified).
* </p>
* <p>
* An alternative to using this annotation would be to use insertable=false,
* updateable=false with @Column and have the DB insert the current time
* (default value on the DB column is SYSTIME etc).
* </p>
* <p>
* The downside to this approach is that the inserted entity does not have the
* timestamp value after the insert has occurred. You need to fetch the entity
* back to get the inserted timestamp if you want to used it.
* </p>
*
* <h3>Example:</h3>
* <pre>{@code
*
* @WhenCreated
* Timestamp whenCreated;
*
* }</pre>
*/
@Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface WhenCreated {
}
@@ -0,0 +1,20 @@
package com.avaje.ebean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* For a timestamp property that is set to the datetime when the entity was last modified.
* <p>
* This is effectively an alias for @UpdatedTimestamp and added to hint
* towards a better naming convention (WhenCreated, WhenModified).
* </p>
* </p>
*/
@Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface WhenModified {
}
@@ -0,0 +1,29 @@
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;
/**
* Mapped onto a entity bean property that represents the user id of
* who created the entity>
* <p>
* To use this annotation you need to implement CurrentUserProvider.
* The type of the bean property should match the type returned by
* CurrentUserProvider.
*</p>
* <h3>Example:</h3>
* <pre>{@code
*
* @WhoCreated
* String whoCreated;
*
* }</pre>
*/
@Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface WhoCreated {
}
@@ -0,0 +1,29 @@
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;
/**
* Mapped onto a entity bean property that represents the user id of
* who last modified the entity>
* <p>
* To use this annotation you need to implement CurrentUserProvider.
* The type of the bean property should match the type returned by
* CurrentUserProvider.
* </p>
*
* <h3>Example:</h3>
* <pre>{@code
*
* @WhoModified
* String whoModified;
*
* }</pre>
*/
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface WhoModified {
}
@@ -608,7 +608,7 @@ public final class EntityBeanIntercept implements Serializable {
} else if (embeddedDirty != null && embeddedDirty[i]) {
// an embedded property has been changed - recurse
EntityBean embeddedBean = (EntityBean)owner._ebean_getField(i);
embeddedBean._ebean_getIntercept().addDirtyPropertyValues(dirtyValues, getProperty(i)+".");
embeddedBean._ebean_getIntercept().addDirtyPropertyValues(dirtyValues, getProperty(i) + ".");
}
}
}
@@ -638,6 +638,20 @@ public final class EntityBeanIntercept implements Serializable {
return hash;
}
/**
* Return a loaded property hash.
*/
public int getLoadedPropertyHash() {
int hash = 37;
int len = getPropertyLength();
for (int i = 0; i < len; i++) {
if (isLoadedProperty(i)) {
hash = hash * 31 + (i+1);
}
}
return hash;
}
/**
* Return the set of property names for changed properties.
*/
-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;
}
}
@@ -0,0 +1,16 @@
package com.avaje.ebean.config;
/**
* Provides the current user in order to support 'Who created', 'Who modified' and other audit features.
*/
public interface CurrentUserProvider {
/**
* Return the current user id.
* <p>
* The type returned should match the type of the properties annotated
* with @WhoCreated and @WhoModified. These are typically String, Long or UUID.
* </p>
*/
Object currentUser();
}
@@ -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
}
}
@@ -113,6 +113,12 @@ public class ServerConfig {
*/
private String classPathReaderClassName;
/**
* This is used to populate @WhoCreated, @WhoModified and
* support other audit features (who executed a query etc).
*/
private CurrentUserProvider currentUserProvider;
/**
* Config controlling the autofetch behaviour.
*/
@@ -123,6 +129,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.
*/
@@ -138,6 +150,18 @@ public class ServerConfig {
*/
private int databaseSequenceBatchSize = 20;
/**
* Suffix appended to the base table to derive the view that contains the union
* of the base table and the history table in order to support asOf queries.
*/
private String asOfViewSuffix = "_with_history";
/**
* Column used to support history and 'As of' queries. This column is a timestamp range
* or equivalent.
*/
private String asOfSysPeriod = "sys_period";
/**
* Use for transaction scoped batch mode.
*/
@@ -219,7 +243,12 @@ public class ServerConfig {
* Behaviour of update to include on the change properties.
*/
private boolean updateChangesOnly = true;
/**
* Behaviour of updates in JDBC batch to by default include all properties.
*/
private boolean updateAllPropertiesInBatch = true;
/**
* Default behaviour for updates when cascade save on a O2M or M2M to delete any missing children.
*/
@@ -231,6 +260,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>();
@@ -292,6 +322,12 @@ public class ServerConfig {
private int queryCacheMaxIdleTime = 600;
private int queryCacheMaxTimeToLive = 60*60*6;
private Object objectMapper;
private boolean diffFlatMode;
/**
* Set to true if you want eq("someProperty", null) to generate 1=1 rather than "is null" sql expression.
*/
private boolean expressionEqualsWithNullAsNoop;
/**
* Construct a Server Configuration for programmatically creating an EbeanServer.
@@ -303,7 +339,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;
@@ -312,7 +348,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;
@@ -332,6 +368,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.
*/
@@ -410,6 +463,22 @@ public class ServerConfig {
this.defaultServer = defaultServer;
}
/**
* Return the CurrentUserProvider. This is used to populate @WhoCreated, @WhoModified and
* support other audit features (who executed a query etc).
*/
public CurrentUserProvider getCurrentUserProvider() {
return currentUserProvider;
}
/**
* Set the CurrentUserProvider. This is used to populate @WhoCreated, @WhoModified and
* support other audit features (who executed a query etc).
*/
public void setCurrentUserProvider(CurrentUserProvider currentUserProvider) {
this.currentUserProvider = currentUserProvider;
}
/**
* Return the PersistBatch mode to use by default at the transaction level.
* <p>
@@ -555,6 +624,38 @@ public class ServerConfig {
this.databaseSequenceBatchSize = databaseSequenceBatchSize;
}
/**
* Return the suffix appended to the base table to derive the view that contains the union
* of the base table and the history table in order to support asOf queries.
*/
public String getAsOfViewSuffix() {
return asOfViewSuffix;
}
/**
* Set the suffix appended to the base table to derive the view that contains the union
* of the base table and the history table in order to support asOf queries.
*/
public void setAsOfViewSuffix(String asOfViewSuffix) {
this.asOfViewSuffix = asOfViewSuffix;
}
/**
* Return the database column used to support history and 'As of' queries. This column is a timestamp range
* or equivalent.
*/
public String getAsOfSysPeriod() {
return asOfSysPeriod;
}
/**
* Set the database column used to support history and 'As of' queries. This column is a timestamp range
* or equivalent.
*/
public void setAsOfSysPeriod(String asOfSysPeriod) {
this.asOfSysPeriod = asOfSysPeriod;
}
/**
* Return true if we are running in a JTA Transaction manager.
*/
@@ -1425,7 +1526,26 @@ public class ServerConfig {
public void setUpdateChangesOnly(boolean updateChangesOnly) {
this.updateChangesOnly = updateChangesOnly;
}
/**
* Returns true if updates in JDBC batch default to include all properties by default.
*/
public boolean isUpdateAllPropertiesInBatch() {
return updateAllPropertiesInBatch;
}
/**
* Set to false if by default updates in JDBC batch should not include all properties.
* <p>
* This mode can be explicitly set per transaction.
* </p>
*
* @see com.avaje.ebean.Transaction#setUpdateAllLoadedProperties(boolean)
*/
public void setUpdateAllPropertiesInBatch(boolean updateAllPropertiesInBatch) {
this.updateAllPropertiesInBatch = updateAllPropertiesInBatch;
}
/**
* Return true if updates by default delete missing children when cascading save to a OneToMany or
* ManyToMany. When not set this defaults to true.
@@ -1540,6 +1660,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.
*/
@@ -1736,6 +1864,7 @@ public class ServerConfig {
autoCommitMode = p.getBoolean("autoCommitMode", autoCommitMode);
useJtaTransactionManager = p.getBoolean("useJtaTransactionManager", useJtaTransactionManager);
currentUserProvider = createInstance(p, CurrentUserProvider.class, "currentUserProvider");
disableClasspathSearch = p.getBoolean("disableClasspathSearch", disableClasspathSearch);
databasePlatform = createInstance(p, DatabasePlatform.class, "databasePlatform");
encryptKeyManager = createInstance(p, EncryptKeyManager.class, "encryptKeyManager");
@@ -1760,6 +1889,7 @@ public class ServerConfig {
collectQueryStatsByNode = p.getBoolean("collectQueryStatsByNode", collectQueryStatsByNode);
collectQueryOrigins = p.getBoolean("collectQueryOrigins", collectQueryOrigins);
updateAllPropertiesInBatch = p.getBoolean("updateAllPropertiesInBatch", updateAllPropertiesInBatch);
updateChangesOnly = p.getBoolean("updateChangesOnly", updateChangesOnly);
boolean defaultDeleteMissingChildren = p.getBoolean("defaultDeleteMissingChildren", updatesDeleteMissingChildren);
@@ -1775,8 +1905,12 @@ 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"));
expressionEqualsWithNullAsNoop = p.getBoolean("expressionEqualsWithNullAsNoop", expressionEqualsWithNullAsNoop);
diffFlatMode = p.getBoolean("diffFlatMode", diffFlatMode);
asOfViewSuffix = p.get("asOfViewSuffix", asOfViewSuffix);
asOfSysPeriod = p.get("asOfSysPeriod", asOfSysPeriod);
dataSourceJndiName = p.get("dataSourceJndiName", dataSourceJndiName);
databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize);
databaseBooleanTrue = p.get("databaseBooleanTrue", databaseBooleanTrue);
@@ -1788,6 +1922,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);
@@ -1819,8 +1954,7 @@ public class ServerConfig {
String classNames = properties.get("classes", null);
if (classNames == null) {
return null;
return classes;
}
List<Class<?>> classes = new ArrayList<Class<?>>();
@@ -1866,11 +2000,58 @@ public class ServerConfig {
return databasePlatform.isDisallowBatchOnCascade() ? PersistBatch.NONE : persistBatchOnCascade;
}
/**
* Return the Jackson ObjectMapper.
* <p>
* Note that this is not strongly typed as Jackson ObjectMapper is an optional dependency.
* </p>
*/
public Object getObjectMapper() {
return objectMapper;
}
/**
* Set the Jackson ObjectMapper.
* <p>
* Note that this is not strongly typed as Jackson ObjectMapper is an optional dependency.
* </p>
*/
public void setObjectMapper(Object objectMapper) {
this.objectMapper = objectMapper;
}
/**
* Return true if diff should return flat properties with dot notation rather than
* embedded beans or reference beans (when the associated bean id is different).
*/
public boolean isDiffFlatMode() {
return diffFlatMode;
}
/**
* Set to true if diff should return flat properties with dot notation rather than
* embedded beans or reference beans (when the associated bean id is different).
*/
public void setDiffFlatMode(boolean diffFlatMode) {
this.diffFlatMode = diffFlatMode;
}
/**
* Return true if eq("someProperty", null) should to generate "1=1" rather than "is null" sql expression.
*/
public boolean isExpressionEqualsWithNullAsNoop() {
return expressionEqualsWithNullAsNoop;
}
/**
* Set to true if you want eq("someProperty", null) to generate "1=1" rather than "is null" sql expression.
* <p>
* Setting this to true has the effect that eq(propertyName, value), ieq(propertyName, value) and
* ne(propertyName, value) have no effect when the value is null. The expression factory adds a NoopExpression
* which will add "1=1" into the SQL rather than "is null".
* </p>
*/
public void setExpressionEqualsWithNullAsNoop(boolean expressionEqualsWithNullAsNoop) {
this.expressionEqualsWithNullAsNoop = expressionEqualsWithNullAsNoop;
}
}
@@ -80,6 +80,11 @@ public class DatabasePlatform {
*/
protected DbIdentity dbIdentity = new DbIdentity();
/**
* The history support for this database platform.
*/
protected DbHistorySupport historySupport;
/**
* The JDBC type to map booleans to (by default).
*/
@@ -215,6 +220,20 @@ public class DatabasePlatform {
this.dbEncrypt = dbEncrypt;
}
/**
* Return the history support for this database platform.
*/
public DbHistorySupport getHistorySupport() {
return historySupport;
}
/**
* Set the history support for this database platform.
*/
public void setHistorySupport(DbHistorySupport historySupport) {
this.historySupport = historySupport;
}
/**
* Return the mapping of JDBC to DB types.
*
@@ -0,0 +1,33 @@
package com.avaje.ebean.config.dbplatform;
/**
* History support for the database platform.
*/
public interface DbHistorySupport {
/**
* Return the 'as of' predicate added for the given table alias.
*
* @param tableAlias The table alias this predicate is added for
* @param sysPeriod The name of the 'sys_period' column used for effective date time range.
* @return The predicate containing a single ? bind parameter which will be bound to the 'as at' timestamp value
*/
String getAsOfPredicate(String tableAlias, String sysPeriod);
/**
* Return the column for the system period lower bound that will be included in findVersions() queries.
*
* @param tableAlias the table alias which will typically be 't0'
* @param sysPeriod the name of the sys_period column
*/
String getSysPeriodLower(String tableAlias, String sysPeriod);
/**
* Return the column for the system period upper bound that will be included in findVersions() queries.
*
* @param tableAlias the table alias which will typically be 't0'
* @param sysPeriod the name of the sys_period column
*/
String getSysPeriodUpper(String tableAlias, String sysPeriod);
}
@@ -21,6 +21,7 @@ public class Postgres8Platform extends DatabasePlatform {
this.clobDbType = Types.VARCHAR;
this.dbEncrypt = new PostgresDbEncrypt();
this.historySupport = new PostgresHistorySupport();
this.dbIdentity.setSupportsGetGeneratedKeys(false);
this.dbIdentity.setIdType(IdType.SEQUENCE);
@@ -47,15 +48,13 @@ public class Postgres8Platform extends DatabasePlatform {
dbDdlSyntax.setDropTableCascade("cascade");
dbDdlSyntax.setDropIfExists("if exists");
}
/**
* Create a Postgres specific sequence IdGenerator.
*/
@Override
public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds,
String seqName, int batchSize) {
public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) {
return new PostgresSequenceIdGenerator(be, ds, seqName, batchSize);
}
@@ -0,0 +1,33 @@
package com.avaje.ebean.config.dbplatform;
/**
* Postgres support for history features.
*/
public class PostgresHistorySupport implements DbHistorySupport {
/**
* Build and return the 'as of' predicate for a given table alias.
* <p>
* Each @History entity involved in the query has this predicate added using the related table alias.
* </p>
*/
@Override
public String getAsOfPredicate(String asOfTableAlias, String asOfSysPeriod) {
// for Postgres we are using the 'timestamp with timezone range' data type
// as our sys_period column so hence the predicate below
StringBuilder sb = new StringBuilder(40);
sb.append(asOfTableAlias).append(".").append(asOfSysPeriod).append(" @> ?::timestamptz");
return sb.toString();
}
@Override
public String getSysPeriodLower(String tableAlias, String sysPeriod) {
return "lower("+tableAlias+"."+sysPeriod+")";
}
@Override
public String getSysPeriodUpper(String tableAlias, String sysPeriod) {
return "upper("+tableAlias+"."+sysPeriod+")";
}
}
@@ -27,6 +27,7 @@ public class PostgresPlatform extends DatabasePlatform {
this.clobDbType = Types.VARCHAR;
this.dbEncrypt = new PostgresDbEncrypt();
this.historySupport = new PostgresHistorySupport();
// Use Identity and getGeneratedKeys
this.dbIdentity.setIdType(IdType.IDENTITY);
@@ -57,15 +58,14 @@ public class PostgresPlatform extends DatabasePlatform {
dbDdlSyntax.setDropTableCascade("cascade");
dbDdlSyntax.setDropIfExists("if exists");
}
/**
* Create a Postgres specific sequence IdGenerator.
*/
@Override
public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds,
String seqName, int batchSize) {
public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) {
return new PostgresSequenceIdGenerator(be, ds, seqName, batchSize);
}
@@ -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);
}
@@ -163,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;
@@ -173,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;
@@ -182,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;
@@ -15,6 +15,8 @@ public class JsonReadOptions {
protected Map<String, JsonReadBeanVisitor<?>> visitorMap;
protected Object objectMapper;
/**
* Default constructor.
*/
@@ -44,4 +46,17 @@ public class JsonReadOptions {
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;
}
}
@@ -0,0 +1,46 @@
package com.avaje.ebeaninternal.api;
import com.avaje.ebeaninternal.server.util.ClassPathSearchFilter;
import com.avaje.ebeaninternal.server.util.ClassPathSearchMatcher;
import java.io.IOException;
import java.util.List;
import java.util.Set;
/**
* This interface allows us to have more than one ClassPathSearch
* to scan the resources by a customized way.
*
* @author Kefeng Deng (deng@51any.com)
*/
public interface ClassPathSearchService {
/**
* Initialize this ClassPathSearchService with given parameters
*
* @param classLoader is current classLoader
* @param filter is filter
* @param matcher
* @param classPathReaderClassName
*/
void init(ClassLoader classLoader, ClassPathSearchFilter filter, ClassPathSearchMatcher matcher, String classPathReaderClassName);
/**
* Searches the class path for all matching classes.
*
* @return a collection of all matching classes
* @throws IOException if a resource is un-reachable
*/
List<Class<?>> findClasses() throws IOException;
/**
* Return the set of jars that contained classes that matched.
*/
Set<String> getJarHits();
/**
* Return the set of packages that contained classes that matched.
*/
Set<String> getPackageHits();
}
@@ -6,88 +6,108 @@ 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 javax validation annotations like Size and NotNull are present.
*/
public static boolean isJavaxValidationAnnotationsPresent() {
return isPresent("javax.validation.constraints.NotNull", null);
}
/**
* 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);
}
@@ -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);
}
@@ -152,6 +152,16 @@ public class ScopedTransaction implements SpiTransaction {
transaction.setPersistCascade(persistCascade);
}
@Override
public void setUpdateAllLoadedProperties(boolean updateAllLoaded) {
transaction.setUpdateAllLoadedProperties(updateAllLoaded);
}
@Override
public Boolean isUpdateAllLoadedProperties() {
return transaction.isUpdateAllLoadedProperties();
}
@Override
public void setBatchMode(boolean useBatch) {
transaction.setBatchMode(useBatch);
@@ -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,27 @@ 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 true if updates in JDBC batch should include all columns if unspecified on the transaction.
*/
boolean isUpdateAllPropertiesInBatch();
/**
* 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 +54,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 +63,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 +113,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 +121,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 +167,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();
}
@@ -1,15 +1,12 @@
package com.avaje.ebeaninternal.api;
import java.util.ArrayList;
import java.util.List;
import com.avaje.ebean.EbeanServer;
import com.avaje.ebean.ExpressionList;
import com.avaje.ebean.OrderBy;
import com.avaje.ebean.PersistenceContextScope;
import com.avaje.ebean.Query;
import com.avaje.ebean.bean.BeanCollectionTouched;
import com.avaje.ebean.bean.CallStack;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.bean.ObjectGraphNode;
import com.avaje.ebean.bean.PersistenceContext;
import com.avaje.ebean.event.BeanQueryRequest;
@@ -22,6 +19,9 @@ import com.avaje.ebeaninternal.server.querydefn.NaturalKeyBindParam;
import com.avaje.ebeaninternal.server.querydefn.OrmQueryDetail;
import com.avaje.ebeaninternal.server.querydefn.OrmQueryProperties;
import java.sql.Timestamp;
import java.util.List;
/**
* Object Relational query - Internal extension to Query object.
*/
@@ -87,6 +87,30 @@ public interface SpiQuery<T> extends Query<T> {
SUBQUERY
}
enum TemporalMode {
/**
* Query runs against current data (normal).
*/
CURRENT,
/**
* Query runs potentially returning many versions of the same bean.
*/
VERSIONS,
/**
* Query runs 'As Of' a given date time.
*/
AS_OF;
/**
* Return the mode of the query of if null return CURRENT mode.
*/
public static TemporalMode of(SpiQuery<?> query) {
return (query != null) ? query.getTemporalMode() : TemporalMode.CURRENT;
}
}
/**
* Return the PersistenceContextScope that this query should use.
* <p>
@@ -116,6 +140,31 @@ public interface SpiQuery<T> extends Query<T> {
*/
Mode getMode();
/**
* Return the Temporal mode for the query.
*/
TemporalMode getTemporalMode();
/**
* Return true if this is a 'As Of' query.
*/
boolean isAsOfQuery();
/**
* Return the asOf Timestamp which the query should run as.
*/
Timestamp getAsOf();
/**
* Add a table alias for a @History entity involved in a 'As Of' query.
*/
void addAsOfTableAlias(String tableAlias);
/**
* Return the list of table alias involved in a 'As Of' query that have @History support.
*/
List<String> getAsOfTableAlias();
/**
* Return a listener that wants to be notified when the bean collection is
* first used.
@@ -148,6 +197,11 @@ public interface SpiQuery<T> extends Query<T> {
*/
SpiQuery<T> copy();
/**
* Return a copy of the query attaching to a different EbeanServer.
*/
SpiQuery<T> copy(EbeanServer server);
/**
* Return the type of query (List, Set, Map, Bean, rowCount etc).
*/
@@ -171,18 +225,13 @@ public interface SpiQuery<T> extends Query<T> {
/**
* This becomes a lazy loading query for a many relationship.
*/
void setLazyLoadForParents(List<Object> parentIds, BeanPropertyAssocMany<?> many);
void setLazyLoadForParents(BeanPropertyAssocMany<?> many);
/**
* Return the lazy loading 'many' property.
*/
BeanPropertyAssocMany<?> getLazyLoadForParentsProperty();
/**
* Return the list of parent Id's for lazy loading.
*/
List<Object> getLazyLoadForParentIds();
/**
* Set the load mode (+lazy or +query) and the load description.
*/
@@ -203,11 +252,6 @@ public interface SpiQuery<T> extends Query<T> {
*/
ManyWhereJoins getManyWhereJoins();
/**
* Convert this natural key query into a find by id query.
*/
void convertWhereNaturalKeyToId(Object idValue);
/**
* Return a Natural Key bind parameter if supported by this query.
*/
@@ -341,11 +385,6 @@ public interface SpiQuery<T> extends Query<T> {
*/
String getLazyLoadProperty();
/**
* Return the lazy load path.
*/
String getLazyLoadManyPath();
/**
* Used to hook back a lazy loading query to the original query (query
* point).
@@ -476,27 +515,11 @@ public interface SpiQuery<T> extends Query<T> {
*/
Boolean isReadOnly();
/**
* Adds this bean to the persistence context prior to executing the query.
*/
void contextAdd(EntityBean bean);
/**
* Return the type of beans queries.
*/
Class<T> getBeanType();
/**
* Return the query timeout.
*/
int getTimeout();
/**
* Return the objects that should be added to the persistence context prior
* to executing the query.
*/
ArrayList<EntityBean> getContextAdditions();
/**
* Return the bind parameters.
*/
@@ -553,9 +576,14 @@ public interface SpiQuery<T> extends Query<T> {
*/
int getFirstRow();
/**
* Return true if lazy loading has been disabled on the query.
*/
boolean isDisableLazyLoading();
/**
* Internally set by Ebean when this query must use the DISTINCT keyword.
* <p/>
* <p>
* This does not exclude/remove the use of the id property.
*/
Query<T> setSqlDistinct(boolean sqlDistinct);
@@ -580,11 +608,6 @@ public interface SpiQuery<T> extends Query<T> {
*/
String getRawWhereClause();
/**
* Return the Id value.
*/
Object getId();
/**
* Set the generated sql for debug purposes.
*/
@@ -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,19 @@ 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 true if this transaction has updateAllLoadedProperties set.
* If null is returned the server default is used (set on ServerConfig).
*/
Boolean isUpdateAllLoadedProperties();
/**
* Return the batchSize specifically set for this transaction or 0.
@@ -105,7 +111,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 +125,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 +146,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 +178,7 @@ public interface SpiTransaction extends Transaction {
* behaviour.
* </p>
*/
public PersistenceContext getPersistenceContext();
PersistenceContext getPersistenceContext();
/**
* Set the persistence context to this transaction.
@@ -185,47 +191,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();
}
@@ -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();
}
}
}
@@ -1,109 +1,128 @@
package com.avaje.ebeaninternal.server.core;
import com.avaje.ebeaninternal.server.util.ClassPathSearch;
import com.avaje.ebeaninternal.api.ClassPathSearchService;
import com.avaje.ebeaninternal.server.util.ClassPathSearchFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Set;
import java.util.*;
/**
* Searches for interesting classes such as Entities, Embedded and ScalarTypes.
*/
public class BootupClassPathSearch {
private static final Logger logger = LoggerFactory.getLogger(BootupClassPathSearch.class);
private static final Logger logger = LoggerFactory.getLogger(BootupClassPathSearch.class);
private final Object monitor = new Object();
private final Object monitor = new Object();
private final ClassLoader classLoader;
private final ClassLoader classLoader;
private final List<String> packages;
private final List<String> packages;
private final List<String> jars;
private BootupClasses bootupClasses;
private List<ClassPathSearchService> classPathSearchServices;
private BootupClasses bootupClasses;
private final String classPathReaderClassName;
/**
* Construct and search for interesting classes.
*/
public BootupClassPathSearch(ClassLoader classLoader, List<String> packages, List<String> jars, String classPathReaderClassName) {
this.classLoader = (classLoader == null) ? getClass().getClassLoader() : classLoader;
this.packages = packages;
this.jars = jars;
/**
* Construct and search for interesting classes.
*/
public BootupClassPathSearch(ClassLoader classLoader, List<String> packages, List<String> jars, String classPathReaderClassName) {
this.classLoader = (classLoader == null) ? getClass().getClassLoader() : classLoader;
this.packages = packages;
this.jars = jars;
this.classPathReaderClassName = classPathReaderClassName;
}
public BootupClasses getBootupClasses() {
synchronized (monitor) {
if (bootupClasses == null){
bootupClasses = search();
}
return bootupClasses;
}
}
loadAndInitializeClassPathSearchServices();
}
/**
* Search the classPath for the classes we are interested in.
*/
private BootupClasses search() {
synchronized (monitor) {
try {
BootupClasses bc = new BootupClasses();
public BootupClasses getBootupClasses() {
synchronized (monitor) {
long st = System.currentTimeMillis();
if (bootupClasses == null) {
bootupClasses = search();
}
ClassPathSearchFilter filter = createFilter();
return bootupClasses;
}
}
ClassPathSearch finder = new ClassPathSearch(classLoader, filter, bc, classPathReaderClassName);
/**
* Search the classPath for the classes we are interested in.
*/
private BootupClasses search() {
synchronized (monitor) {
try {
finder.findClasses();
Set<String> jars = finder.getJarHits();
Set<String> pkgs = finder.getPackageHits();
BootupClasses bc = new BootupClasses();
long searchTime = System.currentTimeMillis() - st;
long st = System.currentTimeMillis();
String msg = "Classpath search hits in jars" + jars + " pkgs" + pkgs + " searchTime[" + searchTime+ "]";
logger.info(msg);
ClassPathSearchFilter filter = createFilter();
return bc;
Set<String> foundJars = new HashSet<String>();
Set<String> foundPkgs = new HashSet<String>();
} catch (Exception ex) {
String msg = "Error in classpath search (looking for entities etc)";
throw new RuntimeException(msg, ex);
}
}
}
private ClassPathSearchFilter createFilter() {
ClassPathSearchFilter filter = new ClassPathSearchFilter();
filter.addDefaultExcludePackages();
if (packages != null && packages.size() > 0) {
for (String packageName : packages) {
filter.includePackage(packageName);
}
// if they specified include packages, they don't want by default to include everything
filter.setDefaultPackageMatch(false);
for (ClassPathSearchService finder : this.classPathSearchServices) {
finder.init(classLoader, filter, bc, classPathReaderClassName);
finder.findClasses();
foundJars.addAll(finder.getJarHits());
foundPkgs.addAll(finder.getPackageHits());
}
if (jars != null && jars.size() > 0) {
for (String jarName : jars) {
filter.includeJar(jarName);
}
long searchTime = System.currentTimeMillis() - st;
// if they specified jars to specifically include, they don't want everything included
filter.setDefaultJarMatch(false);
}
logger.info("Classpath search hits in jars {} pkgs {} searchTime [{}]", foundJars, foundPkgs, searchTime);
return bc;
} catch (Exception ex) {
String msg = "Error in classpath search (looking for entities etc)";
throw new RuntimeException(msg, ex);
}
}
}
private ClassPathSearchFilter createFilter() {
ClassPathSearchFilter filter = new ClassPathSearchFilter();
filter.addDefaultExcludePackages();
if (packages != null && packages.size() > 0) {
for (String packageName : packages) {
filter.includePackage(packageName);
}
// if they specified include packages, they don't want by default to include everything
filter.setDefaultPackageMatch(false);
}
if (jars != null && jars.size() > 0) {
for (String jarName : jars) {
filter.includeJar(jarName);
}
// if they specified jars to specifically include, they don't want everything included
filter.setDefaultJarMatch(false);
}
return filter;
}
/**
* Load and initialize all ClassPathSearchServices
*/
private void loadAndInitializeClassPathSearchServices() {
if (this.classPathSearchServices == null) {
this.classPathSearchServices = new ArrayList<ClassPathSearchService>();
}
for (ClassPathSearchService searchService : ServiceLoader.load(ClassPathSearchService.class, classLoader)) {
this.classPathSearchServices.add(searchService);
}
}
return filter;
}
}
@@ -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();
}
@@ -121,7 +121,7 @@ public class DefaultBeanLoader {
query.where().raw(ew);
}
query.setLazyLoadForParents(idList, many);
query.setLazyLoadForParents(many);
many.addWhereParentIdIn(query, idList);
query.setPersistenceContext(pc);
@@ -70,5 +70,9 @@ public class DefaultBeanState implements BeanState {
public void setLoaded() {
intercept.setLoaded();
}
@Override
public void setDisableLazyLoad(boolean disableLazyLoading) {
intercept.setDisableLazyLoad(disableLazyLoading);
}
}
@@ -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());
@@ -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;
@@ -87,7 +88,7 @@ public final class DefaultServer implements SpiEbeanServer {
private final BeanDescriptorManager beanDescriptorManager;
private final DiffHelp diffHelp = new DiffHelp();
private final DiffHelp diffHelp;
private final AutoFetchManager autoFetchManager;
@@ -147,6 +148,8 @@ public final class DefaultServer implements SpiEbeanServer {
*/
private List<SpiEbeanPlugin> ebeanPlugins;
private final boolean updateAllPropertiesInBatch;
private final boolean collectQueryOrigins;
private final boolean collectQueryStatsByNode;
@@ -170,6 +173,7 @@ public final class DefaultServer implements SpiEbeanServer {
this.backgroundExecutor = config.getBackgroundExecutor();
this.serverName = serverConfig.getName();
this.diffHelp = new DiffHelp(serverConfig.isDiffFlatMode());
this.lazyLoadBatchSize = serverConfig.getLazyLoadBatchSize();
this.queryBatchSize = serverConfig.getQueryBatchSize();
this.cqueryEngine = config.getCQueryEngine();
@@ -180,6 +184,7 @@ public final class DefaultServer implements SpiEbeanServer {
this.beanDescriptorManager = config.getBeanDescriptorManager();
beanDescriptorManager.setEbeanServer(this);
this.updateAllPropertiesInBatch = serverConfig.isUpdateAllPropertiesInBatch();
this.collectQueryOrigins = serverConfig.isCollectQueryOrigins();
this.collectQueryStatsByNode = serverConfig.isCollectQueryStatsByNode();
this.maxCallStack = serverConfig.getMaxCallStack();
@@ -198,19 +203,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 +228,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);
}
}
@@ -243,6 +255,11 @@ public final class DefaultServer implements SpiEbeanServer {
return collectQueryOrigins;
}
@Override
public boolean isUpdateAllPropertiesInBatch() {
return updateAllPropertiesInBatch;
}
public int getLazyLoadBatchSize() {
return lazyLoadBatchSize;
}
@@ -1155,16 +1172,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,15 +1332,6 @@ 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.ITERATE, 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.ITERATE, query, t);
@@ -1357,6 +1364,19 @@ public final class DefaultServer implements SpiEbeanServer {
}
}
@Override
public <T> List<Version<T>> findVersions(Query<T> query, Transaction transaction) {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.LIST, query, transaction);
try {
request.initTransIfRequired();
return request.findVersions();
} finally {
request.endTransIfRequired();
}
}
@SuppressWarnings("unchecked")
public <T> List<T> findList(Query<T> query, Transaction t) {
@@ -1492,17 +1512,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 +1558,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 +1680,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 +1736,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 +1771,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 +1995,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) {
@@ -18,7 +18,12 @@ import com.avaje.ebeaninternal.util.ValueUtil;
*/
public class DiffHelp {
private final boolean flatMode;
public DiffHelp(boolean flatMode) {
this.flatMode = flatMode;
}
/**
* Return a map of the differences between a and b.
* <p>
@@ -29,45 +34,45 @@ public class DiffHelp {
* This intentionally does not include as OneToMany or ManyToMany properties.
* </p>
*/
public Map<String, ValuePair> diff(Object a, Object b, BeanDescriptor<?> desc) {
public Map<String, ValuePair> diff(Object newBean, Object oldBean, BeanDescriptor<?> desc) {
if (a instanceof EntityBean == false) {
throw new IllegalArgumentException("First bean expected to be an enhanced EntityBean? bean:"+a);
if (!(newBean instanceof EntityBean)) {
throw new IllegalArgumentException("First bean expected to be an enhanced EntityBean? bean:"+newBean);
}
if (b != null) {
if (b instanceof EntityBean == false) {
throw new IllegalArgumentException("Second bean expected to be an enhanced EntityBean? bean:"+b);
if (oldBean != null) {
if (!(oldBean instanceof EntityBean)) {
throw new IllegalArgumentException("Second bean expected to be an enhanced EntityBean? bean:"+oldBean);
}
if (!a.getClass().isAssignableFrom(b.getClass())) {
if (!newBean.getClass().isAssignableFrom(oldBean.getClass())) {
throw new IllegalArgumentException("Second bean not assignable to the first bean?");
}
}
if (b == null) {
return ((EntityBean) a)._ebean_getIntercept().getDirtyValues();
if (oldBean == null) {
return ((EntityBean) newBean)._ebean_getIntercept().getDirtyValues();
}
Map<String, ValuePair> map = new LinkedHashMap<String, ValuePair>();
diff(null, map, (EntityBean)a, (EntityBean)b, desc);
diff(null, map, (EntityBean) newBean, (EntityBean) oldBean, desc);
return map;
}
public void diff(String prefix, Map<String, ValuePair> map, EntityBean first, EntityBean sec, BeanDescriptor<?> desc) {
public void diff(String prefix, Map<String, ValuePair> map, EntityBean newBean, EntityBean oldBean, BeanDescriptor<?> desc) {
// check the simple properties
BeanProperty[] base = desc.propertiesBaseScalar();
for (int i = 0; i < base.length; i++) {
Object aval = base[i].getValue(first);
Object bval = base[i].getValue(sec);
if (!ValueUtil.areEqual(aval, bval)) {
Object newVal = (newBean == null) ? null : base[i].getValue(newBean);
Object oldVal = (oldBean == null) ? null : base[i].getValue(oldBean);
if (!ValueUtil.areEqual(newVal, oldVal)) {
String propName = (prefix == null) ? base[i].getName() : prefix + base[i].getName();
map.put(propName, new ValuePair(aval, bval));
map.put(propName, new ValuePair(newVal, oldVal));
}
}
diffAssocOne(prefix, first, sec, desc, map);
diffEmbedded(prefix, first, sec, desc, map);
diffAssocOne(prefix, newBean, oldBean, desc, map);
diffEmbedded(prefix, newBean, oldBean, desc, map);
}
/**
@@ -77,24 +82,29 @@ public class DiffHelp {
* determined to be different as is added to the map.
* </p>
*/
private void diffEmbedded(String prefix, EntityBean a, EntityBean b, BeanDescriptor<?> desc, Map<String, ValuePair> map) {
private void diffEmbedded(String prefix, EntityBean newBean, EntityBean oldBean, BeanDescriptor<?> desc, Map<String, ValuePair> map) {
BeanPropertyAssocOne<?>[] emb = desc.propertiesEmbedded();
for (int i = 0; i < emb.length; i++) {
EntityBean aval = (EntityBean)emb[i].getValue(a);
EntityBean bval = (EntityBean)emb[i].getValue(b);
EntityBean newVal = (EntityBean)emb[i].getValue(newBean);
EntityBean oldVal = (EntityBean)emb[i].getValue(oldBean);
if (!isBothNull(aval, bval)) {
if (!isBothNull(newVal, oldVal)) {
String propName = (prefix == null) ? emb[i].getName() : prefix + emb[i].getName();
if (isDiffNull(aval, bval)) {
if (isDiffNull(newVal, oldVal)) {
// one of the embedded beans is null
map.put(propName, new ValuePair(aval, bval));
if (flatMode) {
BeanDescriptor<?> embDesc = emb[i].getTargetDescriptor();
diff(emb[i].getName()+".", map, newVal, oldVal, embDesc);
} else {
map.put(propName, new ValuePair(newVal, oldVal));
}
} else {
// recursively diff into the embedded bean
BeanDescriptor<?> embDesc = emb[i].getTargetDescriptor();
diff(emb[i].getName()+".", map, aval, bval, embDesc);
diff(emb[i].getName()+".", map, newVal, oldVal, embDesc);
}
}
}
@@ -104,45 +114,43 @@ public class DiffHelp {
* If the properties are different by null OR if the id value is different,
* then add the Assoc One bean to the map.
*/
private void diffAssocOne(String prefix, EntityBean a, EntityBean b, BeanDescriptor<?> desc, Map<String, ValuePair> map) {
private void diffAssocOne(String prefix, EntityBean newBean, EntityBean oldBean, BeanDescriptor<?> desc, Map<String, ValuePair> map) {
BeanPropertyAssocOne<?>[] ones = desc.propertiesOne();
for (int i = 0; i < ones.length; i++) {
Object aval = ones[i].getValue(a);
Object bval = ones[i].getValue(b);
Object newVal = ones[i].getValue(newBean);
Object oldVal = ones[i].getValue(oldBean);
if (!isBothNull(aval, bval)) {
String propName = (prefix == null) ? ones[i].getName() : prefix + ones[i].getName();
if (isDiffNull(aval, bval)) {
// one of them is/was null
map.put(propName, new ValuePair(aval, bval));
if (!isBothNull(newVal, oldVal)) {
BeanDescriptor<?> oneDesc = ones[i].getTargetDescriptor();
Object newId = (newVal == null) ? null : oneDesc.getId((EntityBean)newVal);
Object oldId = (oldVal == null) ? null : oneDesc.getId((EntityBean)oldVal);
} else {
// check to see if the Id properties
// are different
BeanDescriptor<?> oneDesc = ones[i].getTargetDescriptor();
Object aOneId = oneDesc.getId((EntityBean)aval);
Object bOneId = oneDesc.getId((EntityBean)bval);
if (!ValueUtil.areEqual(newId, oldId)) {
String propName = (prefix == null) ? ones[i].getName() : prefix + ones[i].getName();
// the ids are different
if (flatMode) {
String idName = oneDesc.getIdProperty().getName();
map.put(propName + "." + idName, new ValuePair(newId, oldId));
if (!ValueUtil.areEqual(aOneId, bOneId)) {
// the ids are different
map.put(propName, new ValuePair(aval, bval));
}
}
}
} else {
map.put(propName, new ValuePair(newVal, oldVal));
}
}
}
}
}
private boolean isBothNull(Object aval, Object bval) {
return aval == null && bval == null;
private boolean isBothNull(Object newVal, Object oldVal) {
return newVal == null && oldVal == null;
}
private boolean isDiffNull(Object aval, Object bval) {
if (aval == null) {
return bval != null;
private boolean isDiffNull(Object newVal, Object oldVal) {
if (newVal == null) {
return oldVal != null;
} else {
return bval == null;
return oldVal == null;
}
}
}
@@ -2,6 +2,7 @@ package com.avaje.ebeaninternal.server.core;
import javax.sql.DataSource;
import com.avaje.ebeaninternal.server.deploy.generatedproperty.GeneratedPropertyFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -41,6 +42,8 @@ import com.avaje.ebeaninternal.server.type.DefaultTypeManager;
import com.avaje.ebeaninternal.server.type.TypeManager;
import com.fasterxml.jackson.core.JsonFactory;
import java.util.Map;
/**
* Used to extend the ServerConfig with additional objects used to configure and
* construct an EbeanServer.
@@ -90,7 +93,7 @@ public class InternalConfiguration {
private final XmlConfig xmlConfig;
private final JsonFactory jsonFactory;
public InternalConfiguration(XmlConfig xmlConfig, ClusterManager clusterManager,
ServerCacheManager cacheManager, SpiBackgroundExecutor backgroundExecutor,
ServerConfig serverConfig, BootupClasses bootupClasses, PstmtBatch pstmtBatch) {
@@ -103,7 +106,7 @@ public class InternalConfiguration {
this.cacheManager = cacheManager;
this.serverConfig = serverConfig;
this.bootupClasses = bootupClasses;
this.expressionFactory = new DefaultExpressionFactory();
this.expressionFactory = new DefaultExpressionFactory(serverConfig.isExpressionEqualsWithNullAsNoop());
this.typeManager = new DefaultTypeManager(serverConfig, bootupClasses);
this.binder = new Binder(typeManager);
@@ -116,11 +119,11 @@ public class InternalConfiguration {
this.deployUtil = new DeployUtil(typeManager, serverConfig);
this.beanDescriptorManager = new BeanDescriptorManager(this);
beanDescriptorManager.deploy();
Map<String, String> asOfTableMapping = beanDescriptorManager.deploy();
this.transactionManager = createTransactionManager();
this.cQueryEngine = new CQueryEngine(serverConfig.getDatabasePlatform(), binder);
this.cQueryEngine = new CQueryEngine(serverConfig.getDatabasePlatform(), binder, asOfTableMapping, serverConfig.getAsOfSysPeriod());
ExternalTransactionManager externalTransactionManager = serverConfig.getExternalTransactionManager();
if (externalTransactionManager == null && serverConfig.isUseJtaTransactionManager()) {
@@ -182,7 +185,7 @@ public class InternalConfiguration {
}
public OrmQueryEngine createOrmQueryEngine() {
return new DefaultOrmQueryEngine(beanDescriptorManager, cQueryEngine);
return new DefaultOrmQueryEngine(cQueryEngine);
}
public Persister createPersister(SpiEbeanServer server) {
@@ -265,4 +268,7 @@ public class InternalConfiguration {
return backgroundExecutor;
}
public GeneratedPropertyFactory getGeneratedPropertyFactory() {
return new GeneratedPropertyFactory(serverConfig.getCurrentUserProvider());
}
}
@@ -1,38 +1,42 @@
package com.avaje.ebeaninternal.server.core;
import com.avaje.ebean.QueryIterator;
import com.avaje.ebean.Version;
import com.avaje.ebean.bean.BeanCollection;
import com.avaje.ebeaninternal.api.BeanIdList;
import java.util.List;
/**
* The Object Relational query execution API.
*/
public interface OrmQueryEngine {
/**
* Execute the 'find by id' query returning a single bean.
*/
public <T> T findId(OrmQueryRequest<T> request);
/**
* Execute the 'find by id' query returning a single bean.
*/
<T> T findId(OrmQueryRequest<T> request);
/**
* Execute the findList, findSet, findMap query returning an appropriate BeanCollection.
*/
public <T> BeanCollection<T> findMany(OrmQueryRequest<T> request);
/**
* Execute the findList, findSet, findMap query returning an appropriate BeanCollection.
*/
<T> BeanCollection<T> findMany(OrmQueryRequest<T> request);
/**
* Execute the query using a QueryIterator.
*/
public <T> QueryIterator<T> findIterate(OrmQueryRequest<T> request);
/**
* Execute the row count query.
*/
public <T> int findRowCount(OrmQueryRequest<T> request);
/**
* Execute the find id's query.
*/
public <T> BeanIdList findIds(OrmQueryRequest<T> request);
<T> List<Version<T>> findVersions(OrmQueryRequest<T> request);
/**
* Execute the query using a QueryIterator.
*/
<T> QueryIterator<T> findIterate(OrmQueryRequest<T> request);
/**
* Execute the row count query.
*/
<T> int findRowCount(OrmQueryRequest<T> request);
/**
* Execute the find id's query.
*/
<T> BeanIdList findIds(OrmQueryRequest<T> request);
}
@@ -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);
}
@@ -284,6 +271,10 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
return (List<T>) queryEngine.findMany(this);
}
public List<Version<T>> findVersions() {
return queryEngine.findVersions(this);
}
/**
* Execute the query as findSet.
*/
@@ -315,7 +306,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;
}
@@ -117,6 +117,11 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
*/
private boolean batchOnCascadeSet;
/**
* Set for updates to determine if all loaded properties are included in the update.
*/
private boolean requestUpdateAllLoadedProps;
public PersistRequestBean(SpiEbeanServer server, T bean, Object parentBean, BeanManager<T> mgr, SpiTransaction t,
PersistExecute persistExecute, PersistRequest.Type type, boolean saveRecurse) {
@@ -544,6 +549,9 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
// if bean persisted again then should result in an update
intercept.setLoaded();
if (isInsert()) {
postInsert();
}
addEvent();
@@ -641,17 +649,21 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
}
/**
* Test if the property value has changed and if so include it in the update.
* Return true if the property should be included in the update.
*/
public boolean isAddToUpdate(BeanProperty prop) {
return intercept.isDirtyProperty(prop.getPropertyIndex());
if (requestUpdateAllLoadedProps) {
return intercept.isLoadedProperty(prop.getPropertyIndex());
} else {
return intercept.isDirtyProperty(prop.getPropertyIndex());
}
}
public List<DerivedRelationshipData> getDerivedRelationships() {
return transaction.getDerivedRelationship(bean);
}
public void postInsert() {
private void postInsert() {
// mark all properties as loaded after an insert to support immediate update
int len = intercept.getPropertyLength();
for (int i = 0; i < len; i++) {
@@ -706,4 +718,24 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
return updatedManysOnly;
}
/**
* Determine if all loaded properties should be used for an update.
* <p>
* Takes into account transaction setting and JDBC batch.
* </p>
*/
public boolean determineUpdateAllLoadedProperties() {
Boolean txnUpdateAll = transaction.isUpdateAllLoadedProperties();
if (txnUpdateAll != null) {
// use the setting explicitly set on the transaction
requestUpdateAllLoadedProps = txnUpdateAll;
} else {
// if using batch use the server default setting
requestUpdateAllLoadedProps = isBatchThisRequest() && ebeanServer.isUpdateAllPropertiesInBatch();
}
return requestUpdateAllLoadedProps;
}
}
@@ -1,115 +1,110 @@
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.Version;
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 finVersions() query.
*/
List<Version<T>> findVersions();
/**
* Execute the query as findMap.
*/
public Map<?, ?> findMap();
/**
* Execute the query as findList.
*/
List<T> findList();
/**
* Try to get the object out of the persistence context.
*/
//public T getFromPersistenceContextOrCache();
/**
* Execute the query as findSet.
*/
Set<?> findSet();
/**
* Try to get the query result from the query cache.
*/
public BeanCollection<T> getFromQueryCache();
/**
* Execute the query as findMap.
*/
Map<?, ?> findMap();
/**
* Return the Database platform like clause.
*/
public String getDBLikeClause();
/**
* Try to get the query result from the query cache.
*/
BeanCollection<T> getFromQueryCache();
/**
* Return the Database platform like clause.
*/
String getDBLikeClause();
}
@@ -10,10 +10,7 @@ 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.*;
@@ -115,6 +112,8 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
* The base database table.
*/
private final String baseTable;
private final String baseTableAsOf;
private final boolean historySupport;
/**
* Map of BeanProperty Linked so as to preserve order.
@@ -153,7 +152,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.
@@ -335,8 +334,9 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
this.updateChangesOnly = deploy.isUpdateChangesOnly();
this.compoundUniqueConstraints = deploy.getCompoundUniqueConstraints();
this.historySupport = deploy.isHistorySupport();
this.baseTable = InternString.intern(deploy.getBaseTable());
this.baseTableAsOf = deploy.getBaseTableAsOf();
this.autoFetchTunable = EntityType.ORM.equals(entityType) && (beanFinder == null);
// helper object used to derive lists of properties
@@ -499,13 +499,19 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
* These properties need to be initialised prior to the association properties
* as they are used to get the imported and exported properties.
* </p>
* @param withHistoryTables map populated if @History is supported on this entity bean
*/
public void initialiseId() {
public void initialiseId(Map<String, String> withHistoryTables) {
if (logger.isTraceEnabled()) {
logger.trace("BeanDescriptor initialise " + fullName);
}
if (historySupport) {
// add mapping (used to swap out baseTable for asOf queries)
withHistoryTables.put(baseTable, baseTableAsOf);
}
if (inheritInfo != null) {
inheritInfo.setDescriptor(this);
}
@@ -525,8 +531,25 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
/**
* Initialise the exported and imported parts for associated properties.
*
* @param asOfTableMap the map of base tables to associated 'with history' tables
* @param asOfViewSuffix the suffix added to the table name to derive the 'with history' view name
*/
public void initialiseOther() {
public void initialiseOther(Map<String, String> asOfTableMap, String asOfViewSuffix) {
if (historySupport) {
// history support on this bean so check all associated intersection tables
// and if they are not excluded register the associated 'with history' table
for (int i = 0; i < propertiesManyToMany.length; i++) {
if (!propertiesManyToMany[i].isExcludedFromHistory()) {
// this intersection table has history support so also register
// it into the asOfTableMap
TableJoin intersectionTableJoin = propertiesManyToMany[i].getIntersectionTableJoin();
String intersectionTableName = intersectionTableJoin.getTable();
asOfTableMap.put(intersectionTableName, intersectionTableName + asOfViewSuffix);
}
}
}
if (!isEmbedded()) {
// initialise all the non-id properties
@@ -634,7 +657,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
}
public boolean calculateUseCache(Boolean queryUseCache) {
return (queryUseCache != null) ? queryUseCache.booleanValue() : isBeanCaching();
return (queryUseCache != null) ? queryUseCache : isBeanCaching();
}
/**
@@ -764,7 +787,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
}
public void cacheBeanPut(T bean) {
cacheBeanPutData((EntityBean)bean);
cacheBeanPutData((EntityBean) bean);
}
/**
@@ -1514,7 +1537,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 +1548,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 +1590,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 +1612,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);
}
}
}
@@ -1613,6 +1654,24 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
return baseTable;
}
/**
* Return the base table to use given the query temporal mode.
*/
public String getBaseTable(SpiQuery.TemporalMode mode) {
switch (mode) {
case VERSIONS: return baseTableAsOf;
case AS_OF: return baseTableAsOf;
default: return baseTable;
}
}
/**
* Return true if this entity bean has history support.
*/
public boolean isHistorySupport() {
return historySupport;
}
/**
* Return the identity generation type.
*/
@@ -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;
}
@@ -10,11 +10,11 @@ import com.avaje.ebean.cache.ServerCacheManager;
import com.avaje.ebean.config.EncryptKey;
import com.avaje.ebean.config.EncryptKeyManager;
import com.avaje.ebean.config.NamingConvention;
import com.avaje.ebean.config.ServerConfig;
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.*;
@@ -52,7 +52,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
private static final BeanDescComparator beanDescComparator = new BeanDescComparator();
private final ReadAnnotations readAnnotations = new ReadAnnotations();
private final ReadAnnotations readAnnotations;
private final TransientProperties transientProperties;
@@ -128,41 +128,51 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
private final boolean eagerFetchLobs;
private final String asOfViewSuffix;
/**
* Map of base tables to 'with history views' used to support 'as of' queries.
*/
private final Map<String,String> asOfTableMap = new HashMap<String, String>();
/**
* Create for a given database dbConfig.
*/
public BeanDescriptorManager(InternalConfiguration config) {
this.serverName = InternString.intern(config.getServerConfig().getName());
ServerConfig serverConfig = config.getServerConfig();
this.serverName = InternString.intern(serverConfig.getName());
this.cacheManager = config.getCacheManager();
this.xmlConfig = config.getXmlConfig();
this.dbSequenceBatchSize = config.getServerConfig().getDatabaseSequenceBatchSize();
this.dbSequenceBatchSize = serverConfig.getDatabaseSequenceBatchSize();
this.backgroundExecutor = config.getBackgroundExecutor();
this.dataSource = config.getServerConfig().getDataSource();
this.encryptKeyManager = config.getServerConfig().getEncryptKeyManager();
this.databasePlatform = config.getServerConfig().getDatabasePlatform();
this.dataSource = serverConfig.getDataSource();
this.encryptKeyManager = serverConfig.getEncryptKeyManager();
this.databasePlatform = serverConfig.getDatabasePlatform();
this.idBinderFactory = new IdBinderFactory(databasePlatform.isIdInExpandedForm());
this.eagerFetchLobs = config.getServerConfig().isEagerFetchLobs();
this.eagerFetchLobs = serverConfig.isEagerFetchLobs();
this.asOfViewSuffix = serverConfig.getAsOfViewSuffix();
this.readAnnotations = new ReadAnnotations(config.getGeneratedPropertyFactory(), asOfViewSuffix);
this.bootupClasses = config.getBootupClasses();
this.createProperties = config.getDeployCreateProperties();
this.typeManager = config.getTypeManager();
this.namingConvention = config.getServerConfig().getNamingConvention();
this.namingConvention = serverConfig.getNamingConvention();
this.dbIdentity = config.getDatabasePlatform().getDbIdentity();
this.deplyInherit = config.getDeployInherit();
this.deployOrmXml = config.getDeployOrmXml();
this.deployUtil = config.getDeployUtil();
this.beanManagerFactory = new BeanManagerFactory(config.getServerConfig(), config.getDatabasePlatform());
this.beanManagerFactory = new BeanManagerFactory(serverConfig, config.getDatabasePlatform());
this.updateChangesOnly = config.getServerConfig().isUpdateChangesOnly();
this.updateChangesOnly = serverConfig.isUpdateChangesOnly();
this.beanLifecycleAdapterFactory = new BeanLifecycleAdapterFactory();
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();
@@ -207,7 +217,10 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
return idBinderFactory.createIdBinder(idProperty);
}
public void deploy() {
/**
* Deploy returning the asOfTableMap (which is required by the SQL builders).
*/
public Map<String,String> deploy() {
try {
createListeners();
@@ -239,6 +252,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
deplyInfoMap.clear();
deplyInfoMap = null;
return asOfTableMap;
} catch (RuntimeException e) {
String msg = "Error in deployment";
logger.error(msg, e);
@@ -326,7 +342,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
// first (as they are needed to initialise the
// associated properties in the second pass).
for (BeanDescriptor<?> d : descMap.values()) {
d.initialiseId();
d.initialiseId(asOfTableMap);
}
// PASS 2:
@@ -338,7 +354,10 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
// PASS 3:
// now initialise all the associated properties
for (BeanDescriptor<?> d : descMap.values()) {
d.initialiseOther();
// also look for intersection tables with
// associated history support and register them
// into the asOfTableMap
d.initialiseOther(asOfTableMap, asOfViewSuffix);
}
// create BeanManager for each non-embedded entity bean
@@ -407,7 +426,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 +454,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 +475,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 +954,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);
}
/**
@@ -982,7 +994,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
if (!EntityType.ORM.equals(desc.getEntityType())) {
// not using base table
desc.setBaseTable(null);
desc.setBaseTable(null, null);
}
// mark transient properties
@@ -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();
}
}
@@ -22,6 +22,8 @@ import com.avaje.ebeaninternal.server.text.json.WriteJson;
import com.avaje.ebeaninternal.server.type.DataBind;
import com.avaje.ebeaninternal.server.type.ScalarType;
import com.fasterxml.jackson.core.JsonToken;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.PersistenceException;
import java.io.DataInput;
@@ -39,6 +41,8 @@ import java.util.Map;
*/
public class BeanProperty implements ElPropertyValue {
private static final Logger logger = LoggerFactory.getLogger(BeanProperty.class);
/**
* Flag to mark this at part of the unique id.
*/
@@ -169,6 +173,8 @@ public class BeanProperty implements ElPropertyValue {
*/
final int dbType;
final boolean excludedFromHistory;
/**
* The default value to insert if null.
*/
@@ -252,6 +258,7 @@ public class BeanProperty implements ElPropertyValue {
this.dbRead = deploy.isDbRead();
this.dbInsertable = deploy.isDbInsertable();
this.dbUpdatable = deploy.isDbUpdateable();
this.excludedFromHistory = deploy.isExcludedFromHistory();
this.secondaryTable = deploy.isSecondaryTable();
if (secondaryTable) {
@@ -299,8 +306,8 @@ public class BeanProperty implements ElPropertyValue {
this.elPlaceHolder = tableAliasIntern(descriptor, deploy.getElPlaceHolder(et), false, null);
this.elPlaceHolderEncrypted = tableAliasIntern(descriptor, deploy.getElPlaceHolder(et), dbEncrypted, dbColumn);
this.jsonSerialize = deploy.isExposeSerialize();
this.jsonDeserialize = deploy.isExposeDeserialize();
this.jsonSerialize = deploy.isJsonSerialize();
this.jsonDeserialize = deploy.isJsonDeserialize();
}
private String tableAliasIntern(BeanDescriptor<?> descriptor, String s, boolean dbEncrypted, String dbColumn) {
@@ -337,6 +344,7 @@ public class BeanProperty implements ElPropertyValue {
this.sqlFormulaSelect = InternString.intern(override.getSqlFormulaSelect());
this.formula = sqlFormulaSelect != null;
this.excludedFromHistory = source.excludedFromHistory;
this.fetchEager = source.fetchEager;
this.unidirectionalShadow = source.unidirectionalShadow;
this.discriminator = source.discriminator;
@@ -533,7 +541,7 @@ public class BeanProperty implements ElPropertyValue {
sqlBeanLoad.load(this);
}
public void buildSelectExpressionChain(String prefix, List<String> selectChain) {
public void buildRawSqlSelectChain(String prefix, List<String> selectChain) {
if (prefix == null) {
selectChain.add(name);
} else {
@@ -1000,6 +1008,13 @@ public class BeanProperty implements ElPropertyValue {
return dbEncryptedType;
}
/**
* Return true if this property is excluded from history.
*/
public boolean isExcludedFromHistory() {
return excludedFromHistory;
}
/**
* Return true if this property should be included in an Insert.
*/
@@ -1070,24 +1085,42 @@ public class BeanProperty implements ElPropertyValue {
}
Object value = getValueIntercept(bean);
if (value == null) {
writeJson.writeNull(name);
writeJson.writeNullField(name);
} else {
scalarType.jsonWrite(writeJson.gen(), name, value);
if (scalarType != null) {
scalarType.jsonWrite(writeJson, name, value);
} else {
writeJson.writeValueUsingObjectMapper(name, value);
}
}
}
public void jsonRead(ReadJson ctx, EntityBean bean) throws IOException {
if (!jsonDeserialize) {
return;
}
JsonToken event = ctx.nextToken();
if (JsonToken.VALUE_NULL == event) {
setValue(bean, null);
if (jsonDeserialize) {
setValue(bean, null);
}
} else {
// expect to read non-null json value
Object objValue = scalarType.jsonRead(ctx.getParser(), event);
setValue(bean, objValue);
Object objValue;
if (scalarType != null) {
objValue = scalarType.jsonRead(ctx.getParser(), event);
} else {
try {
objValue = ctx.readValueUsingObjectMapper(propertyType);
} catch (IOException e) {
// change in behavior for #318
objValue = null;
String msg = "Error trying to use Jackson ObjectMapper to read transient property "
+ getFullBeanName() +" - consider marking this property with @JsonIgnore";
logger.error(msg, e);
}
}
if (jsonDeserialize) {
setValue(bean, objValue);
}
}
}
}
File diff suppressed because it is too large Load Diff
@@ -24,6 +24,7 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* Property mapped to a List Set or Map.
@@ -180,9 +181,27 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
help.add(bc, detailBean);
}
public boolean isEmptyBeanCollection(EntityBean bean) {
/**
* Return true if this is considered 'empty' from a save perspective.
*/
public boolean isEmptyBeanCollection(EntityBean bean, boolean insertedParent) {
Object val = getValue(bean);
return val == null || (val instanceof BeanCollection<?>) && ((BeanCollection<?>) val).isEmptyAndUntouched();
if (val == null) {
return true;
}
if ((val instanceof BeanCollection<?>)) {
return ((BeanCollection<?>) val).isEmptyAndUntouched();
}
if (insertedParent) {
// check 'vanilla' collection types
if (val instanceof Collection<?>){
return ((Collection<?>) val).isEmpty();
}
if (val instanceof Map<?,?>) {
return ((Map<?,?>) val).isEmpty();
}
}
return false;
}
/**
@@ -225,7 +244,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,7 +892,14 @@ 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();
}
@@ -1,23 +1,42 @@
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();
}
/**
* Read the JSON for this property.
*/
public void jsonRead(ReadJson readJson, EntityBean parentBean) throws IOException {
if (!this.many.jsonDeserialize) {
@@ -33,6 +52,11 @@ 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 {
@@ -51,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);
}
}
@@ -0,0 +1,44 @@
package com.avaje.ebeaninternal.server.deploy;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebeaninternal.server.text.json.ReadJson;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.CollectionType;
import com.fasterxml.jackson.databind.type.MapType;
import com.fasterxml.jackson.databind.type.TypeFactory;
import java.io.IOException;
import java.util.LinkedHashMap;
/**
* Helper used to read transient many properties using Jackson ObjectMapper.
*/
public class BeanPropertyAssocManyJsonTransient {
/**
* Use Jackson ObjectMapper to read the transient 'many' property.
*/
public void jsonReadUsingObjectMapper(BeanPropertyAssocMany<?> many, ReadJson readJson, EntityBean parentBean) throws IOException {
ObjectMapper mapper = readJson.getObjectMapper();
ManyType manyType = many.getManyType();
Object value;
if (manyType.isMap()) {
// read map using Jackson object mapper with unknown key type
TypeFactory typeFactory = mapper.getTypeFactory();
JavaType target = typeFactory.constructType(many.getTargetType());
MapType jacksonType = typeFactory.constructMapType(LinkedHashMap.class, typeFactory.unknownType(), target);
value = mapper.readValue(readJson.getParser(), jacksonType);
} else {
// read list or set using Jackson object mapper
CollectionType jacksonType = mapper.getTypeFactory().constructCollectionType(manyType.getCollectionType(), many.getTargetType());
value = mapper.readValue(readJson.getParser(), jacksonType);
}
many.setValue(parentBean, value);
}
}
File diff suppressed because it is too large Load Diff
@@ -171,7 +171,7 @@ public class BeanPropertyCompound extends BeanProperty {
}
Object value = getValueIntercept(bean);
if (value == null) {
ctx.writeNull(name);
ctx.writeNullField(name);
} else {
compoundType.jsonWrite(ctx, value, name);
}
@@ -139,11 +139,13 @@ public final class BeanSetHelp<T> implements BeanCollectionHelp<T> {
set = (Set<?>) collection;
}
ctx.writeStartArray(name);
Iterator<?> it = set.iterator();
while (it.hasNext()) {
targetDescriptor.jsonWrite(ctx, (EntityBean) it.next());
if (!set.isEmpty() || ctx.isIncludeEmpty()) {
ctx.writeStartArray(name);
Iterator<?> it = set.iterator();
while (it.hasNext()) {
targetDescriptor.jsonWrite(ctx, (EntityBean) it.next());
}
ctx.writeEndArray();
}
ctx.writeEndArray();
}
}
@@ -9,6 +9,11 @@ import java.util.Set;
import com.avaje.ebean.event.BeanPersistController;
import com.avaje.ebean.event.BeanPersistRequest;
/**
* Chains multiple BeanPersistController's together.
*
* Used when multiple BeanPersistController register for the same bean type.
*/
public class ChainedBeanPersistController implements BeanPersistController {
private static final Sorter SORTER = new Sorter();
@@ -35,7 +40,6 @@ public class ChainedBeanPersistController implements BeanPersistController {
/**
* Construct given the list of BeanPersistController's.
* @param list
*/
public ChainedBeanPersistController(List<BeanPersistController> list) {
this.list = list;
@@ -43,7 +47,14 @@ public class ChainedBeanPersistController implements BeanPersistController {
Arrays.sort(c, SORTER);
this.chain = c;
}
/**
* Return the size of the chain.
*/
protected int size() {
return chain.length;
}
/**
* Register a new BeanPersistController and return the resulting chain.
*/
@@ -22,6 +22,13 @@ public class ChainedBeanPersistListener implements BeanPersistListener {
this(addList(c1, c2));
}
/**
* Return the size of the chain.
*/
protected int size() {
return chain.length;
}
@Override
public boolean isRegisterFor(Class<?> cls) {
// never called
@@ -40,7 +47,6 @@ public class ChainedBeanPersistListener implements BeanPersistListener {
/**
* Construct given the list of BeanPersistController's.
* @param list
*/
public ChainedBeanPersistListener(List<BeanPersistListener> list) {
this.list = list;
@@ -152,7 +152,7 @@ public class DRawSqlSelect {
}
}
SqlTreeNode sqlRoot = new SqlTreeNodeRoot(desc, selectProps, null, withId);
SqlTreeNode sqlRoot = new SqlTreeNodeRoot(desc, selectProps, withId, false);
return new SqlTree(desc.getName(), sqlRoot);
}
@@ -10,108 +10,114 @@ public interface DbSqlContext {
/**
* Add a join to the sql query.
*/
public void addJoin(String type, String table, TableJoinColumn[] cols, String a1, String a2, String inheritance);
void addJoin(String type, String table, TableJoinColumn[] cols, String a1, String a2, String inheritance);
public void pushSecondaryTableAlias(String alias);
void pushSecondaryTableAlias(String alias);
/**
* Push the current table alias onto the stack.
*/
public void pushTableAlias(String tableAlias);
void pushTableAlias(String tableAlias);
/**
* Pop the current table alias from the stack.
*/
public void popTableAlias();
void popTableAlias();
/**
* Add an encrypted property which will require additional binding.
*/
public void addEncryptedProp(BeanProperty prop);
void addEncryptedProp(BeanProperty prop);
/**
* Return a list of encrypted properties which require additional binding.
*/
public BeanProperty[] getEncryptedProps();
BeanProperty[] getEncryptedProps();
/**
* Append a char directly to the SQL buffer.
*/
public DbSqlContext append(char s);
DbSqlContext append(char s);
/**
* Append a string directly to the SQL buffer.
*/
public DbSqlContext append(String s);
DbSqlContext append(String s);
/**
* Peek the current table alias.
*/
public String peekTableAlias();
String peekTableAlias();
/**
* Add a raw column to the sql.
*/
public void appendRawColumn(String rawcolumnWithTableAlias);
void appendRawColumn(String rawcolumnWithTableAlias);
/**
* Append a column with an explicit table alias.
*/
public void appendColumn(String tableAlias, String column);
void appendColumn(String tableAlias, String column);
/**
* Append a column with the current table alias.
*/
public void appendColumn(String column);
void appendColumn(String column);
/**
* Append a Sql Formula select. This converts the "${ta}" keyword to the
* current table alias.
*/
public void appendFormulaSelect(String sqlFormulaSelect);
void appendFormulaSelect(String sqlFormulaSelect);
/**
* Append a Sql Formula join. This converts the "${ta}" keyword to the current
* table alias.
*/
public void appendFormulaJoin(String sqlFormulaJoin, SqlJoinType joinType);
void appendFormulaJoin(String sqlFormulaJoin, SqlJoinType joinType);
/**
* Return the current content length.
*/
public int length();
int length();
/**
* Return the current context of the sql context.
*/
public String getContent();
String getContent();
/**
* Return the current join node.
*/
public String peekJoin();
String peekJoin();
/**
* Push a join node onto the stack.
*/
public void pushJoin(String prefix);
void pushJoin(String prefix);
/**
* Pop a join node off the stack.
*/
public void popJoin();
void popJoin();
/**
* Return a table alias without many where clause joins. Typically this is for
* the select clause (fetch joins).
*/
public String getTableAlias(String prefix);
String getTableAlias(String prefix);
/**
* Return a table alias that takes into account many where joins.
*/
public String getTableAliasManyWhere(String prefix);
String getTableAliasManyWhere(String prefix);
public String getRelativePrefix(String propName);
String getRelativePrefix(String propName);
/**
* Append the lower and upper bound columns into the select clause
* for findVersions() queries.
*/
void appendHistorySysPeriod();
}
@@ -1,61 +0,0 @@
package com.avaje.ebeaninternal.server.deploy;
import java.util.HashMap;
import java.util.List;
import javax.persistence.PersistenceException;
import com.avaje.ebean.event.BeanFinder;
/**
* Default implementation for BeanFinderFactory.
*/
public class DefaultBeanFinderManager implements BeanFinderManager {
HashMap<Class<?>, BeanFinder<?>> registerFor = new HashMap<Class<?>, BeanFinder<?>>();
public int createBeanFinders(List<Class<?>> finderClassList) {
for (Class<?> cls : finderClassList) {
Class<?> entityType = getEntityClass(cls);
try {
BeanFinder<?> beanFinder = (BeanFinder<?>) cls.newInstance();
registerFor.put(entityType, beanFinder);
} catch (Exception ex) {
throw new PersistenceException(ex);
}
}
return registerFor.size();
}
public int getRegisterCount() {
return registerFor.size();
}
/**
* Return the BeanFinder for a given entity type.
*/
@SuppressWarnings("unchecked")
public <T> BeanFinder<T> getBeanFinder(Class<T> entityType) {
return (BeanFinder<T>)registerFor.get(entityType);
}
/**
* Find the entity class given the controller class.
* <p>
* This uses reflection to find the generics parameter type.
* </p>
*/
private Class<?> getEntityClass(Class<?> controller){
Class<?> cls = ParamTypeUtil.findParamType(controller, BeanFinder.class);
if (cls == null){
String msg = "Could not determine the entity class (generics parameter type) from "+controller+" using reflection.";
throw new PersistenceException(msg);
}
return cls;
}
}
@@ -2,58 +2,76 @@ package com.avaje.ebeaninternal.server.deploy;
import com.avaje.ebeaninternal.api.SpiQuery;
import java.util.Collection;
import java.util.List;
import java.util.Set;
/**
* Represents the type of a OneToMany or ManyToMany property.
*/
public class ManyType {
public static final ManyType JAVA_LIST = new ManyType(Underlying.LIST);
public static final ManyType JAVA_SET = new ManyType(Underlying.SET);
public static final ManyType JAVA_MAP = new ManyType(Underlying.MAP);
public enum Underlying {
LIST,
SET,
MAP
}
private final SpiQuery.Type queryType;
private final Underlying underlying;
public static final ManyType JAVA_LIST = new ManyType(Underlying.LIST);
public static final ManyType JAVA_SET = new ManyType(Underlying.SET);
public static final ManyType JAVA_MAP = new ManyType(Underlying.MAP);
public ManyType(Underlying underlying) {
this.underlying = underlying;
switch (underlying) {
case LIST:
queryType = SpiQuery.Type.LIST;
break;
case SET:
queryType = SpiQuery.Type.SET;
break;
public enum Underlying {
default:
queryType = SpiQuery.Type.MAP;
break;
}
}
LIST(List.class),
SET(Set.class),
MAP(null);
public boolean isMap() {
return Underlying.MAP.equals(underlying);
Class<? extends Collection> type;
Underlying(Class<? extends Collection> type) {
this.type = type;
}
/**
* Return the matching Query type.
*/
public SpiQuery.Type getQueryType() {
return queryType;
}
private final SpiQuery.Type queryType;
private final Underlying underlying;
public ManyType(Underlying underlying) {
this.underlying = underlying;
switch (underlying) {
case LIST:
queryType = SpiQuery.Type.LIST;
break;
case SET:
queryType = SpiQuery.Type.SET;
break;
default:
queryType = SpiQuery.Type.MAP;
break;
}
/**
* Return the underlying type.
*/
public Underlying getUnderlying() {
return underlying;
}
}
public boolean isMap() {
return Underlying.MAP.equals(underlying);
}
/**
* Return the matching Query type.
*/
public SpiQuery.Type getQueryType() {
return queryType;
}
/**
* Return the underlying type.
*/
public Underlying getUnderlying() {
return underlying;
}
/**
* Returns List.class or Set.class and null for Map.
* Not intended to be called for maps.
*/
public Class<? extends Collection> getCollectionType() {
return underlying.type;
}
}
@@ -13,31 +13,31 @@ import org.slf4j.LoggerFactory;
*/
public class PersistControllerManager {
private static final Logger logger = LoggerFactory.getLogger(PersistControllerManager.class);
private static final Logger logger = LoggerFactory.getLogger(PersistControllerManager.class);
private final List<BeanPersistController> list;
public PersistControllerManager(BootupClasses bootupClasses){
list = bootupClasses.getBeanPersistControllers();
private final List<BeanPersistController> list;
public PersistControllerManager(BootupClasses bootupClasses) {
list = bootupClasses.getBeanPersistControllers();
}
public int getRegisterCount() {
return list.size();
}
/**
* Return the BeanPersistController for a given entity type.
*/
public void addPersistControllers(DeployBeanDescriptor<?> deployDesc) {
for (int i = 0; i < list.size(); i++) {
BeanPersistController c = list.get(i);
if (c.isRegisterFor(deployDesc.getBeanType())) {
logger.debug("BeanPersistController on[" + deployDesc.getFullName() + "] " + c.getClass().getName());
deployDesc.addPersistController(c);
}
}
public int getRegisterCount() {
return list.size();
}
/**
* Return the BeanPersistController for a given entity type.
*/
public void addPersistControllers(DeployBeanDescriptor<?> deployDesc){
for (int i = 0; i < list.size(); i++) {
BeanPersistController c = list.get(i);
if (c.isRegisterFor(deployDesc.getBeanType())){
logger.debug("BeanPersistController on[" + deployDesc.getFullName() + "] " + c.getClass().getName());
deployDesc.addPersistController(c);
}
}
}
}
}
@@ -3,6 +3,7 @@ package com.avaje.ebeaninternal.server.deploy.generatedproperty;
import java.math.BigDecimal;
import java.util.HashSet;
import com.avaje.ebean.config.CurrentUserProvider;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
/**
@@ -10,19 +11,27 @@ import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
*/
public class GeneratedPropertyFactory {
CounterFactory counterFactory;
private final CounterFactory counterFactory = new CounterFactory();;
InsertTimestampFactory insertFactory;
private final InsertTimestampFactory insertFactory = new InsertTimestampFactory();
UpdateTimestampFactory updateFactory;
private final UpdateTimestampFactory updateFactory = new UpdateTimestampFactory();
HashSet<String> numberTypes = new HashSet<String>();
private final HashSet<String> numberTypes = new HashSet<String>();
public GeneratedPropertyFactory() {
counterFactory = new CounterFactory();
insertFactory = new InsertTimestampFactory();
updateFactory = new UpdateTimestampFactory();
private final GeneratedWhoModified generatedWhoModified;
private final GeneratedWhoCreated generatedWhoCreated;
public GeneratedPropertyFactory(CurrentUserProvider currentUserProvider) {
if (currentUserProvider != null) {
generatedWhoCreated = new GeneratedWhoCreated(currentUserProvider);
generatedWhoModified = new GeneratedWhoModified(currentUserProvider);
} else {
generatedWhoCreated = null;
generatedWhoModified = null;
}
numberTypes.add(Integer.class.getName());
numberTypes.add(int.class.getName());
@@ -62,4 +71,18 @@ public class GeneratedPropertyFactory {
updateFactory.setUpdateTimestamp(property);
}
public void setWhoCreated(DeployBeanProperty property) {
if (generatedWhoCreated == null) {
throw new IllegalStateException("No CurrentUserProvider has been set so @WhoCreated is not supported");
}
property.setGeneratedProperty(generatedWhoCreated);
}
public void setWhoModified(DeployBeanProperty property) {
if (generatedWhoModified == null) {
throw new IllegalStateException("No CurrentUserProvider has been set so @WhoModified is not supported");
}
property.setGeneratedProperty(generatedWhoModified);
}
}

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