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: - *

- * - */ - 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 extends AbstractQuery implements SpiQuery< } @Override - public Query setOrderBy(OrderBy orderBy) { + public final Query setOrderBy(OrderBy orderBy) { this.orderBy = orderBy; if (orderBy != null) { orderBy.setQuery(this); @@ -1640,12 +1639,12 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery< } @Override - public boolean isManualId() { + public final boolean isManualId() { return manualId; } @Override - public void setManualId() { + public final void setManualId() { if (detail != null && detail.hasSelectClause()) { this.manualId = true; } @@ -1655,7 +1654,7 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery< * return true if user specified to use SQL DISTINCT (effectively excludes id property). */ @Override - public boolean isDistinct() { + public final boolean isDistinct() { return distinct; } @@ -1663,35 +1662,35 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery< * Internally set to use SQL DISTINCT on the query but still have id property included. */ @Override - public Query setDistinct(boolean distinct) { + public final Query setDistinct(boolean distinct) { this.distinct = distinct; return this; } @Override - public Query setCountDistinct(CountDistinctOrder countDistinctOrder) { + public final Query setCountDistinct(CountDistinctOrder countDistinctOrder) { this.countDistinctOrder = countDistinctOrder; return this; } @Override - public boolean isCountDistinct() { + public final boolean isCountDistinct() { return countDistinctOrder != null; } @Override - public Class getBeanType() { + public final Class getBeanType() { return beanType; } @Override - public Class getInheritType() { + public final Class getInheritType() { return beanDescriptor.type(); } @SuppressWarnings("unchecked") @Override - public Query setInheritType(Class type) { + public final Query setInheritType(Class type) { if (type == beanType) { return this; } @@ -1705,71 +1704,71 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery< } @Override - public String toString() { + public final String toString() { return "Query [" + whereExpressions + "]"; } @Override - public TableJoin getM2mIncludeJoin() { + public final TableJoin getM2mIncludeJoin() { return m2mIncludeJoin; } @Override - public void setM2MIncludeJoin(TableJoin m2mIncludeJoin) { + public final void setM2MIncludeJoin(TableJoin m2mIncludeJoin) { this.m2mIncludeJoin = m2mIncludeJoin; } @Override - public Query setDisableLazyLoading(boolean disableLazyLoading) { + public final Query setDisableLazyLoading(boolean disableLazyLoading) { this.disableLazyLoading = disableLazyLoading; return this; } @Override - public boolean isDisableLazyLoading() { + public final boolean isDisableLazyLoading() { return disableLazyLoading; } @Override - public int getFirstRow() { + public final int getFirstRow() { return firstRow; } @Override - public Query setFirstRow(int firstRow) { + public final Query setFirstRow(int firstRow) { this.firstRow = firstRow; return this; } @Override - public int getMaxRows() { + public final int getMaxRows() { return maxRows; } @Override - public Query setMaxRows(int maxRows) { + public final Query setMaxRows(int maxRows) { this.maxRows = maxRows; return this; } @Override - public String getMapKey() { + public final String getMapKey() { return mapKey; } @Override - public Query setMapKey(String mapKey) { + public final Query setMapKey(String mapKey) { this.mapKey = mapKey; return this; } @Override - public Object getId() { + public final Object getId() { return id; } @Override - public Query setId(Object id) { + public final Query setId(Object id) { if (id == null) { throw new NullPointerException("The id is null"); } @@ -1778,18 +1777,18 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery< } @Override - public BindParams getBindParams() { + public final BindParams getBindParams() { return bindParams; } @Override - public Query where(Expression expression) { + public final Query where(Expression expression) { where().add(expression); return this; } @Override - public ExpressionList text() { + public final ExpressionList text() { if (textExpressions == null) { useDocStore = true; textExpressions = new DefaultExpressionList<>(this); @@ -1798,7 +1797,7 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery< } @Override - public ExpressionList where() { + public final ExpressionList where() { if (whereExpressions == null) { whereExpressions = new DefaultExpressionList<>(this, null); } @@ -1806,20 +1805,20 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery< } @Override - public void simplifyExpressions() { + public final void simplifyExpressions() { if (whereExpressions != null) { whereExpressions.simplify(); } } @Override - public Query having(Expression expression) { + public final Query having(Expression expression) { having().add(expression); return this; } @Override - public ExpressionList having() { + public final ExpressionList having() { if (havingExpressions == null) { havingExpressions = new DefaultExpressionList<>(this, null); } @@ -1827,32 +1826,32 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery< } @Override - public SpiExpressionList getHavingExpressions() { + public final SpiExpressionList getHavingExpressions() { return havingExpressions; } @Override - public SpiExpressionList getWhereExpressions() { + public final SpiExpressionList getWhereExpressions() { return whereExpressions; } @Override - public SpiExpressionList getTextExpression() { + public final SpiExpressionList getTextExpression() { return textExpressions; } @Override - public String getGeneratedSql() { + public final String getGeneratedSql() { return generatedSql; } @Override - public void setGeneratedSql(String generatedSql) { + public final void setGeneratedSql(String generatedSql) { this.generatedSql = generatedSql; } @Override - public void checkNamedParameters() { + public final void checkNamedParameters() { if (namedParams != null) { for (ONamedParam value : namedParams.values()) { value.checkValueSet(); @@ -1861,7 +1860,7 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery< } @Override - public SpiNamedParam createNamedParameter(String name) { + public final SpiNamedParam createNamedParameter(String name) { if (namedParams == null) { namedParams = new HashMap<>(); } @@ -1869,84 +1868,84 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery< } @Override - public void setDefaultFetchBuffer(int fetchSize) { + public final void setDefaultFetchBuffer(int fetchSize) { if (bufferFetchSizeHint == 0) { bufferFetchSizeHint = fetchSize; } } @Override - public Query setBufferFetchSizeHint(int bufferFetchSizeHint) { + public final Query setBufferFetchSizeHint(int bufferFetchSizeHint) { this.bufferFetchSizeHint = bufferFetchSizeHint; return this; } @Override - public int getBufferFetchSizeHint() { + public final int getBufferFetchSizeHint() { return bufferFetchSizeHint; } @Override - public Query setDisableReadAuditing() { + public final Query setDisableReadAuditing() { this.disableReadAudit = true; return this; } @Override - public boolean isDisableReadAudit() { + public final boolean isDisableReadAudit() { return disableReadAudit; } @Override - public boolean isFutureFetch() { + public final boolean isFutureFetch() { return futureFetch; } @Override - public void setFutureFetch(boolean backgroundFetch) { + public final void setFutureFetch(boolean backgroundFetch) { this.futureFetch = backgroundFetch; } @Override - public void setFutureFetchAudit(ReadEvent event) { + public final void setFutureFetchAudit(ReadEvent event) { this.futureFetchAudit = event; } @Override - public ReadEvent getFutureFetchAudit() { + public final ReadEvent getFutureFetchAudit() { return futureFetchAudit; } @Override - public Query setBaseTable(String baseTable) { + public final Query setBaseTable(String baseTable) { this.baseTable = baseTable; return this; } @Override - public String getBaseTable() { + public final String getBaseTable() { return baseTable; } @Override - public Query alias(String alias) { + public final Query alias(String alias) { this.rootTableAlias = alias; return this; } @Override - public String getAlias() { + public final String getAlias() { return rootTableAlias; } @Override - public String getAlias(String defaultAlias) { + public final String getAlias(String defaultAlias) { return rootTableAlias != null ? rootTableAlias : defaultAlias; } @Override - public Set validate() { + public final Set validate() { return server.validateQuery(this); } @@ -1954,7 +1953,7 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery< * Validate all the expression properties/paths given the bean descriptor. */ @Override - public Set validate(BeanType desc) { + public final Set validate(BeanType desc) { SpiExpressionValidation validation = new SpiExpressionValidation(desc); if (whereExpressions != null) { whereExpressions.validate(validation); @@ -1970,29 +1969,29 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery< return validation.getUnknownProperties(); } - void setUpdateProperties(OrmUpdateProperties updateProperties) { + final void setUpdateProperties(OrmUpdateProperties updateProperties) { this.updateProperties = updateProperties; } @Override - public OrmUpdateProperties getUpdateProperties() { + public final OrmUpdateProperties getUpdateProperties() { return updateProperties; } @Override - public ProfileLocation getProfileLocation() { + public final ProfileLocation getProfileLocation() { return profileLocation; } @Override - public void handleLoadError(String fullName, Exception e) { + public final void handleLoadError(String fullName, Exception e) { if (!allowLoadErrors) { throw new PersistenceException("Error loading on " + fullName, e); } } @Override - public Query orderById(boolean orderById) { + public final Query orderById(boolean orderById) { this.orderById = orderById; return this; } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmUpdate.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmUpdate.java index 88b84fc2f..3f0d306e8 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmUpdate.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmUpdate.java @@ -1,6 +1,6 @@ package io.ebeaninternal.server.querydefn; -import io.ebean.EbeanServer; +import io.ebean.Database; import io.ebean.Update; import io.ebeaninternal.api.BindParams; import io.ebeaninternal.api.SpiUpdate; @@ -14,7 +14,7 @@ public final class DefaultOrmUpdate implements SpiUpdate, Serializable { private static final long serialVersionUID = -8791423602246515438L; - private transient final EbeanServer server; + private transient final Database server; private final Class beanType; private final String name; private String label; @@ -35,7 +35,7 @@ public final class DefaultOrmUpdate implements SpiUpdate, Serializable { * Create with a specific server. This means you can use the * UpdateSql.execute() method. */ - public DefaultOrmUpdate(Class beanType, EbeanServer server, String baseTable, String updateStatement) { + public DefaultOrmUpdate(Class beanType, Database server, String baseTable, String updateStatement) { this.beanType = beanType; this.server = server; this.baseTable = baseTable; diff --git a/ebean-core/src/main/java/module-info.java b/ebean-core/src/main/java/module-info.java index bbcc1772f..c35c37b34 100644 --- a/ebean-core/src/main/java/module-info.java +++ b/ebean-core/src/main/java/module-info.java @@ -4,7 +4,6 @@ module io.ebean.core { uses io.ebean.cache.ServerCachePlugin; uses io.ebean.cache.ServerCacheNotifyPlugin; uses io.ebean.config.DatabaseConfigProvider; - uses io.ebean.config.ServerConfigProvider; uses io.ebean.config.ModuleInfoLoader; uses io.ebean.config.dbplatform.DatabasePlatformProvider; uses io.ebean.datasource.DataSourceAlertFactory; diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/cache/DefaultServerCacheConfigTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/cache/DefaultServerCacheConfigTest.java index 512f663fd..19047e9c7 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/cache/DefaultServerCacheConfigTest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/cache/DefaultServerCacheConfigTest.java @@ -6,8 +6,7 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; -public class DefaultServerCacheConfigTest { - +class DefaultServerCacheConfigTest { private DefaultServerCacheConfig create(int maxSize, int maxIdleSecs, int maxSecsToLive, int trimFreq) { ServerCacheOptions options = new ServerCacheOptions(); @@ -20,33 +19,45 @@ public class DefaultServerCacheConfigTest { } @Test - public void trimFreq_halfIdle() { - + void trimFreq_halfIdle() { assertEquals(create(10000,10,20, 0).determineTrimFrequency(), 4); } - @Test - public void trimFreq_halfIdle_withRounding() { - + void trimFreq_halfIdle_withRounding() { assertEquals(create(10000,11,20, 0).determineTrimFrequency(), 4); } @Test - public void trimFreq_halfTTL() { - + void trimFreq_halfTTL() { assertEquals(create(10000,0,20, 0).determineTrimFrequency(), 9); } @Test - public void trimFreq_halfTTL_withRounding() { - + void trimFreq_halfTTL_withRounding() { assertEquals(create(10000,0,21, 0).determineTrimFrequency(), 9); } @Test - public void trimFreq_explicit() { - + void trimFreq_explicit() { assertEquals(create(10000,10,20, 42).determineTrimFrequency(), 42); } + + @Test + void trimOnPut_default() { + assertEquals(create(0,0,0, 0).determineTrimOnPut(), 1_000); + } + + @Test + void trimOnPut_tenPercent() { + assertEquals(create(10_000,0,0, 0).determineTrimOnPut(), 1_000); + assertEquals(create(9_000,0,0, 0).determineTrimOnPut(), 900); + assertEquals(create(100,0,0, 0).determineTrimOnPut(), 10); + } + + @Test + void trimOnPut_roundDown() { + assertEquals(create(9010,0,0, 0).determineTrimOnPut(), 901); + assertEquals(create(9009,0,0, 0).determineTrimOnPut(), 900); + } } diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/cache/DefaultServerCache_RunEvictionTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/cache/DefaultServerCache_RunEvictionTest.java index c6596e6d8..d98c48707 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/cache/DefaultServerCache_RunEvictionTest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/cache/DefaultServerCache_RunEvictionTest.java @@ -10,16 +10,14 @@ import org.junit.jupiter.api.Test; import java.util.Random; -public class DefaultServerCache_RunEvictionTest { - +class DefaultServerCache_RunEvictionTest { private DefaultServerCache createCache() { - ServerCacheOptions cacheOptions = new ServerCacheOptions(); - cacheOptions.setMaxSize(10000); + cacheOptions.setMaxSize(300); cacheOptions.setMaxIdleSecs(1); cacheOptions.setMaxSecsToLive(2); - cacheOptions.setTrimFrequency(1); + cacheOptions.setTrimFrequency(5); ServerCacheConfig con = new ServerCacheConfig(ServerCacheType.BEAN, "foo", "foo", cacheOptions, null, null); return new DefaultServerCache(new DefaultServerCacheConfig(con)); @@ -35,8 +33,7 @@ public class DefaultServerCache_RunEvictionTest { @Disabled("test takes long time") @Test - public void runEvict() throws InterruptedException { - + void runEvict() throws InterruptedException { for (int i = 0; i < 15; i++) { doStuff(); cache.runEviction(); @@ -47,12 +44,10 @@ public class DefaultServerCache_RunEvictionTest { } private void doStuff() { - - for (int i = 0; i < 500; i++) { + for (int i = 0; i < 5000; i++) { String key = "" + random.nextInt(20000); - int mode = random.nextInt(10); - if (mode < 8) { + if (mode < 7) { cache.get(key); } else { cache.put(key, key + "-" + System.currentTimeMillis()); diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/ElasticSearchSetup.java b/ebean-test/src/main/java/io/ebean/test/config/platform/ElasticSearchSetup.java index 011bfcbd2..87d74c29b 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/ElasticSearchSetup.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/ElasticSearchSetup.java @@ -1,6 +1,5 @@ package io.ebean.test.config.platform; -import io.ebean.docker.commands.ElasticConfig; import io.ebean.docker.commands.ElasticContainer; import java.util.Properties; @@ -19,27 +18,18 @@ class ElasticSearchSetup { } void run() { - ElasticConfig elasticConfig = readConfig(); - if (elasticConfig != null) { - new ElasticContainer(elasticConfig).start(); - } - } - - ElasticConfig readConfig() { - String version = read("version", null); - if (version == null) { - // we need an explicit version to run - return null; + if (version != null) { + Properties properties = populateDockerProperties(version); + ElasticContainer.newBuilder(version) + .properties(properties) + .build() + .start(); } - - return new ElasticConfig(version, populateDockerProperties(version)); } private Properties populateDockerProperties(String version) { - PropertiesBuilder properties = new PropertiesBuilder(); - String mode = config.getProperty("ebean.test.shutdown"); if (mode != null) { properties.set("shutdown", mode); @@ -63,7 +53,7 @@ class ElasticSearchSetup { private static class PropertiesBuilder { - private Properties dockerProperties = new Properties(); + private final Properties dockerProperties = new Properties(); private void set(String key, String val) { dockerProperties.setProperty("elastic." + key, val); diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/RedisSetup.java b/ebean-test/src/main/java/io/ebean/test/config/platform/RedisSetup.java index c8fc01671..41ed3c185 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/RedisSetup.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/RedisSetup.java @@ -1,6 +1,5 @@ package io.ebean.test.config.platform; -import io.ebean.docker.commands.RedisConfig; import io.ebean.docker.commands.RedisContainer; import java.util.Properties; @@ -16,9 +15,10 @@ class RedisSetup { String host = dockerHost.dockerHost(properties.getProperty("ebean.test.dockerHost")); properties.setProperty("redis.host", host); } - RedisConfig redisConfig = new RedisConfig(version, properties); - RedisContainer container = new RedisContainer(redisConfig); - container.start(); + RedisContainer.newBuilder(version) + .properties(properties) + .build() + .start(); } } } diff --git a/ebean-test/src/test/java/io/ebean/xtest/internal/server/cluster/binarymessage/BinaryTransactionEventReadWriteTest.java b/ebean-test/src/test/java/io/ebean/xtest/internal/server/cluster/binarymessage/BinaryTransactionEventReadWriteTest.java index 81a382ce8..6111cbe12 100644 --- a/ebean-test/src/test/java/io/ebean/xtest/internal/server/cluster/binarymessage/BinaryTransactionEventReadWriteTest.java +++ b/ebean-test/src/test/java/io/ebean/xtest/internal/server/cluster/binarymessage/BinaryTransactionEventReadWriteTest.java @@ -1,7 +1,7 @@ package io.ebean.xtest.internal.server.cluster.binarymessage; +import io.ebean.Database; import io.ebean.xtest.BaseTestCase; -import io.ebean.EbeanServer; import io.ebean.xtest.internal.api.TDSpiEbeanServer; import io.ebeaninternal.api.TransactionEventTable; import io.ebeaninternal.server.cache.RemoteCacheEvent; @@ -94,7 +94,7 @@ public class BinaryTransactionEventReadWriteTest extends BaseTestCase { class TDServerLookup implements ServerLookup { @Override - public EbeanServer getServer(String name) { + public Database getServer(String name) { return mockEbeanServer; } } diff --git a/ebean-test/src/test/java/main/StartCockroach.java b/ebean-test/src/test/java/main/StartCockroach.java index bb189daa0..fe8c3a0c3 100644 --- a/ebean-test/src/test/java/main/StartCockroach.java +++ b/ebean-test/src/test/java/main/StartCockroach.java @@ -1,16 +1,13 @@ package main; -import io.ebean.docker.commands.CockroachConfig; import io.ebean.docker.commands.CockroachContainer; public class StartCockroach { public static void main(String[] args) { - - CockroachConfig config = new CockroachConfig("v21.2.4"); - config.setDbName("unit"); - - CockroachContainer container = new CockroachContainer(config); - container.start(); + CockroachContainer.newBuilder("v21.2.4") + .dbName("unit") + .build() + .start(); } } diff --git a/ebean-test/src/test/java/main/StartDb2.java b/ebean-test/src/test/java/main/StartDb2.java index dbfd6b38d..53e9ff6eb 100644 --- a/ebean-test/src/test/java/main/StartDb2.java +++ b/ebean-test/src/test/java/main/StartDb2.java @@ -1,22 +1,18 @@ package main; -import io.ebean.docker.commands.Db2Config; import io.ebean.docker.commands.Db2Container; public class StartDb2 { public static void main(String[] args) { - - Db2Config config = new Db2Config("11.5.6.0a"); - config.setDbName("unit"); - config.setUser("unit"); - config.setPassword("unit"); - - // to change collation, charset and other parameters like pagesize: - config.setCreateOptions("USING CODESET UTF-8 TERRITORY DE COLLATE USING IDENTITY PAGESIZE 32768"); - config.setConfigOptions("USING STRING_UNITS CODEUNITS32"); - - Db2Container container = new Db2Container(config); - container.startWithDropCreate(); + Db2Container.newBuilder("11.5.6.0a") + .dbName("unit") + .user("unit") + .password("unit") + // to change collation, charset and other parameters like pagesize: + .configOptions("USING CODESET UTF-8 TERRITORY DE COLLATE USING IDENTITY PAGESIZE 32768") + .configOptions("USING STRING_UNITS CODEUNITS32") + .build() + .startWithDropCreate(); } } diff --git a/ebean-test/src/test/java/main/StartMariaDb.java b/ebean-test/src/test/java/main/StartMariaDb.java index 8bdf82bd7..6d38eb7ef 100644 --- a/ebean-test/src/test/java/main/StartMariaDb.java +++ b/ebean-test/src/test/java/main/StartMariaDb.java @@ -1,18 +1,15 @@ package main; -import io.ebean.docker.commands.MariaDBConfig; import io.ebean.docker.commands.MariaDBContainer; public class StartMariaDb { public static void main(String[] args) { - - MariaDBConfig config = new MariaDBConfig("10.5"); - config.setDbName("unit"); - config.setUser("unit"); - config.setPassword("unit"); - - MariaDBContainer container = new MariaDBContainer(config); - container.startWithDropCreate(); + MariaDBContainer.newBuilder("10.5") + .dbName("unit") + .user("unit") + .password("unit") + .build() + .startWithDropCreate(); } } diff --git a/ebean-test/src/test/java/main/StartMySql.java b/ebean-test/src/test/java/main/StartMySql.java index d7590c511..c9dddeef4 100644 --- a/ebean-test/src/test/java/main/StartMySql.java +++ b/ebean-test/src/test/java/main/StartMySql.java @@ -1,16 +1,17 @@ package main; -import io.ebean.docker.commands.MySqlConfig; import io.ebean.docker.commands.MySqlContainer; public class StartMySql { public static void main(String[] args) { - MySqlConfig config = new MySqlConfig("8.0"); - config.setDbName("unit"); - config.setUser("unit"); - config.setPassword("unit"); + MySqlContainer.newBuilder("8.0") + .dbName("unit") + .user("unit") + .password("unit") + .build() + .startWithDropCreate(); // by default this mysql docker collation is case sensitive // using utf8mb4_bin @@ -22,7 +23,5 @@ public class StartMySql { // config.setCollation("utf8mb4_unicode_ci"); // config.setCharacterSet("utf8mb4"); - MySqlContainer container = new MySqlContainer(config); - container.startWithDropCreate(); } } diff --git a/ebean-test/src/test/java/main/StartNuoDB.java b/ebean-test/src/test/java/main/StartNuoDB.java index e6b6f240a..08fed492a 100644 --- a/ebean-test/src/test/java/main/StartNuoDB.java +++ b/ebean-test/src/test/java/main/StartNuoDB.java @@ -1,16 +1,14 @@ package main; -import io.ebean.docker.commands.NuoDBConfig; import io.ebean.docker.commands.NuoDBContainer; public class StartNuoDB { public static void main(String[] args) { + NuoDBContainer container = NuoDBContainer.newBuilder("4.0") + .schema("test_user") + .build(); - NuoDBConfig config = new NuoDBConfig(); - config.setSchema("test_user"); - - NuoDBContainer container = new NuoDBContainer(config); container.stopRemove(); container.startWithDropCreate(); } diff --git a/ebean-test/src/test/java/main/StartOracle.java b/ebean-test/src/test/java/main/StartOracle.java index df489be07..47ec2cf69 100644 --- a/ebean-test/src/test/java/main/StartOracle.java +++ b/ebean-test/src/test/java/main/StartOracle.java @@ -1,16 +1,13 @@ package main; -import io.ebean.docker.commands.OracleConfig; import io.ebean.docker.commands.OracleContainer; public class StartOracle { public static void main(String[] args) { - - OracleConfig config = new OracleConfig(); - config.setUser("test_ebean"); - - OracleContainer container = new OracleContainer(config); - container.startWithDropCreate(); + OracleContainer.newBuilder("latest") + .user("test_ebean") + .build() + .startWithDropCreate(); } } diff --git a/ebean-test/src/test/java/main/StartPostgres.java b/ebean-test/src/test/java/main/StartPostgres.java index 5b107d2dc..2ea3d8d7d 100644 --- a/ebean-test/src/test/java/main/StartPostgres.java +++ b/ebean-test/src/test/java/main/StartPostgres.java @@ -1,21 +1,18 @@ package main; -import io.ebean.docker.commands.PostgresConfig; import io.ebean.docker.commands.PostgresContainer; public class StartPostgres { public static void main(String[] args) { - - PostgresConfig config = new PostgresConfig("13"); - config.setPort(5432); - config.setDbName("unit"); - config.setUser("unit"); - config.setPassword("unit"); - config.setContainerName("pg13x"); - config.setExtensions("hstore,pgcrypto"); - - PostgresContainer container = new PostgresContainer(config); - container.startWithDropCreate(); + PostgresContainer.newBuilder("13") + .port(5432) + .dbName("unit") + .user("unit") + .password("unit") + .containerName("pg13x") + .extensions("hstore,pgcrypto") + .build() + .startWithDropCreate(); } } diff --git a/ebean-test/src/test/java/main/StartSqlServer.java b/ebean-test/src/test/java/main/StartSqlServer.java index 90cf6434a..f4f4b9f4b 100644 --- a/ebean-test/src/test/java/main/StartSqlServer.java +++ b/ebean-test/src/test/java/main/StartSqlServer.java @@ -1,15 +1,15 @@ package main; -import io.ebean.docker.commands.SqlServerConfig; import io.ebean.docker.commands.SqlServerContainer; public class StartSqlServer { public static void main(String[] args) { - - SqlServerConfig config = new SqlServerConfig("2019-GA-ubuntu-16.04"); - config.setDbName("test_ebean"); - config.setUser("test_ebean"); + SqlServerContainer.newBuilder("2019-GA-ubuntu-16.04") + .dbName("test_ebean") + .user("test_ebean") + .build() + .start(); // by default this sqlserver docker collation is case sensitive // using MSSQL_COLLATION=Latin1_General_100_BIN2 @@ -20,8 +20,5 @@ public class StartSqlServer { //config.setCollation("default"); //config.setCollation("Latin1_General_100_CI"); - - SqlServerContainer container = new SqlServerContainer(config); - container.start(); } } diff --git a/ebean-test/src/test/java/main/StartYugabyte.java b/ebean-test/src/test/java/main/StartYugabyte.java index 01b670c21..9f7449671 100644 --- a/ebean-test/src/test/java/main/StartYugabyte.java +++ b/ebean-test/src/test/java/main/StartYugabyte.java @@ -1,20 +1,16 @@ package main; -import io.ebean.docker.commands.YugabyteConfig; import io.ebean.docker.commands.YugabyteContainer; public class StartYugabyte { public static void main(String[] args) { - - // Check add extensions ? - YugabyteConfig config = new YugabyteConfig("2.11.2.0-b89"); - config.setDbName("unit"); - config.setUser("unit"); - config.setExtensions("pgcrypto"); - - YugabyteContainer container = new YugabyteContainer(config); - container.startWithDropCreate(); + YugabyteContainer.newBuilder("2.11.2.0-b89") + .dbName("unit") + .user("unit") + .extensions("pgcrypto") + .build() + .startWithDropCreate(); // Run container ut_yugabyte with host:localhost port:6433 db:unit user:unit/test shutdown:None // docker run -d --name ut_yugabyte -p 6433:5433 -p 7000:7000 -p 9000:9000 -p 9042:9042 yugabytedb/yugabyte:2.11.2.0-b89 bin/yugabyted start --daemon=false diff --git a/pom.xml b/pom.xml index 829f9a53b..19a937176 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ 1.3 1.2 13.0.0 - 4.9 + 5.0 7.5 13.5.0 13.5.0