diff --git a/README.md b/README.md
index 694c73f96..83bcbae96 100644
--- a/README.md
+++ b/README.md
@@ -55,9 +55,38 @@ Post questions or issues to the Ebean google group - https://groups.google.com/f
## Documentation
Goto [https://ebean.io/docs/](https://ebean.io/docs/)
-
## Maven central
[Maven central - io.ebean](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22io.ebean%22%20)
+## Building Ebean from source
+
+- JDK 11 or higher installed
+- Maven installed
+- `git clone git@github.com:ebean-orm/ebean.git`
+- `mvn clean install`
+
+Ebean 13 uses Java modules with module-info. This means that there are stricter compilation
+rules in place now than when building with classpath pre version 13.
+
+For Maven Surefire testing we use `false` such
+that tests run using classpath and not module-path. We are doing this until all the tooling
+(Maven, IDE) improves in the area of testing with module-info.
+
+#### Eclipse IDE
+
+Right now we can't use Eclipse IDE to build Ebean and run its tests due to its poor support
+for java modules. See [ebean/issues/2653](https://github.com/ebean-orm/ebean/issues/2653)
+
+The current recommendation is to use IntelliJ IDEA as the IDE to build and hack Ebean.
+
+
+#### IntelliJ IDEA
+
+We want to get IntelliJ to run tests using classpath similar to Maven Surefire. To do this set:
+`JUnit -> modify options -> Do not use module-path option`
+
+To set this option as the global default for IntelliJ use:
+
+`Run - Edit Configurations -> Edit configuration templates -> JUnit -> modify options - Do not use module-path option`
diff --git a/ebean-api/src/main/java/io/ebean/Ebean.java b/ebean-api/src/main/java/io/ebean/Ebean.java
deleted file mode 100644
index f58c9dac0..000000000
--- a/ebean-api/src/main/java/io/ebean/Ebean.java
+++ /dev/null
@@ -1,1226 +0,0 @@
-package io.ebean;
-
-import io.avaje.lang.Nullable;
-import io.ebean.annotation.TxIsolation;
-import io.ebean.cache.ServerCacheManager;
-import io.ebean.plugin.Property;
-import io.ebean.text.csv.CsvReader;
-import io.ebean.text.json.JsonContext;
-
-import javax.persistence.OptimisticLockException;
-import javax.persistence.PersistenceException;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Callable;
-
-/**
- * Deprecated - please migrate to use io.ebean.DB.
- *
- * Ebean is a registry of {@link Database} by name. Ebean has now been renamed to {@link DB}.
- *
- * Ebean is effectively this is an alias for {@link DB} which is the new and improved name for Ebean.
- *
- * The preference is to use DB and Database rather than Ebean and EbeanServer.
- */
-@Deprecated
-public final class Ebean {
-
- private static final DbContext context = DbContext.getInstance();
-
- private Ebean() {
- }
-
- /**
- * Get the Database for a given DataSource. If name is null this will
- * return the 'default' EbeanServer.
- *
- * This is provided to access EbeanServer for databases other than the
- * 'default' database. EbeanServer also provides more control over
- * transactions and the ability to use transactions created externally to
- * Ebean.
- *
- * {@code
- * // use the "hr" database
- * EbeanServer hrDatabase = Ebean.getServer("hr");
- *
- * Person person = hrDatabase.find(Person.class, 10);
- * }
- *
- * @param name the name of the server, can use null for the 'default server'
- */
- public static EbeanServer getServer(String name) {
- return (EbeanServer)context.get(name);
- }
-
- /**
- * Returns the default EbeanServer.
- *
- * This is equivalent to Ebean.getServer(null);
- *
- */
- public static EbeanServer getDefaultServer() {
- return (EbeanServer)context.getDefault();
- }
-
- /**
- * Register the server with this Ebean singleton. Specify if the registered
- * server is the primary/default database.
- */
- @Deprecated
- public static void register(EbeanServer server, boolean defaultServer) {
- context.register(server, defaultServer);
- }
-
- /**
- * Backdoor for registering a mock implementation of EbeanServer as the default database.
- */
- protected static EbeanServer mock(String name, EbeanServer server, boolean defaultServer) {
- return (EbeanServer)context.mock(name, server, defaultServer);
- }
-
- private static Database getDefault() {
- return context.getDefault();
- }
-
- /**
- * Return the ExpressionFactory from the default database.
- *
- * The ExpressionFactory is used internally by the query and ExpressionList to
- * build the WHERE and HAVING clauses. Alternatively you can use the
- * ExpressionFactory directly to create expressions to add to the query where
- * clause.
- *
- *
- * Alternatively you can use the {@link Expr} as a shortcut to the
- * ExpressionFactory of the 'Default' EbeanServer.
- *
- *
- * You generally need to the an ExpressionFactory (or {@link Expr}) to build
- * an expression that uses OR like Expression e = Expr.or(..., ...);
- *
- */
- public static ExpressionFactory getExpressionFactory() {
- return getDefault().expressionFactory();
- }
-
- /**
- * Return the next identity value for a given bean type.
- *
- * This will only work when a IdGenerator is on this bean type such as a DB
- * sequence or UUID.
- *
- *
- * For DB's supporting getGeneratedKeys and sequences such as Oracle10 you do
- * not need to use this method generally. It is made available for more
- * complex cases where it is useful to get an ID prior to some processing.
- *
- */
- public static Object nextId(Class> beanType) {
- return getDefault().nextId(beanType);
- }
-
- /**
- * Start a transaction with 'REQUIRED' semantics.
- *
- * With REQUIRED semantics if an active transaction already exists that transaction will be used.
- *
- *
- * The transaction is stored in a ThreadLocal variable and typically you only
- * need to use the returned Transaction IF you wish to do things like
- * use batch mode, change the transaction isolation level, use savepoints or
- * log comments to the transaction log.
- *
- *
- * Example of using a transaction to span multiple calls to find(), save()
- * etc.
- *
- * {@code
- *
- * // start a transaction (stored in a ThreadLocal)
- * Ebean.beginTransaction();
- * try {
- * Order order = Ebean.find(Order.class,10); ...
- *
- * Ebean.save(order);
- *
- * Ebean.commitTransaction();
- *
- * } finally {
- * // rollback if we didn't commit
- * // i.e. an exception occurred before commitTransaction().
- * Ebean.endTransaction();
- * }
- *
- * }
- *
- * If you want to externalise the transaction management then you should be
- * able to do this via EbeanServer. Specifically with EbeanServer you can pass
- * the transaction to the various find() and save() execute() methods. This
- * gives you the ability to create the transactions yourself externally from
- * Ebean and pass those transactions through to the various methods available
- * on EbeanServer.
- *
- */
- public static Transaction beginTransaction() {
- return getDefault().beginTransaction();
- }
-
- /**
- * Start a transaction additionally specifying the isolation level.
- *
- * @param isolation the Transaction isolation level
- */
- public static Transaction beginTransaction(TxIsolation isolation) {
- return getDefault().beginTransaction(isolation);
- }
-
- /**
- * Start a transaction typically specifying REQUIRES_NEW or REQUIRED semantics.
- *
- * Note that this provides an try finally alternative to using {@link #executeCall(TxScope, Callable)} or
- * {@link #execute(TxScope, Runnable)}.
- *
- *
- *
REQUIRES_NEW example:
- * {@code
- * // Start a new transaction. If there is a current transaction
- * // suspend it until this transaction ends
- * Transaction txn = Ebean.beginTransaction(TxScope.requiresNew());
- * try {
- *
- * ...
- *
- * // commit the transaction
- * txn.commit();
- *
- * } finally {
- * // end this transaction which:
- * // A) will rollback transaction if it has not been committed already
- * // B) will restore a previously suspended transaction
- * txn.end();
- * }
- *
- * }
- * REQUIRED example:
- * {@code
- *
- * // start a new transaction if there is not a current transaction
- * Transaction txn = Ebean.beginTransaction(TxScope.required());
- * try {
- *
- * ...
- *
- * // commit the transaction if it was created or
- * // do nothing if there was already a current transaction
- * txn.commit();
- *
- * } finally {
- * // end this transaction which will rollback the transaction
- * // if it was created for this try finally scope and has not
- * // already been committed
- * txn.end();
- * }
- *
- * }
- */
- public static Transaction beginTransaction(TxScope scope) {
- return getDefault().beginTransaction(scope);
- }
-
- /**
- * Returns the current transaction or null if there is no current transaction
- * in scope.
- */
- public static Transaction currentTransaction() {
- return getDefault().currentTransaction();
- }
-
- /**
- * The batch will be flushing automatically but you can use this to explicitly
- * flush the batch if you like.
- *
- * Flushing occurs automatically when:
- *
- *
- * - the batch size is reached
- * - A query is executed on the same transaction
- * - UpdateSql or CallableSql are mixed with bean save and delete
- * - Transaction commit occurs
- * - A getter method is called on a batched bean
- *
- */
- public static void flush() {
- currentTransaction().flush();
- }
-
- /**
- * Register a TransactionCallback on the currently active transaction.
- *
- * If there is no currently active transaction then a PersistenceException is thrown.
- *
- * @param transactionCallback the transaction callback to be registered with the current transaction
- * @throws PersistenceException if there is no currently active transaction
- */
- public static void register(TransactionCallback transactionCallback) throws PersistenceException {
- getDefault().register(transactionCallback);
- }
-
- /**
- * Commit the current transaction.
- */
- public static void commitTransaction() {
- getDefault().commitTransaction();
- }
-
- /**
- * Rollback the current transaction.
- */
- public static void rollbackTransaction() {
- getDefault().rollbackTransaction();
- }
-
- /**
- * If the current transaction has already been committed do nothing otherwise
- * rollback the transaction.
- *
- * Useful to put in a finally block to ensure the transaction is ended, rather
- * than a rollbackTransaction() in each catch block.
- *
- *
- * Code example:
- *
- * {@code
- * Ebean.beginTransaction();
- * try {
- * // do some fetching and or persisting
- *
- * // commit at the end
- * Ebean.commitTransaction();
- *
- * } finally {
- * // if commit didn't occur then rollback the transaction
- * Ebean.endTransaction();
- * }
- * }
- */
- public static void endTransaction() {
- getDefault().endTransaction();
- }
-
- /**
- * Mark the current transaction as rollback only.
- */
- public static void setRollbackOnly() {
- getDefault().currentTransaction().setRollbackOnly();
- }
-
- /**
- * Return a map of the differences between two objects of the same type.
- *
- * When null is passed in for b, then the 'OldValues' of a is used for the
- * difference comparison.
- *
- */
- public static Map diff(Object a, Object b) {
- return getDefault().diff(a, b);
- }
-
- /**
- * Either Insert or Update the bean depending on its state.
- *
- * If there is no current transaction one will be created and committed for
- * you automatically.
- *
- *
- * Save can cascade along relationships. For this to happen you need to
- * specify a cascade of CascadeType.ALL or CascadeType.PERSIST on the
- * OneToMany, OneToOne or ManyToMany annotation.
- *
- *
- * In this example below the details property has a CascadeType.ALL set so
- * saving an order will also save all its details.
- *
- * {@code
- * public class Order { ...
- *
- * @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
- * List details;
- * ...
- * }
- * }
- *
- * When a save cascades via a OneToMany or ManyToMany Ebean will automatically
- * set the 'parent' object to the 'detail' object. In the example below in
- * saving the order and cascade saving the order details the 'parent' order
- * will be set against each order detail when it is saved.
- *
- */
- public static void save(Object bean) throws OptimisticLockException {
- getDefault().save(bean);
- }
-
- /**
- * Insert the bean. This is useful when you set the Id property on a bean and
- * want to explicitly insert it.
- */
- public static void insert(Object bean) {
- getDefault().insert(bean);
- }
-
- /**
- * Insert a collection of beans.
- */
- public static void insertAll(Collection> beans) {
- getDefault().insertAll(beans);
- }
-
- /**
- * Marks the entity bean as dirty.
- *
- * This is used so that when a bean that is otherwise unmodified is updated with the version
- * property updated.
- *
- * An unmodified bean that is saved or updated is normally skipped and this marks the bean as
- * dirty so that it is not skipped.
- *
{@code
- *
- * Customer customer = Ebean.find(Customer, id);
- *
- * // mark the bean as dirty so that a save() or update() will
- * // increment the version property
- * Ebean.markAsDirty(customer);
- * Ebean.save(customer);
- *
- * }
- */
- public static void markAsDirty(Object bean) throws OptimisticLockException {
- getDefault().markAsDirty(bean);
- }
-
- /**
- * Saves the bean using an update. If you know you are updating a bean then it is preferrable to
- * use this update() method rather than save().
- *
- * Stateless updates: Note that the bean does not have to be previously fetched to call
- * update().You can create a new instance and set some of its properties programmatically for via
- * JSON/XML marshalling etc. This is described as a 'stateless update'.
- *
- *
- * Optimistic Locking: Note that if the version property is not set when update() is
- * called then no optimistic locking is performed (internally ConcurrencyMode.NONE is used).
- *
- * {@code
- *
- * // A 'stateless update' example
- * Customer customer = new Customer();
- * customer.setId(7);
- * customer.setName("ModifiedNameNoOCC");
- *
- * DB.update(customer);
- *
- * }
- */
- public static void update(Object bean) throws OptimisticLockException {
- getDefault().update(bean);
- }
-
- /**
- * Update the beans in the collection.
- */
- public static void updateAll(Collection> beans) throws OptimisticLockException {
- getDefault().updateAll(beans);
- }
-
- /**
- * Merge the bean using the default merge options.
- *
- * @param bean The bean to merge
- */
- public static void merge(Object bean) {
- getDefault().merge(bean);
- }
-
- /**
- * Merge the bean using the given merge options.
- *
- * @param bean The bean to merge
- * @param options The options to control the merge
- */
- public static void merge(Object bean, MergeOptions options) {
- getDefault().merge(bean, options);
- }
-
- /**
- * Save all the beans from a Collection.
- */
- public static int saveAll(Collection> beans) throws OptimisticLockException {
- return getDefault().saveAll(beans);
- }
-
- /**
- * This method checks the uniqueness of a bean. I.e. if the save will work. It will return the
- * properties that violates an unique / primary key. This may be done in an UI save action to
- * validate if the user has entered correct values.
- *
- * Note: This method queries the DB for uniqueness of all indices, so do not use it in a batch update.
- *
- * Note: This checks only the root bean!
- *
- *
{@code
- *
- * // there is a unique constraint on title
- *
- * Document doc = new Document();
- * doc.setTitle("One flew over the cuckoo's nest");
- * doc.setBody("clashes with doc1");
- *
- * Set properties = server().checkUniqueness(doc);
- *
- * if (properties.isEmpty()) {
- * // it is unique ... carry on
- *
- * } else {
- * // build a user friendly message
- * // to return message back to user
- *
- * String uniqueProperties = properties.toString();
- *
- * StringBuilder msg = new StringBuilder();
- *
- * properties.forEach((it)-> {
- * Object propertyValue = it.getVal(doc);
- * String propertyName = it.getName();
- * msg.append(" property["+propertyName+"] value["+propertyValue+"]");
- * });
- *
- * // uniqueProperties > [title]
- * // custom msg > property[title] value[One flew over the cuckoo's nest]
- *
- * }
- *
- * }
- *
- * @param bean The entity bean to check uniqueness on
- * @return a set of Properties if constraint validation was detected or empty list.
- */
- public static Set checkUniqueness(Object bean) {
- return getDefault().checkUniqueness(bean);
- }
-
- /**
- * Same as {@link #checkUniqueness(Object)}. but with given transaction.
- */
- public static Set checkUniqueness(Object bean, Transaction transaction) {
- return getDefault().checkUniqueness(bean, transaction);
- }
-
- /**
- * Delete the bean.
- *
- * This will return true if the bean was deleted successfully or JDBC batch is being used.
- *
- *
- * If there is no current transaction one will be created and committed for
- * you automatically.
- *
- *
- * If the bean is configured with @SoftDelete then this will perform a soft
- * delete rather than a hard/permanent delete.
- *
- *
- * If the Bean does not have a version property (or loaded version property) and
- * the bean does not exist then this returns false indicating that nothing was
- * deleted. Note that, if JDBC batch mode is used then this always returns true.
- *
- */
- public static boolean delete(Object bean) throws OptimisticLockException {
- return getDefault().delete(bean);
- }
-
- /**
- * Delete the bean in permanent fashion (will not use soft delete).
- */
- public static boolean deletePermanent(Object bean) throws OptimisticLockException {
- return getDefault().deletePermanent(bean);
- }
-
- /**
- * Delete the bean given its type and id.
- */
- public static int delete(Class> beanType, Object id) {
- return getDefault().delete(beanType, id);
- }
-
- /**
- * Delete permanent the bean given its type and id.
- */
- public static int deletePermanent(Class> beanType, Object id) {
- return getDefault().deletePermanent(beanType, id);
- }
-
- /**
- * Delete several beans given their type and id values.
- */
- public static int deleteAll(Class> beanType, Collection> ids) {
- return getDefault().deleteAll(beanType, ids);
- }
-
- /**
- * Delete permanent several beans given their type and id values.
- */
- public static int deleteAllPermanent(Class> beanType, Collection> ids) {
- return getDefault().deleteAllPermanent(beanType, ids);
- }
-
- /**
- * Delete all the beans in the Collection.
- */
- public static int deleteAll(Collection> beans) throws OptimisticLockException {
- return getDefault().deleteAll(beans);
- }
-
- /**
- * Delete permanent all the beans in the Collection (will not use soft delete).
- */
- public static int deleteAllPermanent(Collection> beans) throws OptimisticLockException {
- return getDefault().deleteAllPermanent(beans);
- }
-
- /**
- * Refresh the values of a bean.
- *
- * Note that this resets OneToMany and ManyToMany properties so that if they
- * are accessed a lazy load will refresh the many property.
- *
- */
- public static void refresh(Object bean) {
- getDefault().refresh(bean);
- }
-
- /**
- * Refresh a 'many' property of a bean.
- * {@code
- *
- * Order order = ...;
- * ...
- * // refresh the order details...
- * Ebean.refreshMany(order, "details");
- *
- * }
- *
- * @param bean the entity bean containing the List Set or Map to refresh.
- * @param manyPropertyName the property name of the List Set or Map to refresh.
- */
- public static void refreshMany(Object bean, String manyPropertyName) {
- getDefault().refreshMany(bean, manyPropertyName);
- }
-
- /**
- * Get a reference object.
- *
- * This is sometimes described as a proxy (with lazy loading).
- *
- * {@code
- *
- * Product product = Ebean.getReference(Product.class, 1);
- *
- * // You can get the id without causing a fetch/lazy load
- * Integer productId = product.getId();
- *
- * // If you try to get any other property a fetch/lazy loading will occur
- * // This will cause a query to execute...
- * String name = product.getName();
- *
- * }
- *
- * @param beanType the type of entity bean
- * @param id the id value
- */
- public static T getReference(Class beanType, Object id) {
- return getDefault().reference(beanType, id);
- }
-
- /**
- * Sort the list using the sortByClause which can contain a comma delimited
- * list of property names and keywords asc, desc, nullsHigh and nullsLow.
- *
- * - asc - ascending order (which is the default)
- * - desc - Descending order
- * - nullsHigh - Treat null values as high/large values (which is the
- * default)
- * - nullsLow- Treat null values as low/very small values
- *
- *
- * If you leave off any keywords the defaults are ascending order and treating
- * nulls as high values.
- *
- *
- * Note that the sorting uses a Comparator and Collections.sort(); and does
- * not invoke a DB query.
- *
- * {@code
- *
- * // find orders and their customers
- * List list = Ebean.find(Order.class)
- * .fetch("customer")
- * .order("id")
- * .findList();
- *
- * // sort by customer name ascending, then by order shipDate
- * // ... then by the order status descending
- * Ebean.sort(list, "customer.name, shipDate, status desc");
- *
- * // sort by customer name descending (with nulls low)
- * // ... then by the order id
- * Ebean.sort(list, "customer.name desc nullsLow, id");
- *
- * }
- *
- * @param list the list of entity beans
- * @param sortByClause the properties to sort the list by
- */
- public static void sort(List list, String sortByClause) {
- getDefault().sort(list, sortByClause);
- }
-
- /**
- * Find a bean using its unique id. This will not use caching.
- * {@code
- *
- * // Fetch order 1
- * Order order = Ebean.find(Order.class, 1);
- *
- * }
- *
- * If you want more control over the query then you can use createQuery() and
- * Query.findOne();
- *
- * {@code
- *
- * // ... additionally fetching customer, customer shipping address,
- * // order details, and the product associated with each order detail.
- * // note: only product id and name is fetch (its a "partial object").
- * // note: all other objects use "*" and have all their properties fetched.
- *
- * Query query = Ebean.find(Order.class)
- * .setId(1)
- * .fetch("customer")
- * .fetch("customer.shippingAddress")
- * .fetch("details")
- * .query();
- *
- * // fetch associated products but only fetch their product id and name
- * query.fetch("details.product", "name");
- *
- * // traverse the object graph...
- *
- * Order order = query.findOne();
- *
- * Customer customer = order.getCustomer();
- * Address shippingAddress = customer.getShippingAddress();
- * List details = order.getDetails();
- * OrderDetail detail0 = details.get(0);
- * Product product = detail0.getProduct();
- * String productName = product.getName();
- *
- * }
- *
- * @param beanType the type of entity bean to fetch
- * @param id the id value
- */
- @Nullable
- public static T find(Class beanType, Object id) {
- return getDefault().find(beanType, id);
- }
-
- /**
- * Deprecated - migrate to DB.sqlQuery().
- *
- * Create a SqlQuery for executing native sql
- * query statements.
- *
- * Note that you can use raw SQL with entity beans, refer to the SqlSelect
- * annotation for examples.
- *
- */
- @Deprecated
- public static SqlQuery createSqlQuery(String sql) {
- return getDefault().sqlQuery(sql);
- }
-
- /**
- * Deprecated - migrate to DB.sqlUpdate().
- *
- * Create a sql update for executing native dml statements.
- *
- * Use this to execute a Insert Update or Delete statement. The statement will
- * be native to the database and contain database table and column names.
- *
- * See {@link SqlUpdate} for example usage.
- */
- @Deprecated
- public static SqlUpdate createSqlUpdate(String sql) {
- return getDefault().sqlUpdate(sql);
- }
-
- /**
- * Create a CallableSql to execute a given stored procedure.
- *
- * @see CallableSql
- */
- public static CallableSql createCallableSql(String sql) {
- return getDefault().createCallableSql(sql);
- }
-
- /**
- * Create a orm update where you will supply the insert/update or delete
- * statement (rather than using a named one that is already defined using the
- * @NamedUpdates annotation).
- *
- * The orm update differs from the sql update in that it you can use the bean
- * name and bean property names rather than table and column names.
- *
- *
- * An example:
- *
- * {@code
- *
- * // The bean name and properties - "topic","postCount" and "id"
- *
- * // will be converted into their associated table and column names
- * String updStatement = "update topic set postCount = :pc where id = :id";
- *
- * Update update = Ebean.createUpdate(Topic.class, updStatement);
- *
- * update.set("pc", 9);
- * update.set("id", 3);
- *
- * int rows = update.execute();
- * System.out.println("rows updated:" + rows);
- *
- * }
- */
- public static Update createUpdate(Class beanType, String ormUpdate) {
- return getDefault().createUpdate(beanType, ormUpdate);
- }
-
- /**
- * Create a CsvReader for a given beanType.
- */
- public static CsvReader createCsvReader(Class beanType) {
- return getDefault().createCsvReader(beanType);
- }
-
- /**
- * Create a named query.
- *
- * For RawSql the named query is expected to be in ebean.xml.
- *
- *
- * @param beanType The type of entity bean
- * @param namedQuery The name of the query
- * @param The type of entity bean
- * @return The query
- */
- public static Query createNamedQuery(Class beanType, String namedQuery) {
- return getDefault().createNamedQuery(beanType, namedQuery);
- }
-
- /**
- * Create a query for a type of entity bean.
- *
- * You can use the methods on the Query object to specify fetch paths,
- * predicates, order by, limits etc.
- *
- *
- * You then use findList(), findSet(), findMap() and findOne() to execute
- * the query and return the collection or bean.
- *
- *
- * Note that a query executed by {@link Query#findList()}
- * {@link Query#findSet()} etc will execute against the same EbeanServer from
- * which is was created.
- *
- *
- * @param beanType the class of entity to be fetched
- * @return A ORM Query object for this beanType
- */
- public static Query createQuery(Class beanType) {
- return getDefault().createQuery(beanType);
- }
-
- /**
- * Parse the Ebean query language statement returning the query which can then
- * be modified (add expressions, change order by clause, change maxRows, change
- * fetch and select paths etc).
- *
- *
Example
- * {@code
- *
- * // Find order additionally fetching the customer, details and details.product name.
- *
- * String eql = "fetch customer fetch details fetch details.product (name) where id = :orderId ";
- *
- * Query query = Ebean.createQuery(Order.class, eql);
- * query.setParameter("orderId", 2);
- *
- * Order order = query.findOne();
- *
- * // This is the same as:
- *
- * Order order = Ebean.find(Order.class)
- * .fetch("customer")
- * .fetch("details")
- * .fetch("detail.product", "name")
- * .setId(2)
- * .findOne();
- *
- * }
- *
- * @param beanType The type of bean to fetch
- * @param eql The Ebean query
- * @param The type of the entity bean
- * @return The query with expressions defined as per the parsed query statement
- */
- public static Query createQuery(Class beanType, String eql) {
- return getDefault().createQuery(beanType, eql);
- }
-
- /**
- * Create a query for a type of entity bean.
- *
- * This is actually the same as {@link #createQuery(Class)}. The reason it
- * exists is that people used to JPA will probably be looking for a
- * createQuery method (the same as entityManager).
- *
- *
- * @param beanType the type of entity bean to find
- * @return A ORM Query object for this beanType
- */
- public static Query find(Class beanType) {
- return getDefault().find(beanType);
- }
-
- /**
- * Create a query using native SQL.
- *
- * The native SQL can contain named parameters or positioned parameters.
- *
- * {@code
- *
- * String sql = "select c.id, c.name from customer c where c.name like ? order by c.name";
- *
- * List customers = DB.findNative(Customer.class, sql)
- * .setParameter(1, "Rob%")
- * .findList()
- *
- * }
- *
- * @param beanType The type of entity bean to fetch
- * @param nativeSql The SQL that can contain named or positioned parameters
- * @return The query to set parameters and execute
- */
- public static Query findNative(Class beanType, String nativeSql) {
- return getDefault().findNative(beanType, nativeSql);
- }
-
- /**
- * Create a Query for DTO beans.
- *
- * DTO beans are just normal bean like classes with public constructor(s) and setters.
- * They do not need to be registered with Ebean before use.
- *
- *
- * @param dtoType The type of the DTO bean the rows will be mapped into.
- * @param sql The SQL query to execute.
- * @param The type of the DTO bean.
- */
- public static DtoQuery findDto(Class dtoType, String sql) {
- return getDefault().findDto(dtoType, sql);
- }
-
- /**
- * Create an Update query to perform a bulk update.
- *
- *
{@code
- *
- * int rows = Ebean.update(Customer.class)
- * .set("status", Customer.Status.ACTIVE)
- * .set("updtime", new Timestamp(System.currentTimeMillis()))
- * .where()
- * .gt("id", 1000)
- * .update();
- *
- * }
- *
- * @param beanType The type of entity bean to update
- * @param The type of entity bean
- * @return The update query to use
- */
- public static UpdateQuery update(Class beanType) {
- return getDefault().update(beanType);
- }
-
- /**
- * Create a filter for sorting and filtering lists of entities locally without
- * going back to the database.
- *
- * This produces and returns a new list with the sort and filters applied.
- *
- *
- * Refer to {@link Filter} for an example of its use.
- *
- */
- public static Filter filter(Class beanType) {
- return getDefault().filter(beanType);
- }
-
- /**
- * Execute a Sql Update Delete or Insert statement. This returns the number of
- * rows that where updated, deleted or inserted. If is executed in batch then
- * this returns -1. You can get the actual rowCount after commit() from
- * updateSql.getRowCount().
- *
- * If you wish to execute a Sql Select natively then you should use the
- * FindByNativeSql object.
- *
- *
- * Note that the table modification information is automatically deduced and
- * you do not need to call the Ebean.externalModification() method when you
- * use this method.
- *
- *
- * Example:
- *
- * {@code
- *
- * // example that uses 'named' parameters
- * String s = "UPDATE f_topic set post_count = :count where id = :id"
- *
- * SqlUpdate update = Ebean.createSqlUpdate(s);
- *
- * update.setParameter("id", 1);
- * update.setParameter("count", 50);
- *
- * int modifiedCount = Ebean.execute(update);
- *
- * String msg = "There where " + modifiedCount + "rows updated";
- *
- * }
- *
- * @param sqlUpdate the update sql potentially with bind values
- * @return the number of rows updated or deleted. -1 if executed in batch.
- * @see SqlUpdate
- * @see CallableSql
- * @see Ebean#execute(CallableSql)
- */
- public static int execute(SqlUpdate sqlUpdate) {
- return getDefault().execute(sqlUpdate);
- }
-
- /**
- * For making calls to stored procedures.
- *
- * Example:
- *
- * {@code
- *
- * String sql = "{call sp_order_modify(?,?,?)}";
- *
- * CallableSql cs = Ebean.createCallableSql(sql);
- * cs.setParameter(1, 27);
- * cs.setParameter(2, "SHIPPED");
- * cs.registerOut(3, Types.INTEGER);
- *
- * Ebean.execute(cs);
- *
- * // read the out parameter
- * Integer returnValue = (Integer) cs.getObject(3);
- *
- * }
- *
- * @see CallableSql
- * @see Ebean#execute(SqlUpdate)
- */
- public static int execute(CallableSql callableSql) {
- return getDefault().execute(callableSql);
- }
-
- /**
- * Execute a TxRunnable in a Transaction with an explicit scope.
- *
- * The scope can control the transaction type, isolation and rollback
- * semantics.
- *
- * {@code
- *
- * // set specific transactional scope settings
- * TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
- *
- * Ebean.execute(scope, new TxRunnable() {
- * public void run() {
- * User u1 = Ebean.find(User.class, 1);
- * ...
- * }
- * });
- *
- * }
- */
- public static void execute(TxScope scope, Runnable r) {
- getDefault().execute(scope, r);
- }
-
- /**
- * Execute a Runnable in a Transaction with the default scope.
- *
- * The default scope runs with REQUIRED and by default will rollback on any
- * exception (checked or runtime).
- *
- * {@code
- *
- * Ebean.execute(() -> {
- *
- * User u1 = Ebean.find(User.class, 1);
- * User u2 = Ebean.find(User.class, 2);
- *
- * u1.setName("u1 mod");
- * u2.setName("u2 mod");
- *
- * Ebean.save(u1);
- * Ebean.save(u2);
- *
- * });
- *
- * }
- */
- public static void execute(Runnable r) {
- getDefault().execute(r);
- }
-
- /**
- * Execute a Callable in a Transaction with an explicit scope.
- *
- * The scope can control the transaction type, isolation and rollback
- * semantics.
- *
- * {@code
- *
- * // set specific transactional scope settings
- * TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
- *
- * Ebean.executeCall(scope, new Callable() {
- * public String call() {
- * User u1 = Ebean.find(User.class, 1);
- * ...
- * return u1.getEmail();
- * }
- * });
- *
- * }
- */
- public static T executeCall(TxScope scope, Callable c) {
- return getDefault().executeCall(scope, c);
- }
-
- /**
- * Execute a Callable in a Transaction with the default scope.
- *
- * The default scope runs with REQUIRED and by default will rollback on any
- * exception (checked or runtime).
- *
- *
- * This is basically the same as TxRunnable except that it returns an Object
- * (and you specify the return type via generics).
- *
- * {@code
- *
- * Ebean.executeCall(() -> {
- *
- * User u1 = Ebean.find(User.class, 1);
- * User u2 = Ebean.find(User.class, 2);
- *
- * u1.setName("u1 mod");
- * u2.setName("u2 mod");
- *
- * Ebean.save(u1);
- * Ebean.save(u2);
- *
- * return u1.getEmail();
- *
- * });
- *
- * }
- */
- public static T executeCall(Callable c) {
- return getDefault().executeCall(c);
- }
-
- /**
- * Inform Ebean that tables have been modified externally. These could be the
- * result of from calling a stored procedure, other JDBC calls or external
- * programs including other frameworks.
- *
- * If you use Ebean.execute(UpdateSql) then the table modification information
- * is automatically deduced and you do not need to call this method yourself.
- *
- *
- * This information is used to invalidate objects out of the cache and
- * potentially text indexes. This information is also automatically broadcast
- * across the cluster.
- *
- *
- * If there is a transaction then this information is placed into the current
- * transactions event information. When the transaction is committed this
- * information is registered (with the transaction manager). If this
- * transaction is rolled back then none of the transaction event information
- * registers including the information you put in via this method.
- *
- *
- * If there is NO current transaction when you call this method then this
- * information is registered immediately (with the transaction manager).
- *
- *
- * @param tableName the name of the table that was modified
- * @param inserts true if rows where inserted into the table
- * @param updates true if rows on the table where updated
- * @param deletes true if rows on the table where deleted
- */
- public static void externalModification(String tableName, boolean inserts, boolean updates, boolean deletes) {
- getDefault().externalModification(tableName, inserts, updates, deletes);
- }
-
- /**
- * Return the BeanState for a given entity bean.
- *
- * This will return null if the bean is not an enhanced entity bean.
- *
- */
- public static BeanState getBeanState(Object bean) {
- return getDefault().beanState(bean);
- }
-
- /**
- * Return the manager of the server cache ("L2" cache).
- */
- public static ServerCacheManager getServerCacheManager() {
- return getDefault().cacheManager();
- }
-
- /**
- * Return the BackgroundExecutor service for asynchronous processing of
- * queries.
- */
- public static BackgroundExecutor getBackgroundExecutor() {
- return getDefault().backgroundExecutor();
- }
-
- /**
- * Return the JsonContext for reading/writing JSON.
- */
- public static JsonContext json() {
- return getDefault().json();
- }
-
-}
diff --git a/ebean-api/src/main/java/io/ebean/EbeanServer.java b/ebean-api/src/main/java/io/ebean/EbeanServer.java
deleted file mode 100644
index 010dd5a8e..000000000
--- a/ebean-api/src/main/java/io/ebean/EbeanServer.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package io.ebean;
-
-/**
- * Deprecated - please migrate to io.ebean.Database.
- * Provides the API for fetching and saving beans to a particular Database.
- *
- * Effectively this is an alias for {@link Database} which is now the new
- * and improved name for EbeanServer.
- *
- * The preference is to use DB and Database rather than Ebean and EbeanServer.
- */
-@Deprecated
-public interface EbeanServer extends Database {
-
-}
diff --git a/ebean-api/src/main/java/io/ebean/EbeanServerFactory.java b/ebean-api/src/main/java/io/ebean/EbeanServerFactory.java
deleted file mode 100644
index c774488a0..000000000
--- a/ebean-api/src/main/java/io/ebean/EbeanServerFactory.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package io.ebean;
-
-import io.ebean.config.ContainerConfig;
-import io.ebean.config.ServerConfig;
-
-/**
- * Deprecated - please migrate to DatabaseFactory.
- *
- * Creates EbeanServer instances.
- *
- * This uses either a ServerConfig or properties in the ebean.properties file to
- * configure and create a EbeanServer instance.
- *
- *
- * The EbeanServer instance can either be registered with the Ebean singleton or
- * not. The Ebean singleton effectively holds a map of EbeanServers by a name.
- * If the EbeanServer is registered with the Ebean singleton you can retrieve it
- * later via {@link Ebean#getServer(String)}.
- *
- *
- * One EbeanServer can be nominated as the 'default/primary' EbeanServer. Many
- * methods on the Ebean singleton such as {@link Ebean#find(Class)} are just a
- * convenient way of using the 'default/primary' EbeanServer.
- *
- */
-@Deprecated
-public class EbeanServerFactory {
-
- /**
- * Initialise the container with clustering configuration.
- *
- * Call this prior to creating any EbeanServer instances or alternatively set the
- * ContainerConfig on the ServerConfig when creating the first EbeanServer instance.
- */
- public static void initialiseContainer(ContainerConfig containerConfig) {
- DatabaseFactory.initialiseContainer(containerConfig);
- }
-
- /**
- * Create using ebean.properties to configure the database.
- */
- public static EbeanServer create(String name) {
- return (EbeanServer)DatabaseFactory.create(name);
- }
-
- /**
- * Create using the ServerConfig object to configure the database.
- */
- public static EbeanServer create(ServerConfig config) {
- return (EbeanServer)DatabaseFactory.create(config);
- }
-
- /**
- * Create using the ServerConfig additionally specifying a classLoader to use as the context class loader.
- */
- public static EbeanServer createWithContextClassLoader(ServerConfig config, ClassLoader classLoader) {
- return (EbeanServer)DatabaseFactory.createWithContextClassLoader(config, classLoader);
- }
-
- /**
- * Shutdown gracefully all EbeanServers cleaning up any resources as required.
- *
- * This is typically invoked via JVM shutdown hook and not explicitly called.
- *
- */
- public static void shutdown() {
- DatabaseFactory.shutdown();
- }
-
-}
diff --git a/ebean-api/src/main/java/io/ebean/config/ServerConfig.java b/ebean-api/src/main/java/io/ebean/config/ServerConfig.java
deleted file mode 100644
index de02ae681..000000000
--- a/ebean-api/src/main/java/io/ebean/config/ServerConfig.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package io.ebean.config;
-
-import io.ebean.DatabaseFactory;
-
-/**
- * Deprecated - please migrate to io.ebean.DatabaseConfig.
- *
- * The configuration used for creating a Database.
- *
- * Used to programmatically construct a Database and optionally register it
- * with the DB singleton.
- *
- *
- * If you just use DB without this programmatic configuration DB will read
- * the application.properties file and take the configuration from there. This usually
- * includes searching the class path and automatically registering any entity
- * classes and listeners etc.
- *
- * {@code
- *
- * ServerConfig config = new ServerConfig();
- *
- * // read the ebean.properties and load
- * // those settings into this serverConfig object
- * config.loadFromProperties();
- *
- * // explicitly register the entity beans to avoid classpath scanning
- * config.addClass(Customer.class);
- * config.addClass(User.class);
- *
- * Database database = DatabaseFactory.create(config);
- *
- * }
- *
- *
- * Note that ServerConfigProvider provides a standard Java ServiceLoader mechanism that can
- * be used to apply configuration to the ServerConfig.
- *
- *
- * @author emcgreal
- * @author rbygrave
- * @see DatabaseFactory
- */
-@Deprecated
-public class ServerConfig extends DatabaseConfig {
-
-}
diff --git a/ebean-api/src/main/java/io/ebean/config/ServerConfigProvider.java b/ebean-api/src/main/java/io/ebean/config/ServerConfigProvider.java
deleted file mode 100644
index 1ba45907d..000000000
--- a/ebean-api/src/main/java/io/ebean/config/ServerConfigProvider.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package io.ebean.config;
-
-/**
- * Deprecated - migrate to DatabaseConfigProvider.
- *
- * Provides a ServiceLoader based mechanism to configure a ServerConfig.
- *
- * Provide an implementation and register it via the standard Java ServiceLoader mechanism
- * via a file at META-INF/services/io.ebean.config.ServerConfigProvider.
- *
- * If you are using a DI container like Spring or Guice you are unlikely to use this but instead use a
- * spring specific configuration. When we are not using a DI container we may use this mechanism to
- * explicitly register the entity beans and avoid classpath scanning.
- *
- * {@code
- *
- * public class EbeanConfigProvider implements ServerConfigProvider {
- *
- * @Override
- * public void apply(ServerConfig config) {
- *
- * // register the entity bean classes explicitly
- * config.addClass(Customer.class);
- * config.addClass(User.class);
- * ...
- * }
- * }
- *
- * }
- */
-@Deprecated
-public interface ServerConfigProvider {
-
- /**
- * Apply the configuration to the ServerConfig.
- *
- * Typically we explicitly register entity bean classes and thus avoid classpath scanning.
- *
- */
- void apply(ServerConfig config);
-}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java
index 027956e1f..57ca5e9bc 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java
@@ -23,7 +23,7 @@ import java.util.stream.Stream;
/**
* Service Provider extension to EbeanServer.
*/
-public interface SpiEbeanServer extends SpiServer, ExtendedServer, EbeanServer, BeanCollectionLoader {
+public interface SpiEbeanServer extends SpiServer, ExtendedServer, BeanCollectionLoader {
/**
* Return true if the L2 cache has been disabled.
@@ -55,7 +55,6 @@ public interface SpiEbeanServer extends SpiServer, ExtendedServer, EbeanServer,
*
* Typically used to identify the origin of queries for AutoTune and object
* graph costing.
- *
*/
CallOrigin createCallOrigin();
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/cache/DefaultServerCache.java b/ebean-core/src/main/java/io/ebeaninternal/server/cache/DefaultServerCache.java
index ae3a297b3..f3b49fd2e 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/cache/DefaultServerCache.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/cache/DefaultServerCache.java
@@ -13,6 +13,8 @@ import java.io.Serializable;
import java.lang.ref.SoftReference;
import java.util.*;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.ReentrantLock;
/**
* The default cache implementation.
@@ -43,10 +45,13 @@ public class DefaultServerCache implements ServerCache {
protected final String name;
protected final String shortName;
- private final int maxSize;
- private final int trimFrequency;
- private final int maxIdleSecs;
- private final int maxSecsToLive;
+ protected final int maxSize;
+ protected final int trimFrequency;
+ protected final int maxIdleSecs;
+ protected final int maxSecsToLive;
+ protected final long trimOnPut;
+ protected final ReentrantLock lock = new ReentrantLock();
+ protected final AtomicLong mutationCounter = new AtomicLong();
public DefaultServerCache(DefaultServerCacheConfig config) {
this.name = config.getName();
@@ -56,6 +61,7 @@ public class DefaultServerCache implements ServerCache {
this.maxIdleSecs = config.getMaxIdleSecs();
this.maxSecsToLive = config.getMaxSecsToLive();
this.trimFrequency = config.determineTrimFrequency();
+ this.trimOnPut = config.determineTrimOnPut();
MetricFactory factory = MetricFactory.get();
String prefix = "l2n.";
@@ -187,6 +193,9 @@ public class DefaultServerCache implements ServerCache {
public void put(Object key, Object value) {
map.put(key, new SoftReference<>(new CacheEntry(key, value)));
putCount.increment();
+ if (mutationCounter.incrementAndGet() > trimOnPut) {
+ runEviction();
+ }
}
/**
@@ -222,62 +231,72 @@ public class DefaultServerCache implements ServerCache {
* Run the eviction based on Idle time, Time to live and LRU last access.
*/
public void runEviction() {
- long trimForMaxSize;
- if (maxSize == 0) {
- trimForMaxSize = 0;
- } else {
- trimForMaxSize = size() - maxSize;
- }
- if (maxIdleSecs == 0 && maxSecsToLive == 0 && trimForMaxSize < 0) {
- // nothing to trim on this cache
- return;
- }
- long startNanos = System.nanoTime();
- long trimmedByIdle = 0;
- long trimmedByGC = 0;
- long trimmedByTTL = 0;
- long trimmedByLRU = 0;
-
- List activeList = new ArrayList<>(map.size());
- long idleExpireNano = startNanos - TimeUnit.SECONDS.toNanos(maxIdleSecs);
- long ttlExpireNano = startNanos - TimeUnit.SECONDS.toNanos(maxSecsToLive);
- Iterator> it = map.values().iterator();
- while (it.hasNext()) {
- SoftReference ref = it.next();
- final CacheEntry cacheEntry = ref.get();
- if (cacheEntry == null) {
- it.remove();
- trimmedByGC++;
- } else if (maxIdleSecs > 0 && idleExpireNano > cacheEntry.getLastAccessTime()) {
- it.remove();
- trimmedByIdle++;
- } else if (maxSecsToLive > 0 && ttlExpireNano > cacheEntry.getCreateTime()) {
- it.remove();
- trimmedByTTL++;
- } else if (trimForMaxSize > 0) {
- activeList.add(cacheEntry);
+ lock.lock();
+ try {
+ long trimForMaxSize;
+ if (maxSize == 0) {
+ trimForMaxSize = 0;
+ } else {
+ trimForMaxSize = size() - maxSize;
}
- }
- if (trimForMaxSize > 0 && activeList.size() > maxSize) {
- // sort into last access time ascending
- activeList.sort(BY_LAST_ACCESS);
- int trimSize = getTrimSize();
- for (int i = trimSize; i < activeList.size(); i++) {
- // remove if still in the cache
- if (map.remove(activeList.get(i).getKey()) != null) {
- trimmedByLRU++;
+ if (maxIdleSecs == 0 && maxSecsToLive == 0 && trimForMaxSize < 0) {
+ // nothing to trim on this cache
+ mutationCounter.set(0);
+ return;
+ }
+ long startNanos = System.nanoTime();
+ long trimmedByIdle = 0;
+ long trimmedByGC = 0;
+ long trimmedByTTL = 0;
+ long trimmedByLRU = 0;
+
+ try {
+ List activeList = new ArrayList<>(map.size());
+ long idleExpireNano = startNanos - TimeUnit.SECONDS.toNanos(maxIdleSecs);
+ long ttlExpireNano = startNanos - TimeUnit.SECONDS.toNanos(maxSecsToLive);
+ Iterator> it = map.values().iterator();
+ while (it.hasNext()) {
+ SoftReference ref = it.next();
+ final CacheEntry cacheEntry = ref.get();
+ if (cacheEntry == null) {
+ it.remove();
+ trimmedByGC++;
+ } else if (maxIdleSecs > 0 && idleExpireNano > cacheEntry.getLastAccessTime()) {
+ it.remove();
+ trimmedByIdle++;
+ } else if (maxSecsToLive > 0 && ttlExpireNano > cacheEntry.getCreateTime()) {
+ it.remove();
+ trimmedByTTL++;
+ } else if (trimForMaxSize > 0) {
+ activeList.add(cacheEntry.forSort());
+ }
}
+ if (trimForMaxSize > 0 && activeList.size() > maxSize) {
+ // sort into last access time ascending
+ activeList.sort(BY_LAST_ACCESS);
+ int trimSize = getTrimSize();
+ for (int i = trimSize; i < activeList.size(); i++) {
+ // remove if still in the cache
+ if (map.remove(activeList.get(i).getKey()) != null) {
+ trimmedByLRU++;
+ }
+ }
+ }
+ mutationCounter.set(0);
+ evictCount.add(trimmedByIdle);
+ evictCount.add(trimmedByGC);
+ evictCount.add(trimmedByTTL);
+ evictCount.add(trimmedByLRU);
+ if (logger.isTraceEnabled()) {
+ long exeMicros = TimeUnit.MICROSECONDS.convert(System.nanoTime() - startNanos, TimeUnit.NANOSECONDS);
+ logger.trace("Executed trim of cache {} in [{}]millis idle[{}] timeToLive[{}] accessTime[{}] gc[{}]",
+ name, exeMicros, trimmedByIdle, trimmedByTTL, trimmedByLRU, trimmedByGC);
+ }
+ } catch (Throwable e) {
+ logger.warn("Error during trim of DefaultServerCache [" + name + "]. Cache might be bigger than desired.", e);
}
- }
-
- evictCount.add(trimmedByIdle);
- evictCount.add(trimmedByGC);
- evictCount.add(trimmedByTTL);
- evictCount.add(trimmedByLRU);
- if (logger.isTraceEnabled()) {
- long exeMicros = TimeUnit.MICROSECONDS.convert(System.nanoTime() - startNanos, TimeUnit.NANOSECONDS);
- logger.trace("Executed trim of cache {} in [{}]millis idle[{}] timeToLive[{}] accessTime[{}] gc[{}]",
- name, exeMicros, trimmedByIdle, trimmedByTTL, trimmedByLRU, trimmedByGC);
+ } finally {
+ lock.unlock();
}
}
@@ -293,7 +312,7 @@ public class DefaultServerCache implements ServerCache {
}
/**
- * Comparator for sorting by last access time.
+ * Comparator for sorting by last access sort, a copy of last access time that should not mutate during trim processing.
*/
public static final class CompareByLastAccess implements Comparator, Serializable {
@@ -301,7 +320,7 @@ public class DefaultServerCache implements ServerCache {
@Override
public int compare(CacheEntry e1, CacheEntry e2) {
- return Long.compare(e1.getLastAccessTime(), e2.getLastAccessTime());
+ return Long.compare(e1.lastAccessSort, e2.lastAccessSort);
}
}
@@ -314,6 +333,7 @@ public class DefaultServerCache implements ServerCache {
private final Object value;
private final long createTime;
private long lastAccessTime;
+ private long lastAccessSort;
public CacheEntry(Object key, Object value) {
this.key = key;
@@ -322,6 +342,14 @@ public class DefaultServerCache implements ServerCache {
this.lastAccessTime = createTime;
}
+ /**
+ * Store a copy of lastAccessTime used for sorting. This value should not change during trim processing.
+ */
+ public CacheEntry forSort() {
+ this.lastAccessSort = lastAccessTime;
+ return this;
+ }
+
/**
* Return the entry key.
*/
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/cache/DefaultServerCacheConfig.java b/ebean-core/src/main/java/io/ebeaninternal/server/cache/DefaultServerCacheConfig.java
index 2e5c5dbcd..3f3a5c0f0 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/cache/DefaultServerCacheConfig.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/cache/DefaultServerCacheConfig.java
@@ -76,4 +76,14 @@ public final class DefaultServerCacheConfig {
}
return 0;
}
+
+ /**
+ * Determine the number of mutations/puts required to trigger a runEviction() in the foreground.
+ */
+ public long determineTrimOnPut() {
+ if (maxSize > 0) {
+ return maxSize / 10;
+ }
+ return 1000;
+ }
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/cluster/ClusterManager.java b/ebean-core/src/main/java/io/ebeaninternal/server/cluster/ClusterManager.java
index a85444486..b273c031a 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/cluster/ClusterManager.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/cluster/ClusterManager.java
@@ -1,6 +1,6 @@
package io.ebeaninternal.server.cluster;
-import io.ebean.EbeanServer;
+import io.ebean.Database;
import io.ebean.config.ContainerConfig;
import io.ebeaninternal.server.transaction.RemoteTransactionEvent;
import org.slf4j.Logger;
@@ -20,7 +20,7 @@ public class ClusterManager implements ServerLookup {
private final ReentrantLock lock = new ReentrantLock();
- private final ConcurrentHashMap serverMap = new ConcurrentHashMap<>();
+ private final ConcurrentHashMap serverMap = new ConcurrentHashMap<>();
private final Object monitor = new Object();
@@ -53,7 +53,7 @@ public class ClusterManager implements ServerLookup {
return factory;
}
- public void registerServer(EbeanServer server) {
+ public void registerServer(Database server) {
lock.lock();
try {
serverMap.put(server.name(), server);
@@ -66,7 +66,7 @@ public class ClusterManager implements ServerLookup {
}
@Override
- public EbeanServer getServer(String name) {
+ public Database getServer(String name) {
lock.lock();
try {
return serverMap.get(name);
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/cluster/ServerLookup.java b/ebean-core/src/main/java/io/ebeaninternal/server/cluster/ServerLookup.java
index abf835371..c3240bf8c 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/cluster/ServerLookup.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/cluster/ServerLookup.java
@@ -1,14 +1,14 @@
package io.ebeaninternal.server.cluster;
-import io.ebean.EbeanServer;
+import io.ebean.Database;
/**
- * Returns EbeanServer instances for remote message reading.
+ * Returns Database instances for remote message reading.
*/
public interface ServerLookup {
/**
* Return the EbeanServer instance by name.
*/
- EbeanServer getServer(String name);
+ Database getServer(String name);
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java
index bde0e1ce4..fc84373b0 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java
@@ -5,8 +5,6 @@ import io.ebean.config.ContainerConfig;
import io.ebean.config.DatabaseConfig;
import io.ebean.config.DatabaseConfigProvider;
import io.ebean.config.ModuleInfoLoader;
-import io.ebean.config.ServerConfig;
-import io.ebean.config.ServerConfigProvider;
import io.ebean.config.TenantMode;
import io.ebean.config.UnderscoreNamingConvention;
import io.ebean.config.dbplatform.DatabasePlatform;
@@ -128,15 +126,8 @@ public final class DefaultContainer implements SpiContainer {
private void applyConfigServices(DatabaseConfig config) {
if (config.isDefaultServer()) {
- boolean appliedConfig = false;
for (DatabaseConfigProvider configProvider : ServiceLoader.load(DatabaseConfigProvider.class)) {
configProvider.apply(config);
- appliedConfig = true;
- }
- if (!appliedConfig && config instanceof ServerConfig) {
- for (ServerConfigProvider configProvider : ServiceLoader.load(ServerConfigProvider.class)) {
- configProvider.apply((ServerConfig)config);
- }
}
}
if (config.isAutoLoadModuleInfo()) {
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java
index 1736618dc..df2e1a2aa 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java
@@ -32,7 +32,7 @@ import java.util.stream.Stream;
* Default implementation of an Object Relational query.
*/
@NonNullApi
-public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery {
+public class DefaultOrmQuery extends AbstractQuery implements SpiQuery {
private static final String DEFAULT_QUERY_NAME = "default";
private static final FetchConfig FETCH_CACHE = FetchConfig.ofCache();
@@ -173,33 +173,32 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
this.detail = new OrmQueryDetail();
}
- public void setNativeSql(String nativeSql) {
+ public final void setNativeSql(String nativeSql) {
this.nativeSql = nativeSql;
}
@Override
- public DtoQuery asDto(Class dtoClass) {
+ public final DtoQuery asDto(Class dtoClass) {
return server.findDto(dtoClass, this);
}
@Override
- public UpdateQuery asUpdate() {
+ public final UpdateQuery asUpdate() {
return new DefaultUpdateQuery<>(this);
}
@Override
- public BeanDescriptor getBeanDescriptor() {
+ public final BeanDescriptor getBeanDescriptor() {
return beanDescriptor;
}
-
@Override
- public boolean isFindAll() {
+ public final boolean isFindAll() {
return whereExpressions == null && nativeSql == null && rawSql == null;
}
@Override
- public boolean isFindById() {
+ public final boolean isFindById() {
if (id == null && whereExpressions != null) {
id = whereExpressions.idEqualTo(beanDescriptor.idName());
if (id != null) {
@@ -210,7 +209,7 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public String profileEventId() {
+ public final String profileEventId() {
switch (mode) {
case LAZYLOAD_BEAN:
return FIND_ONE_LAZY;
@@ -222,23 +221,23 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public String getProfileId() {
+ public final String getProfileId() {
return getPlanLabel();
}
@Override
- public Query setProfileLocation(ProfileLocation profileLocation) {
+ public final Query setProfileLocation(ProfileLocation profileLocation) {
this.profileLocation = profileLocation;
return this;
}
@Override
- public String getLabel() {
+ public final String getLabel() {
return label;
}
@Override
- public String getPlanLabel() {
+ public final String getPlanLabel() {
if (label != null) {
return label;
}
@@ -249,41 +248,41 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public void setProfilePath(String label, String relativePath, ProfileLocation profileLocation) {
+ public final void setProfilePath(String label, String relativePath, ProfileLocation profileLocation) {
this.profileLocation = profileLocation;
this.label = ((profileLocation == null) ? label : profileLocation.label()) + "_" + relativePath;
}
@Override
- public Query setLabel(String label) {
+ public final Query setLabel(String label) {
this.label = label;
return this;
}
@Override
- public boolean isAutoTunable() {
+ public final boolean isAutoTunable() {
return nativeSql == null && beanDescriptor.isAutoTunable();
}
@Override
- public Query setUseDocStore(boolean useDocStore) {
+ public final Query setUseDocStore(boolean useDocStore) {
this.useDocStore = useDocStore;
return this;
}
@Override
- public boolean isUseDocStore() {
+ public final boolean isUseDocStore() {
return useDocStore;
}
@Override
- public Query apply(FetchPath fetchPath) {
+ public final Query apply(FetchPath fetchPath) {
fetchPath.apply(this);
return this;
}
@Override
- public void addSoftDeletePredicate(String softDeletePredicate) {
+ public final void addSoftDeletePredicate(String softDeletePredicate) {
if (softDeletePredicates == null) {
softDeletePredicates = new ArrayList<>();
}
@@ -291,91 +290,91 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public List getSoftDeletePredicates() {
+ public final List getSoftDeletePredicates() {
return softDeletePredicates;
}
@Override
- public boolean isAsOfBaseTable() {
+ public final boolean isAsOfBaseTable() {
return asOfBaseTable;
}
@Override
- public void setAsOfBaseTable() {
+ public final void setAsOfBaseTable() {
this.asOfBaseTable = true;
}
@Override
- public Query setAllowLoadErrors() {
+ public final Query setAllowLoadErrors() {
this.allowLoadErrors = true;
return this;
}
@Override
- public void incrementAsOfTableCount() {
+ public final void incrementAsOfTableCount() {
asOfTableCount++;
}
@Override
- public void incrementAsOfTableCount(int increment) {
+ public final void incrementAsOfTableCount(int increment) {
asOfTableCount += increment;
}
@Override
- public int getAsOfTableCount() {
+ public final int getAsOfTableCount() {
return asOfTableCount;
}
@Override
- public Timestamp getAsOf() {
+ public final Timestamp getAsOf() {
return asOf;
}
@Override
- public Query asOf(Timestamp asOfDateTime) {
+ public final Query asOf(Timestamp asOfDateTime) {
this.temporalMode = (asOfDateTime != null) ? TemporalMode.AS_OF : TemporalMode.CURRENT;
this.asOf = asOfDateTime;
return this;
}
@Override
- public Query asDraft() {
+ public final Query asDraft() {
this.temporalMode = TemporalMode.DRAFT;
this.useBeanCache = CacheMode.OFF;
return this;
}
@Override
- public Query setIncludeSoftDeletes() {
+ public final Query setIncludeSoftDeletes() {
this.temporalMode = TemporalMode.SOFT_DELETED;
return this;
}
@Override
- public Query setDocIndexName(String indexName) {
+ public final Query setDocIndexName(String indexName) {
this.docIndexName = indexName;
this.useDocStore = true;
return this;
}
@Override
- public String getDocIndexName() {
+ public final String getDocIndexName() {
return docIndexName;
}
@Override
- public SpiRawSql getRawSql() {
+ public final SpiRawSql getRawSql() {
return rawSql;
}
@Override
- public Query setRawSql(RawSql rawSql) {
+ public final Query setRawSql(RawSql rawSql) {
this.rawSql = (SpiRawSql) rawSql;
return this;
}
@Override
- public String getOriginKey() {
+ public final String getOriginKey() {
if (parentNode == null || parentNode.getOriginQueryPoint() == null) {
return null;
} else {
@@ -384,32 +383,32 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public int getLazyLoadBatchSize() {
+ public final int getLazyLoadBatchSize() {
return lazyLoadBatchSize;
}
@Override
- public Query setLazyLoadBatchSize(int lazyLoadBatchSize) {
+ public final Query setLazyLoadBatchSize(int lazyLoadBatchSize) {
this.lazyLoadBatchSize = lazyLoadBatchSize;
return this;
}
@Override
- public String getLazyLoadProperty() {
+ public final String getLazyLoadProperty() {
return lazyLoadProperty;
}
@Override
- public void setLazyLoadProperty(String lazyLoadProperty) {
+ public final void setLazyLoadProperty(String lazyLoadProperty) {
this.lazyLoadProperty = lazyLoadProperty;
}
@Override
- public ExpressionFactory getExpressionFactory() {
+ public final ExpressionFactory getExpressionFactory() {
return expressionFactory;
}
- private void createExtraJoinsToSupportManyWhereClause() {
+ private final void createExtraJoinsToSupportManyWhereClause() {
manyWhereJoins = new ManyWhereJoins();
if (whereExpressions != null) {
whereExpressions.containsMany(beanDescriptor, manyWhereJoins);
@@ -431,7 +430,7 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
* Return the extra joins required to support the where clause for 'Many' properties.
*/
@Override
- public ManyWhereJoins getManyWhereJoins() {
+ public final ManyWhereJoins getManyWhereJoins() {
return manyWhereJoins;
}
@@ -440,7 +439,7 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
* included in the query.
*/
@Override
- public boolean selectAllForLazyLoadProperty() {
+ public final boolean selectAllForLazyLoadProperty() {
if (lazyLoadProperty != null) {
if (!detail.containsProperty(lazyLoadProperty)) {
detail.select("*");
@@ -481,12 +480,12 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public void setLazyLoadManyPath(String lazyLoadManyPath) {
+ public final void setLazyLoadManyPath(String lazyLoadManyPath) {
this.lazyLoadManyPath = lazyLoadManyPath;
}
@Override
- public SpiQuerySecondary convertJoins() {
+ public final SpiQuerySecondary convertJoins() {
if (!useDocStore) {
createExtraJoinsToSupportManyWhereClause();
}
@@ -510,7 +509,7 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public void setDefaultSelectClause() {
+ public final void setDefaultSelectClause() {
if (type.defaultSelect()) {
detail.setDefaultSelectClause(beanDescriptor);
} else if (!detail.hasSelectClause()) {
@@ -520,39 +519,39 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public void setTenantId(Object tenantId) {
+ public final void setTenantId(Object tenantId) {
this.tenantId = tenantId;
}
@Override
- public Object getTenantId() {
+ public final Object getTenantId() {
return tenantId;
}
@Override
- public void setDetail(OrmQueryDetail detail) {
+ public final void setDetail(OrmQueryDetail detail) {
this.detail = detail;
}
@Override
- public boolean tuneFetchProperties(OrmQueryDetail tunedDetail) {
+ public final boolean tuneFetchProperties(OrmQueryDetail tunedDetail) {
return detail.tuneFetchProperties(tunedDetail);
}
@Override
- public OrmQueryDetail getDetail() {
+ public final OrmQueryDetail getDetail() {
return detail;
}
@Override
- public ExpressionList filterMany(String prop) {
+ public final ExpressionList filterMany(String prop) {
OrmQueryProperties chunk = detail.getChunk(prop, true);
return chunk.filterMany(this);
}
@Override
- public void setFilterMany(String prop, ExpressionList> filterMany) {
+ public final void setFilterMany(String prop, ExpressionList> filterMany) {
if (filterMany != null) {
OrmQueryProperties chunk = detail.getChunk(prop, true);
chunk.setFilterMany((SpiExpressionList>) filterMany);
@@ -560,7 +559,7 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public void prepareDocNested() {
+ public final void prepareDocNested() {
if (textExpressions != null) {
textExpressions.prepareDocNested(beanDescriptor);
}
@@ -573,14 +572,14 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
* Setup to be a delete or update query.
*/
@Override
- public void setupForDeleteOrUpdate() {
+ public final void setupForDeleteOrUpdate() {
forUpdate = null;
rootTableAlias = "${RTA}"; // alias we remove later
setSelectId();
}
@Override
- public CQueryPlanKey setDeleteByIdsPlan() {
+ public final CQueryPlanKey setDeleteByIdsPlan() {
// re-build plan for cascading via delete by ids
queryPlanKey = queryPlanKey.withDeleteByIds();
return queryPlanKey;
@@ -590,14 +589,14 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
* Set the select clause to select the Id property.
*/
@Override
- public void setSelectId() {
+ public final void setSelectId() {
// clear select and fetch joins
detail.clear();
select(beanDescriptor.idSelect());
}
@Override
- public void setSingleAttribute() {
+ public final void setSingleAttribute() {
this.singleAttribute = true;
}
@@ -605,12 +604,12 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
* Return true if this is a single attribute query.
*/
@Override
- public boolean isSingleAttribute() {
+ public final boolean isSingleAttribute() {
return singleAttribute;
}
@Override
- public CountDistinctOrder getCountDistinctOrder() {
+ public final CountDistinctOrder getCountDistinctOrder() {
return countDistinctOrder;
}
@@ -618,12 +617,12 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
* Return true if the Id should be included in the query.
*/
@Override
- public boolean isWithId() {
+ public final boolean isWithId() {
return !manualId && !distinct && !singleAttribute;
}
@Override
- public CacheIdLookup cacheIdLookup() {
+ public final CacheIdLookup cacheIdLookup() {
if (whereExpressions == null) {
return null;
}
@@ -647,7 +646,7 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public NaturalKeyQueryData naturalKey() {
+ public final NaturalKeyQueryData naturalKey() {
if (whereExpressions == null) {
return null;
}
@@ -667,7 +666,7 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public NaturalKeyBindParam getNaturalKeyBindParam() {
+ public final NaturalKeyBindParam getNaturalKeyBindParam() {
NaturalKeyBindParam namedBind = null;
if (bindParams != null) {
namedBind = bindParams.getNaturalKeyBindParam();
@@ -752,38 +751,38 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public Query setPersistenceContextScope(PersistenceContextScope scope) {
+ public final Query setPersistenceContextScope(PersistenceContextScope scope) {
this.persistenceContextScope = scope;
return this;
}
@Override
- public PersistenceContextScope getPersistenceContextScope() {
+ public final PersistenceContextScope getPersistenceContextScope() {
return persistenceContextScope;
}
@Override
- public Type getType() {
+ public final Type getType() {
return type;
}
@Override
- public void setType(Type type) {
+ public final void setType(Type type) {
this.type = type;
}
@Override
- public String getLoadDescription() {
+ public final String getLoadDescription() {
return loadDescription;
}
@Override
- public String getLoadMode() {
+ public final String getLoadMode() {
return loadMode;
}
@Override
- public void setLoadDescription(String loadMode, String loadDescription) {
+ public final void setLoadDescription(String loadMode, String loadDescription) {
this.loadMode = loadMode;
this.loadDescription = loadDescription;
}
@@ -796,7 +795,7 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
*
*/
@Override
- public PersistenceContext getPersistenceContext() {
+ public final PersistenceContext getPersistenceContext() {
return persistenceContext;
}
@@ -808,17 +807,17 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
*
*/
@Override
- public void setPersistenceContext(PersistenceContext persistenceContext) {
+ public final void setPersistenceContext(PersistenceContext persistenceContext) {
this.persistenceContext = persistenceContext;
}
@Override
- public void setLazyLoadForParents(BeanPropertyAssocMany> many) {
+ public final void setLazyLoadForParents(BeanPropertyAssocMany> many) {
this.lazyLoadForParentsProperty = many;
}
@Override
- public BeanPropertyAssocMany> getLazyLoadMany() {
+ public final BeanPropertyAssocMany> getLazyLoadMany() {
return lazyLoadForParentsProperty;
}
@@ -826,60 +825,60 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
* Return true if the query detail has neither select or joins specified.
*/
@Override
- public boolean isDetailEmpty() {
+ public final boolean isDetailEmpty() {
return detail.isEmpty();
}
@Override
- public boolean isAutoTuned() {
+ public final boolean isAutoTuned() {
return autoTuned;
}
@Override
- public void setAutoTuned(boolean autoTuned) {
+ public final void setAutoTuned(boolean autoTuned) {
this.autoTuned = autoTuned;
}
@Override
- public Boolean isAutoTune() {
+ public final Boolean isAutoTune() {
return autoTune;
}
@Override
- public void setDefaultRawSqlIfRequired() {
+ public final void setDefaultRawSqlIfRequired() {
if (beanDescriptor.isRawSqlBased() && rawSql == null) {
rawSql = beanDescriptor.namedRawSql(DEFAULT_QUERY_NAME);
}
}
@Override
- public Query setAutoTune(boolean autoTune) {
+ public final Query setAutoTune(boolean autoTune) {
this.autoTune = autoTune;
return this;
}
@Override
- public Query withLock(LockType lockType) {
+ public final Query withLock(LockType lockType) {
return setForUpdateWithMode(LockWait.WAIT, lockType);
}
@Override
- public Query withLock(LockType lockType, LockWait lockWait) {
+ public final Query withLock(LockType lockType, LockWait lockWait) {
return setForUpdateWithMode(lockWait, lockType);
}
@Override
- public Query forUpdate() {
+ public final Query forUpdate() {
return setForUpdateWithMode(LockWait.WAIT, LockType.DEFAULT);
}
@Override
- public Query forUpdateNoWait() {
+ public final Query forUpdateNoWait() {
return setForUpdateWithMode(LockWait.NOWAIT, LockType.DEFAULT);
}
@Override
- public Query forUpdateSkipLocked() {
+ public final Query forUpdateSkipLocked() {
return setForUpdateWithMode(LockWait.SKIPLOCKED, LockType.DEFAULT);
}
@@ -891,32 +890,32 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public boolean isForUpdate() {
+ public final boolean isForUpdate() {
return forUpdate != null;
}
@Override
- public LockWait getForUpdateLockWait() {
+ public final LockWait getForUpdateLockWait() {
return forUpdate;
}
@Override
- public LockType getForUpdateLockType() {
+ public final LockType getForUpdateLockType() {
return lockType;
}
@Override
- public ProfilingListener getProfilingListener() {
+ public final ProfilingListener getProfilingListener() {
return profilingListener;
}
@Override
- public void setProfilingListener(ProfilingListener profilingListener) {
+ public final void setProfilingListener(ProfilingListener profilingListener) {
this.profilingListener = profilingListener;
}
@Override
- public QueryType getQueryType() {
+ public final QueryType getQueryType() {
if (type != null) {
switch (type) {
case DELETE:
@@ -929,57 +928,57 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public Mode getMode() {
+ public final Mode getMode() {
return mode;
}
@Override
- public TemporalMode getTemporalMode() {
+ public final TemporalMode getTemporalMode() {
return temporalMode;
}
@Override
- public boolean isAsOfQuery() {
+ public final boolean isAsOfQuery() {
return asOf != null;
}
@Override
- public boolean isAsDraft() {
+ public final boolean isAsDraft() {
return TemporalMode.DRAFT == temporalMode;
}
@Override
- public boolean isIncludeSoftDeletes() {
+ public final boolean isIncludeSoftDeletes() {
return TemporalMode.SOFT_DELETED == temporalMode;
}
@Override
- public void setMode(Mode mode) {
+ public final void setMode(Mode mode) {
this.mode = mode;
}
@Override
- public boolean isUsageProfiling() {
+ public final boolean isUsageProfiling() {
return usageProfiling;
}
@Override
- public void setUsageProfiling(boolean usageProfiling) {
+ public final void setUsageProfiling(boolean usageProfiling) {
this.usageProfiling = usageProfiling;
}
@Override
- public void setParentNode(ObjectGraphNode parentNode) {
+ public final void setParentNode(ObjectGraphNode parentNode) {
this.parentNode = parentNode;
}
@Override
- public ObjectGraphNode getParentNode() {
+ public final ObjectGraphNode getParentNode() {
return parentNode;
}
@Override
- public ObjectGraphNode setOrigin(CallOrigin callOrigin) {
+ public final ObjectGraphNode setOrigin(CallOrigin callOrigin) {
// create a 'origin' which links this query to the profiling information
ObjectGraphOrigin o = new ObjectGraphOrigin(calculateOriginQueryHash(), callOrigin, beanType.getName());
parentNode = new ObjectGraphNode(o, null);
@@ -1006,7 +1005,7 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
/**
* Calculate the query hash for either AutoTune query tuning or Query Plan caching.
*/
- CQueryPlanKey createQueryPlanKey() {
+ final CQueryPlanKey createQueryPlanKey() {
if (isNativeSql()) {
String bindHash = (bindParams == null) ? "" : bindParams.calcQueryPlanHash();
queryPlanKey = new NativeSqlQueryPlanKey(type.ordinal() + nativeSql + "-" + firstRow + "-" + maxRows + "-" + bindHash);
@@ -1101,17 +1100,17 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public boolean isNativeSql() {
+ public final boolean isNativeSql() {
return nativeSql != null;
}
@Override
- public String getNativeSql() {
+ public final String getNativeSql() {
return nativeSql;
}
@Override
- public Object getQueryPlanKey() {
+ public final Object getQueryPlanKey() {
return queryPlanKey;
}
@@ -1119,7 +1118,7 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
* Prepare the query which prepares any expressions (sub-query expressions etc) and calculates the query plan key.
*/
@Override
- public CQueryPlanKey prepare(SpiOrmQueryRequest request) {
+ public final CQueryPlanKey prepare(SpiOrmQueryRequest request) {
prepareExpressions(request);
prepareForPaging();
queryPlanKey = createQueryPlanKey();
@@ -1157,7 +1156,7 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public void queryBindKey(BindValuesKey key) {
+ public final void queryBindKey(BindValuesKey key) {
key.add(id);
if (whereExpressions != null) whereExpressions.queryBindKey(key);
if (havingExpressions != null) havingExpressions.queryBindKey(key);
@@ -1173,7 +1172,7 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
*
*/
@Override
- public HashQuery queryHash() {
+ public final HashQuery queryHash() {
// calculateQueryPlanHash is called just after potential AutoTune tuning
// so queryPlanHash is calculated well before this method is called
BindValuesKey bindKey = new BindValuesKey();
@@ -1182,7 +1181,7 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public boolean isRawSql() {
+ public final boolean isRawSql() {
return rawSql != null;
}
@@ -1190,151 +1189,151 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
* Return the timeout.
*/
@Override
- public int getTimeout() {
+ public final int getTimeout() {
return timeout;
}
@Override
- public boolean hasMaxRowsOrFirstRow() {
+ public final boolean hasMaxRowsOrFirstRow() {
return maxRows > 0 || firstRow > 0;
}
@Override
- public boolean isVersionsBetween() {
+ public final boolean isVersionsBetween() {
return versionsStart != null;
}
@Override
- public Timestamp getVersionStart() {
+ public final Timestamp getVersionStart() {
return versionsStart;
}
@Override
- public Timestamp getVersionEnd() {
+ public final Timestamp getVersionEnd() {
return versionsEnd;
}
@Override
- public Boolean isReadOnly() {
+ public final Boolean isReadOnly() {
return readOnly;
}
@Override
- public Query setReadOnly(boolean readOnly) {
+ public final Query setReadOnly(boolean readOnly) {
this.readOnly = readOnly;
return this;
}
@Override
- public boolean isBeanCachePut() {
+ public final boolean isBeanCachePut() {
return useBeanCache.isPut() && beanDescriptor.isBeanCaching();
}
@Override
- public boolean isBeanCacheGet() {
+ public final boolean isBeanCacheGet() {
return useBeanCache.isGet() && beanDescriptor.isBeanCaching();
}
@Override
- public boolean isForceHitDatabase() {
+ public final boolean isForceHitDatabase() {
return forUpdate != null || CacheMode.PUT == useBeanCache;
}
@Override
- public void resetBeanCacheAutoMode(boolean findOne) {
+ public final void resetBeanCacheAutoMode(boolean findOne) {
if (useBeanCache == CacheMode.AUTO && useQueryCache != CacheMode.OFF) {
useBeanCache = CacheMode.OFF;
}
}
@Override
- public CacheMode getUseBeanCache() {
+ public final CacheMode getUseBeanCache() {
return useBeanCache;
}
@Override
- public CacheMode getUseQueryCache() {
+ public final CacheMode getUseQueryCache() {
return useQueryCache;
}
@Override
- public Query setBeanCacheMode(CacheMode beanCacheMode) {
+ public final Query setBeanCacheMode(CacheMode beanCacheMode) {
this.useBeanCache = beanCacheMode;
return this;
}
@Override
- public Query setUseQueryCache(CacheMode useQueryCache) {
+ public final Query setUseQueryCache(CacheMode useQueryCache) {
this.useQueryCache = useQueryCache;
return this;
}
@Override
- public Query setLoadBeanCache(boolean loadBeanCache) {
+ public final Query setLoadBeanCache(boolean loadBeanCache) {
this.useBeanCache = CacheMode.PUT;
return this;
}
@Override
- public Query setTimeout(int secs) {
+ public final Query setTimeout(int secs) {
this.timeout = secs;
return this;
}
@Override
- public void selectProperties(Set props) {
+ public final void selectProperties(Set props) {
detail.selectProperties(props);
}
@Override
- public void fetchProperties(String property, Set columns, FetchConfig config) {
+ public final void fetchProperties(String property, Set columns, FetchConfig config) {
detail.fetchProperties(property, columns, config);
}
@Override
- public void selectProperties(OrmQueryProperties properties) {
+ public final void selectProperties(OrmQueryProperties properties) {
detail.selectProperties(properties);
}
@Override
- public void fetchProperties(String path, OrmQueryProperties other) {
+ public final void fetchProperties(String path, OrmQueryProperties other) {
detail.fetchProperties(path, other);
}
@Override
- public void addNested(String name, OrmQueryDetail nestedDetail, FetchConfig config) {
+ public final void addNested(String name, OrmQueryDetail nestedDetail, FetchConfig config) {
detail.addNested(name, nestedDetail, config);
}
@Override
- public Query select(String columns) {
+ public final Query select(String columns) {
detail.select(columns);
return this;
}
@Override
- public Query select(FetchGroup fetchGroup) {
+ public final Query select(FetchGroup fetchGroup) {
this.detail = ((SpiFetchGroup) fetchGroup).detail();
return this;
}
@Override
- public Query fetch(String path) {
+ public final Query fetch(String path) {
return fetch(path, null, null);
}
@Override
- public Query fetch(String path, FetchConfig joinConfig) {
+ public final Query fetch(String path, FetchConfig joinConfig) {
return fetch(path, null, joinConfig);
}
@Override
- public Query fetch(String path, String properties) {
+ public final Query fetch(String path, String properties) {
return fetch(path, properties, null);
}
@Override
- public Query fetch(String path, String properties, FetchConfig config) {
+ public final Query fetch(String path, String properties, FetchConfig config) {
if (nativeSql != null && (config == null || config.isJoin())) {
// can't use fetch join with nativeSql (as the root query)
config = FETCH_QUERY;
@@ -1343,32 +1342,32 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public Query fetchQuery(String path) {
+ public final Query fetchQuery(String path) {
return fetchInternal(path, null, FETCH_QUERY);
}
@Override
- public Query fetchCache(String path) {
+ public final Query fetchCache(String path) {
return fetchInternal(path, null, FETCH_CACHE);
}
@Override
- public Query fetchLazy(String path) {
+ public final Query fetchLazy(String path) {
return fetchInternal(path, null, FETCH_LAZY);
}
@Override
- public Query fetchQuery(String path, String properties) {
+ public final Query fetchQuery(String path, String properties) {
return fetchInternal(path, properties, FETCH_QUERY);
}
@Override
- public Query fetchCache(String path, String properties) {
+ public final Query fetchCache(String path, String properties) {
return fetchInternal(path, properties, FETCH_CACHE);
}
@Override
- public Query fetchLazy(String path, String properties) {
+ public final Query fetchLazy(String path, String properties) {
return fetchInternal(path, properties, FETCH_LAZY);
}
@@ -1378,45 +1377,45 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public Query usingTransaction(Transaction transaction) {
+ public final Query usingTransaction(Transaction transaction) {
this.transaction = (SpiTransaction) transaction;
return this;
}
@Override
- public Query usingConnection(Connection connection) {
+ public final Query usingConnection(Connection connection) {
this.transaction = new ExternalJdbcTransaction(connection);
return this;
}
@Override
- public Query usingDatabase(Database database) {
+ public final Query usingDatabase(Database database) {
this.server = (SpiEbeanServer) database;
return this;
}
@Override
- public int delete() {
+ public final int delete() {
return server.delete(this, transaction);
}
@Override
- public int delete(Transaction transaction) {
+ public final int delete(Transaction transaction) {
return server.delete(this, transaction);
}
@Override
- public int update() {
+ public final int update() {
return server.update(this, transaction);
}
@Override
- public int update(Transaction transaction) {
+ public final int update(Transaction transaction) {
return server.update(this, transaction);
}
@Override
- public List findIds() {
+ public final List findIds() {
// a copy of this query is made in the server
// as the query needs to modified (so we modify
// the copy rather than this query instance)
@@ -1424,12 +1423,12 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public boolean exists() {
+ public final boolean exists() {
return server.exists(this, transaction);
}
@Override
- public int findCount() {
+ public final int findCount() {
// a copy of this query is made in the server
// as the query needs to modified (so we modify
// the copy rather than this query instance)
@@ -1437,38 +1436,38 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public void findEachWhile(Predicate consumer) {
+ public final void findEachWhile(Predicate consumer) {
server.findEachWhile(this, consumer, transaction);
}
@Override
- public void findEach(Consumer consumer) {
+ public final void findEach(Consumer consumer) {
server.findEach(this, consumer, transaction);
}
@Override
- public void findEach(int batch, Consumer> consumer) {
+ public final void findEach(int batch, Consumer> consumer) {
server.findEach(this, batch, consumer, transaction);
}
@Override
- public QueryIterator findIterate() {
+ public final QueryIterator findIterate() {
return server.findIterate(this, transaction);
}
@Override
- public Stream findStream() {
+ public final Stream findStream() {
return server.findStream(this, transaction);
}
@Override
- public List> findVersions() {
+ public final List> findVersions() {
this.temporalMode = TemporalMode.VERSIONS;
return server.findVersions(this, transaction);
}
@Override
- public List> findVersionsBetween(Timestamp start, Timestamp end) {
+ public final List> findVersionsBetween(Timestamp start, Timestamp end) {
if (start == null || end == null) {
throw new IllegalArgumentException("start and end must not be null");
}
@@ -1479,64 +1478,64 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public List findList() {
+ public final List findList() {
return server.findList(this, transaction);
}
@Override
- public Set findSet() {
+ public final Set findSet() {
return server.findSet(this, transaction);
}
@Override
- public Map findMap() {
+ public final Map findMap() {
return server.findMap(this, transaction);
}
@Override
@SuppressWarnings("unchecked")
- public List findSingleAttributeList() {
+ public final List findSingleAttributeList() {
return (List) server.findSingleAttributeList(this, transaction);
}
@Override
- public A findSingleAttribute() {
+ public final A findSingleAttribute() {
List list = findSingleAttributeList();
return !list.isEmpty() ? list.get(0) : null;
}
@Override
- public T findOne() {
+ public final T findOne() {
return server.findOne(this, transaction);
}
@Override
- public Optional findOneOrEmpty() {
+ public final Optional findOneOrEmpty() {
return server.findOneOrEmpty(this, transaction);
}
@Override
- public FutureIds findFutureIds() {
+ public final FutureIds findFutureIds() {
return server.findFutureIds(this, transaction);
}
@Override
- public FutureList findFutureList() {
+ public final FutureList findFutureList() {
return server.findFutureList(this, transaction);
}
@Override
- public FutureRowCount findFutureCount() {
+ public final FutureRowCount findFutureCount() {
return server.findFutureCount(this, transaction);
}
@Override
- public PagedList findPagedList() {
+ public final PagedList findPagedList() {
return server.findPagedList(this, transaction);
}
@Override
- public Query setParameter(Object value) {
+ public final Query setParameter(Object value) {
if (bindParams == null) {
bindParams = new BindParams();
}
@@ -1545,7 +1544,7 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public Query setParameters(Object... values) {
+ public final Query setParameters(Object... values) {
if (bindParams == null) {
bindParams = new BindParams();
}
@@ -1559,7 +1558,7 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
* have in the query.
*/
@Override
- public Query setParameter(int position, Object value) {
+ public final Query setParameter(int position, Object value) {
if (bindParams == null) {
bindParams = new BindParams();
}
@@ -1571,7 +1570,7 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
* Set a named bind parameter. Named parameters have a colon to prefix the name.
*/
@Override
- public Query setParameter(String name, Object value) {
+ public final Query setParameter(String name, Object value) {
if (namedParams != null) {
ONamedParam param = namedParams.get(name);
if (param != null) {
@@ -1587,7 +1586,7 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public void setArrayParameter(String name, Collection> values) {
+ public final void setArrayParameter(String name, Collection> values) {
if (namedParams != null) {
throw new IllegalStateException("setArrayParameter() not supported when EQL parsed query");
}
@@ -1598,22 +1597,22 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public boolean checkPagingOrderBy() {
+ public final boolean checkPagingOrderBy() {
return orderById && !useDocStore;
}
@Override
- public boolean orderByIsEmpty() {
+ public final boolean orderByIsEmpty() {
return orderBy == null || orderBy.isEmpty();
}
@Override
- public OrderBy getOrderBy() {
+ public final OrderBy getOrderBy() {
return orderBy;
}
@Override
- public OrderBy orderBy() {
+ public final OrderBy orderBy() {
if (orderBy == null) {
orderBy = new OrderBy<>(this, null);
}
@@ -1621,7 +1620,7 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery<
}
@Override
- public Query orderBy(String orderByClause) {
+ public final Query orderBy(String orderByClause) {
if (orderByClause == null || orderByClause.trim().isEmpty()) {
this.orderBy = null;
} else {
@@ -1631,7 +1630,7 @@ public final class DefaultOrmQuery