Compare commits

..
Author SHA1 Message Date
rob bygrave a674d0d696 [maven-release-plugin] prepare release ebean-parent-12.6.3 2020-12-18 15:03:53 +13:00
Rob BygraveandGitHub 5393161c16 Merge pull request #2132 from ebean-orm/feature/redisModule
Add ebean-redis as module
2020-12-18 14:58:07 +13:00
rob bygrave 1bdc6d8f7f #2134 - Modify ChangeLog to send the last set of changes Pre Commit (rather than post commit). Expose this for spring transactions. 2020-12-18 14:54:44 +13:00
rob bygrave e9081a176f #2133 - Spring transactions not getting ChangeLog changeSet as part of postCommit() processing 2020-12-18 14:14:43 +13:00
rob bygrave 3e7db2887f Add ebean-redis as module 2020-12-17 14:38:54 +13:00
rob bygrave fcf14ac222 Add ebean-redis as module 2020-12-17 11:56:34 +13:00
Rob BygraveandGitHub 55324653a5 #2127 - Adding a new list of children to @OneToMany with orphanRemoval true does not delete existing orphans (#2131) 2020-12-16 15:36:44 +13:00
SnōwballandGitHub a132f09b03 Ignore javax.persistence.Transient in query beans (#2129)
* Add failing tests for transient types

* Ignore jpa @Transient fields in query beans

Any field marked with jpa @Transient should be ignored
2020-12-15 12:40:06 +13:00
rob bygrave 48eac84930 #2128 - Bump avaje-config dependency to 1.3 - Fix for - Repeated calls to Config.get() with no value, expect to return passed default value 2020-12-14 09:31:08 +13:00
rob bygrave 948619a125 [maven-release-plugin] prepare for next development iteration 2020-12-09 13:11:19 +13:00
rob bygrave 0cd0741f18 [maven-release-plugin] prepare release ebean-parent-12.6.2 2020-12-09 13:11:07 +13:00
rob bygrave 01a3455ecb Bump test dependency for kotlin-querybean-generator release 2020-12-08 20:51:52 +13:00
rob bygrave 610f7db1cb Bump test dependency kotlin version to 1.4.21 after issues downloading 1.4.10 from maven central? 2020-12-08 20:46:36 +13:00
rob bygrave 373ef6d1eb #2126 - Bump ebean-migration to 12.4.0 2020-12-08 20:29:34 +13:00
rob bygrave f1b1cee2fd Bump enhancement tile 2020-12-08 15:43:31 +13:00
rob bygrave a73e4f23ff Bump agent version in BOM 2020-12-08 15:41:59 +13:00
rob bygrave 9a5d3498c1 #2125 - Bump ebean-test-docker dependency to 4.1 2020-12-07 23:00:02 +13:00
rob bygrave 0b24d635ad Tests only - update ddl review 2020-12-07 22:48:32 +13:00
rob bygrave b623e19dae update git ignore 2020-12-07 22:47:43 +13:00
rob bygrave 7389a8b344 #2124 - ENH: Add name() attribute to @DbArray, @DbJson, @DbJsonB, @DbMap 2020-12-07 22:46:04 +13:00
rob bygrave d68f477e8e #2120 - DbEnumValue without database constraint 2020-12-07 21:53:03 +13:00
rob bygrave dbe273bb56 #2123 - Modify BackgroundExecutor API - add scheduleWithFixedDelay() and mark executePeriodically() as deprecated 2020-12-07 17:14:03 +13:00
rob bygrave 1a4377da29 Improve tests TestQueryForUpdate and TestSoftDeleteBasic 2020-12-07 13:29:47 +13:00
rob bygrave c3cdecaa60 Fix test TestSqlUpdateBatch with correct bind type for Postgres 2020-12-07 10:06:15 +13:00
rob bygrave 9d706056c6 No functional change, replace new ReentrantLock(false) with new ReentrantLock() 2020-12-04 21:18:55 +13:00
rob bygrave cb0100f02a Refactor tidy BeanDescriptor, no effective change 2020-12-04 21:11:02 +13:00
rob bygrave 9c6dd0989a Refactor tidy BeanDescriptorManager whitespace and raw types 2020-12-04 21:03:08 +13:00
rob bygrave a23a179bbf Fix test bump kotlin-querybean-generator 12.6.2-SNAPSHOT 2020-12-04 20:45:38 +13:00
rob bygrave 365b7c4600 #2122 - Metrics for ElementCollection query not included in reporting (via MetaInfoManager) 2020-12-04 20:41:40 +13:00
rob bygrave ed2455f460 #2121 - Refactor internals move DefaultBackgroundExecutor etc 2020-12-03 15:47:14 +13:00
rob bygrave 046033627a Update tests - generated sql for add constraint foreign key 2020-12-03 13:22:13 +13:00
Rob BygraveandGitHub 786444a6b9 Refactor BackgroundExecutor add submit() methods returning Future (#2121)
- Adds submit() methods that return Future
- Refactor internals to use DaemonScheduleThreadPool
- Delete the now unused DaemonExecutorService
- Tidy internals using wrapMDC() methods
2020-12-03 13:16:51 +13:00
rob bygrave 9ab26cfb9d #2118 - Fix test only PlatformDdl_AlterColumnTest 2020-12-03 09:48:41 +13:00
rob bygrave aa1e3ea1bc #2118 - Generated code for @DbForeignKey reading onDelete and Ignores onUpdate 2020-12-01 22:04:07 +13:00
Rob BygraveandGitHub c66875449b Add Query.withLock(LockType) and withLock(LockType, LockWait) (#2116)
Add Query.withLock(LockType) and withLock(LockType, LockWait)
2020-12-01 21:31:53 +13:00
rob bygrave f6c4024ae5 No effective change - tidy test only, TestStatelessUpdate 2020-12-01 21:17:19 +13:00
rob bygrave 2c8cc793ab No effective change - tidy test only, TestStatelessUpdate 2020-12-01 14:29:37 +13:00
rob bygrave 66454d2e61 No effective change - bump test dependency for ebean-ddl-generator 2020-11-26 08:57:19 +13:00
rob bygrave e7b13cf2d9 [maven-release-plugin] prepare for next development iteration 2020-11-25 22:48:17 +13:00
rob bygrave 04cd520719 [maven-release-plugin] prepare release ebean-parent-12.6.1 2020-11-25 22:48:05 +13:00
rob bygrave 838af0478e #2113 - Refactor rename Query.LockType enum names 2020-11-25 22:32:59 +13:00
rob bygrave 9064e96b90 #2113 - Refactor rename Query.ForUpdate to Query.LockWait
Slightly improve the name of the enum. Note that although this is on public Query it's only internally used.
2020-11-25 22:23:17 +13:00
Rob BygraveandGitHub 8e91268979 #2110 Part2 - addBatch() does not auto flush (#2115) 2020-11-25 22:18:05 +13:00
rob bygrave cc637d56e1 Tidy tests only TestInsertSqlLogging and TestSqlUpdateExceptions 2020-11-25 21:11:16 +13:00
Rob BygraveandGitHub 9846ebd65d Merge pull request #2112 from ebean-orm/FOCONIS-bug-ebean/sql_update_batch_flush
2110 - Fix and test for executeBatch() on SqlUpdate
2020-11-25 20:40:02 +13:00
rob bygrave b568e2efc7 #2114 - Fix PreparedStatement leak when findEach() with invalid SQL 2020-11-25 20:19:20 +13:00
rob bygrave 20fc74219a #2089 - Postgres - Use NO KEY with FOR UPDATE clauses with Postgres
Rename PlatformConfig.defaultLockWithKey to PlatformConfig.forUpdateNoKey
2020-11-24 23:58:58 +13:00
Rob BygraveandGitHub 92a4bfb38e Merge pull request #2113 from ebean-orm/feature/QueryLockType
Add support for Postgres lock types (no key, share, key share) with FOR UPDATE
2020-11-24 23:48:55 +13:00
rob bygrave 5c34b0daa5 Add support for Postgres lock types (no key, share, key share) with FOR UPDATE 2020-11-24 23:36:54 +13:00
rob bygrave f4ea674d60 #2108 - ebean-k8scache and ebean-cluster not invalidated when only remoteTableMod or remoteCacheEvent 2020-11-24 22:16:14 +13:00
Rob BygraveandGitHub 21f43dc395 Merge pull request #2107 from ebean-orm/feature/ModifyAwareType
Refactor io.ebeaninternal.json.ModifyAwareOwner to io.ebean.ModifyAwareType
2020-11-24 22:05:04 +13:00
rob bygrave 5082ce4280 #2089 Postgres - Support NO KEY option with FOR UPDATE clauses with Postgres 2020-11-24 22:02:06 +13:00
Rob BygraveandGitHub ed061fb3b1 Merge pull request #2090 from ebean-orm/feature/2089
#2089 - Postgres - Use NO KEY with FOR UPDATE clauses with Postgres
2020-11-24 21:49:28 +13:00
rob bygrave 247e96f5db #2110 - Fix for executeBatch() on SqlUpdate + refactor
- Changes to generally not close BatchedPstmt on executeBatch() and instead closed on commit/rollback
2020-11-24 16:40:10 +13:00
Jonas Pöhler (JPo) ce60eac583 ADD: failing testcases for executeBatch() on SqlUpdate
Signed-off-by: Jonas Pöhler (JPo) <jonas.poehler@foconis.de>
2020-11-20 15:56:08 +01:00
rob bygrave c34fcdf7b7 #2089 - Add PlatformConfig.lockWithKey configuration option for - Postgres - Use NO KEY with FOR UPDATE clauses 2020-11-19 22:47:15 +13:00
rob bygrave dcfada0b52 Refactor io.ebeaninternal.json.ModifyAwareOwner to io.ebean.ModifyAwareType
- Rename ModifyAwareOwner to ModifyAwareType
- Move to io.ebean (making it properly public)
- Remove the requirement for Serializable
- Simplify to effectively a getter/setter pair (dirty state flag)
- Simplify to reset the dirty state flag via
2020-11-19 21:50:29 +13:00
Rob BygraveandGitHub fb3fd439bb Merge pull request #2106 from ebean-orm/feature/2105-ebean-core-type
Refactor extract ebean-core-type module moving ScalarType and related interfaces to io.ebean.core.type
2020-11-19 19:56:09 +13:00
rob bygrave 6226672d27 Fix kotlin-querybean-generator version in test 2020-11-19 17:28:44 +13:00
rob bygrave bf72794a4c #2105 - Fix kotlin-querybean-generator version in test 2020-11-19 17:27:53 +13:00
rob bygrave 30a00cb092 #2105 - Refactor extract ebean-core-type module
- Move ScalarType, DataBinder, DataReader, ExtraTypeFactory to ebean-core-type module
- Update the ebean-postgis and other modules
2020-11-19 16:10:00 +13:00
rob bygrave 0bfb6895ad #2105 - Refactor extract interface DataBinder from DataBind 2020-11-19 14:52:19 +13:00
rob bygrave 29345c823e Bump test dependency on ebean-ddl-generator 2020-11-19 09:53:19 +13:00
rob bygrave e71cb4f2ff [maven-release-plugin] prepare for next development iteration 2020-11-19 09:29:27 +13:00
rob bygrave c044bc52f7 #2089 - Postgres - Use NO KEY with FOR UPDATE clauses with Postgres 2020-10-22 16:37:18 +13:00
338 changed files with 47419 additions and 1800 deletions
+1 -4
View File
@@ -1,6 +1,4 @@
*.autofetch
*create-all.sql
*drop-all.sql
*.orig
.classpath
.project
@@ -12,7 +10,6 @@ ebean-autotune.xml
ebean-profiling*.xml
/db
/mydb.db
!src/test/ddl-review/*.sql
profiling/
# Intellij project files
@@ -20,4 +17,4 @@ profiling/
*.ipr
*.iws
.idea/
*uuid.state
*uuid.state
+3 -3
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.0</version>
<version>12.6.3</version>
</parent>
<name>ebean api</name>
@@ -32,7 +32,7 @@
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-config</artifactId>
<version>1.2</version>
<version>1.3</version>
</dependency>
<!--
@@ -55,7 +55,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-annotation</artifactId>
<version>6.13</version>
<version>6.15</version>
</dependency>
<dependency>
@@ -1,33 +1,43 @@
package io.ebean;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
* Background thread pool service for executing of tasks asynchronously.
* Background executor service for executing of tasks asynchronously.
* <p>
* This service is used internally by Ebean for executing background tasks such
* as the {@link Query#findFutureList()} and also for executing background tasks
* periodically.
* </p>
* This service can be used to execute tasks in the background.
* <p>
* This service has been made available so you can use it for your application
* code if you want. It can be useful for some server caching implementations
* (background population and trimming of the cache etc).
* </p>
*
* @author rbygrave
* This service is managed by Ebean and will perform a clean shutdown
* waiting for background tasks to complete with a default 30 second
* timeout. Shutdown occurs prior to DataSource shutdown.
* <p>
* This also propagates MDC context from the current thread to the
* background task if defined.
*/
public interface BackgroundExecutor {
/**
* Execute a task in the background.
* Execute a callable task in the background returning the Future.
*/
void execute(Runnable r);
<T> Future<T> submit(Callable<T> task);
/**
* Execute a runnable task in the background returning the Future.
*/
Future<?> submit(Runnable task);
/**
* Execute a task in the background. Effectively the same as
* {@link BackgroundExecutor#submit(Runnable)} but returns void.
*/
void execute(Runnable task);
/**
* Deprecated - migrate to scheduleWithFixedDelay().
* Execute a task periodically with a fixed delay between each execution.
* <p>
* For example, execute a runnable every minute.
@@ -36,27 +46,64 @@ public interface BackgroundExecutor {
* That is, this method has the same behaviour characteristics as
* {@link ScheduledExecutorService#scheduleWithFixedDelay(Runnable, long, long, TimeUnit)}
*/
void executePeriodically(Runnable r, long delay, TimeUnit unit);
@Deprecated
void executePeriodically(Runnable task, long delay, TimeUnit unit);
/**
* Deprecated - migrate to scheduleWithFixedDelay().
* Execute a task periodically additionally with an initial delay different from delay.
*/
void executePeriodically(Runnable r, long initialDelay, long delay, TimeUnit unit);
@Deprecated
void executePeriodically(Runnable task, long initialDelay, long delay, TimeUnit unit);
/**
* Execute a task periodically with a given delay.
*
* @param task the task to execute
* @param initialDelay the time to delay first execution
* @param delay the delay between the termination of one
* execution and the commencement of the next
* @param unit the time unit of the initialDelay and delay parameters
* @return a ScheduledFuture representing pending completion of
* the series of repeated tasks. The future's {@link
* Future#get() get()} method will never return normally,
* and will throw an exception upon task cancellation or
* abnormal termination of a task execution.
*/
ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long initialDelay, long delay, TimeUnit unit);
/**
* Execute a task periodically with a given period.
*
* <p>If any execution of this task takes longer than its period, then
* subsequent executions may start late, but will not concurrently
* execute.
*
* @param task the task to execute
* @param initialDelay the time to delay first execution
* @param period the period between successive executions
* @param unit the time unit of the initialDelay and period parameters
* @return a ScheduledFuture representing pending completion of
* the series of repeated tasks. The future's {@link
* Future#get() get()} method will never return normally,
* and will throw an exception upon task cancellation or
* abnormal termination of a task execution.
*/
ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long initialDelay, long period, TimeUnit unit);
/**
* Schedules a Runnable for one-shot action that becomes enabled after the given delay.
*
* @return a ScheduledFuture representing pending completion of the task and
* whose get() method will return null upon completion
* whose get() method will return null upon completion
*/
ScheduledFuture<?> schedule(Runnable r, long delay, TimeUnit unit);
ScheduledFuture<?> schedule(Runnable task, long delay, TimeUnit unit);
/**
* Schedules a Callable for one-shot action that becomes enabled after the given delay.
*
* @return a ScheduledFuture that can be used to extract result or cancel
*/
<V> ScheduledFuture<V> schedule(Callable<V> c, long delay, TimeUnit unit);
<V> ScheduledFuture<V> schedule(Callable<V> task, long delay, TimeUnit unit);
}
@@ -31,7 +31,7 @@ import java.util.concurrent.locks.ReentrantLock;
*/
public class DatabaseFactory {
private static final ReentrantLock lock = new ReentrantLock(false);
private static final ReentrantLock lock = new ReentrantLock();
private static SpiContainer container;
static {
@@ -27,7 +27,7 @@ final class DbContext {
private final HashMap<String, Database> syncMap = new HashMap<>();
private final ReentrantLock lock = new ReentrantLock(false);
private final ReentrantLock lock = new ReentrantLock();
/**
* The 'default' Database.
@@ -12,7 +12,7 @@ import java.util.concurrent.locks.ReentrantLock;
*/
class DbPrimary {
private static final ReentrantLock lock = new ReentrantLock(false);
private static final ReentrantLock lock = new ReentrantLock();
private static String defaultServerName;
private static boolean skip;
@@ -169,11 +169,40 @@ public interface ExpressionList<T> {
*/
UpdateQuery<T> asUpdate();
/**
* Execute the query with the given lock type and WAIT.
* <p>
* Note that <code>forUpdate()</code> is the same as
* <code>withLock(LockType.UPDATE)</code>.
* <p>
* Provides us with the ability to explicitly use Postgres
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
*/
Query<T> withLock(Query.LockType lockType);
/**
* Execute the query with the given lock type and lock wait.
* <p>
* Note that <code>forUpdateNoWait()</code> is the same as
* <code>withLock(LockType.UPDATE, LockWait.NOWAIT)</code>.
* <p>
* Provides us with the ability to explicitly use Postgres
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
*/
Query<T> withLock(Query.LockType lockType, Query.LockWait lockWait);
/**
* Execute using "for update" clause which results in the DB locking the record.
*/
Query<T> forUpdate();
/**
* Deprecated - migrate to withLock().
* Execute using "for update" with given lock type (currently Postgres only).
*/
@Deprecated
Query<T> forUpdate(Query.LockType lockType);
/**
* Execute using "for update" clause with No Wait option.
* <p>
@@ -182,6 +211,13 @@ public interface ExpressionList<T> {
*/
Query<T> forUpdateNoWait();
/**
* Deprecated - migrate to withLock().
* Execute using "for update nowait" with given lock type (currently Postgres only).
*/
@Deprecated
Query<T> forUpdateNoWait(Query.LockType lockType);
/**
* Execute using "for update" clause with Skip Locked option.
* <p>
@@ -190,6 +226,13 @@ public interface ExpressionList<T> {
*/
Query<T> forUpdateSkipLocked();
/**
* Deprecated - migrate to withLock().
* Execute using "for update skip locked" with given lock type (currently Postgres only).
*/
@Deprecated
Query<T> forUpdateSkipLocked(Query.LockType lockType);
/**
* Execute the query including soft deleted rows.
*/
@@ -1,11 +1,9 @@
package io.ebeaninternal.json;
import java.io.Serializable;
package io.ebean;
/**
* Owner object notified when a modification is detected.
*/
public interface ModifyAwareOwner extends Serializable {
public interface ModifyAwareType {
/**
* Return true if the value is considered dirty.
@@ -16,11 +14,6 @@ public interface ModifyAwareOwner extends Serializable {
/**
* Marks the object as modified.
*/
void markAsModified();
/**
* Reset the dirty state to clean.
*/
void resetMarkedDirty();
void setMarkedDirty(boolean markedDirty);
}
+87 -7
View File
@@ -180,13 +180,44 @@ import java.util.stream.Stream;
public interface Query<T> {
/**
* For update mode.
* The lock type (strength) to use with query FOR UPDATE row locking.
*/
enum ForUpdate {
enum LockType {
/**
* The default lock type being either UPDATE or NO_KEY_UPDATE based on
* PlatformConfig.forUpdateNoKey configuration (Postgres option).
*/
DEFAULT,
/**
* FOR UPDATE.
*/
UPDATE,
/**
* FOR NO KEY UPDATE (Postgres only).
*/
NO_KEY_UPDATE,
/**
* FOR SHARE (Postgres only).
*/
SHARE,
/**
* FOR KEY SHARE (Postgres only).
*/
KEY_SHARE
}
/**
* FOR UPDATE wait mode.
*/
enum LockWait {
/**
* Standard For update clause.
*/
BASE,
WAIT,
/**
* For update with No Wait option.
@@ -1613,36 +1644,85 @@ public interface Query<T> {
*/
String getGeneratedSql();
/**
* Execute the query with the given lock type and WAIT.
* <p>
* Note that <code>forUpdate()</code> is the same as
* <code>withLock(LockType.UPDATE)</code>.
* <p>
* Provides us with the ability to explicitly use Postgres
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
*/
Query<T> withLock(LockType lockType);
/**
* Execute the query with the given lock type and lock wait.
* <p>
* Note that <code>forUpdateNoWait()</code> is the same as
* <code>withLock(LockType.UPDATE, LockWait.NOWAIT)</code>.
* <p>
* Provides us with the ability to explicitly use Postgres
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
*/
Query<T> withLock(LockType lockType, LockWait lockWait);
/**
* Execute using "for update" clause which results in the DB locking the record.
* <p>
* The same as <code>withLock(LockType.UPDATE, LockWait.WAIT)</code>.
*/
Query<T> forUpdate();
/**
* Execute using "for update" with given lock type (currently Postgres only).
*/
@Deprecated
Query<T> forUpdate(LockType lockType);
/**
* Execute using "for update" clause with "no wait" option.
* <p>
* This is typically a Postgres and Oracle only option at this stage.
* </p>
* <p>
* The same as <code>withLock(LockType.UPDATE, LockWait.NOWAIT)</code>.
*/
Query<T> forUpdateNoWait();
/**
* Execute using "for update nowait" with given lock type (currently Postgres only).
*/
@Deprecated
Query<T> forUpdateNoWait(LockType lockType);
/**
* Execute using "for update" clause with "skip locked" option.
* <p>
* This is typically a Postgres and Oracle only option at this stage.
* </p>
* <p>
* The same as <code>withLock(LockType.UPDATE, LockWait.SKIPLOCKED)</code>.
*/
Query<T> forUpdateSkipLocked();
/**
* Execute using "for update skip locked" with given lock type (currently Postgres only).
*/
@Deprecated
Query<T> forUpdateSkipLocked(LockType lockType);
/**
* Return true if this query has forUpdate set.
*/
boolean isForUpdate();
/**
* Return the "for update" mode to use.
* Return the "for update" wait mode to use.
*/
ForUpdate getForUpdateMode();
LockWait getForUpdateLockWait();
/**
* Return the lock type (strength) to use with "for update".
*/
LockType getForUpdateLockType();
/**
* Set root table alias.
@@ -32,7 +32,7 @@ public final class EntityBeanIntercept implements Serializable {
private static final int STATE_REFERENCE = 1;
private static final int STATE_LOADED = 2;
private transient final ReentrantLock lock = new ReentrantLock(false);
private transient final ReentrantLock lock = new ReentrantLock();
private transient NodeUsageCollector nodeUsageCollector;
@@ -10,7 +10,7 @@ import java.util.concurrent.locks.ReentrantLock;
*/
public abstract class SingleBeanLoader implements BeanLoader {
private final ReentrantLock lock = new ReentrantLock(false);
private final ReentrantLock lock = new ReentrantLock();
protected final Database database;
@@ -16,7 +16,7 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
private static final long serialVersionUID = 3365725236140187588L;
protected final ReentrantLock lock = new ReentrantLock(false);
protected final ReentrantLock lock = new ReentrantLock();
protected boolean readOnly;
@@ -20,7 +20,7 @@ public final class CopyOnFirstWriteList<E> extends AbstractList<E> implements Li
private static final long serialVersionUID = 1L;
private final ReentrantLock lock = new ReentrantLock(false);
private final ReentrantLock lock = new ReentrantLock();
/**
* The underlying List implementation.
@@ -17,6 +17,11 @@ public class PlatformConfig {
private boolean allQuotedIdentifiers;
/**
* Set this to true for Postgres FOR UPDATE to use NO KEY option.
*/
private boolean forUpdateNoKey;
private DbConstraintNaming constraintNaming;
/**
@@ -77,6 +82,7 @@ public class PlatformConfig {
* Construct based on given config - typically for DbMigration generation with many platforms.
*/
public PlatformConfig(PlatformConfig platformConfig) {
this.forUpdateNoKey = platformConfig.forUpdateNoKey;
this.databaseBooleanFalse = platformConfig.databaseBooleanFalse;
this.databaseBooleanTrue = platformConfig.databaseBooleanTrue;
this.databaseSequenceBatchSize = platformConfig.databaseSequenceBatchSize;
@@ -133,14 +139,26 @@ public class PlatformConfig {
this.caseSensitiveCollation = caseSensitiveCollation;
}
/**
* Return true if Postgres FOR UPDATE should use the NO KEY option.
*/
public boolean isForUpdateNoKey() {
return forUpdateNoKey;
}
/**
* Set to true such that Postgres FOR UPDATE should use the NO KEY option.
*/
public void setForUpdateNoKey(boolean forUpdateNoKey) {
this.forUpdateNoKey = forUpdateNoKey;
}
/**
* Return a value used to represent TRUE in the database.
* <p>
* This is used for databases that do not support boolean natively.
* </p>
* <p>
* The value returned is either a Integer or a String (e.g. "1", or "T").
* </p>
*/
public String getDatabaseBooleanTrue() {
return databaseBooleanTrue;
@@ -150,10 +168,8 @@ public class PlatformConfig {
* Set the value to represent TRUE in the database.
* <p>
* This is used for databases that do not support boolean natively.
* </p>
* <p>
* The value set is either a Integer or a String (e.g. "1", or "T").
* </p>
*/
public void setDatabaseBooleanTrue(String databaseBooleanTrue) {
this.databaseBooleanTrue = databaseBooleanTrue;
@@ -245,7 +261,6 @@ public class PlatformConfig {
/**
* Add a custom type mapping.
* <p>
* <pre>{@code
*
* // set the default mapping for BigDecimal.class/decimal
@@ -266,7 +281,6 @@ public class PlatformConfig {
/**
* Add a custom type mapping that applies to all platforms.
* <p>
* <pre>{@code
*
* // set the default mapping for BigDecimal/decimal
@@ -294,6 +308,7 @@ public class PlatformConfig {
public void loadSettings(PropertiesWrapper p) {
idType = p.getEnum(IdType.class, "idType", idType);
forUpdateNoKey = p.getBoolean("forUpdateNoKey", forUpdateNoKey);
databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize);
databaseBooleanTrue = p.get("databaseBooleanTrue", databaseBooleanTrue);
databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse);
@@ -334,7 +349,6 @@ public class PlatformConfig {
*/
public enum DbUuid {
/**
* Store using native UUID in H2 and Postgres and otherwise fallback to VARCHAR(40).
*/
@@ -679,21 +679,20 @@ public class DatabasePlatform {
public String completeSql(String sql, Query<?> query) {
if (query.isForUpdate()) {
sql = withForUpdate(sql, query.getForUpdateMode());
sql = withForUpdate(sql, query.getForUpdateLockWait(), query.getForUpdateLockType());
}
return sql;
}
/**
* For update hint on the FROM clause (SQL server only).
*/
public String fromForUpdate(Query.ForUpdate forUpdateMode) {
public String fromForUpdate(Query.LockWait lockWait) {
// return null except for sql server
return null;
}
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
// silently assume the database does not support the "for update" clause.
logger.info("it seems your database does not support the 'for update' clause");
return sql;
@@ -26,9 +26,7 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
protected static final Logger logger = LoggerFactory.getLogger("io.ebean.SEQ");
private final ReentrantLock lock = new ReentrantLock(false);
private final ReentrantLock loadLock = new ReentrantLock(false);
private final ReentrantLock lock = new ReentrantLock();
/**
* The actual sequence name.
@@ -51,7 +51,7 @@ public class H2Platform extends DatabasePlatform {
}
@Override
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
// NOWAIT and SKIP LOCKED currently not supported with H2
return sql + " for update";
}
@@ -1,6 +1,7 @@
package io.ebean.config.dbplatform.hana;
import io.ebean.Query.ForUpdate;
import io.ebean.Query;
import io.ebean.Query.LockWait;
import io.ebean.annotation.PersistBatch;
import io.ebean.annotation.Platform;
import io.ebean.config.PlatformConfig;
@@ -68,16 +69,16 @@ public class HanaPlatform extends DatabasePlatform {
}
@Override
protected String withForUpdate(String sql, ForUpdate forUpdateMode) {
switch (forUpdateMode) {
case BASE:
protected String withForUpdate(String sql, LockWait lockWait, Query.LockType lockType) {
switch (lockWait) {
case WAIT:
return sql + " for update";
case NOWAIT:
return sql + " for update nowait";
case SKIPLOCKED:
return sql + " for update ignore locked";
default:
throw new IllegalArgumentException("Unknown update mode: " + forUpdateMode.name());
throw new IllegalArgumentException("Unknown update mode: " + lockWait);
}
}
@@ -60,7 +60,7 @@ public abstract class BaseMySqlPlatform extends DatabasePlatform {
}
@Override
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
// NOWAIT and SKIP LOCKED currently not supported with MySQL
return sql + " for update";
}
@@ -48,8 +48,8 @@ public class NuoDbPlatform extends DatabasePlatform {
}
@Override
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
switch (forUpdateMode) {
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
switch (lockWait) {
case NOWAIT:
return sql + " for update nowait";
case SKIPLOCKED:
@@ -79,8 +79,8 @@ public class OraclePlatform extends DatabasePlatform {
}
@Override
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
switch (forUpdateMode) {
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
switch (lockWait) {
case SKIPLOCKED:
return sql + " for update skip locked";
case NOWAIT:
@@ -4,6 +4,7 @@ import io.ebean.BackgroundExecutor;
import io.ebean.Query;
import io.ebean.annotation.PartitionMode;
import io.ebean.annotation.Platform;
import io.ebean.config.PlatformConfig;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.DbPlatformType;
import io.ebean.config.dbplatform.DbType;
@@ -25,6 +26,15 @@ import java.sql.Types;
*/
public class PostgresPlatform extends DatabasePlatform {
private static final String SKIP_LOCKED = " skip locked";
private static final String NO_WAIT = " nowait";
private static final String FOR_UPDATE = " for update";
private static final String FOR_NO_KEY_UPDATE = " for no key update";
private static final String FOR_SHARE = " for share";
private static final String FOR_KEY_SHARE = " for key share";
private boolean forUpdateNoKey;
public PostgresPlatform() {
super();
this.platform = Platform.POSTGRES;
@@ -81,6 +91,12 @@ public class PostgresPlatform extends DatabasePlatform {
dbTypeMap.put(DbType.LONGVARCHAR, dbTypeText);
}
@Override
public void configure(PlatformConfig config) {
super.configure(config);
forUpdateNoKey = config.isForUpdateNoKey();
}
@Override
protected void addGeoTypes(int srid) {
dbTypeMap.put(DbType.POINT, geoType("point", srid));
@@ -108,22 +124,32 @@ public class PostgresPlatform extends DatabasePlatform {
*/
@Override
public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, int stepSize, String seqName) {
return new PostgresSequenceIdGenerator(be, ds, seqName, sequenceBatchSize);
}
@Override
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
switch (forUpdateMode) {
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
switch (lockWait) {
case SKIPLOCKED:
return sql + " for update skip locked";
return sql + lock(lockType) + SKIP_LOCKED;
case NOWAIT:
return sql + " for update nowait";
return sql + lock(lockType) + NO_WAIT;
default:
return sql + " for update";
return sql + lock(lockType);
}
}
private String lock(Query.LockType lockType) {
switch (lockType) {
case UPDATE: return FOR_UPDATE;
case NO_KEY_UPDATE: return FOR_NO_KEY_UPDATE;
case SHARE: return FOR_SHARE;
case KEY_SHARE: return FOR_KEY_SHARE;
case DEFAULT: return forUpdateNoKey ? FOR_NO_KEY_UPDATE : FOR_UPDATE;
}
return FOR_UPDATE;
}
@Override
public boolean tablePartitionsExist(Connection connection, String table) throws SQLException {
try (PreparedStatement statement = connection.prepareStatement("select count(*) from pg_inherits i WHERE i.inhparent = ?::regclass")) {
@@ -105,8 +105,8 @@ abstract class SqlServerBasePlatform extends DatabasePlatform {
* For update is part of the FROM clause on the base table for sql server.
*/
@Override
public String fromForUpdate(Query.ForUpdate forUpdateMode) {
switch (forUpdateMode) {
public String fromForUpdate(Query.LockWait lockWait) {
switch (lockWait) {
case SKIPLOCKED:
return "with (updlock,readpast)";
case NOWAIT:
@@ -117,7 +117,7 @@ abstract class SqlServerBasePlatform extends DatabasePlatform {
}
@Override
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
// for update are hints on from clause of base table
return sql;
}
@@ -23,7 +23,7 @@ public final class ShutdownManager {
private static final Logger logger = LoggerFactory.getLogger(ShutdownManager.class);
private static final ReentrantLock lock = new ReentrantLock(false);
private static final ReentrantLock lock = new ReentrantLock();
private static final List<Database> databases = new ArrayList<>();
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.0</version>
<version>12.6.3</version>
</parent>
<!-- <parent>-->
<!-- <groupId>org.avaje</groupId>-->
@@ -14,7 +14,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.6.0</tag>
<tag>ebean-parent-12.6.3</tag>
</scm>
<name>ebean autotune</name>
@@ -26,7 +26,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.6.0</version>
<version>12.6.3</version>
<scope>provided</scope>
</dependency>
@@ -64,7 +64,7 @@
<configuration>
<tiles>
<!-- other tiles ... -->
<tile>io.ebean.tile:enhancement:12.5.0</tile>
<tile>io.ebean.tile:enhancement:12.6.0</tile>
</tiles>
</configuration>
</plugin>
@@ -23,7 +23,7 @@ public class DefaultAutoTuneService implements AutoTuneService {
private static final Logger logger = LoggerFactory.getLogger(DefaultAutoTuneService.class);
private final ReentrantLock lock = new ReentrantLock(false);
private final ReentrantLock lock = new ReentrantLock();
private final SpiEbeanServer server;
@@ -77,7 +77,7 @@ public class DefaultAutoTuneService implements AutoTuneService {
loadTuningFile();
if (isRuntimeTuningUpdates()) {
// periodically gather and update query tuning
server.getBackgroundExecutor().executePeriodically(new ProfilingUpdate(), profilingUpdateFrequency, TimeUnit.SECONDS);
server.getBackgroundExecutor().scheduleWithFixedDelay(new ProfilingUpdate(), profilingUpdateFrequency, profilingUpdateFrequency, TimeUnit.SECONDS);
}
}
}
@@ -18,7 +18,7 @@ import java.util.concurrent.locks.ReentrantLock;
*/
public class ProfileManager implements ProfilingListener {
private final ReentrantLock lock = new ReentrantLock(false);
private final ReentrantLock lock = new ReentrantLock();
private final boolean queryTuningAddVersion;
@@ -16,7 +16,7 @@ import java.util.concurrent.locks.ReentrantLock;
public class ProfileOrigin {
private final ReentrantLock lock = new ReentrantLock(false);
private final ReentrantLock lock = new ReentrantLock();
private static final long RESET_COUNT = -1000000000L;
@@ -21,7 +21,7 @@ public class ProfileOriginNodeUsage {
private static final Logger logger = LoggerFactory.getLogger(ProfileOriginNodeUsage.class);
private final ReentrantLock lock = new ReentrantLock(false);
private final ReentrantLock lock = new ReentrantLock();
private final String path;
+16 -16
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.0</version>
<version>12.6.3</version>
</parent>
<name>ebean bom</name>
@@ -15,11 +15,11 @@
<properties>
<ebean-ddl-runner.version>1.0</ebean-ddl-runner.version>
<ebean-migration-auto.version>1.0</ebean-migration-auto.version>
<ebean-migration.version>12.2.0</ebean-migration.version>
<ebean-test-docker.version>4.0</ebean-test-docker.version>
<ebean-migration.version>12.4.0</ebean-migration.version>
<ebean-test-docker.version>4.1</ebean-test-docker.version>
<ebean-datasource.version>7.0</ebean-datasource.version>
<ebean-agent.version>12.6.0</ebean-agent.version>
<ebean-maven-plugin.version>12.6.0</ebean-maven-plugin.version>
<ebean-agent.version>12.6.2</ebean-agent.version>
<ebean-maven-plugin.version>12.6.2</ebean-maven-plugin.version>
</properties>
<dependencyManagement>
@@ -81,69 +81,69 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>12.6.0</version>
<version>12.6.3</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.6.0</version>
<version>12.6.3</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.6.0</version>
<version>12.6.3</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.6.0</version>
<version>12.6.3</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>12.6.0</version>
<version>12.6.3</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-xml</artifactId>
<version>12.6.0</version>
<version>12.6.3</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-autotune</artifactId>
<version>12.6.0</version>
<version>12.6.3</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>12.6.0</version>
<version>12.6.3</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>12.6.0</version>
<version>12.6.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId>
<version>12.6.0</version>
<version>12.6.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.6.0</version>
<version>12.6.3</version>
<scope>test</scope>
</dependency>
+34
View File
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.3</version>
</parent>
<artifactId>ebean-core-type</artifactId>
<properties>
<jackson-core.version>2.11.3</jackson-core.version>
<jackson-databind.version>2.11.3</jackson-databind.version>
</properties>
<dependencies>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.6.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson-core.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,166 @@
package io.ebean.core.type;
import java.io.InputStream;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.List;
/**
* Data binder for ScalarTypes generally to an underlying PreparedStatement.
*/
public interface DataBinder {
/**
* Add something to the binding log.
*/
StringBuilder append(Object entry);
/**
* Return the binding log.
*/
StringBuilder log();
/**
* Close the underlying prepared statement.
*/
void close() throws SQLException;
/**
* Return the current position. Effectively column binding position.
*/
int currentPos();
/**
* Return the next position.
*/
int nextPos();
/**
* Decrement the position.
*/
void decrementPos();
/**
* Execute as a dml statement.
*/
int executeUpdate() throws SQLException;
/**
* Return the underlying PreparedStatement.
*/
PreparedStatement getPstmt();
/**
* Return any inputStreams that have been bound (and should be closed).
* This is used for batched statement execution only.
*/
List<InputStream> getInputStreams();
/**
* Bind an object.
*/
void setObject(Object value) throws SQLException;
/**
* Bind an object with given sql type.
*/
void setObject(Object value, int sqlType) throws SQLException;
/**
* Bind null.
*/
void setNull(int jdbcType) throws SQLException;
/**
* Bind a string value.
*/
void setString(String value) throws SQLException;
/**
* Bind a int value.
*/
void setInt(int value) throws SQLException;
/**
* Bind a long value.
*/
void setLong(long value) throws SQLException;
/**
* Bind a short value.
*/
void setShort(short value) throws SQLException;
/**
* Bind a float value.
*/
void setFloat(float value) throws SQLException;
/**
* Bind a double value.
*/
void setDouble(double value) throws SQLException;
/**
* Bind a BigDecimal value.
*/
void setBigDecimal(BigDecimal value) throws SQLException;
/**
* Bind a date value.
*/
void setDate(java.sql.Date value) throws SQLException;
/**
* Bind a timestamp value.
*/
void setTimestamp(Timestamp value) throws SQLException;
/**
* Bind a time value.
*/
void setTime(Time value) throws SQLException;
/**
* Bind a boolean value.
*/
void setBoolean(boolean value) throws SQLException;
/**
* Bind a byte array value.
*/
void setBytes(byte[] value) throws SQLException;
/**
* Bind a byte value.
*/
void setByte(byte value) throws SQLException;
/**
* Bind a char value.
*/
void setChar(char value) throws SQLException;
/**
* Bind a InputStream value.
*/
void setBinaryStream(InputStream inputStream, long length) throws SQLException;
/**
* Bind a byte array value.
*/
void setBlob(byte[] bytes) throws SQLException;
/**
* Bind a string clob value.
*/
void setClob(String content) throws SQLException;
/**
* Bind an array value.
*/
void setArray(String arrayType, Object[] elements) throws SQLException;
}
@@ -1,4 +1,4 @@
package io.ebeaninternal.server.type;
package io.ebean.core.type;
import java.io.InputStream;
import java.math.BigDecimal;
@@ -1,4 +1,4 @@
package io.ebeanservice.docstore.api.mapping;
package io.ebean.core.type;
/**
* Types as defined for document store property types.
@@ -1,7 +1,6 @@
package io.ebeaninternal.api;
package io.ebean.core.type;
import io.ebean.config.DatabaseConfig;
import io.ebeaninternal.server.type.ScalarType;
import java.util.List;
@@ -1,4 +1,4 @@
package io.ebeaninternal.server.type;
package io.ebean.core.type;
import java.sql.SQLException;
@@ -10,6 +10,6 @@ public interface ScalarDataReader<T> {
/**
* Read and return the appropriate value from the dataReader.
*/
T read(DataReader dataReader) throws SQLException;
T read(DataReader reader) throws SQLException;
}
@@ -1,10 +1,9 @@
package io.ebeaninternal.server.type;
package io.ebean.core.type;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import io.ebean.text.StringFormatter;
import io.ebean.text.StringParser;
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
import java.io.DataInput;
import java.io.DataOutput;
@@ -112,7 +111,7 @@ public interface ScalarType<T> extends StringParser, StringFormatter, ScalarData
* JDBC type.
* </p>
*/
void bind(DataBind bind, T value) throws SQLException;
void bind(DataBinder binder, T value) throws SQLException;
/**
* Convert the value as necessary to the JDBC type.
+13 -7
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.6.0</version>
<version>12.6.3</version>
</parent>
<artifactId>ebean-core</artifactId>
@@ -15,7 +15,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.6.0</tag>
<tag>ebean-parent-12.6.3</tag>
</scm>
<properties>
@@ -76,8 +76,8 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddlgen</artifactId>
<version>12.5.2A</version>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.6.1</version>
<scope>test</scope>
</dependency>
@@ -92,13 +92,19 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.6.0</version>
<version>12.6.3</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>12.6.3</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>12.6.0</version>
<version>12.6.3</version>
</dependency>
<dependency>
@@ -196,7 +202,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test-docker</artifactId>
<version>4.0</version>
<version>4.1</version>
<scope>test</scope>
</dependency>
@@ -237,7 +237,7 @@ public interface SpiQuery<T> extends Query<T>, TxnProfileEventCodes {
* Return the ForUpdate mode.
*/
@Override
ForUpdate getForUpdateMode();
LockWait getForUpdateLockWait();
/**
* Return the bean descriptor for this query.
@@ -318,4 +318,20 @@ public interface SpiTransaction extends Transaction {
* Return true if explicitly set to skip cache (ignores skipOnWrite).
*/
boolean isSkipCacheExplicit();
/**
* Fire pre commit processing/listeners.
*/
void preCommit();
/**
* Fire post commit events and listeners.
*/
void postCommit();
/**
* Fire post rollback events and listeners.
*/
void postRollback(Throwable cause);
}
@@ -418,4 +418,18 @@ public abstract class SpiTransactionProxy implements SpiTransaction {
transaction.flushBatchOnCollection();
}
@Override
public void preCommit() {
transaction.preCommit();
}
@Override
public void postCommit() {
transaction.postCommit();
}
@Override
public void postRollback(Throwable cause) {
transaction.postRollback(cause);
}
}
@@ -3,6 +3,7 @@ package io.ebeaninternal.json;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import io.ebean.ModifyAwareType;
import java.io.IOException;
import java.io.Reader;
@@ -145,7 +146,7 @@ class EJsonReader {
currentContext = stack.pop(currentContext);
}
if (modifyAwareOwner != null) {
modifyAwareOwner.resetMarkedDirty();
modifyAwareOwner.setMarkedDirty(false);
}
}
@@ -296,7 +297,7 @@ class EJsonReader {
map = new LinkedHashMap<>();
}
ObjectContext(ModifyAwareOwner owner) {
ObjectContext(ModifyAwareType owner) {
map = new ModifyAwareMap<>(owner, new LinkedHashMap<>());
}
@@ -334,7 +335,7 @@ class EJsonReader {
values = new ArrayList<>();
}
ArrayContext(ModifyAwareOwner owner) {
ArrayContext(ModifyAwareType owner) {
values = new ModifyAwareList<>(owner, new ArrayList<>());
}
@@ -1,28 +1,26 @@
package io.ebeaninternal.json;
import io.ebean.ModifyAwareType;
import java.io.Serializable;
/**
* Detects when content has been modified and as such needs to be persisted (included in an update).
*/
public class ModifyAwareFlag implements ModifyAwareOwner {
public class ModifyAwareFlag implements ModifyAwareType, Serializable {
private static final long serialVersionUID = 1;
boolean dirty;
private boolean markedDirty;
@Override
public boolean isMarkedDirty() {
if (!dirty) return false;
dirty = false;
return true;
return markedDirty;
}
@Override
public void markAsModified() {
dirty = true;
public void setMarkedDirty(boolean markedDirty) {
this.markedDirty = markedDirty;
}
@Override
public void resetMarkedDirty() {
dirty = false;
}
}
@@ -1,5 +1,7 @@
package io.ebeaninternal.json;
import io.ebean.ModifyAwareType;
import java.util.Iterator;
/**
@@ -7,7 +9,7 @@ import java.util.Iterator;
*/
public class ModifyAwareIterator<E> implements Iterator<E> {
private final ModifyAwareOwner owner;
private final ModifyAwareType owner;
private final Iterator<E> it;
@@ -17,7 +19,7 @@ public class ModifyAwareIterator<E> implements Iterator<E> {
* The owner is notified of the removals.
* </p>
*/
public ModifyAwareIterator(ModifyAwareOwner owner, Iterator<E> it) {
public ModifyAwareIterator(ModifyAwareType owner, Iterator<E> it) {
this.owner = owner;
this.it = it;
}
@@ -34,7 +36,7 @@ public class ModifyAwareIterator<E> implements Iterator<E> {
@Override
public void remove() {
owner.markAsModified();
owner.setMarkedDirty(true);
it.remove();
}
@@ -1,5 +1,8 @@
package io.ebeaninternal.json;
import io.ebean.ModifyAwareType;
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
@@ -10,20 +13,20 @@ import java.util.Objects;
/**
* Modify aware wrapper of a list.
*/
public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
public class ModifyAwareList<E> implements List<E>, ModifyAwareType, Serializable {
private static final long serialVersionUID = 1;
final List<E> list;
final ModifyAwareOwner owner;
final ModifyAwareType owner;
public ModifyAwareList(List<E> list) {
this.list = list;
this.owner = new ModifyAwareFlag();
}
public ModifyAwareList(ModifyAwareOwner owner, List<E> list) {
public ModifyAwareList(ModifyAwareType owner, List<E> list) {
this.list = list;
this.owner = owner;
}
@@ -56,13 +59,12 @@ public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
}
@Override
public void markAsModified() {
owner.markAsModified();
public void setMarkedDirty(boolean markedDirty) {
owner.setMarkedDirty(markedDirty);
}
@Override
public void resetMarkedDirty() {
owner.resetMarkedDirty();
private void markAsDirty() {
owner.setMarkedDirty(true);
}
@Override
@@ -98,13 +100,13 @@ public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
@Override
public boolean add(E e) {
owner.markAsModified();
markAsDirty();
return list.add(e);
}
@Override
public boolean remove(Object o) {
owner.markAsModified();
markAsDirty();
return list.remove(o);
}
@@ -115,31 +117,31 @@ public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
@Override
public boolean addAll(Collection<? extends E> c) {
owner.markAsModified();
markAsDirty();
return list.addAll(c);
}
@Override
public boolean addAll(int index, Collection<? extends E> c) {
owner.markAsModified();
markAsDirty();
return list.addAll(index, c);
}
@Override
public boolean removeAll(Collection<?> c) {
owner.markAsModified();
markAsDirty();
return list.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
owner.markAsModified();
markAsDirty();
return list.retainAll(c);
}
@Override
public void clear() {
owner.markAsModified();
markAsDirty();
list.clear();
}
@@ -150,19 +152,19 @@ public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
@Override
public E set(int index, E element) {
owner.markAsModified();
markAsDirty();
return list.set(index, element);
}
@Override
public void add(int index, E element) {
owner.markAsModified();
markAsDirty();
list.add(index, element);
}
@Override
public E remove(int index) {
owner.markAsModified();
markAsDirty();
return list.remove(index);
}
@@ -195,7 +197,6 @@ public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
* Create an return a modify aware Set.
*/
public ModifyAwareSet<E> asSet() {
return new ModifyAwareSet<>(owner, new LinkedHashSet<>(list));
}
}
@@ -1,5 +1,7 @@
package io.ebeaninternal.json;
import io.ebean.ModifyAwareType;
import java.util.ListIterator;
/**
@@ -7,11 +9,11 @@ import java.util.ListIterator;
*/
public class ModifyAwareListIterator<E> implements ListIterator<E> {
final ModifyAwareOwner owner;
final ModifyAwareType owner;
final ListIterator<E> iterator;
public ModifyAwareListIterator(ModifyAwareOwner owner, ListIterator<E> iterator) {
public ModifyAwareListIterator(ModifyAwareType owner, ListIterator<E> iterator) {
this.owner = owner;
this.iterator = iterator;
}
@@ -48,19 +50,19 @@ public class ModifyAwareListIterator<E> implements ListIterator<E> {
@Override
public void remove() {
owner.markAsModified();
owner.setMarkedDirty(true);
iterator.remove();
}
@Override
public void set(E e) {
owner.markAsModified();
owner.setMarkedDirty(true);
iterator.set(e);
}
@Override
public void add(E e) {
owner.markAsModified();
owner.setMarkedDirty(true);
iterator.add(e);
}
}
@@ -1,5 +1,8 @@
package io.ebeaninternal.json;
import io.ebean.ModifyAwareType;
import java.io.Serializable;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Map;
@@ -9,11 +12,11 @@ import java.util.Set;
/**
* Map that is wraps an underlying map for the purpose of detecting changes.
*/
public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareType, Serializable {
private static final long serialVersionUID = 1;
final ModifyAwareOwner owner;
final ModifyAwareType owner;
/**
* The underlying map.
@@ -25,7 +28,7 @@ public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
this.owner = new ModifyAwareFlag();
}
public ModifyAwareMap(ModifyAwareOwner owner, Map<K, V> underlying) {
public ModifyAwareMap(ModifyAwareType owner, Map<K, V> underlying) {
this.owner = owner;
this.map = underlying;
}
@@ -58,13 +61,12 @@ public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
}
@Override
public void markAsModified() {
owner.markAsModified();
public void setMarkedDirty(boolean markedDirty) {
owner.setMarkedDirty(markedDirty);
}
@Override
public void resetMarkedDirty() {
owner.resetMarkedDirty();
private void markAsDirty() {
owner.setMarkedDirty(true);
}
@Override
@@ -94,7 +96,7 @@ public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
@Override
public V put(K key, V value) {
markAsModified();
markAsDirty();
return map.put(key, value);
}
@@ -102,14 +104,14 @@ public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
public V remove(Object key) {
V value = map.remove(key);
if (value != null) {
markAsModified();
markAsDirty();
}
return value;
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
markAsModified();
markAsDirty();
map.putAll(m);
}
@@ -117,7 +119,7 @@ public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
@Override
public void clear() {
if (!map.isEmpty()) {
markAsModified();
markAsDirty();
}
map.clear();
}
@@ -1,5 +1,8 @@
package io.ebeaninternal.json;
import io.ebean.ModifyAwareType;
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.Objects;
@@ -8,11 +11,11 @@ import java.util.Set;
/**
* Wraps a Set for the purposes of detecting modifications.
*/
public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
public class ModifyAwareSet<E> implements Set<E>, ModifyAwareType, Serializable {
private static final long serialVersionUID = 1;
protected final ModifyAwareOwner owner;
protected final ModifyAwareType owner;
protected final Set<E> set;
@@ -26,7 +29,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
/**
* Create with an Owner that is notified of modifications.
*/
public ModifyAwareSet(ModifyAwareOwner owner, Set<E> underlying) {
public ModifyAwareSet(ModifyAwareType owner, Set<E> underlying) {
this.owner = owner;
this.set = underlying;
}
@@ -37,16 +40,14 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
}
@Override
public void markAsModified() {
owner.markAsModified();
public void setMarkedDirty(boolean markedDirty) {
owner.setMarkedDirty(markedDirty);
}
@Override
public void resetMarkedDirty() {
owner.resetMarkedDirty();
private void markAsDirty() {
owner.setMarkedDirty(true);
}
@Override
public String toString() {
return set.toString();
@@ -72,7 +73,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
@Override
public boolean add(E o) {
if (set.add(o)) {
owner.markAsModified();
markAsDirty();
return true;
}
return false;
@@ -83,7 +84,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
boolean changed = false;
for (E o : collection) {
if (set.add(o)) {
owner.markAsModified();
markAsDirty();
changed = true;
}
}
@@ -93,7 +94,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
@Override
public void clear() {
if (!set.isEmpty()) {
owner.markAsModified();
markAsDirty();
}
set.clear();
}
@@ -121,7 +122,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
@Override
public boolean remove(Object o) {
if (set.remove(o)) {
owner.markAsModified();
markAsDirty();
return true;
}
return false;
@@ -132,7 +133,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
boolean changed = false;
for (Object element : collection) {
if (set.remove(element)) {
owner.markAsModified();
markAsDirty();
changed = true;
}
}
@@ -147,7 +148,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
Object o = it.next();
if (!collection.contains(o)) {
it.remove();
owner.markAsModified();
markAsDirty();
changed = true;
}
}
@@ -27,7 +27,7 @@ class DefaultCacheHolder {
private static final Logger log = LoggerFactory.getLogger("io.ebean.cache.ALL");
private final ReentrantLock lock = new ReentrantLock(false);
private final ReentrantLock lock = new ReentrantLock();
private final ConcurrentHashMap<String, ServerCache> allCaches = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, Set<String>> collectIdCaches = new ConcurrentHashMap<>();
@@ -86,7 +86,7 @@ public class DefaultServerCache implements ServerCache {
// default to trimming the cache every 60 seconds
long trimFreqSecs = (trimFrequency == 0) ? 60 : trimFrequency;
executor.executePeriodically(trim, trimFreqSecs, TimeUnit.SECONDS);
executor.scheduleWithFixedDelay(trim, trimFreqSecs, trimFreqSecs, TimeUnit.SECONDS);
}
@Override
@@ -18,7 +18,7 @@ public class ClusterManager implements ServerLookup {
private static final Logger clusterLogger = LoggerFactory.getLogger("io.ebean.Cluster");
private final ReentrantLock lock = new ReentrantLock(false);
private final ReentrantLock lock = new ReentrantLock();
private final ConcurrentHashMap<String, EbeanServer> serverMap = new ConcurrentHashMap<>();
@@ -1,112 +0,0 @@
package io.ebeaninternal.server.core;
import io.ebeaninternal.api.SpiBackgroundExecutor;
import io.ebeaninternal.server.lib.DaemonExecutorService;
import io.ebeaninternal.server.lib.DaemonScheduleThreadPool;
import org.slf4j.MDC;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
* The default implementation of the BackgroundExecutor.
*/
public class DefaultBackgroundExecutor implements SpiBackgroundExecutor {
private final DaemonScheduleThreadPool schedulePool;
private final DaemonExecutorService pool;
/**
* Construct the default implementation of BackgroundExecutor.
*/
public DefaultBackgroundExecutor(int schedulePoolSize, int shutdownWaitSeconds, String namePrefix) {
this.pool = new DaemonExecutorService(shutdownWaitSeconds, namePrefix);
this.schedulePool = new DaemonScheduleThreadPool(schedulePoolSize, shutdownWaitSeconds, namePrefix + "-periodic-");
}
/**
* Execute a Runnable using a background thread.
*/
@Override
public void execute(Runnable r) {
final Map<String, String> map = MDC.getCopyOfContextMap();
if (map == null) {
pool.execute(r);
} else {
pool.execute(() -> {
MDC.setContextMap(map);
try {
r.run();
} finally {
MDC.clear();
}
});
}
}
@Override
public void executePeriodically(Runnable r, long delay, TimeUnit unit) {
executePeriodically(r, delay, delay, unit);
}
@Override
public void executePeriodically(Runnable r, long initialDelay, long delay, TimeUnit unit) {
final Map<String, String> map = MDC.getCopyOfContextMap();
if (map == null) {
schedulePool.scheduleWithFixedDelay(r, initialDelay, delay, unit);
} else {
schedulePool.scheduleWithFixedDelay(() -> {
MDC.setContextMap(map);
try {
r.run();
} finally {
MDC.clear();
}
}, initialDelay, delay, unit);
}
}
@Override
public ScheduledFuture<?> schedule(Runnable r, long delay, TimeUnit unit) {
final Map<String, String> map = MDC.getCopyOfContextMap();
if (map == null) {
return schedulePool.schedule(r, delay, unit);
} else {
return schedulePool.schedule(() -> {
MDC.setContextMap(map);
try {
r.run();
} finally {
MDC.clear();
}
}, delay, unit);
}
}
@Override
public <V> ScheduledFuture<V> schedule(Callable<V> c, long delay, TimeUnit unit) {
final Map<String, String> map = MDC.getCopyOfContextMap();
if (map == null) {
return schedulePool.schedule(c, delay, unit);
} else {
return schedulePool.schedule(() -> {
MDC.setContextMap(map);
try {
return c.call();
} finally {
MDC.clear();
}
}, delay, unit);
}
}
@Override
public void shutdown() {
pool.shutdown();
schedulePool.shutdown();
}
}
@@ -10,14 +10,15 @@ import io.ebean.config.TenantMode;
import io.ebean.config.UnderscoreNamingConvention;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.h2.H2Platform;
import io.ebean.event.ShutdownManager;
import io.ebean.service.SpiContainer;
import io.ebeaninternal.api.DbOffline;
import io.ebeaninternal.api.SpiBackgroundExecutor;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.DbOffline;
import io.ebeaninternal.server.cluster.ClusterManager;
import io.ebeaninternal.server.core.bootup.BootupClassPathSearch;
import io.ebeaninternal.server.core.bootup.BootupClasses;
import io.ebean.event.ShutdownManager;
import io.ebeaninternal.server.executor.DefaultBackgroundExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -35,7 +36,7 @@ public class DefaultContainer implements SpiContainer {
private static final Logger logger = LoggerFactory.getLogger("io.ebean.internal.DefaultContainer");
private final ReentrantLock lock = new ReentrantLock(false);
private final ReentrantLock lock = new ReentrantLock();
private final ClusterManager clusterManager;
public DefaultContainer(ContainerConfig containerConfig) {
@@ -161,7 +161,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
private static final Logger logger = LoggerFactory.getLogger(DefaultServer.class);
private final ReentrantLock lock = new ReentrantLock(false);
private final ReentrantLock lock = new ReentrantLock();
private final DatabaseConfig config;
private final String serverName;
private final DatabasePlatform databasePlatform;
@@ -451,16 +451,20 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
backgroundExecutor.shutdown();
// shutdown DataSource (if its an Ebean one)
transactionManager.shutdown(shutdownDataSource, deregisterDriver);
dumpMetrics();
shutdown = true;
if (shutdownDataSource) {
config.setDataSource(null);
}
}
private void shutdownPlugins() {
private void dumpMetrics() {
if (config.isDumpMetricsOnShutdown()) {
new DumpMetrics(this, config.getDumpMetricsOptions()).dump();
}
}
private void shutdownPlugins() {
for (Plugin plugin : serverPlugins) {
try {
plugin.shutdown();
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.core;
import io.ebean.core.type.DataReader;
import io.ebeaninternal.api.SpiDtoQuery;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiQuery;
@@ -8,7 +9,6 @@ import io.ebeaninternal.server.dto.DtoMappingRequest;
import io.ebeaninternal.server.dto.DtoQueryPlan;
import io.ebeaninternal.server.persist.Binder;
import io.ebeaninternal.server.query.DtoQueryEngine;
import io.ebeaninternal.server.type.DataReader;
import io.ebeaninternal.server.type.RsetDataReader;
import java.sql.ResultSet;
@@ -13,7 +13,7 @@ public final class InternString {
private static final HashMap<String, String> map = new HashMap<>();
private static final ReentrantLock lock = new ReentrantLock(false);
private static final ReentrantLock lock = new ReentrantLock();
/**
* Return the shared instance of this string.
@@ -104,7 +104,6 @@ public abstract class PersistRequest extends BeanRequest implements BatchPostExe
return transaction.isLogSummary();
}
/**
* Return true if this persist request should use JDBC batch.
*/
@@ -119,23 +118,22 @@ public abstract class PersistRequest extends BeanRequest implements BatchPostExe
return transaction.translate(e.getMessage(), e);
}
/**
* Execute the statement.
*/
int executeStatement() {
return executeStatement(false);
}
int executeStatement(boolean addBatch) {
boolean batch = isBatchThisRequest();
try {
int rows;
BatchControl control = transaction.getBatchControl();
if (control != null) {
rows = control.executeStatementOrBatch(this, batch);
rows = control.executeStatementOrBatch(this, batch, addBatch);
} else if (batch) {
// need to create the BatchControl
control = persistExecute.createBatchControl(transaction);
rows = control.executeStatementOrBatch(this, true);
rows = control.executeStatementOrBatch(this, true, addBatch);
} else {
rows = executeNow();
}
@@ -59,7 +59,7 @@ public final class PersistRequestUpdateSql extends PersistRequest {
*/
public int addBatch() {
this.addBatch = true;
return executeOrQueue();
return executeStatement(true);
}
/**
@@ -73,13 +73,13 @@ public final class PersistRequestUpdateSql extends PersistRequest {
/**
* Add this request to BatchControl to flush later.
*/
public void addToFlushQueue(boolean early) {
public void addToFlushQueue(int pos) {
BatchControl control = transaction.getBatchControl();
if (control == null) {
control = persistExecute.createBatchControl(transaction);
}
flushQueue = true;
control.addToFlushQueue(this, early);
control.addToFlushQueue(this, pos);
}
@Override
@@ -104,18 +104,14 @@ public interface Persister {
void executeOrQueue(SpiSqlUpdate update, SpiTransaction t, boolean queue);
/**
* Queue the SqlUpdate for early execution (with JDBC batch).
* Queue the SqlUpdate for execution with position 0, 1 or 2 defining
* when it executes relative to the flush of beans .
*/
void addToFlushQueue(SpiSqlUpdate update, SpiTransaction t);
void addToFlushQueue(SpiSqlUpdate update, SpiTransaction t, int pos);
/**
* Queue the SqlUpdate for late execution (with JDBC batch).
* Add the statement to JDBC batch for later execution via executeBatch.
*/
void addToFlushQueueLast(SpiSqlUpdate update, SpiTransaction t);
/**
* Add the statement to JDBC batch for later execution via executeBatch.
*/
void addBatch(SpiSqlUpdate sqlUpdate, SpiTransaction transaction);
/**
@@ -5,6 +5,7 @@ import io.ebean.annotation.DocStore;
import io.ebean.config.DatabaseConfig;
import io.ebean.config.IdGenerator;
import io.ebean.config.ScalarTypeConverter;
import io.ebean.core.type.ScalarType;
import io.ebean.event.BeanFindController;
import io.ebean.event.BeanPersistController;
import io.ebean.event.BeanPersistListener;
@@ -18,7 +19,6 @@ import io.ebean.event.changelog.ChangeLogRegister;
import io.ebean.event.readaudit.ReadAuditLogger;
import io.ebean.event.readaudit.ReadAuditPrepare;
import io.ebean.util.AnnotationUtil;
import io.ebeaninternal.server.type.ScalarType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -223,12 +223,9 @@ public class BootupClasses implements ClassFilter {
*/
private <T> T create(Class<T> cls, boolean logOnException) {
try {
// instantiate via found class
Constructor<T> constructor = cls.getConstructor();
return constructor.newInstance();
return cls.getConstructor().newInstance();
} catch (NoSuchMethodException e) {
logger.debug("Ignore/expected - no default constructor", e);
logger.debug("Ignore/expected - no default constructor: " +e.getMessage());
return null;
} catch (Exception e) {
@@ -2,8 +2,8 @@ package io.ebeaninternal.server.deploy;
import io.ebean.bean.EntityBean;
import io.ebean.bean.PersistenceContext;
import io.ebean.core.type.DataReader;
import io.ebeaninternal.server.query.SqlJoinType;
import io.ebeaninternal.server.type.DataReader;
import java.sql.SQLException;
@@ -1,7 +1,7 @@
package io.ebeaninternal.server.deploy;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.server.type.DataReader;
import io.ebean.core.type.DataReader;
import java.sql.SQLException;
@@ -16,6 +16,8 @@ import io.ebean.config.DatabaseConfig;
import io.ebean.config.EncryptKey;
import io.ebean.config.dbplatform.IdType;
import io.ebean.config.dbplatform.PlatformIdGenerator;
import io.ebean.core.type.DocPropertyType;
import io.ebean.core.type.ScalarType;
import io.ebean.event.BeanFindController;
import io.ebean.event.BeanPersistController;
import io.ebean.event.BeanPersistListener;
@@ -82,7 +84,6 @@ import io.ebeaninternal.server.querydefn.OrmQueryDetail;
import io.ebeaninternal.server.querydefn.OrmQueryProperties;
import io.ebeaninternal.server.rawsql.SpiRawSql;
import io.ebeaninternal.server.type.DataBind;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeaninternal.util.SortByClause;
import io.ebeaninternal.util.SortByClauseParser;
import io.ebeanservice.docstore.api.DocStoreBeanAdapter;
@@ -90,7 +91,6 @@ import io.ebeanservice.docstore.api.DocStoreUpdateContext;
import io.ebeanservice.docstore.api.DocStoreUpdates;
import io.ebeanservice.docstore.api.mapping.DocMappingBuilder;
import io.ebeanservice.docstore.api.mapping.DocPropertyMapping;
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
import io.ebeanservice.docstore.api.mapping.DocumentMapping;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -522,7 +522,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
return null;
}
try {
return (EntityBean) beanType.newInstance();
return (EntityBean) beanType.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new IllegalStateException("Error trying to create the prototypeEntityBean for " + beanType, e);
}
@@ -814,7 +814,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
int propertyLength = toEbi.getPropertyLength();
String[] names = getProperties();
for (int i = 0; i < propertyLength; i++) {
if (fromEbi.isLoadedProperty(i)) {
BeanProperty property = getBeanProperty(names[i]);
if (!toEbi.isLoadedProperty(i)) {
@@ -1865,17 +1864,12 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
}
/**
* We actually need to do a query because we don't know the type without the discriminator
* value, just select the id property and discriminator column (auto added)
* We actually need to do a query because we don't know the type without the discriminator value.
*/
private T findReferenceBean(Object id, PersistenceContext pc) {
DefaultOrmQuery<T> query = new DefaultOrmQuery<>(this, ebeanServer, ebeanServer.getExpressionFactory());
query.setPersistenceContext(pc);
return query
// .select(getIdProperty().getName())
// we do not select the id because we
// probably have to load the entire bean
.setId(id).findOne();
return query.setId(id).findOne();
}
/**
@@ -2087,6 +2081,13 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
return name;
}
/**
* Return the simple name of the entity bean.
*/
public String getSimpleName() {
return beanType.getSimpleName();
}
/**
* Summary description.
*/
@@ -2271,8 +2272,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
*/
public void lazyLoadRegister(String prefix, EntityBeanIntercept ebi, EntityBean bean, LoadContext loadContext) {
// load the List/Set/Map proxy objects (deferred fetching of lists)
BeanPropertyAssocMany<?>[] manys = propertiesMany();
for (BeanPropertyAssocMany<?> many : manys) {
for (BeanPropertyAssocMany<?> many : propertiesMany()) {
if (!ebi.isLoadedProperty(many.getPropertyIndex())) {
BeanCollection<?> ref = many.createReferenceIfNull(bean);
if (ref != null && !ref.isRegisteredWithLoadContext()) {
@@ -1,8 +1,8 @@
package io.ebeaninternal.server.deploy;
import io.ebean.bean.EntityBean;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
import io.ebeaninternal.server.type.ScalarType;
import java.util.Arrays;
@@ -14,13 +14,32 @@ import java.util.Arrays;
*/
abstract class BeanDescriptorElement<T> extends BeanDescriptor<T> {
private final String simpleName;
final ElementHelp elementHelp;
BeanDescriptorElement(BeanDescriptorMap owner, DeployBeanDescriptor<T> deploy, ElementHelp elementHelp) {
super(owner, deploy);
this.simpleName = shortName(deploy.getName());
this.elementHelp = elementHelp;
}
private String shortName(String name) {
int pos = name.lastIndexOf('.');
if (pos > 1) {
pos = name.lastIndexOf('.', pos - 1);
if (pos > 1) {
return name.substring(pos + 1);
}
}
return name;
}
@Override
public String getSimpleName() {
return simpleName;
}
@Override
public boolean isJsonReadCollection() {
return true;
@@ -1,12 +1,11 @@
package io.ebeaninternal.server.deploy;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import io.ebean.bean.EntityBean;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.api.json.SpiJsonReader;
import io.ebeaninternal.api.json.SpiJsonWriter;
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
import io.ebeaninternal.server.type.ScalarType;
import java.io.IOException;
import java.util.Map;
@@ -5,10 +5,10 @@ import com.fasterxml.jackson.core.JsonToken;
import io.ebean.PersistenceIOException;
import io.ebean.SqlUpdate;
import io.ebean.bean.EntityBean;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.api.json.SpiJsonReader;
import io.ebeaninternal.api.json.SpiJsonWriter;
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
import io.ebeaninternal.server.type.ScalarType;
import java.io.IOException;
@@ -2,10 +2,10 @@ package io.ebeaninternal.server.deploy;
import com.fasterxml.jackson.core.JsonParser;
import io.ebean.bean.EntityBean;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.api.json.SpiJsonReader;
import io.ebeaninternal.api.json.SpiJsonWriter;
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
import io.ebeaninternal.server.type.ScalarType;
import java.io.IOException;
import java.util.Arrays;
@@ -16,6 +16,7 @@ import io.ebean.config.dbplatform.DbHistorySupport;
import io.ebean.config.dbplatform.DbIdentity;
import io.ebean.config.dbplatform.IdType;
import io.ebean.config.dbplatform.PlatformIdGenerator;
import io.ebean.core.type.ScalarType;
import io.ebean.event.changelog.ChangeLogFilter;
import io.ebean.event.changelog.ChangeLogListener;
import io.ebean.event.changelog.ChangeLogPrepare;
@@ -56,7 +57,6 @@ import io.ebeaninternal.server.persist.platform.MultiValueBind;
import io.ebeaninternal.server.properties.BeanPropertiesReader;
import io.ebeaninternal.server.properties.BeanPropertyAccess;
import io.ebeaninternal.server.properties.EnhanceBeanPropertyAccess;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeaninternal.server.type.ScalarTypeInteger;
import io.ebeaninternal.server.type.TypeManager;
import io.ebeaninternal.xmapping.api.XmapEbean;
@@ -117,6 +117,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
private final TypeManager typeManager;
private final BootupClasses bootupClasses;
private final String serverName;
private final List<BeanDescriptor<?>> elementDescriptors = new ArrayList<>();
private final Map<Class<?>, BeanTable> beanTableMap = new HashMap<>();
private final Map<String, BeanDescriptor<?>> descMap = new HashMap<>();
private final Map<String, BeanDescriptor<?>> descQueueMap = new HashMap<>();
@@ -202,7 +203,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* Run periodic trim of query plans.
*/
public void scheduleBackgroundTrim() {
backgroundExecutor.executePeriodically(this::trimQueryPlans, 117L, 60L, TimeUnit.SECONDS);
backgroundExecutor.scheduleWithFixedDelay(this::trimQueryPlans, 117L, 60L, TimeUnit.SECONDS);
}
private void trimQueryPlans() {
@@ -237,7 +238,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* Return the versions between timestamp suffix based on the DbHistorySupport.
*/
private String getVersionsBetweenSuffix(DatabasePlatform databasePlatform, DatabaseConfig serverConfig) {
DbHistorySupport historySupport = databasePlatform.getHistorySupport();
// with historySupport returns a simple view suffix or the sql2011 versions between timestamp suffix
return (historySupport == null) ? serverConfig.getAsOfViewSuffix() : historySupport.getVersionsBetweenSuffix(serverConfig.getAsOfViewSuffix());
@@ -361,7 +361,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
private void readEntityMapping(ClassLoader classLoader, XmapEntity entityDeploy) {
String entityClassName = entityDeploy.getClazz();
Class<?> entityClass;
try {
@@ -411,7 +410,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* For SQL based modifications we need to invalidate appropriate parts of the cache.
*/
public void cacheNotify(TransactionEventTable.TableIUD tableIUD, CacheChangeSet changeSet) {
String tableName = tableIUD.getTableName().toLowerCase();
List<BeanDescriptor<?>> normalBeanTypes = tableToDescMap.get(tableName);
if (normalBeanTypes != null) {
@@ -447,7 +445,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* Invalidate entity beans based on views via their dependent tables.
*/
public void processViewInvalidation(Set<String> viewInvalidation) {
for (String depTable : viewInvalidation) {
List<BeanDescriptor<?>> list = tableToViewDescMap.get(depTable.toLowerCase());
if (list != null) {
@@ -460,12 +457,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
/**
* Build a map of table names to BeanDescriptors.
* <p>
* This is generally used to maintain caches from table names.
* </p>
*/
private void readTableToDescriptor() {
for (BeanDescriptor<?> desc : descMap.values()) {
String baseTable = desc.getBaseTable();
if (baseTable != null) {
@@ -489,7 +482,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
private void readForeignKeys() {
for (BeanDescriptor<?> d : descMap.values()) {
d.initialiseFkeys();
}
@@ -500,18 +492,14 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* <p>
* This occurs after all the BeanDescriptors have been created. This resolves
* circular relationships between BeanDescriptors.
* </p>
* <p>
* Also responsible for creating all the BeanManagers which contain the
* persister, listener etc.
* </p>
*/
private void initialiseAll() {
// now that all the BeanDescriptors are in their map
// we can initialise them which sorts out circular
// dependencies for OneToMany and ManyToOne etc
BeanDescriptorInitContext initContext = new BeanDescriptorInitContext(asOfTableMap, draftTableMap, asOfViewSuffix);
// PASS 1:
@@ -569,7 +557,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
private void checkMissingHashCodeOrEquals(Exception source, Class<?> idType, Class<?> beanType) {
String msg = "SERIOUS ERROR: The hashCode() and equals() methods *MUST* be implemented ";
msg += "on Embedded bean " + idType + " as it is used as an Id for " + beanType;
throw new PersistenceException(msg, source);
@@ -603,7 +590,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
@SuppressWarnings("unchecked")
public <T> BeanManager<T> getBeanManager(Class<T> entityType) {
return (BeanManager<T>) getBeanManager(entityType.getName());
}
@@ -615,14 +601,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* Create the BeanControllers, BeanFinders and BeanListeners.
*/
private void createListeners() {
int qa = beanQueryAdapterManager.getRegisterCount();
int cc = persistControllerManager.getRegisterCount();
int pl = postLoadManager.getRegisterCount();
int pc = postConstructManager.getRegisterCount();
int lc = persistListenerManager.getRegisterCount();
int fc = beanFinderManager.getRegisterCount();
logger.debug("BeanPersistControllers[{}] BeanFinders[{}] BeanPersistListeners[{}] BeanQueryAdapters[{}] BeanPostLoaders[{}] BeanPostConstructors[{}]", cc, fc, lc, qa, pl, pc);
}
@@ -639,11 +623,16 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
private void registerBeanDescriptor(DeployBeanInfo<?> info) {
BeanDescriptor desc = new BeanDescriptor<>(this, info.getDescriptor());
BeanDescriptor<?> desc = new BeanDescriptor<>(this, info.getDescriptor());
descMap.put(desc.getBeanType().getName(), desc);
if (desc.isDocStoreMapped()) {
descQueueMap.put(desc.getDocStoreQueueId(), desc);
}
for (BeanPropertyAssocMany<?> many : desc.propertiesMany()) {
if (many.isElementCollection()) {
elementDescriptors.add(many.getElementDescriptor());
}
}
}
/**
@@ -651,10 +640,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* <p>
* This stops short of reading relationship meta data until after the
* BeanTables have all been created.
* </p>
*/
private void readEntityDeploymentInitial() {
for (Class<?> entityClass : bootupClasses.getEntities()) {
DeployBeanInfo<?> info = createDeployBeanInfo(entityClass);
deployInfoMap.put(entityClass, info);
@@ -687,15 +674,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* Create the BeanTable information which has the base table and id.
* <p>
* This is determined prior to resolving relationship information.
* </p>
*/
private void readEntityBeanTable() {
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
BeanTable beanTable = createBeanTable(info);
beanTableMap.put(beanTable.getBeanType(), beanTable);
}
// register non-id embedded beans (after bean tables are created)
for (DeployBeanInfo<?> info : embeddedBeans) {
registerEmbeddedBean(info);
@@ -706,17 +690,14 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* Create the BeanTable information which has the base table and id.
* <p>
* This is determined prior to resolving relationship information.
* </p>
*/
private void readEntityDeploymentAssociations() {
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
readDeployAssociations(info);
}
}
private void readInheritedIdGenerators() {
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
DeployBeanDescriptor<?> descriptor = info.getDescriptor();
InheritInfo inheritInfo = descriptor.getInheritInfo();
@@ -734,17 +715,14 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* Create the BeanTable from the deployment information gathered so far.
*/
private BeanTable createBeanTable(DeployBeanInfo<?> info) {
DeployBeanDescriptor<?> deployDescriptor = info.getDescriptor();
DeployBeanTable beanTable = deployDescriptor.createDeployBeanTable();
return new BeanTable(beanTable, this);
}
private void readEntityRelationships() {
// We only perform 'circular' checks etc after we have
// all the DeployBeanDescriptors created and in the map.
List<DeployBeanPropertyAssocOne<?>> primaryKeyJoinCheck = new ArrayList<>();
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
checkMappedBy(info, primaryKeyJoinCheck);
@@ -752,15 +730,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
for (DeployBeanPropertyAssocOne<?> prop : primaryKeyJoinCheck) {
checkUniDirectionalPrimaryKeyJoin(prop);
}
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
secondaryPropsJoins(info);
}
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
setInheritanceInfo(info);
}
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
if (!info.isEmbedded()) {
registerBeanDescriptor(info);
@@ -769,12 +744,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
/**
* Sets the inheritance info. ~EMG fix for join problem
*
* @param info the new inheritance info
* Sets the inheritance info.
*/
private void setInheritanceInfo(DeployBeanInfo<?> info) {
for (DeployBeanPropertyAssocOne<?> oneProp : info.getDescriptor().propertiesAssocOne()) {
if (!oneProp.isTransient()) {
DeployBeanInfo<?> assoc = deployInfoMap.get(oneProp.getTargetType());
@@ -783,7 +755,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
}
}
for (DeployBeanPropertyAssocMany<?> manyProp : info.getDescriptor().propertiesAssocMany()) {
if (!manyProp.isTransient()) {
DeployBeanInfo<?> assoc = deployInfoMap.get(manyProp.getTargetType());
@@ -795,7 +766,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
private void secondaryPropsJoins(DeployBeanInfo<?> info) {
DeployBeanDescriptor<?> descriptor = info.getDescriptor();
for (DeployBeanProperty prop : descriptor.propertiesBase()) {
if (prop.isSecondaryTable()) {
@@ -819,10 +789,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* This will read join information defined on the 'owning/other' side of the
* relationship. It also does some extra work for unidirectional
* relationships.
* </p>
*/
private void checkMappedBy(DeployBeanInfo<?> info, List<DeployBeanPropertyAssocOne<?>> primaryKeyJoinCheck) {
for (DeployBeanPropertyAssocOne<?> oneProp : info.getDescriptor().propertiesAssocOne()) {
if (!oneProp.isTransient()) {
if (oneProp.getMappedBy() != null) {
@@ -845,14 +813,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
private DeployBeanDescriptor<?> getTargetDescriptor(DeployBeanPropertyAssoc<?> prop) {
Class<?> targetType = prop.getTargetType();
DeployBeanInfo<?> info = deployInfoMap.get(targetType);
if (info == null) {
String msg = "Can not find descriptor [" + targetType + "] for " + prop.getFullBeanName();
throw new PersistenceException(msg);
}
return info.getDescriptor();
}
@@ -861,10 +827,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* mark it as unidirectional.
*/
private boolean findMappedBy(DeployBeanPropertyAssocMany<?> prop) {
// this is the entity bean type - that owns this property
Class<?> owningType = prop.getOwningType();
Set<String> matchSet = new HashSet<>();
// get the bean descriptor that holds the mappedBy property
@@ -918,7 +882,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
return true;
}
}
}
}
// multiple options so should specify mappedBy property
@@ -930,12 +893,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
private void makeOrderColumn(DeployBeanPropertyAssocMany<?> oneToMany) {
DeployBeanDescriptor<?> targetDesc = getTargetDescriptor(oneToMany);
DeployOrderColumn orderColumn = oneToMany.getOrderColumn();
DeployBeanProperty orderProperty = new DeployBeanProperty(targetDesc, Integer.class, ScalarTypeInteger.INSTANCE, null);
orderProperty.setName(DeployOrderColumn.LOGICAL_NAME);
orderProperty.setDbColumn(orderColumn.getName());
orderProperty.setNullable(orderColumn.isNullable());
@@ -943,7 +903,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
orderProperty.setDbUpdateable(orderColumn.isUpdatable());
orderProperty.setDbRead(true);
orderProperty.setOwningType(targetDesc.getBeanType());
final InheritInfo targetInheritInfo = targetDesc.getInheritInfo();
if (targetInheritInfo != null) {
for (InheritInfo child : targetInheritInfo.getChildren()) {
@@ -951,7 +910,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
childDescriptor.setOrderColumn(orderProperty);
}
}
targetDesc.setOrderColumn(orderProperty);
}
@@ -960,19 +918,14 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* unidirectional.
* <p>
* This means that inserts MUST cascade for this property.
* </p>
* <p>
* Create a "Shadow"/Unidirectional property on the target. It is used with
* inserts to set the foreign key value (e.g. inserts the foreign key value
* into the order_id column on the order_lines table).
* </p>
*/
private void makeUnidirectional(DeployBeanPropertyAssocMany<?> oneToMany) {
DeployBeanDescriptor<?> targetDesc = getTargetDescriptor(oneToMany);
Class<?> owningType = oneToMany.getOwningType();
if (!oneToMany.getCascadeInfo().isSave()) {
// The property MUST have persist cascading so that inserts work.
@@ -1020,11 +973,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
private void checkMappedByOneToOne(DeployBeanPropertyAssocOne<?> prop) {
// check that the mappedBy property is valid and read
// its associated join information if it is available
String mappedBy = prop.getMappedBy();
// get the mappedBy property
DeployBeanDescriptor<?> targetDesc = getTargetDescriptor(prop);
DeployBeanProperty mappedProp = targetDesc.getBeanProperty(mappedBy);
@@ -1077,10 +1028,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* <p>
* We can use the join information from the mappedBy property and reverse it
* for using in the OneToMany direction.
* </p>
*/
private void checkMappedByOneToMany(DeployBeanInfo<?> info, DeployBeanPropertyAssocMany<?> prop) {
if (prop.isElementCollection()) {
// skip mapping check
return;
@@ -1161,7 +1110,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* For mappedBy copy the joins from the other side.
*/
private void checkMappedByManyToMany(DeployBeanPropertyAssocMany<?> prop) {
// get the bean descriptor that holds the mappedBy property
String mappedBy = prop.getMappedBy();
if (mappedBy == null) {
@@ -1222,50 +1170,40 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
private <T> void setBeanControllerFinderListener(DeployBeanDescriptor<T> descriptor) {
persistControllerManager.addPersistControllers(descriptor);
postLoadManager.addPostLoad(descriptor);
postConstructManager.addPostConstructListeners(descriptor);
persistListenerManager.addPersistListeners(descriptor);
beanQueryAdapterManager.addQueryAdapter(descriptor);
beanFinderManager.addFindControllers(descriptor);
if (changeLogRegister != null) {
ChangeLogFilter changeFilter = changeLogRegister.getChangeFilter(descriptor.getBeanType());
if (changeFilter != null) {
descriptor.setChangeLogFilter(changeFilter);
}
}
}
/**
* Read the initial deployment information for a given bean type.
*/
private <T> DeployBeanInfo<T> createDeployBeanInfo(Class<T> beanClass) {
DeployBeanDescriptor<T> desc = new DeployBeanDescriptor<>(this, beanClass, config);
beanLifecycleAdapterFactory.addLifecycleMethods(desc);
// set bean controller, finder and listener
setBeanControllerFinderListener(desc);
deplyInherit.process(desc);
desc.checkInheritanceMapping();
createProperties.createProperties(desc);
DeployBeanInfo<T> info = new DeployBeanInfo<>(deployUtil, desc);
readAnnotations.readInitial(info);
return info;
}
private <T> void readDeployAssociations(DeployBeanInfo<T> info) {
DeployBeanDescriptor<T> desc = info.getDescriptor();
readAnnotations.readAssociations(info, this);
if (EntityType.SQL == desc.getEntityType()) {
desc.setBaseTable(null, null, null);
}
@@ -1273,15 +1211,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
// mark transient properties
transientProperties.process(desc);
setScalarType(desc);
if (!desc.isEmbedded()) {
// Set IdGenerator or use DB Identity
setIdGeneration(desc);
// find the appropriate default concurrency mode
setConcurrencyMode(desc);
}
// generate the byte code
createByteCode(desc);
}
@@ -1290,7 +1225,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* Set the Identity generation mechanism.
*/
private <T> void setIdGeneration(DeployBeanDescriptor<T> desc) {
if (desc.getIdGenerator() != null) {
// already assigned (So custom or UUID)
return;
@@ -1298,7 +1232,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
if (desc.idProperty() == null) {
return;
}
final DeployIdentityMode identityMode = desc.getIdentityMode();
if (identityMode.isSequence() && !dbIdentity.isSupportsSequence()) {
// explicit sequence but not supported by the DatabasePlatform
@@ -1355,11 +1288,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
private void createByteCode(DeployBeanDescriptor<?> deploy) {
// check to see if the bean supports EntityBean interface
// generate a subclass if required
setEntityBeanClass(deploy);
// use Code generation or Standard reflection to support
// getter and setter methods
setBeanReflect(deploy);
@@ -1373,10 +1304,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* <p>
* Enums are treated a bit differently in that they always have a ScalarType
* as one is built for them.
* </p>
*/
private void setScalarType(DeployBeanDescriptor<?> deployDesc) {
for (DeployBeanProperty prop : deployDesc.propertiesAll()) {
if (!(prop instanceof DeployBeanPropertyAssoc<?>)) {
deployUtil.setScalarType(prop);
@@ -1390,17 +1319,13 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* This sets the implementation of constructing entity beans and the setting
* and getting of properties. It is generally faster to use code generation
* rather than reflection to do this.
* </p>
*/
private void setBeanReflect(DeployBeanDescriptor<?> desc) {
// Set the BeanReflectGetter and BeanReflectSetter that typically
// use generated code. NB: Due to Bug 166 so now doing this for
// abstract classes as well.
BeanPropertiesReader reflectProps = new BeanPropertiesReader(desc.getBeanType());
desc.setProperties(reflectProps.getProperties());
for (DeployBeanProperty prop : desc.propertiesAll()) {
String propName = prop.getName();
Integer pos = reflectProps.getPropertyIndex(propName);
@@ -1410,7 +1335,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
"If you are running in an IDE with enhancement plugin try a Build -> Rebuild Project to recompile and enhance all entity beans. " +
"Error - property " + propName + " not found in " + reflectProps + " for type " + desc.getBeanType());
}
} else {
final int propertyIndex = pos;
prop.setPropertyIndex(propertyIndex);
@@ -1427,7 +1351,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* Return true if this is a persistent field (not transient or static).
*/
private boolean isPersistentField(DeployBeanProperty prop) {
Field field = prop.getField();
if (field == null) {
return false;
@@ -1442,12 +1365,10 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* which contain version properties.
*/
private void setConcurrencyMode(DeployBeanDescriptor<?> desc) {
if (desc.getConcurrencyMode() != null) {
// concurrency mode explicitly set during deployment
return;
}
if (checkForVersionProperties(desc)) {
desc.setConcurrencyMode(ConcurrencyMode.VERSION);
} else {
@@ -1459,23 +1380,16 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* Search for version properties also including embedded beans.
*/
private boolean checkForVersionProperties(DeployBeanDescriptor<?> desc) {
boolean hasVersionProperty = false;
List<DeployBeanProperty> props = desc.propertiesBase();
for (DeployBeanProperty prop : props) {
for (DeployBeanProperty prop : desc.propertiesBase()) {
if (prop.isVersionColumn()) {
hasVersionProperty = true;
return true;
}
}
return hasVersionProperty;
return false;
}
private boolean hasEntityBeanInterface(Class<?> beanClass) {
Class<?>[] interfaces = beanClass.getInterfaces();
for (Class<?> anInterface : interfaces) {
for (Class<?> anInterface : beanClass.getInterfaces()) {
if (anInterface.equals(EntityBean.class)) {
return true;
}
@@ -1487,18 +1401,14 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* Test the bean type to see if it implements EntityBean interface already.
*/
private void setEntityBeanClass(DeployBeanDescriptor<?> desc) {
Class<?> beanClass = desc.getBeanType();
if (!hasEntityBeanInterface(beanClass)) {
String msg = "Bean " + beanClass + " is not enhanced? Check packages specified in ebean.mf. If you are running in IDEA or " +
"Eclipse check that the enhancement plugin is installed. See https://ebean.io/docs/trouble-shooting#not-enhanced";
throw new BeanNotEnhancedException(msg);
}
// the bean already implements EntityBean
checkInheritedClasses(beanClass);
entityBeanCount++;
}
@@ -1507,7 +1417,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* enhanced or all dynamically subclassed).
*/
private void checkInheritedClasses(Class<?> beanClass) {
Class<?> superclass = beanClass.getSuperclass();
if (Object.class.equals(superclass)) {
// we got to the top of the inheritance
@@ -1566,10 +1475,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
private void addPrimaryKeyJoin(DeployBeanPropertyAssocOne<?> prop) {
String baseTable = prop.getDesc().getBaseTable();
DeployTableJoin inverse = prop.getTableJoin().createInverse(baseTable);
TableJoin inverseJoin = new TableJoin(inverse, prop.getForeignKey());
DeployBeanInfo<?> target = deployInfoMap.get(prop.getTargetType());
target.setPrimaryKeyJoin(inverseJoin);
@@ -1586,7 +1493,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
* Create a BeanDescriptor for an ElementCollection target.
*/
public <A> BeanDescriptor<A> createElementDescriptor(DeployBeanDescriptor<A> elementDescriptor, ManyType manyType, boolean scalar) {
ElementHelp elementHelp = elementHelper(manyType);
if (manyType.isMap()) {
if (scalar) {
@@ -1619,6 +1525,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
for (BeanDescriptor<?> desc : immutableDescriptorList) {
desc.visitMetrics(visitor);
}
for (BeanDescriptor<?> desc : elementDescriptors) {
desc.visitMetrics(visitor);
}
}
public List<MetaQueryPlan> queryPlanInit(QueryPlanInit request) {
@@ -3,10 +3,10 @@ package io.ebeaninternal.server.deploy;
import io.ebean.config.DatabaseConfig;
import io.ebean.config.EncryptKey;
import io.ebean.config.NamingConvention;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.server.cache.SpiCacheManager;
import io.ebeaninternal.server.deploy.id.IdBinder;
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeanservice.docstore.api.DocStoreBeanAdapter;
/**
@@ -8,6 +8,9 @@ import io.ebean.bean.PersistenceContext;
import io.ebean.config.EncryptKey;
import io.ebean.config.dbplatform.DbEncryptFunction;
import io.ebean.config.dbplatform.DbPlatformType;
import io.ebean.core.type.DataReader;
import io.ebean.core.type.DocPropertyType;
import io.ebean.core.type.ScalarType;
import io.ebean.plugin.Property;
import io.ebean.text.StringParser;
import io.ebean.util.SplitName;
@@ -28,9 +31,7 @@ import io.ebeaninternal.server.query.STreeProperty;
import io.ebeaninternal.server.query.SqlBeanLoad;
import io.ebeaninternal.server.query.SqlJoinType;
import io.ebeaninternal.server.type.DataBind;
import io.ebeaninternal.server.type.DataReader;
import io.ebeaninternal.server.type.LocalEncryptedType;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeaninternal.server.type.ScalarTypeBoolean;
import io.ebeaninternal.server.type.ScalarTypeEnum;
import io.ebeaninternal.server.type.ScalarTypeLogicalType;
@@ -38,7 +39,6 @@ import io.ebeaninternal.util.ValueUtil;
import io.ebeanservice.docstore.api.mapping.DocMappingBuilder;
import io.ebeanservice.docstore.api.mapping.DocPropertyMapping;
import io.ebeanservice.docstore.api.mapping.DocPropertyOptions;
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
import io.ebeanservice.docstore.api.support.DocStructure;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.deploy;
import io.ebean.Query;
import io.ebean.bean.EntityBean;
import io.ebean.core.type.DocPropertyType;
import io.ebean.text.PathProperties;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.SpiEbeanServer;
@@ -22,7 +23,6 @@ import io.ebeaninternal.server.query.SqlJoinType;
import io.ebeaninternal.server.querydefn.DefaultOrmQuery;
import io.ebeanservice.docstore.api.mapping.DocMappingBuilder;
import io.ebeanservice.docstore.api.mapping.DocPropertyMapping;
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
import io.ebeanservice.docstore.api.support.DocStructure;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -569,6 +569,13 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
return elementCollection;
}
/**
* Return the element bean descriptor (for an element collection only).
*/
public BeanDescriptor<T> getElementDescriptor() {
return elementDescriptor;
}
/**
* ManyToMany only, join from local table to intersection table.
*/
@@ -7,6 +7,9 @@ import io.ebean.ValuePair;
import io.ebean.bean.EntityBean;
import io.ebean.bean.EntityBeanIntercept;
import io.ebean.bean.PersistenceContext;
import io.ebean.core.type.DataReader;
import io.ebean.core.type.ScalarDataReader;
import io.ebean.core.type.ScalarType;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiQuery;
@@ -23,9 +26,6 @@ import io.ebeaninternal.server.el.ElPropertyValue;
import io.ebeaninternal.server.query.STreePropertyAssocOne;
import io.ebeaninternal.server.query.SqlBeanLoad;
import io.ebeaninternal.server.query.SqlJoinType;
import io.ebeaninternal.server.type.DataReader;
import io.ebeaninternal.server.type.ScalarDataReader;
import io.ebeaninternal.server.type.ScalarType;
import javax.persistence.PersistenceException;
import java.io.IOException;
@@ -4,9 +4,9 @@ import io.ebean.bean.BeanCollection;
import io.ebean.bean.EntityBean;
import io.ebean.bean.EntityBeanIntercept;
import io.ebean.bean.PersistenceContext;
import io.ebean.core.type.DataReader;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.query.STreePropertyAssocMany;
import io.ebeaninternal.server.type.DataReader;
import java.util.Map;
@@ -1,8 +1,8 @@
package io.ebeaninternal.server.deploy;
import io.ebean.core.type.DataReader;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.server.query.SqlBeanLoad;
import io.ebeaninternal.server.type.DataReader;
import io.ebeaninternal.server.type.ScalarType;
import javax.persistence.PersistenceException;
@@ -1,8 +1,8 @@
package io.ebeaninternal.server.deploy;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.server.query.STreeProperty;
import io.ebeaninternal.server.query.SqlJoinType;
import io.ebeaninternal.server.type.ScalarType;
import java.util.List;
@@ -1,8 +1,8 @@
package io.ebeaninternal.server.deploy;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.server.el.ElPropertyDeploy;
import io.ebeaninternal.server.query.STreeProperty;
import io.ebeaninternal.server.type.ScalarType;
import java.sql.Types;
@@ -1,6 +1,7 @@
package io.ebeaninternal.server.deploy.id;
import io.ebean.bean.EntityBean;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.core.DefaultSqlUpdate;
import io.ebeaninternal.server.core.InternString;
@@ -10,7 +11,6 @@ import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.persist.MultiValueWrapper;
import io.ebeaninternal.server.persist.platform.MultiValueBind;
import io.ebeaninternal.server.type.DataBind;
import io.ebeaninternal.server.type.ScalarType;
import java.io.DataInput;
import java.io.DataOutput;
@@ -17,6 +17,7 @@ import io.ebean.config.ScalarTypeConverter;
import io.ebean.config.dbplatform.DbDefaultValue;
import io.ebean.config.dbplatform.DbEncrypt;
import io.ebean.config.dbplatform.DbEncryptFunction;
import io.ebean.core.type.ScalarType;
import io.ebean.util.AnnotationUtil;
import io.ebeaninternal.server.core.InternString;
import io.ebeaninternal.server.deploy.BeanProperty;
@@ -26,7 +27,6 @@ import io.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty;
import io.ebeaninternal.server.el.ElPropertyValue;
import io.ebeaninternal.server.properties.BeanPropertyGetter;
import io.ebeaninternal.server.properties.BeanPropertySetter;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeaninternal.server.type.ScalarTypeWrapper;
import io.ebeanservice.docstore.api.mapping.DocPropertyOptions;
@@ -8,6 +8,7 @@ import io.ebean.bean.BeanCollection.ModifyListenMode;
import io.ebean.config.BeanNotRegisteredException;
import io.ebean.config.NamingConvention;
import io.ebean.config.TableName;
import io.ebean.core.type.ScalarType;
import io.ebean.util.CamelCaseHelper;
import io.ebeaninternal.server.deploy.BeanDescriptorManager;
import io.ebeaninternal.server.deploy.BeanProperty;
@@ -21,7 +22,6 @@ import io.ebeaninternal.server.deploy.meta.DeployOrderColumn;
import io.ebeaninternal.server.deploy.meta.DeployTableJoin;
import io.ebeaninternal.server.deploy.meta.DeployTableJoinColumn;
import io.ebeaninternal.server.query.SqlJoinType;
import io.ebeaninternal.server.type.ScalarType;
import javax.persistence.CascadeType;
import javax.persistence.CollectionTable;
@@ -39,6 +39,7 @@ import io.ebean.config.dbplatform.DbEncrypt;
import io.ebean.config.dbplatform.DbEncryptFunction;
import io.ebean.config.dbplatform.IdType;
import io.ebean.config.dbplatform.PlatformIdGenerator;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.server.deploy.DbMigrationInfo;
import io.ebeaninternal.server.deploy.IndexDefinition;
import io.ebeaninternal.server.deploy.generatedproperty.GeneratedPropertyFactory;
@@ -46,7 +47,6 @@ import io.ebeaninternal.server.deploy.meta.DeployBeanProperty;
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc;
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
import io.ebeaninternal.server.type.DataEncryptSupport;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeaninternal.server.type.ScalarTypeBytesBase;
import io.ebeaninternal.server.type.ScalarTypeBytesEncrypted;
import io.ebeaninternal.server.type.ScalarTypeEncryptedWrapper;
@@ -311,19 +311,23 @@ public class AnnotationFields extends AnnotationParser {
DbMap dbMap = get(prop, DbMap.class);
if (dbMap != null) {
util.setDbMap(prop, dbMap);
setColumnName(prop, dbMap.name());
}
DbJson dbJson = get(prop, DbJson.class);
if (dbJson != null) {
util.setDbJsonType(prop, dbJson);
setColumnName(prop, dbJson.name());
} else {
DbJsonB dbJsonB = get(prop, DbJsonB.class);
if (dbJsonB != null) {
util.setDbJsonBType(prop, dbJsonB);
setColumnName(prop, dbJsonB.name());
}
}
DbArray dbArray = get(prop, DbArray.class);
if (dbArray != null) {
util.setDbArray(prop, dbArray);
setColumnName(prop, dbArray.name());
}
}
@@ -99,11 +99,7 @@ public abstract class AnnotationParser extends AnnotationBase {
}
void readColumn(Column columnAnn, DeployBeanProperty prop) {
if (!isEmpty(columnAnn.name())) {
prop.setDbColumn(databasePlatform.convertQuotedIdentifiers(columnAnn.name()));
}
setColumnName(prop, columnAnn.name());
prop.setDbInsertable(columnAnn.insertable());
prop.setDbUpdateable(columnAnn.updatable());
prop.setNullable(columnAnn.nullable());
@@ -125,6 +121,12 @@ public abstract class AnnotationParser extends AnnotationBase {
}
}
protected void setColumnName(DeployBeanProperty prop, String name) {
if (!isEmpty(name)) {
prop.setDbColumn(databasePlatform.convertQuotedIdentifiers(name));
}
}
/**
* Return true if the validation groups are {@link Default} (respectively empty)
* can be applied to DDL generation.
@@ -2,10 +2,11 @@ package io.ebeaninternal.server.deploy.parse;
import io.ebean.Model;
import io.ebean.annotation.DbArray;
import io.ebean.annotation.DbMap;
import io.ebean.annotation.DbJson;
import io.ebean.annotation.DbJsonB;
import io.ebean.annotation.DbMap;
import io.ebean.annotation.UnmappedJson;
import io.ebean.core.type.ScalarType;
import io.ebean.util.AnnotationUtil;
import io.ebeaninternal.server.deploy.DetermineManyType;
import io.ebeaninternal.server.deploy.ManyType;
@@ -14,7 +15,6 @@ import io.ebeaninternal.server.deploy.meta.DeployBeanProperty;
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocMany;
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertySimpleCollection;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeaninternal.server.type.TypeManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -14,9 +14,9 @@ import io.ebean.config.NamingConvention;
import io.ebean.config.TableName;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.DbPlatformType;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.server.deploy.meta.DeployBeanProperty;
import io.ebeaninternal.server.type.DataEncryptSupport;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeaninternal.server.type.ScalarTypeArray;
import io.ebeaninternal.server.type.ScalarTypeWrapper;
import io.ebeaninternal.server.type.SimpleAesEncryptor;
@@ -1,7 +1,7 @@
package io.ebeaninternal.server.dto;
import io.ebeaninternal.server.type.DataReader;
import io.ebeaninternal.server.type.ScalarType;
import io.ebean.core.type.DataReader;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.server.type.TypeManager;
import java.lang.invoke.MethodHandle;
@@ -1,7 +1,7 @@
package io.ebeaninternal.server.dto;
import io.ebeaninternal.server.type.DataReader;
import io.ebeaninternal.server.type.ScalarType;
import io.ebean.core.type.DataReader;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.server.type.TypeManager;
import java.lang.invoke.MethodHandle;
@@ -1,7 +1,7 @@
package io.ebeaninternal.server.dto;
import io.ebean.core.type.DataReader;
import io.ebean.meta.MetricVisitor;
import io.ebeaninternal.server.type.DataReader;
import java.sql.SQLException;
@@ -1,6 +1,6 @@
package io.ebeaninternal.server.dto;
import io.ebeaninternal.server.type.DataReader;
import io.ebean.core.type.DataReader;
import java.sql.SQLException;
@@ -1,6 +1,6 @@
package io.ebeaninternal.server.dto;
import io.ebeaninternal.server.type.DataReader;
import io.ebean.core.type.DataReader;
import java.sql.SQLException;
@@ -1,6 +1,6 @@
package io.ebeaninternal.server.dto;
import io.ebeaninternal.server.type.DataReader;
import io.ebean.core.type.DataReader;
import java.sql.SQLException;
@@ -1,6 +1,6 @@
package io.ebeaninternal.server.dto;
import io.ebeaninternal.server.type.DataReader;
import io.ebean.core.type.DataReader;
import java.sql.SQLException;
@@ -1,6 +1,6 @@
package io.ebeaninternal.server.dto;
import io.ebeaninternal.server.type.DataReader;
import io.ebean.core.type.DataReader;
/**
* Placeholder to skip reading a column that isn't mapped to a bean property.
@@ -1,12 +1,12 @@
package io.ebeaninternal.server.el;
import io.ebean.bean.EntityBean;
import io.ebean.core.type.ScalarType;
import io.ebean.plugin.Property;
import io.ebean.text.StringParser;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.type.ScalarType;
import java.util.Arrays;
@@ -1,4 +1,4 @@
package io.ebeaninternal.server.lib;
package io.ebeaninternal.server.executor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -9,15 +9,12 @@ import java.util.concurrent.locks.ReentrantLock;
/**
* Daemon based ScheduleThreadPool.
* <p>
* Uses Daemon threads and hooks into shutdown event.
* </p>
*/
public final class DaemonScheduleThreadPool extends ScheduledThreadPoolExecutor {
private static final Logger logger = LoggerFactory.getLogger(DaemonScheduleThreadPool.class);
private final ReentrantLock lock = new ReentrantLock(false);
private final ReentrantLock lock = new ReentrantLock();
private final String namePrefix;
@@ -35,26 +32,25 @@ public final class DaemonScheduleThreadPool extends ScheduledThreadPoolExecutor
/**
* Shutdown this thread pool nicely if possible.
* <p>
* This will wait a maximum of 20 seconds before terminating any threads still
* working.
* </p>
* This will wait a maximum of shutdownWaitSeconds seconds before
* terminating any threads still working.
*/
@Override
public void shutdown() {
lock.lock();
try {
if (super.isShutdown()) {
logger.debug("DaemonScheduleThreadPool {} already shut down", namePrefix);
logger.debug("Already shutdown {}", namePrefix);
return;
}
try {
logger.debug("DaemonScheduleThreadPool {} shutting down...", namePrefix);
logger.trace("Shutting down {} ...", namePrefix);
super.shutdown();
if (!super.awaitTermination(shutdownWaitSeconds, TimeUnit.SECONDS)) {
logger.info("DaemonScheduleThreadPool shut down timeout exceeded. Terminating running threads.");
logger.info("Shutdown wait timeout exceeded. Terminating running threads for {}", namePrefix);
super.shutdownNow();
}
logger.debug("Shutdown complete for {}", namePrefix);
} catch (Exception e) {
logger.error("Error during shutdown of " + namePrefix, e);
e.printStackTrace();
@@ -1,5 +1,4 @@
package io.ebeaninternal.server.lib;
package io.ebeaninternal.server.executor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
@@ -9,42 +8,28 @@ import java.util.concurrent.atomic.AtomicInteger;
* <p>
* Daemon threads do not stop a JVM stopping. If an application only has Daemon
* threads left it will shutdown.
* </p>
* <p>
* In using Daemon threads you need to either not care about being interrupted
* on shutdown or register with the JVM shutdown hook to perform a nice shutdown
* of the daemon threads etc.
* </p>
*
* @author rbygrave
*/
public class DaemonThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
public DaemonThreadFactory(String namePrefix) {
SecurityManager s = System.getSecurityManager();
this.group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
this.namePrefix = namePrefix != null ? namePrefix : "pool-" + poolNumber.getAndIncrement() + "-thread-";
this.namePrefix = namePrefix;
}
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
Thread t = new Thread(null, r, namePrefix + threadNumber.getAndIncrement(), 0);
t.setDaemon(true);
if (t.getPriority() != Thread.NORM_PRIORITY) {
t.setPriority(Thread.NORM_PRIORITY);
}
return t;
}
}
@@ -0,0 +1,118 @@
package io.ebeaninternal.server.executor;
import io.ebeaninternal.api.SpiBackgroundExecutor;
import org.slf4j.MDC;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
* The default implementation of the BackgroundExecutor.
*/
public class DefaultBackgroundExecutor implements SpiBackgroundExecutor {
private final ScheduledExecutorService executor;
/**
* Construct the default implementation of BackgroundExecutor.
*/
public DefaultBackgroundExecutor(int schedulePoolSize, int shutdownWaitSeconds, String namePrefix) {
this.executor = new DaemonScheduleThreadPool(schedulePoolSize, shutdownWaitSeconds, namePrefix);
}
/**
* Wrap the task with MDC context if defined.
*/
<T> Callable<T> wrapMDC(Callable<T> task) {
final Map<String, String> map = MDC.getCopyOfContextMap();
if (map == null) {
return task;
} else {
return () -> {
MDC.setContextMap(map);
try {
return task.call();
} finally {
MDC.clear();
}
};
}
}
/**
* Wrap the task with MDC context if defined.
*/
Runnable wrapMDC(Runnable task) {
final Map<String, String> map = MDC.getCopyOfContextMap();
if (map == null) {
return task;
} else {
return () -> {
MDC.setContextMap(map);
try {
task.run();
} finally {
MDC.clear();
}
};
}
}
@Override
public <T> Future<T> submit(Callable<T> task) {
return executor.submit(wrapMDC(task));
}
/**
* Execute a Runnable using a background thread.
*/
@Override
public Future<?> submit(Runnable task) {
return executor.submit(wrapMDC(task));
}
@Override
public void execute(Runnable task) {
submit(task);
}
@Override
public void executePeriodically(Runnable task, long delay, TimeUnit unit) {
executor.scheduleWithFixedDelay(wrapMDC(task), delay, delay, unit);
}
@Override
public void executePeriodically(Runnable task, long initialDelay, long delay, TimeUnit unit) {
executor.scheduleWithFixedDelay(wrapMDC(task), initialDelay, delay, unit);
}
@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long initialDelay, long delay, TimeUnit unit) {
return executor.scheduleWithFixedDelay(wrapMDC(task), initialDelay, delay, unit);
}
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long initialDelay, long delay, TimeUnit unit) {
return executor.scheduleAtFixedRate(wrapMDC(task), initialDelay, delay, unit);
}
@Override
public ScheduledFuture<?> schedule(Runnable task, long delay, TimeUnit unit) {
return executor.schedule(wrapMDC(task), delay, unit);
}
@Override
public <V> ScheduledFuture<V> schedule(Callable<V> task, long delay, TimeUnit unit) {
return executor.schedule(wrapMDC(task), delay, unit);
}
@Override
public void shutdown() {
executor.shutdown();
}
}
@@ -486,21 +486,46 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
return query.filterMany(manyProperty).where(expressions, params);
}
@Override
public Query<T> withLock(Query.LockType lockType) {
return query.withLock(lockType);
}
@Override
public Query<T> withLock(Query.LockType lockType, Query.LockWait lockWait) {
return query.withLock(lockType, lockWait);
}
@Override
public Query<T> forUpdate() {
return query.forUpdate();
}
@Override
public Query<T> forUpdate(Query.LockType lockType) {
return query.forUpdate(lockType);
}
@Override
public Query<T> forUpdateNoWait() {
return query.forUpdateNoWait();
}
@Override
public Query<T> forUpdateNoWait(Query.LockType lockType) {
return query.forUpdateNoWait(lockType);
}
@Override
public Query<T> forUpdateSkipLocked() {
return query.forUpdateSkipLocked();
}
@Override
public Query<T> forUpdateSkipLocked(Query.LockType lockType) {
return query.forUpdateSkipLocked(lockType);
}
@Override
public Query<T> select(String fetchProperties) {
return query.select(fetchProperties);
@@ -491,21 +491,46 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
return exprList.findOneOrEmpty();
}
@Override
public Query<T> withLock(Query.LockType lockType) {
return exprList.withLock(lockType);
}
@Override
public Query<T> withLock(Query.LockType lockType, Query.LockWait lockWait) {
return exprList.withLock(lockType, lockWait);
}
@Override
public Query<T> forUpdate() {
return exprList.forUpdate();
}
@Override
public Query<T> forUpdate(Query.LockType lockType) {
return exprList.forUpdate(lockType);
}
@Override
public Query<T> forUpdateNoWait() {
return exprList.forUpdateNoWait();
}
@Override
public Query<T> forUpdateNoWait(Query.LockType lockType) {
return exprList.forUpdateNoWait(lockType);
}
@Override
public Query<T> forUpdateSkipLocked() {
return exprList.forUpdateSkipLocked();
}
@Override
public Query<T> forUpdateSkipLocked(Query.LockType lockType) {
return exprList.forUpdateSkipLocked(lockType);
}
/**
* Path exists - for the given path in a JSON document.
*/
@@ -45,7 +45,7 @@ public class UuidV1RndIdGenerator implements PlatformIdGenerator {
private AtomicLong nanoToMilliOffset = new AtomicLong(currentUuidTime());
private final ReentrantLock lock = new ReentrantLock(false);
private final ReentrantLock lock = new ReentrantLock();
/**
@@ -1,78 +0,0 @@
package io.ebeaninternal.server.lib;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* A "CachedThreadPool" based on Daemon threads.
* <p>
* The Threads are created as needed and once idle live for 60 seconds.
*/
public final class DaemonExecutorService {
private static final Logger logger = LoggerFactory.getLogger(DaemonExecutorService.class);
private final ReentrantLock lock = new ReentrantLock(false);
private final String namePrefix;
private final int shutdownWaitSeconds;
private final ExecutorService service;
/**
* Construct the DaemonThreadPool.
*
* @param shutdownWaitSeconds the time in seconds allowed for the pool to shutdown nicely. After
* this the pool is forced to shutdown.
*/
public DaemonExecutorService(int shutdownWaitSeconds, String namePrefix) {
this.service = Executors.newCachedThreadPool(new DaemonThreadFactory(namePrefix));
this.shutdownWaitSeconds = shutdownWaitSeconds;
this.namePrefix = namePrefix;
}
/**
* Execute the Runnable.
*/
public void execute(Runnable runnable) {
service.execute(runnable);
}
/**
* Shutdown this thread pool nicely if possible.
* <p>
* This will wait a maximum of 20 seconds before terminating any threads still
* working.
* </p>
*/
public void shutdown() {
lock.lock();
try {
if (service.isShutdown()) {
logger.debug("DaemonExecutorService[{}] already shut down", namePrefix);
return;
}
try {
logger.debug("DaemonExecutorService[{}] shutting down...", namePrefix);
service.shutdown();
if (!service.awaitTermination(shutdownWaitSeconds, TimeUnit.SECONDS)) {
logger.info("DaemonExecutorService[{}] shut down timeout exceeded. Terminating running threads.", namePrefix);
service.shutdownNow();
}
} catch (Exception e) {
logger.error("Error during shutdown of DaemonThreadPool[" + namePrefix + "]", e);
e.printStackTrace();
}
} finally {
lock.unlock();
}
}
}

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