mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
47
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f271ea8a0d | ||
|
|
1ced574cd8 | ||
|
|
9dd412cd19 | ||
|
|
8237072f5b | ||
|
|
dd30b43d59 | ||
|
|
09f8967459 | ||
|
|
e3bf3629ee | ||
|
|
b6edd33f9a | ||
|
|
3a11a23e01 | ||
|
|
370267ab6f | ||
|
|
fe65a0ccb9 | ||
|
|
2837324a03 | ||
|
|
a6bd614f87 | ||
|
|
dfaf4b2f31 | ||
|
|
0f26160e1b | ||
|
|
cb66aaf66c | ||
|
|
78b1c05de1 | ||
|
|
c70a4f80eb | ||
|
|
cc788e281f | ||
|
|
d55a7b26f8 | ||
|
|
2195d7ecbc | ||
|
|
983391af94 | ||
|
|
478053263f | ||
|
|
1cd31e13b9 | ||
|
|
374d7faae9 | ||
|
|
6a6cff2236 | ||
|
|
d5d6ac675b | ||
|
|
8ea1f51c7f | ||
|
|
6ecb77dcc2 | ||
|
|
216806074c | ||
|
|
65cb2ae94d | ||
|
|
6677a6199c | ||
|
|
55eaa0b484 | ||
|
|
353f662d70 | ||
|
|
c95d76d6f6 | ||
|
|
e04d6979d1 | ||
|
|
b8078083b1 | ||
|
|
07cdb69a5b | ||
|
|
98f6e1e6af | ||
|
|
fd4d757f87 | ||
|
|
b71b0fc8e2 | ||
|
|
4303bcfd13 | ||
|
|
7f30dc7b1e | ||
|
|
4a882b537c | ||
|
|
641385aab5 | ||
|
|
33ab7eb7a5 | ||
|
|
f6674f8e3b |
@@ -7,6 +7,6 @@ Maven Dependency
|
||||
<dependency>
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm</artifactId>
|
||||
<version>4.1.8</version>
|
||||
<version>4.3.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm</artifactId>
|
||||
<version>4.2.0</version>
|
||||
<version>4.4.1</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>avaje-ebeanorm</name>
|
||||
@@ -99,14 +99,14 @@
|
||||
<dependency>
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm-agent</artifactId>
|
||||
<version>4.1.9</version>
|
||||
<version>4.1.10</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.3.153</version>
|
||||
<version>1.4.182</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<version>3.2</version>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
@@ -233,7 +233,6 @@
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!--
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
@@ -241,19 +240,18 @@
|
||||
<configuration>
|
||||
<doctitle>Ebean 4</doctitle>
|
||||
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
|
||||
<excludePackageNames>com.avaje.ebeaninternal.*:com.avaje.ebean.util</excludePackageNames>
|
||||
<!-- <excludePackageNames>com.avaje.ebeaninternal.*:com.avaje.ebean.util</excludePackageNames> -->
|
||||
<additionalparam>-Xdoclint:none</additionalparam>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<phase>site</phase>
|
||||
<goals>
|
||||
<goal>aggregate</goal>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
-->
|
||||
</plugins>
|
||||
|
||||
</build>
|
||||
|
||||
@@ -15,7 +15,6 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.annotation.CacheStrategy;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.text.csv.CsvReader;
|
||||
import com.avaje.ebean.text.json.JsonContext;
|
||||
@@ -63,34 +62,38 @@ import com.avaje.ebean.text.json.JsonContext;
|
||||
* created automatically they are configured using information in the
|
||||
* ebean.properties file.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // fetch shipped orders (and also their customer)
|
||||
* List<Order> list = Ebean.find(Order.class)
|
||||
* .fetch("customer")
|
||||
* .where()
|
||||
* .eq("status.code", Order.Status.SHIPPED)
|
||||
* .findList();
|
||||
*
|
||||
* // read/use the order list ...
|
||||
* for (Order order : list) {
|
||||
* Customer customer = order.getCustomer();
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // fetch shipped orders (and also their customer)
|
||||
* List<Order> list = Ebean.find(Order.class)
|
||||
* .fetch("customer")
|
||||
* .where()
|
||||
* .eq("status.code", Order.Status.SHIPPED)
|
||||
* .findList();
|
||||
* <pre>{@code
|
||||
*
|
||||
* // fetch order 10, modify and save
|
||||
* Order order = Ebean.find(Order.class, 10);
|
||||
*
|
||||
* // read/use the order list ...
|
||||
* for (Order order : list) {
|
||||
* Customer customer = order.getCustomer();
|
||||
* ...
|
||||
* }
|
||||
* </pre>
|
||||
* OrderStatus shipped = Ebean.getReference(OrderStatus.class,"SHIPPED");
|
||||
* order.setStatus(shipped);
|
||||
* order.setShippedDate(shippedDate);
|
||||
* ...
|
||||
*
|
||||
* <pre class="code">
|
||||
* // fetch order 10, modify and save
|
||||
* Order order = Ebean.find(Order.class, 10);
|
||||
*
|
||||
* OrderStatus shipped = Ebean.getReference(OrderStatus.class,"SHIPPED");
|
||||
* order.setStatus(shipped);
|
||||
* order.setShippedDate(shippedDate);
|
||||
* ...
|
||||
*
|
||||
* // implicitly creates a transaction and commits
|
||||
* Ebean.save(order);
|
||||
* </pre>
|
||||
* // implicitly creates a transaction and commits
|
||||
* Ebean.save(order);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* When you have multiple databases and need access to a specific one the
|
||||
@@ -98,20 +101,22 @@ import com.avaje.ebean.text.json.JsonContext;
|
||||
* specific database.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // Get access to the Human Resources EbeanServer/Database
|
||||
* EbeanServer hrDb = Ebean.getServer("hr");
|
||||
* <pre> {@code
|
||||
*
|
||||
* // Get access to the Human Resources EbeanServer/Database
|
||||
* EbeanServer hrDb = Ebean.getServer("hr");
|
||||
*
|
||||
*
|
||||
* // fetch contact 3 from the HR database
|
||||
* Contact contact = hrDb.find(Contact.class, 3);
|
||||
* // fetch contact 3 from the HR database
|
||||
* Contact contact = hrDb.find(Contact.class, 3);
|
||||
*
|
||||
* contact.setName("I'm going to change");
|
||||
* ...
|
||||
* contact.setName("I'm going to change");
|
||||
* ...
|
||||
*
|
||||
* // save the contact back to the HR database
|
||||
* hrDb.save(contact);
|
||||
* </pre>
|
||||
* // save the contact back to the HR database
|
||||
* hrDb.save(contact);
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public final class Ebean {
|
||||
private static final Logger logger = LoggerFactory.getLogger(Ebean.class);
|
||||
@@ -149,14 +154,14 @@ public final class Ebean {
|
||||
|
||||
// skipDefaultServer is set by EbeanServerFactory
|
||||
// ... when it is creating the primaryServer
|
||||
if (GlobalProperties.isSkipPrimaryServer()) {
|
||||
if (PrimaryServer.isSkip()) {
|
||||
// primary server being created by EbeanServerFactory
|
||||
// ... so we should not try and create it here
|
||||
logger.debug("GlobalProperties.isSkipPrimaryServer()");
|
||||
logger.debug("PrimaryServer.isSkip()");
|
||||
|
||||
} else {
|
||||
// look to see if there is a default server defined
|
||||
String primaryName = getPrimaryServerName();
|
||||
String primaryName = PrimaryServer.getPrimaryServerName();
|
||||
logger.debug("primaryName:" + primaryName);
|
||||
if (primaryName != null && primaryName.trim().length() > 0) {
|
||||
primaryServer = getWithCreate(primaryName.trim());
|
||||
@@ -164,12 +169,6 @@ public final class Ebean {
|
||||
}
|
||||
}
|
||||
|
||||
private String getPrimaryServerName() {
|
||||
|
||||
String serverName = GlobalProperties.get("ebean.default.datasource", null);
|
||||
return GlobalProperties.get("datasource.default", serverName);
|
||||
}
|
||||
|
||||
private EbeanServer getPrimaryServer() {
|
||||
if (primaryServer == null) {
|
||||
String msg = "The default EbeanServer has not been defined?";
|
||||
@@ -242,12 +241,12 @@ public final class Ebean {
|
||||
* Ebean.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // use the "hr" database
|
||||
* EbeanServer hrDatabase = Ebean.getServer("hr");
|
||||
* <pre>{@code
|
||||
* // use the "hr" database
|
||||
* EbeanServer hrDatabase = Ebean.getServer("hr");
|
||||
*
|
||||
* Person person = hrDatabase.find(Person.class, 10);
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* @param name
|
||||
* the name of the server, use null for the 'default server'
|
||||
@@ -281,7 +280,7 @@ public final class Ebean {
|
||||
* Register the server with this Ebean singleton. Specify if the registered
|
||||
* server is the primary/default server.
|
||||
*/
|
||||
protected static void register(EbeanServer server, boolean isPrimaryServer) {
|
||||
public static void register(EbeanServer server, boolean isPrimaryServer) {
|
||||
serverMgr.register(server, isPrimaryServer);
|
||||
}
|
||||
|
||||
@@ -323,22 +322,24 @@ public final class Ebean {
|
||||
* etc.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // start a transaction (stored in a ThreadLocal)
|
||||
* Ebean.beginTransaction();
|
||||
* try {
|
||||
* Order order = Ebean.find(Order.class,10); ...
|
||||
* <pre>{@code
|
||||
*
|
||||
* // start a transaction (stored in a ThreadLocal)
|
||||
* Ebean.beginTransaction();
|
||||
* try {
|
||||
* Order order = Ebean.find(Order.class,10); ...
|
||||
*
|
||||
* Ebean.save(order);
|
||||
*
|
||||
* Ebean.save(order);
|
||||
* Ebean.commitTransaction();
|
||||
*
|
||||
* Ebean.commitTransaction();
|
||||
*
|
||||
* } finally {
|
||||
* // rollback if we didn't commit
|
||||
* // i.e. an exception occurred before commitTransaction().
|
||||
* Ebean.endTransaction();
|
||||
* }
|
||||
* </pre>
|
||||
* } finally {
|
||||
* // rollback if we didn't commit
|
||||
* // i.e. an exception occurred before commitTransaction().
|
||||
* Ebean.endTransaction();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* If you want to externalise the transaction management then you should be
|
||||
@@ -372,6 +373,19 @@ public final class Ebean {
|
||||
return serverMgr.getPrimaryServer().currentTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a TransactionCallback on the currently active transaction.
|
||||
* <p/>
|
||||
* 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 {
|
||||
serverMgr.getPrimaryServer().register(transactionCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit the current transaction.
|
||||
*/
|
||||
@@ -397,17 +411,19 @@ public final class Ebean {
|
||||
* Code example:
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* Ebean.beginTransaction();
|
||||
* try {
|
||||
* // do some fetching and or persisting
|
||||
* // commit at the end Ebean.commitTransaction();
|
||||
* <pre>{@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();
|
||||
* }
|
||||
* </pre>
|
||||
* } finally {
|
||||
* // if commit didn't occur then rollback the transaction
|
||||
* Ebean.endTransaction();
|
||||
* }
|
||||
* }</pre>
|
||||
*/
|
||||
public static void endTransaction() {
|
||||
serverMgr.getPrimaryServer().endTransaction();
|
||||
@@ -440,15 +456,15 @@ public final class Ebean {
|
||||
* saving an order will also save all its details.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* public class Order { ...
|
||||
* <pre>{@code
|
||||
* public class Order { ...
|
||||
*
|
||||
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
|
||||
* @JoinColumn(name="order_id")
|
||||
* List<OrderDetail> details;
|
||||
* ...
|
||||
* }
|
||||
* </pre>
|
||||
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
|
||||
* @JoinColumn(name="order_id")
|
||||
* List<OrderDetail> details;
|
||||
* ...
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* When a save cascades via a OneToMany or ManyToMany Ebean will automatically
|
||||
@@ -485,16 +501,16 @@ public final class Ebean {
|
||||
* An unmodified bean that is saved or updated is normally skipped and this marks the bean as
|
||||
* dirty so that it is not skipped.
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
*
|
||||
* Customer customer = Ebean.find(Customer, id);
|
||||
* 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);
|
||||
* // mark the bean as dirty so that a save() or update() will
|
||||
* // increment the version property
|
||||
* Ebean.markAsDirty(customer);
|
||||
* Ebean.save(customer);
|
||||
*
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*/
|
||||
public static void markAsDirty(Object bean) throws OptimisticLockException {
|
||||
serverMgr.getPrimaryServer().markAsDirty(bean);
|
||||
@@ -523,15 +539,15 @@ public final class Ebean {
|
||||
* properties are included instead.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
*
|
||||
* // A 'stateless update' example
|
||||
* Customer customer = new Customer();
|
||||
* customer.setId(7);
|
||||
* customer.setName("ModifiedNameNoOCC");
|
||||
* ebeanServer.update(customer);
|
||||
* // A 'stateless update' example
|
||||
* Customer customer = new Customer();
|
||||
* customer.setId(7);
|
||||
* customer.setName("ModifiedNameNoOCC");
|
||||
* ebeanServer.update(customer);
|
||||
*
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* @see ServerConfig#setUpdatesDeleteMissingChildren(boolean)
|
||||
* @see ServerConfig#setUpdateChangesOnly(boolean)
|
||||
@@ -665,12 +681,14 @@ public final class Ebean {
|
||||
/**
|
||||
* Refresh a 'many' property of a bean.
|
||||
*
|
||||
* <pre class="code">
|
||||
* Order order = ...;
|
||||
* ...
|
||||
* // refresh the order details...
|
||||
* Ebean.refreshMany(order, "details");
|
||||
* </pre>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Order order = ...;
|
||||
* ...
|
||||
* // refresh the order details...
|
||||
* Ebean.refreshMany(order, "details");
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param bean
|
||||
* the entity bean containing the List Set or Map to refresh.
|
||||
@@ -687,16 +705,18 @@ public final class Ebean {
|
||||
* This is sometimes described as a proxy (with lazy loading).
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* Product product = Ebean.getReference(Product.class, 1);
|
||||
* <pre>{@code
|
||||
*
|
||||
* Product product = Ebean.getReference(Product.class, 1);
|
||||
*
|
||||
* // You can get the id without causing a fetch/lazy load
|
||||
* Integer productId = product.getId();
|
||||
* // 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();
|
||||
* </pre>
|
||||
* // 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();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType
|
||||
* the type of entity bean
|
||||
@@ -726,23 +746,23 @@ public final class Ebean {
|
||||
* not invoke a DB query.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
*
|
||||
* // find orders and their customers
|
||||
* List<Order> list = Ebean.find(Order.class)
|
||||
* .fetch("customer")
|
||||
* .orderBy("id")
|
||||
* // find orders and their customers
|
||||
* List<Order> list = Ebean.find(Order.class)
|
||||
* .fetch("customer")
|
||||
* .orderBy("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 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");
|
||||
* // sort by customer name descending (with nulls low)
|
||||
* // ... then by the order id
|
||||
* Ebean.sort(list, "customer.name desc nullsLow, id");
|
||||
*
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* @param list
|
||||
* the list of entity beans
|
||||
@@ -756,41 +776,43 @@ public final class Ebean {
|
||||
/**
|
||||
* Find a bean using its unique id. This will not use caching.
|
||||
*
|
||||
* <pre class="code">
|
||||
* // Fetch order 1
|
||||
* Order order = Ebean.find(Order.class, 1);
|
||||
* </pre>
|
||||
* <pre>{@code
|
||||
* // Fetch order 1
|
||||
* Order order = Ebean.find(Order.class, 1);
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* If you want more control over the query then you can use createQuery() and
|
||||
* Query.findUnique();
|
||||
* </p>
|
||||
*
|
||||
* <pre class="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.
|
||||
* <pre>{@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<Order> query = Ebean.createQuery(Order.class);
|
||||
* query.setId(1);
|
||||
* query.fetch("customer");
|
||||
* query.fetch("customer.shippingAddress");
|
||||
* query.fetch("details");
|
||||
* Query<Order> 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");
|
||||
* // fetch associated products but only fetch their product id and name
|
||||
* query.fetch("details.product", "name");
|
||||
*
|
||||
* // traverse the object graph...
|
||||
* // traverse the object graph...
|
||||
*
|
||||
* Order order = query.findUnique();
|
||||
* Customer customer = order.getCustomer();
|
||||
* Address shippingAddress = customer.getShippingAddress();
|
||||
* List<OrderDetail> details = order.getDetails();
|
||||
* OrderDetail detail0 = details.get(0);
|
||||
* Product product = detail0.getProduct();
|
||||
* String productName = product.getName();
|
||||
* </pre>
|
||||
* Order order = query.findUnique();
|
||||
* Customer customer = order.getCustomer();
|
||||
* Address shippingAddress = customer.getShippingAddress();
|
||||
* List<OrderDetail> details = order.getDetails();
|
||||
* OrderDetail detail0 = details.get(0);
|
||||
* Product product = detail0.getProduct();
|
||||
* String productName = product.getName();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType
|
||||
* the type of entity bean to fetch
|
||||
@@ -802,7 +824,7 @@ public final class Ebean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a <a href="SqlQuery.html">SqlQuery</a> for executing native sql
|
||||
* Create a SqlQuery for executing native sql
|
||||
* query statements.
|
||||
* <p>
|
||||
* Note that you can use raw SQL with entity beans, refer to the SqlSelect
|
||||
@@ -860,15 +882,17 @@ public final class Ebean {
|
||||
* deployment orm xml file.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // Use a namedQuery
|
||||
* UpdateSql update = Ebean.createNamedSqlUpdate("update.topic.count");
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Use a namedQuery
|
||||
* UpdateSql update = Ebean.createNamedSqlUpdate("update.topic.count");
|
||||
*
|
||||
* update.setParameter("count", 1);
|
||||
* update.setParameter("topicId", 50);
|
||||
* update.setParameter("count", 1);
|
||||
* update.setParameter("topicId", 50);
|
||||
*
|
||||
* int modifiedCount = update.execute();
|
||||
* </pre>
|
||||
* int modifiedCount = update.execute();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static SqlUpdate createNamedSqlUpdate(String namedQuery) {
|
||||
return serverMgr.getPrimaryServer().createNamedSqlUpdate(namedQuery);
|
||||
@@ -883,12 +907,14 @@ public final class Ebean {
|
||||
* need to bind required parameters and then execute the query.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // example
|
||||
* Query<Order> query = Ebean.createNamedQuery(Order.class, "new.for.customer");
|
||||
* query.setParameter("customerId", 23);
|
||||
* List<Order> newOrders = query.findList();
|
||||
* </pre>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // example
|
||||
* Query<Order> query = Ebean.createNamedQuery(Order.class, "new.for.customer");
|
||||
* query.setParameter("customerId", 23);
|
||||
* List<Order> newOrders = query.findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType
|
||||
* the class of entity to be fetched
|
||||
@@ -911,14 +937,15 @@ public final class Ebean {
|
||||
* moved to {@link #createNamedQuery(Class, String)}.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
*
|
||||
* String q = "find order fetch details where status = :st";
|
||||
* String q = "find order fetch details where status = :st";
|
||||
*
|
||||
* List<Order> newOrders = Ebean.createQuery(Order.class, q)
|
||||
* .setParameter("st", Order.Status.NEW)
|
||||
* List<Order> newOrders = Ebean.>findOrder.class, q)
|
||||
* .setParameter("st", Order.Status.NEW)
|
||||
* .findList();
|
||||
* </pre>
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param query
|
||||
* the object query
|
||||
@@ -943,40 +970,43 @@ public final class Ebean {
|
||||
* Example named updates:
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* package app.data;
|
||||
* <pre>{@code
|
||||
* package app.data;
|
||||
*
|
||||
* import ...
|
||||
* import ...
|
||||
*
|
||||
* @NamedUpdates(value = {
|
||||
* @NamedUpdate( name = "setTitle",
|
||||
* isSql = false,
|
||||
* notifyCache = false,
|
||||
* update = "update topic set title = :title, postCount = :postCount where id = :id"),
|
||||
* @NamedUpdate( name = "setPostCount",
|
||||
* notifyCache = false,
|
||||
* update = "update f_topic set post_count = :postCount where id = :id"),
|
||||
* @NamedUpdate( name = "incrementPostCount",
|
||||
* notifyCache = false,
|
||||
* isSql = false,
|
||||
* update = "update Topic set postCount = postCount + 1 where id = :id") })
|
||||
* @Entity
|
||||
* @Table(name = "f_topic")
|
||||
* public class Topic { ...
|
||||
* </pre>
|
||||
* @NamedUpdates(value = {
|
||||
* @NamedUpdate( name = "setTitle",
|
||||
* isSql = false,
|
||||
* notifyCache = false,
|
||||
* update = "update topic set title = :title, postCount = :postCount where id = :id"),
|
||||
* @NamedUpdate( name = "setPostCount",
|
||||
* notifyCache = false,
|
||||
* update = "update f_topic set post_count = :postCount where id = :id"),
|
||||
* @NamedUpdate( name = "incrementPostCount",
|
||||
* notifyCache = false,
|
||||
* isSql = false,
|
||||
* update = "update Topic set postCount = postCount + 1 where id = :id") })
|
||||
* @Entity
|
||||
* @Table(name = "f_topic")
|
||||
* public class Topic { ...
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Example using a named update:
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* Update<Topic> update = Ebean.createNamedUpdate(Topic.class, "setPostCount");
|
||||
* update.setParameter("postCount", 10);
|
||||
* update.setParameter("id", 3);
|
||||
* <pre>{@code
|
||||
*
|
||||
* Update<Topic> update = Ebean.createNamedUpdate(Topic.class, "setPostCount");
|
||||
* update.setParameter("postCount", 10);
|
||||
* update.setParameter("id", 3);
|
||||
*
|
||||
* int rows = update.execute();
|
||||
* System.out.println("rows updated: " + rows);
|
||||
* </pre>
|
||||
* int rows = update.execute();
|
||||
* System.out.println("rows updated: " + rows);
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static <T> Update<T> createNamedUpdate(Class<T> beanType, String namedUpdate) {
|
||||
|
||||
@@ -995,21 +1025,22 @@ public final class Ebean {
|
||||
* An example:
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
*
|
||||
* // The bean name and properties - "topic","postCount" and "id"
|
||||
* // 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";
|
||||
* // will be converted into their associated table and column names
|
||||
* String updStatement = "update topic set postCount = :pc where id = :id";
|
||||
*
|
||||
* Update<Topic> update = Ebean.createUpdate(Topic.class, updStatement);
|
||||
* Update<Topic> update = Ebean.createUpdate(Topic.class, updStatement);
|
||||
*
|
||||
* update.set("pc", 9);
|
||||
* update.set("id", 3);
|
||||
* update.set("pc", 9);
|
||||
* update.set("id", 3);
|
||||
*
|
||||
* int rows = update.execute();
|
||||
* System.out.println("rows updated:" + rows);
|
||||
* </pre>
|
||||
* int rows = update.execute();
|
||||
* System.out.println("rows updated:" + rows);
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static <T> Update<T> createUpdate(Class<T> beanType, String ormUpdate) {
|
||||
|
||||
@@ -1040,38 +1071,37 @@ public final class Ebean {
|
||||
* which is was created.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // Find order 2 additionally fetching the customer, details and details.product
|
||||
* // name.
|
||||
* <pre>{@code
|
||||
* // Find order 2 additionally fetching the customer, details and details.product
|
||||
* // name.
|
||||
*
|
||||
* Query<Order> query = Ebean.createQuery(Order.class);
|
||||
* query.fetch("customer");
|
||||
* query.fetch("details");
|
||||
* query.fetch("detail.product", "name");
|
||||
* query.setId(2);
|
||||
* Order order = Ebean.find(Order.class)
|
||||
* .fetch("customer")
|
||||
* .fetch("details")
|
||||
* .fetch("detail.product", "name")
|
||||
* .setId(2)
|
||||
* .findUnique();
|
||||
*
|
||||
* Order order = query.findUnique();
|
||||
* // Find order 2 additionally fetching the customer, details and details.product
|
||||
* // name.
|
||||
* // Note: same query as above but using the query language
|
||||
* // Note: using a named query would be preferred practice
|
||||
*
|
||||
* // Find order 2 additionally fetching the customer, details and details.product
|
||||
* // name.
|
||||
* // Note: same query as above but using the query language
|
||||
* // Note: using a named query would be preferred practice
|
||||
* String oql = "find order fetch customer fetch details fetch details.product (name) where id = :orderId ";
|
||||
*
|
||||
* String oql = "find order fetch customer fetch details fetch details.product (name) where id = :orderId ";
|
||||
* Query<Order> query = Ebean.find(Order.class);
|
||||
* query.setQuery(oql);
|
||||
* query.setParameter("orderId", 2);
|
||||
*
|
||||
* Query<Order> query = Ebean.createQuery(Order.class);
|
||||
* query.setQuery(oql);
|
||||
* query.setParameter("orderId", 2);
|
||||
* Order order = query.findUnique();
|
||||
*
|
||||
* Order order = query.findUnique();
|
||||
* // Using a named query
|
||||
* Query<Order> query = Ebean.find(Order.class, "with.details");
|
||||
* query.setParameter("orderId", 2);
|
||||
*
|
||||
* // Using a named query
|
||||
* Query<Order> query = Ebean.createQuery(Order.class, "with.details");
|
||||
* query.setParameter("orderId", 2);
|
||||
* Order order = query.findUnique();
|
||||
*
|
||||
* Order order = query.findUnique();
|
||||
*
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType
|
||||
* the class of entity to be fetched
|
||||
@@ -1131,19 +1161,21 @@ public final class Ebean {
|
||||
* Example:
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // example that uses 'named' parameters
|
||||
* String s = "UPDATE f_topic set post_count = :count where id = :id"
|
||||
* <pre>{@code
|
||||
*
|
||||
* // example that uses 'named' parameters
|
||||
* String s = "UPDATE f_topic set post_count = :count where id = :id"
|
||||
*
|
||||
* SqlUpdate update = Ebean.createSqlUpdate(s);
|
||||
* SqlUpdate update = Ebean.createSqlUpdate(s);
|
||||
*
|
||||
* update.setParameter("id", 1);
|
||||
* update.setParameter("count", 50);
|
||||
* update.setParameter("id", 1);
|
||||
* update.setParameter("count", 50);
|
||||
*
|
||||
* int modifiedCount = Ebean.execute(update);
|
||||
* int modifiedCount = Ebean.execute(update);
|
||||
*
|
||||
* String msg = "There where " + modifiedCount + "rows updated";
|
||||
* </pre>
|
||||
* String msg = "There where " + modifiedCount + "rows updated";
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param sqlUpdate
|
||||
* the update sql potentially with bind values
|
||||
@@ -1164,19 +1196,21 @@ public final class Ebean {
|
||||
* Example:
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* String sql = "{call sp_order_modify(?,?,?)}";
|
||||
* <pre>{@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);
|
||||
* CallableSql cs = Ebean.createCallableSql(sql);
|
||||
* cs.setParameter(1, 27);
|
||||
* cs.setParameter(2, "SHIPPED");
|
||||
* cs.registerOut(3, Types.INTEGER);
|
||||
*
|
||||
* Ebean.execute(cs);
|
||||
* Ebean.execute(cs);
|
||||
*
|
||||
* // read the out parameter
|
||||
* Integer returnValue = (Integer) cs.getObject(3);
|
||||
* </pre>
|
||||
* // read the out parameter
|
||||
* Integer returnValue = (Integer) cs.getObject(3);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @see CallableSql
|
||||
* @see Ebean#execute(SqlUpdate)
|
||||
@@ -1192,18 +1226,19 @@ public final class Ebean {
|
||||
* semantics.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="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);
|
||||
* ...
|
||||
*
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
* <pre>{@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);
|
||||
* ...
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static void execute(TxScope scope, TxRunnable r) {
|
||||
serverMgr.getPrimaryServer().execute(scope, r);
|
||||
@@ -1216,20 +1251,22 @@ public final class Ebean {
|
||||
* exception (checked or runtime).
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* Ebean.execute(new TxRunnable() {
|
||||
* public void run() {
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* User u2 = Ebean.find(User.class, 2);
|
||||
* <pre>{@code
|
||||
*
|
||||
* Ebean.execute(new TxRunnable() {
|
||||
* public void run() {
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* User u2 = Ebean.find(User.class, 2);
|
||||
*
|
||||
* u1.setName("u1 mod");
|
||||
* u2.setName("u2 mod");
|
||||
* u1.setName("u1 mod");
|
||||
* u2.setName("u2 mod");
|
||||
*
|
||||
* Ebean.save(u1);
|
||||
* Ebean.save(u2);
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
* Ebean.save(u1);
|
||||
* Ebean.save(u2);
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static void execute(TxRunnable r) {
|
||||
serverMgr.getPrimaryServer().execute(r);
|
||||
@@ -1242,18 +1279,20 @@ public final class Ebean {
|
||||
* semantics.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // set specific transactional scope settings
|
||||
* TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
|
||||
*
|
||||
* Ebean.execute(scope, new TxCallable<String>() {
|
||||
* public String call() {
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* ...
|
||||
* return u1.getEmail();
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // set specific transactional scope settings
|
||||
* TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
|
||||
*
|
||||
* Ebean.execute(scope, new TxCallable<String>() {
|
||||
* public String call() {
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* ...
|
||||
* return u1.getEmail();
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*/
|
||||
public static <T> T execute(TxScope scope, TxCallable<T> c) {
|
||||
@@ -1271,22 +1310,24 @@ public final class Ebean {
|
||||
* (and you specify the return type via generics).
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* Ebean.execute(new TxCallable<String>() {
|
||||
* public String call() {
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* User u2 = Ebean.find(User.class, 2);
|
||||
* <pre>{@code
|
||||
*
|
||||
* Ebean.execute(new TxCallable<String>() {
|
||||
* public String call() {
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* User u2 = Ebean.find(User.class, 2);
|
||||
*
|
||||
* u1.setName("u1 mod");
|
||||
* u2.setName("u2 mod");
|
||||
* u1.setName("u1 mod");
|
||||
* u2.setName("u2 mod");
|
||||
*
|
||||
* Ebean.save(u1);
|
||||
* Ebean.save(u2);
|
||||
* Ebean.save(u1);
|
||||
* Ebean.save(u2);
|
||||
*
|
||||
* return u1.getEmail();
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
* return u1.getEmail();
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static <T> T execute(TxCallable<T> c) {
|
||||
return serverMgr.getPrimaryServer().execute(c);
|
||||
@@ -1307,7 +1348,7 @@ public final class Ebean {
|
||||
* </p>
|
||||
* <p>
|
||||
* If there is a transaction then this information is placed into the current
|
||||
* transactions event information. When the transaction is commited this
|
||||
* 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.
|
||||
|
||||
@@ -7,6 +7,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.annotation.CacheStrategy;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
@@ -48,18 +49,18 @@ import com.avaje.ebean.text.json.JsonContext;
|
||||
* Example: Get a EbeanServer
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
* // Get access to the Human Resources EbeanServer/Database
|
||||
* EbeanServer hrServer = Ebean.getServer("HR");
|
||||
* EbeanServer hrServer = Ebean.getServer("HR");
|
||||
*
|
||||
*
|
||||
* // fetch contact 3 from the HR database Contact contact =
|
||||
* hrServer.find(Contact.class, new Integer(3));
|
||||
*
|
||||
* contact.setStatus("INACTIVE"); ...
|
||||
* contact.setStatus("INACTIVE"); ...
|
||||
*
|
||||
* // save the contact back to the HR database hrServer.save(contact);
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* <b>EbeanServer has more API than Ebean</b><br/>
|
||||
@@ -127,7 +128,6 @@ public interface EbeanServer {
|
||||
*/
|
||||
public MetaInfoManager getMetaInfoManager();
|
||||
|
||||
|
||||
/**
|
||||
* Return the BeanState for a given entity bean.
|
||||
* <p>
|
||||
@@ -191,15 +191,15 @@ public interface EbeanServer {
|
||||
* moved to {@link #createNamedQuery(Class, String)}.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
* EbeanServer ebeanServer = ... ;
|
||||
* String q = "find order fetch details where status = :st";
|
||||
*
|
||||
* List<Order> newOrders
|
||||
* List<Order> newOrders
|
||||
* = ebeanServer.createQuery(Order.class, q)
|
||||
* .setParameter("st", Order.Status.NEW)
|
||||
* .findList();
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* @param query
|
||||
* the object query
|
||||
@@ -207,16 +207,14 @@ public interface EbeanServer {
|
||||
public <T> Query<T> createQuery(Class<T> beanType, String query);
|
||||
|
||||
/**
|
||||
* Create a query for an entity bean (refer {@link Ebean#createQuery(Class)}
|
||||
* ).
|
||||
* Create a query for an entity bean (refer {@link Ebean#createQuery(Class)}).
|
||||
*
|
||||
* @see Ebean#createQuery(Class)
|
||||
*/
|
||||
public <T> Query<T> createQuery(Class<T> beanType);
|
||||
|
||||
/**
|
||||
* Create a query for a type of entity bean (the same as
|
||||
* {@link EbeanServer#createQuery(Class)}).
|
||||
* Create a query for a type of entity bean (the same as {@link EbeanServer#createQuery(Class)}).
|
||||
*/
|
||||
public <T> Query<T> find(Class<T> beanType);
|
||||
|
||||
@@ -272,8 +270,7 @@ public interface EbeanServer {
|
||||
public SqlQuery createSqlQuery(String sql);
|
||||
|
||||
/**
|
||||
* Create a named sql query (refer {@link Ebean#createNamedSqlQuery(String)}
|
||||
* ).
|
||||
* Create a named sql query (refer {@link Ebean#createNamedSqlQuery(String)}).
|
||||
* <p>
|
||||
* The query statement will be defined in a deployment orm xml file.
|
||||
* </p>
|
||||
@@ -283,8 +280,7 @@ public interface EbeanServer {
|
||||
public SqlQuery createNamedSqlQuery(String namedQuery);
|
||||
|
||||
/**
|
||||
* Create a sql update for executing native dml statements (refer
|
||||
* {@link Ebean#createSqlUpdate(String)}).
|
||||
* Create a sql update for executing native dml statements (refer {@link Ebean#createSqlUpdate(String)}).
|
||||
*
|
||||
* @see Ebean#createSqlUpdate(String)
|
||||
*/
|
||||
@@ -296,8 +292,7 @@ public interface EbeanServer {
|
||||
public CallableSql createCallableSql(String callableSql);
|
||||
|
||||
/**
|
||||
* Create a named sql update (refer {@link Ebean#createNamedSqlUpdate(String)}
|
||||
* ).
|
||||
* Create a named sql update (refer {@link Ebean#createNamedSqlUpdate(String)}).
|
||||
* <p>
|
||||
* The statement (an Insert Update or Delete statement) will be defined in a
|
||||
* deployment orm xml file.
|
||||
@@ -307,6 +302,17 @@ public interface EbeanServer {
|
||||
*/
|
||||
public SqlUpdate createNamedSqlUpdate(String namedQuery);
|
||||
|
||||
/**
|
||||
* Register a TransactionCallback on the currently active transaction.
|
||||
* <p/>
|
||||
* 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 void register(TransactionCallback transactionCallback) throws PersistenceException;
|
||||
|
||||
/**
|
||||
* Create a new transaction that is not held in TransactionThreadLocal.
|
||||
* <p>
|
||||
@@ -338,8 +344,7 @@ public interface EbeanServer {
|
||||
public Transaction beginTransaction(TxIsolation isolation);
|
||||
|
||||
/**
|
||||
* Returns the current transaction or null if there is no current transaction
|
||||
* in scope.
|
||||
* Returns the current transaction or null if there is no current transaction in scope.
|
||||
*/
|
||||
public Transaction currentTransaction();
|
||||
|
||||
@@ -367,15 +372,19 @@ public interface EbeanServer {
|
||||
* <p>
|
||||
* Code example:
|
||||
*
|
||||
* <pre class="code">
|
||||
* Ebean.startTransaction(); try { // do some fetching
|
||||
* and or persisting
|
||||
* <pre>{@code
|
||||
* ebeanServer.startTransaction();
|
||||
* try {
|
||||
* // do some fetching and or persisting ...
|
||||
*
|
||||
* // commit at the end Ebean.commitTransaction();
|
||||
* // commit at the end
|
||||
* ebeanServer.commitTransaction();
|
||||
*
|
||||
* } finally { // if commit didn't occur then rollback the transaction
|
||||
* Ebean.endTransaction(); }
|
||||
* </pre>
|
||||
* } finally {
|
||||
* // if commit didn't occur then rollback the transaction
|
||||
* ebeanServer.endTransaction();
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
@@ -417,7 +426,7 @@ public interface EbeanServer {
|
||||
* <p>
|
||||
* This will not perform a query against the database.
|
||||
* </p>
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
* Product product = Ebean.getReference(Product.class, 1);
|
||||
*
|
||||
* // You can get the id without causing a fetch/lazy load
|
||||
@@ -426,7 +435,7 @@ public interface EbeanServer {
|
||||
* // 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();
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType
|
||||
* the type of entity bean
|
||||
@@ -457,6 +466,30 @@ public interface EbeanServer {
|
||||
* Execute the query visiting the results. This is similar to findIterate in
|
||||
* that not all the result beans need to be held in memory at the same time
|
||||
* and as such is go for processing large queries.
|
||||
*
|
||||
* @see Query#findEach(QueryEachConsumer)
|
||||
*/
|
||||
public <T> void findEach(Query<T> query, QueryEachConsumer<T> consumer, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the query visiting the results. This is similar to findIterate in
|
||||
* that not all the result beans need to be held in memory at the same time
|
||||
* and as such is go for processing large queries.
|
||||
*
|
||||
* @see Query#findEachWhile(QueryEachWhileConsumer)
|
||||
*/
|
||||
public <T> void findEachWhile(Query<T> query, QueryEachWhileConsumer<T> consumer, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Deprecated in favor of #findEachWhile which is functionally exactly the same
|
||||
* but has a much better name.
|
||||
* <p>
|
||||
* Execute the query visiting the results. This is similar to findIterate in
|
||||
* that not all the result beans need to be held in memory at the same time
|
||||
* and as such is go for processing large queries.
|
||||
* </p>
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public <T> void findVisit(Query<T> query, QueryResultVisitor<T> visitor, Transaction transaction);
|
||||
|
||||
@@ -512,19 +545,20 @@ public interface EbeanServer {
|
||||
public <T> FutureIds<T> findFutureIds(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute find list query in a background thread.
|
||||
* Execute find list query in a background thread returning a FutureList object.
|
||||
* <p>
|
||||
* This returns a Future object which can be used to cancel, check the
|
||||
* execution status (isDone etc) and get the value (with or without a
|
||||
* timeout).
|
||||
* </p>
|
||||
*
|
||||
* execution status (isDone etc) and get the value (with or without a timeout).
|
||||
* <p>
|
||||
* This query will execute in it's own PersistenceContext and using its own transaction.
|
||||
* What that means is that it will not share any bean instances with other queries.
|
||||
*
|
||||
*
|
||||
* @param query
|
||||
* the query to execute in the background
|
||||
* @param transaction
|
||||
* the transaction (can be null).
|
||||
* @return a Future object for the list result of the query
|
||||
* @deprecated
|
||||
*/
|
||||
public <T> FutureList<T> findFutureList(Query<T> query, Transaction transaction);
|
||||
|
||||
@@ -535,23 +569,15 @@ public interface EbeanServer {
|
||||
* execution status (isDone etc) and get the value (with or without a
|
||||
* timeout).
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @param query
|
||||
* the query to execute in the background
|
||||
* @param transaction
|
||||
* the transaction (can be null).
|
||||
* @return a Future object for the list result of the query
|
||||
* @deprecated
|
||||
*/
|
||||
public SqlFutureList findFutureList(SqlQuery query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Find using a PagingList with explicit transaction and pageSize.
|
||||
* Deprecated in favour of findPagedList().
|
||||
* @deprecated
|
||||
*/
|
||||
public <T> PagingList<T> findPagingList(Query<T> query, Transaction transaction, int pageSize);
|
||||
|
||||
/**
|
||||
* Return a PagedList for this query.
|
||||
* <p>
|
||||
@@ -846,7 +872,7 @@ public interface EbeanServer {
|
||||
* An unmodified bean that is saved or updated is normally skipped and this marks the bean as
|
||||
* dirty so that it is not skipped.
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
*
|
||||
* Customer customer = ebeanServer.find(Customer, id);
|
||||
*
|
||||
@@ -855,7 +881,7 @@ public interface EbeanServer {
|
||||
* ebeanServer.markAsDirty(customer);
|
||||
* ebeanServer.save(customer);
|
||||
*
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*/
|
||||
public void markAsDirty(Object bean);
|
||||
|
||||
@@ -882,15 +908,15 @@ public interface EbeanServer {
|
||||
* properties are included instead.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
*
|
||||
* // A 'stateless update' example
|
||||
* Customer customer = new Customer();
|
||||
* customer.setId(7);
|
||||
* customer.setName("ModifiedNameNoOCC");
|
||||
* customer.setName("ModifiedNameNoOCC");
|
||||
* ebeanServer.update(customer);
|
||||
*
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* @see ServerConfig#setUpdatesDeleteMissingChildren(boolean)
|
||||
* @see ServerConfig#setUpdateChangesOnly(boolean)
|
||||
@@ -1126,6 +1152,9 @@ public interface EbeanServer {
|
||||
|
||||
/**
|
||||
* Return the JsonContext for reading/writing JSON.
|
||||
* <p>
|
||||
* This instance is safe to be used concurrently by multiple threads and this method is cheap to call.
|
||||
* </p>
|
||||
*/
|
||||
public JsonContext json();
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.common.BootupEbeanManager;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebean.config.ContainerConfig;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.util.ClassUtil;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Creates EbeanServer instances.
|
||||
@@ -27,31 +28,43 @@ import com.avaje.ebean.util.ClassUtil;
|
||||
*/
|
||||
public class EbeanServerFactory {
|
||||
|
||||
private static BootupEbeanManager serverFactory = createServerFactory();
|
||||
|
||||
private static BootupEbeanManager bootupEbeanManager;
|
||||
|
||||
/**
|
||||
* 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 synchronized void initialiseContainer(ContainerConfig containerConfig) {
|
||||
getServerFactory(containerConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using ebean.properties to configure the server.
|
||||
*/
|
||||
public static EbeanServer create(String name) {
|
||||
public static synchronized EbeanServer create(String name) {
|
||||
|
||||
EbeanServer server = serverFactory.createServer(name);
|
||||
|
||||
return server;
|
||||
// construct based on loading properties files
|
||||
// and if invoked by Ebean then it handles registration
|
||||
BootupEbeanManager serverFactory = getServerFactory(null);
|
||||
return serverFactory.createServer(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using the ServerConfig object to configure the server.
|
||||
*/
|
||||
public static EbeanServer create(ServerConfig config) {
|
||||
public static synchronized EbeanServer create(ServerConfig config) {
|
||||
|
||||
if (config.getName() == null) {
|
||||
throw new PersistenceException("The name is null (it is required)");
|
||||
}
|
||||
|
||||
EbeanServer server = serverFactory.createServer(config);
|
||||
EbeanServer server = createInternal(config);
|
||||
|
||||
if (config.isDefaultServer()) {
|
||||
GlobalProperties.setSkipPrimaryServer(true);
|
||||
PrimaryServer.setSkip(true);
|
||||
}
|
||||
if (config.isRegister()) {
|
||||
Ebean.register(server, config.isDefaultServer());
|
||||
@@ -60,13 +73,45 @@ public class EbeanServerFactory {
|
||||
return server;
|
||||
}
|
||||
|
||||
private static BootupEbeanManager createServerFactory() {
|
||||
|
||||
private static EbeanServer createInternal(ServerConfig config) {
|
||||
|
||||
return getServerFactory(config.getContainerConfig()).createServer(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the BootupEbeanManager initialising it if necessary.
|
||||
*
|
||||
* @param containerConfig the configuration controlling clustering communication
|
||||
*/
|
||||
private static BootupEbeanManager getServerFactory(ContainerConfig containerConfig) {
|
||||
|
||||
if (bootupEbeanManager != null) {
|
||||
return bootupEbeanManager;
|
||||
}
|
||||
|
||||
if (containerConfig == null) {
|
||||
// effectively load configuration from ebean.properties
|
||||
Properties properties = PrimaryServer.getProperties();
|
||||
containerConfig = new ContainerConfig();
|
||||
containerConfig.loadFromProperties(properties);
|
||||
}
|
||||
bootupEbeanManager = createServerFactory(containerConfig);
|
||||
return bootupEbeanManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the container instance using the configuration.
|
||||
*/
|
||||
private static BootupEbeanManager createServerFactory(ContainerConfig containerConfig) {
|
||||
|
||||
String dflt = "com.avaje.ebeaninternal.server.core.DefaultServerFactory";
|
||||
String implClassName = System.getProperty("ebean.serverfactory", dflt);
|
||||
|
||||
try {
|
||||
return (BootupEbeanManager) ClassUtil.newInstance(implClassName);
|
||||
Class<?> cls = Class.forName(implClassName);
|
||||
Constructor<?> constructor = cls.getConstructor(ContainerConfig.class);
|
||||
return (BootupEbeanManager) constructor.newInstance(containerConfig);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
@@ -102,9 +102,25 @@ public interface ExpressionList<T> extends Serializable {
|
||||
public QueryIterator<T> findIterate();
|
||||
|
||||
/**
|
||||
* Execute the query visiting the results.
|
||||
*
|
||||
* @see Query#findVisit(QueryResultVisitor)
|
||||
* Execute the query process the beans one at a time.
|
||||
*
|
||||
* @see Query#findEach(QueryEachConsumer)
|
||||
*/
|
||||
public void findEach(QueryEachConsumer<T> consumer);
|
||||
|
||||
/**
|
||||
* Execute the query processing the beans one at a time with the ability to
|
||||
* stop processing before reading all the beans.
|
||||
*
|
||||
* @see Query#findEachWhile(QueryEachWhileConsumer)
|
||||
*/
|
||||
public void findEachWhile(QueryEachWhileConsumer<T> consumer);
|
||||
|
||||
/**
|
||||
* Deprecated in favor of #findEachWhile which is functionally exactly the same
|
||||
* but has a much better name.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public void findVisit(QueryResultVisitor<T> visitor);
|
||||
|
||||
@@ -192,25 +208,6 @@ public interface ExpressionList<T> extends Serializable {
|
||||
*/
|
||||
public FutureList<T> findFutureList();
|
||||
|
||||
/**
|
||||
* Return a PagingList for this query.
|
||||
* <p>
|
||||
* This can be used to break up a query into multiple queries to fetch the
|
||||
* data a page at a time.
|
||||
* </p>
|
||||
* <p>
|
||||
* This typically works by using a query per page and setting
|
||||
* {@link Query#setFirstRow(int)} and and {@link Query#setMaxRows(int)} on the
|
||||
* query. This usually would translate into SQL that uses limit offset, rownum
|
||||
* or row_number function to limit the result set.
|
||||
* </p>
|
||||
*
|
||||
* @param pageSize
|
||||
* the number of beans fetched per Page
|
||||
* @deprecated
|
||||
*/
|
||||
public PagingList<T> findPagingList(int pageSize);
|
||||
|
||||
/**
|
||||
* Return a PagedList for this query.
|
||||
* <p>
|
||||
@@ -245,24 +242,6 @@ public interface ExpressionList<T> extends Serializable {
|
||||
*/
|
||||
public Query<T> select(String properties);
|
||||
|
||||
/**
|
||||
* Specify a property (associated bean) to join and <em>fetch</em> including
|
||||
* all its properties.
|
||||
*
|
||||
* @see Query#fetch(String)
|
||||
* @deprecated
|
||||
*/
|
||||
public Query<T> join(String assocProperties);
|
||||
|
||||
/**
|
||||
* Specify a property (associated bean) to join and <em>fetch</em> with its
|
||||
* specific properties to include (aka partial object).
|
||||
*
|
||||
* @see Query#fetch(String,String)
|
||||
* @deprecated
|
||||
*/
|
||||
public Query<T> join(String assocProperty, String assocProperties);
|
||||
|
||||
/**
|
||||
* Set the first row to fetch.
|
||||
*
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/**
|
||||
* FutureList represents the result of a background query execution that will
|
||||
@@ -15,13 +19,13 @@ import java.util.concurrent.Future;
|
||||
* A simple example:
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
* // create a query to find all orders
|
||||
* Query<Order> query = Ebean.find(Order.class);
|
||||
* Query<Order> query = Ebean.find(Order.class);
|
||||
*
|
||||
* // execute the query in a background thread
|
||||
* // immediately returning the futureList
|
||||
* FutureList<Order> futureList = query.findFutureList();
|
||||
* FutureList<Order> futureList = query.findFutureList();
|
||||
*
|
||||
* // do something else ...
|
||||
*
|
||||
@@ -35,13 +39,11 @@ import java.util.concurrent.Future;
|
||||
*
|
||||
* if (!futureList.isCancelled()){
|
||||
* // wait for the query to finish and return the list
|
||||
* List<Order> list = futureList.get();
|
||||
* List<Order> list = futureList.get();
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author rbygrave
|
||||
* }</pre>
|
||||
*/
|
||||
public interface FutureList<T> extends Future<List<T>> {
|
||||
|
||||
@@ -50,4 +52,25 @@ public interface FutureList<T> extends Future<List<T>> {
|
||||
*/
|
||||
public Query<T> getQuery();
|
||||
|
||||
/**
|
||||
* Same as {@link #get()} but wraps InterruptedException and ExecutionException in the
|
||||
* unchecked PersistenceException.
|
||||
*
|
||||
* @return The query list result
|
||||
*
|
||||
* @throws PersistenceException when a InterruptedException or ExecutionException occurs.
|
||||
*/
|
||||
public List<T> getUnchecked();
|
||||
|
||||
/**
|
||||
* Same as {@link #get(long, java.util.concurrent.TimeUnit)} but wraps InterruptedException
|
||||
* and ExecutionException in the unchecked PersistenceException.
|
||||
*
|
||||
* @return The query list result
|
||||
*
|
||||
* @throws TimeoutException if the wait timed out
|
||||
* @throws PersistenceException if a InterruptedException or ExecutionException occurs.
|
||||
*/
|
||||
public List<T> getUnchecked(long timeout, TimeUnit unit) throws TimeoutException;
|
||||
|
||||
}
|
||||
|
||||
@@ -248,10 +248,12 @@ public abstract class Model {
|
||||
return new Finder<I, T>(server, idType, type);
|
||||
}
|
||||
|
||||
// Does not exist yet but I think should
|
||||
// public void deleteById(I id) {
|
||||
// return db().deleteById(type, id);
|
||||
// }
|
||||
/**
|
||||
* Delete a bean by Id.
|
||||
*/
|
||||
public void deleteById(I id) {
|
||||
db().delete(type, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all entities of the given type.
|
||||
@@ -328,6 +330,37 @@ public abstract class Model {
|
||||
return query().findIds();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the query consuming each bean one at a time.
|
||||
* <p>
|
||||
* This is generally used to process large queries where unlike findList
|
||||
* you do not want to hold all the results in memory at once but instead
|
||||
* process them one at a time (requiring far less memory).
|
||||
* </p>
|
||||
* Equivalent to {@link Query#findEach(QueryEachConsumer)}
|
||||
*/
|
||||
public void findEach(QueryEachConsumer<T> consumer) {
|
||||
query().findEach(consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the query consuming each bean one at a time.
|
||||
* <p>
|
||||
* This is similar to #findEach except that you return boolean
|
||||
* true to continue processing beans and return false to stop
|
||||
* processing early.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is generally used to process large queries where unlike findList
|
||||
* you do not want to hold all the results in memory at once but instead
|
||||
* process them one at a time (requiring far less memory).
|
||||
* </p>
|
||||
* Equivalent to {@link Query#findEachWhile(QueryEachWhileConsumer)}
|
||||
*/
|
||||
public void findEachWhile(QueryEachWhileConsumer<T> consumer) {
|
||||
query().findEachWhile(consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all entities of the given type.
|
||||
* <p>
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* Used to page through a query result rather than fetching all the results in a
|
||||
* single query.
|
||||
* <p>
|
||||
* Has the ability to use background threads to 'fetch ahead' the next page and
|
||||
* get the total row count.
|
||||
* </p>
|
||||
* <p>
|
||||
* If you are building a stateless web application and not keeping the
|
||||
* PagingList over multiple requests then there is not much to be gained in
|
||||
* using PagingList. Instead you can just use {@link Query#setFirstRow(int)} and
|
||||
* {@link Query#setMaxRows(int)}.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If you are using PagingList is a stateful web application where the
|
||||
* PagingList is held over multiple requests then PagingList provides the extra
|
||||
* benefits of
|
||||
* <ul>
|
||||
* <li>Fetch ahead - automatically fetching the next page via background query
|
||||
* execution</li>
|
||||
* <li>Automatic propagation of the persistence context</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
* <p>
|
||||
* So with PagingList when you use Page 2 it can automatically fetch Page 3 data
|
||||
* in the background (using a findFutureList() query). It also automatically
|
||||
* propagates the persistence context so that all the queries executed by the
|
||||
* PagingList all use the same persistence context.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* PagingList<TOne> pagingList =
|
||||
* Ebean.find(TOne.class)
|
||||
* .where().gt("name", "2")
|
||||
* .findPagingList(10);
|
||||
*
|
||||
* // get the row count in the background...
|
||||
* // ... otherwise it is fetched on demand
|
||||
* // ... when getRowCount() or getPageCount()
|
||||
* // ... is called
|
||||
* pagingList.getFutureRowCount();
|
||||
*
|
||||
* // get the first page
|
||||
* Page<TOne> page = pagingList.getPage(0);
|
||||
*
|
||||
* // get the beans from the page as a list
|
||||
* List<TOne> list = page.getList();
|
||||
* </pre>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* @param <T>
|
||||
* the entity bean type
|
||||
*/
|
||||
public interface PagingList<T> {
|
||||
|
||||
/**
|
||||
* Refresh will clear all the pages and row count forcing them to be
|
||||
* re-fetched when next required.
|
||||
*/
|
||||
public void refresh();
|
||||
|
||||
// public void fetchAll();
|
||||
// public String? getOrderBy();
|
||||
// public void setOrderBy(String?);
|
||||
|
||||
/**
|
||||
* By default fetchAhead is true so use this to turn off fetchAhead.
|
||||
* <p>
|
||||
* Set this to false if you don't want to fetch ahead using background
|
||||
* fetching.
|
||||
* <p>
|
||||
* If set to true (or left as to default) then the next page is fetched in the
|
||||
* background as soon as the list is accessed.
|
||||
* </p>
|
||||
*/
|
||||
public PagingList<T> setFetchAhead(boolean fetchAhead);
|
||||
|
||||
/**
|
||||
* Return the Future for getting the total row count.
|
||||
*/
|
||||
public Future<Integer> getFutureRowCount();
|
||||
|
||||
/**
|
||||
* Return the data for all the pages in the form of a single List.
|
||||
* <p>
|
||||
* Iterating through this list will automatically fire the paging queries as
|
||||
* required.
|
||||
* </p>
|
||||
*/
|
||||
public List<T> getAsList();
|
||||
|
||||
/**
|
||||
* Return the page size. This is the number of rows per page.
|
||||
*/
|
||||
public int getPageSize();
|
||||
|
||||
/**
|
||||
* Return the total row count.
|
||||
* <p>
|
||||
* This gets the result from getFutureRowCount and will wait until that query
|
||||
* has completed.
|
||||
* </p>
|
||||
*/
|
||||
public int getTotalRowCount();
|
||||
|
||||
/**
|
||||
* Return the total page count.
|
||||
* <p>
|
||||
* This is based on the total row count. This will wait until the row count
|
||||
* has returned if it has not already.
|
||||
* </p>
|
||||
*/
|
||||
public int getTotalPageCount();
|
||||
|
||||
/**
|
||||
* Return the page for a given page position (starting at 0).
|
||||
*/
|
||||
public Page<T> getPage(int i);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Defines the scope for PersistenceContext.
|
||||
* <p/>
|
||||
* Ebean has traditionally used Transaction scope for the PersistenceContext. This is used to change the scope to
|
||||
* use (by default) and explicitly set the scope to use for an individual query.
|
||||
*
|
||||
* @see com.avaje.ebean.config.ServerConfig#setPersistenceContextScope(PersistenceContextScope)
|
||||
* @see com.avaje.ebean.Query#setPersistenceContextScope(PersistenceContextScope)
|
||||
*/
|
||||
public enum PersistenceContextScope {
|
||||
|
||||
/**
|
||||
* PersistenceContext is scoped to the transaction.
|
||||
* <p/>
|
||||
* If a transaction spans 2 or more queries that fetch the same bean in terms of same type
|
||||
* and same Id value then they share the same bean instance.
|
||||
* <p/>
|
||||
* You may want to change to use QUERY scope when you want a query executing in a transaction to effectively
|
||||
* ignore beans that have already been loaded (by other queries in the same transaction) and instead get a
|
||||
* 'fresh copy' of the bean.
|
||||
*/
|
||||
TRANSACTION,
|
||||
|
||||
/**
|
||||
* PersistenceContext is scoped to the query.
|
||||
* <p/>
|
||||
* This means that for this query running in an existing transaction then it will effectively ignore any beans
|
||||
* that have already been queried/loaded by prior queries in the same transaction.
|
||||
* <p/>
|
||||
* You may use QUERY scope on a query that is executed in a transaction and you want to get a 'fresh copy' of the bean.
|
||||
*/
|
||||
QUERY
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.config.PropertyMap;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Provides singleton state for the default server.
|
||||
* <p/>
|
||||
* Intended for internal use as part of bootup, construction, registration of the default server.
|
||||
*/
|
||||
class PrimaryServer {
|
||||
|
||||
private static Properties globalProperties;
|
||||
|
||||
private static String defaultServerName;
|
||||
|
||||
private static boolean skip;
|
||||
|
||||
/**
|
||||
* Set whether to skip automatically creating the primary server.
|
||||
*/
|
||||
static synchronized void setSkip(boolean skip) {
|
||||
PrimaryServer.skip = skip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true to skip automatically creating the primary server.
|
||||
*/
|
||||
static synchronized boolean isSkip() {
|
||||
return skip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default server name.
|
||||
*/
|
||||
static synchronized String getPrimaryServerName() {
|
||||
getProperties();
|
||||
return defaultServerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default configuration Properties.
|
||||
*/
|
||||
static synchronized Properties getProperties() {
|
||||
if (globalProperties == null) {
|
||||
globalProperties = PropertyMap.defaultProperties();
|
||||
}
|
||||
defaultServerName = globalProperties.getProperty("datasource.default");
|
||||
if (defaultServerName == null) {
|
||||
defaultServerName = globalProperties.getProperty("ebean.default.datasource");
|
||||
}
|
||||
return globalProperties;
|
||||
}
|
||||
}
|
||||
@@ -301,6 +301,21 @@ public interface Query<T> extends Serializable {
|
||||
*/
|
||||
public Query<T> copy();
|
||||
|
||||
/**
|
||||
* Specify the PersistenceContextScope to use for this query.
|
||||
* <p/>
|
||||
* When this is not set the 'default' configured on {@link com.avaje.ebean.config.ServerConfig#setPersistenceContextScope(PersistenceContextScope)}
|
||||
* is used - this value defaults to {@link com.avaje.ebean.PersistenceContextScope#TRANSACTION}.
|
||||
* <p/>
|
||||
* Note that the same persistence Context is used for subsequent lazy loading and query join queries.
|
||||
* <p/>
|
||||
* Note that #findEach uses a 'per object graph' PersistenceContext so this scope is ignored for
|
||||
* queries executed as #findIterate, #findEach, #findEachWhile.
|
||||
*
|
||||
* @param scope The scope to use for this query and subsequent lazy loading.
|
||||
*/
|
||||
public Query<T> setPersistenceContextScope(PersistenceContextScope scope);
|
||||
|
||||
/**
|
||||
* Return the ExpressionFactory used by this query.
|
||||
*/
|
||||
@@ -325,22 +340,32 @@ public interface Query<T> extends Serializable {
|
||||
*/
|
||||
public Query<T> setAutofetch(boolean autofetch);
|
||||
|
||||
/**
|
||||
* Set the default lazy loading batch size to use.
|
||||
* <p>
|
||||
* When lazy loading is invoked on beans loaded by this query then this sets the
|
||||
* batch size used to load those beans.
|
||||
*
|
||||
* @param lazyLoadBatchSize the number of beans to lazy load in a single batch
|
||||
*/
|
||||
public Query<T> setLazyLoadBatchSize(int lazyLoadBatchSize);
|
||||
|
||||
/**
|
||||
* Explicitly set a comma delimited list of the properties to fetch on the
|
||||
* 'main' entity bean (aka partial object). Note that '*' means all
|
||||
* properties.
|
||||
*
|
||||
*
|
||||
* <pre class="code">
|
||||
* Query<Customer> query = Ebean.createQuery(Customer.class);
|
||||
*
|
||||
*
|
||||
* // Only fetch the customer id, name and status.
|
||||
* // This is described as a "Partial Object"
|
||||
* query.select("name, status");
|
||||
* query.where("lower(name) like :custname").setParameter("custname", "rob%");
|
||||
*
|
||||
*
|
||||
* List<Customer> customerList = query.findList();
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* @param fetchProperties
|
||||
* the properties to fetch for this bean (* = all properties).
|
||||
*/
|
||||
@@ -446,37 +471,89 @@ public interface Query<T> extends Serializable {
|
||||
*/
|
||||
public QueryIterator<T> findIterate();
|
||||
|
||||
/**
|
||||
* This is deprecated in favor of #findEachWhile.
|
||||
* <p>
|
||||
* This is functionally exactly the same as #findEachWhile. It is
|
||||
* replaced by findEachWhile because the method name is much better.
|
||||
* </p>
|
||||
*
|
||||
* @param visitor
|
||||
* the visitor used to process the queried beans.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public void findVisit(QueryResultVisitor<T> visitor);
|
||||
|
||||
/**
|
||||
* Execute the query processing the beans one at a time.
|
||||
* <p>
|
||||
* This method is appropriate to process very large query results as the
|
||||
* beans are consumed one at a time and do not need to be held in memory
|
||||
* (unlike #findList #findSet etc)
|
||||
* </p>
|
||||
* <p>
|
||||
* Compared with #findEachWhile this will always process all the beans where as
|
||||
* #findEachWhile provides a way to stop processing the query result early before
|
||||
* all the beans have been read.
|
||||
* </p>
|
||||
* <p>
|
||||
* This method is functionally equivalent to findIterate() but instead of using an
|
||||
* iterator uses the QueryEachConsumer (SAM) interface which is better suited to use
|
||||
* with Java8 closures.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* Query<Customer> query = server.find(Customer.class)
|
||||
* .where().gt("id", 0)
|
||||
* .orderBy("id")
|
||||
* .setMaxRows(2);
|
||||
*
|
||||
* query.findVisit((Customer customer) -> {
|
||||
*
|
||||
* // do something with customer
|
||||
* System.out.println("-- visit " + customer);
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param consumer
|
||||
* the consumer used to process the queried beans.
|
||||
*/
|
||||
public void findEach(QueryEachConsumer<T> consumer);
|
||||
|
||||
/**
|
||||
* Execute the query using callbacks to a visitor to process the resulting
|
||||
* beans one at a time.
|
||||
* <p>
|
||||
* Similar to findIterate() this query method does not require all the result
|
||||
* beans to be all held in memory at once and as such is useful for processing
|
||||
* large queries.
|
||||
* This method is functionally equivalent to findIterate() but instead of using an
|
||||
* iterator uses the QueryEachWhileConsumer (SAM) interface which is better suited to use
|
||||
* with Java8 closures.
|
||||
* </p>
|
||||
*
|
||||
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
*
|
||||
* Query<Customer> query = server.find(Customer.class)
|
||||
* .fetch("contacts", new FetchConfig().query(2))
|
||||
* .where().gt("id", 0)
|
||||
* .orderBy("id")
|
||||
* .setMaxRows(2);
|
||||
*
|
||||
* query.findVisit(new QueryResultVisitor<Customer>() {
|
||||
*
|
||||
* public boolean accept(Customer customer) {
|
||||
*
|
||||
* query.findEachWhile((Customer customer) -> {
|
||||
*
|
||||
* // do something with customer
|
||||
* System.out.println("-- visit " + customer);
|
||||
* return true;
|
||||
* }
|
||||
*
|
||||
* // return true to continue processing or false to stop
|
||||
* return (customer.getId() < 40);
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param visitor
|
||||
* the visitor used to process the queried beans.
|
||||
*
|
||||
* @param consumer
|
||||
* the consumer used to process the queried beans.
|
||||
*/
|
||||
public void findVisit(QueryResultVisitor<T> visitor);
|
||||
public void findEachWhile(QueryEachWhileConsumer<T> consumer);
|
||||
|
||||
/**
|
||||
* Execute the query returning the list of objects.
|
||||
@@ -599,21 +676,14 @@ public interface Query<T> extends Serializable {
|
||||
/**
|
||||
* Execute find list query in a background thread.
|
||||
* <p>
|
||||
* Deprecated with a view to simplifying internals.
|
||||
* This query will execute in it's own PersistenceContext and using its own transaction.
|
||||
* What that means is that it will not share any bean instances with other queries.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @return a Future object for the list result of the query
|
||||
* @deprecated
|
||||
*/
|
||||
public FutureList<T> findFutureList();
|
||||
|
||||
/**
|
||||
* This is being deprecated in favour of the simplier {@link Query#findPagedList(int, int)}.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public PagingList<T> findPagingList(int pageSize);
|
||||
|
||||
/**
|
||||
* Return a PagedList for this query.
|
||||
* <p>
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Used to process a query result one bean at a time via a callback to this
|
||||
* visitor.
|
||||
* <p>
|
||||
* If you wish to stop further processing return false from the accept method.
|
||||
* </p>
|
||||
* <p>
|
||||
* Unlike findList() and findSet() using a QueryResultVisitor does not require
|
||||
* all the beans in the query result to be held in memory at once. This makes
|
||||
* QueryResultVisitor useful for processing large queries.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* Query<Customer> query = server.find(Customer.class)
|
||||
* .where().gt("id", 0)
|
||||
* .orderBy("id")
|
||||
* .setMaxRows(2);
|
||||
*
|
||||
* query.findVisit((Customer customer) -> {
|
||||
*
|
||||
* // do something with customer
|
||||
* System.out.println("-- visit " + customer);
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param <T>
|
||||
* the type of entity bean being queried.
|
||||
*/
|
||||
public interface QueryEachConsumer<T> {
|
||||
|
||||
/**
|
||||
* Process the bean.
|
||||
*
|
||||
* @param bean
|
||||
* the entity bean to process
|
||||
*/
|
||||
public void accept(T bean);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Used to process a query result one bean at a time via a callback to this
|
||||
* visitor.
|
||||
* <p>
|
||||
* If you wish to stop further processing return false from the accept method.
|
||||
* </p>
|
||||
* <p>
|
||||
* Unlike findList() and findSet() using a QueryResultVisitor does not require
|
||||
* all the beans in the query result to be held in memory at once. This makes
|
||||
* QueryResultVisitor useful for processing large queries.
|
||||
* </p>
|
||||
* <p/>
|
||||
* <pre class="code">
|
||||
*
|
||||
* Query<Customer> query = server.find(Customer.class)
|
||||
* .fetch("contacts", new FetchConfig().query(2))
|
||||
* .where().gt("id", 0)
|
||||
* .orderBy("id")
|
||||
* .setMaxRows(2);
|
||||
*
|
||||
* query.findEachWhile((Customer customer) -> {
|
||||
*
|
||||
* // do something with customer
|
||||
* System.out.println("-- visit " + customer);
|
||||
*
|
||||
* // return true to continue processing or false to stop
|
||||
* return (customer.getId() < 40);
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param <T> the type of entity bean being queried.
|
||||
*/
|
||||
public interface QueryEachWhileConsumer<T> {
|
||||
|
||||
/**
|
||||
* Process the bean and return true if you want to continue processing more
|
||||
* beans. Return false if you want to stop processing further.
|
||||
*
|
||||
* @param bean the entity bean to process
|
||||
* @return true to continue processing more beans or false to stop.
|
||||
*/
|
||||
public boolean accept(T bean);
|
||||
}
|
||||
@@ -91,6 +91,11 @@ public interface SqlUpdate {
|
||||
*/
|
||||
public String getSql();
|
||||
|
||||
/**
|
||||
* Return the generated sql that has named parameters converted to positioned parameters.
|
||||
*/
|
||||
public String getGeneratedSql();
|
||||
|
||||
/**
|
||||
* Return the timeout used to execute this statement.
|
||||
*/
|
||||
|
||||
@@ -35,6 +35,11 @@ public interface Transaction extends Closeable {
|
||||
*/
|
||||
public static final int SERIALIZABLE = java.sql.Connection.TRANSACTION_SERIALIZABLE;
|
||||
|
||||
/**
|
||||
* Register a TransactionCallback with this transaction.
|
||||
*/
|
||||
public void register(TransactionCallback callback);
|
||||
|
||||
/**
|
||||
* Return true if this transaction is read only.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Provides a callback that can be registered with a Transaction.
|
||||
* <p/>
|
||||
* The callback methods are called just prior to and after the transaction performs a commit or rollback.
|
||||
* <p/>
|
||||
* A typical use of TransactionCallback would be to clean up non-transactional resources like files. For example,
|
||||
* when processing files on postCommit/postRollback clean up the associated files. As another example when
|
||||
* on postCommit of a delete remove associated resources from the file system or remote service.
|
||||
*/
|
||||
public interface TransactionCallback {
|
||||
|
||||
/**
|
||||
* Perform processing just prior to the transaction commit.
|
||||
*/
|
||||
void preCommit();
|
||||
|
||||
/**
|
||||
* Perform processing just after the transaction commit.
|
||||
*/
|
||||
void postCommit();
|
||||
|
||||
/**
|
||||
* Perform processing just prior to the transaction rollback.
|
||||
*/
|
||||
void preRollback();
|
||||
|
||||
/**
|
||||
* Perform processing just after the transaction rollback.
|
||||
*/
|
||||
void postRollback();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Adapter that can be extended for easier implementation of TransactionCallback.
|
||||
* <p/>
|
||||
* Provides 'no operation' implementation for each of the TransactionCallback methods. It is expected that this
|
||||
* class is extended and override the methods you need to.
|
||||
*/
|
||||
public abstract class TransactionCallbackAdapter implements TransactionCallback {
|
||||
|
||||
/**
|
||||
* Perform processing just prior to the transaction commit.
|
||||
*/
|
||||
@Override
|
||||
public void preCommit() {
|
||||
// do nothing - override as necessary
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform processing just after the transaction commit.
|
||||
*/
|
||||
@Override
|
||||
public void postCommit() {
|
||||
// do nothing - override as necessary
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform processing just prior to the transaction rollback.
|
||||
*/
|
||||
@Override
|
||||
public void preRollback() {
|
||||
// do nothing - override as necessary
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform processing just after the transaction rollback.
|
||||
*/
|
||||
@Override
|
||||
public void postRollback() {
|
||||
// do nothing - override as necessary
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,13 @@ public interface BeanCollection<E> extends Serializable {
|
||||
ALL
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the collection back to an empty state ready for reloading.
|
||||
* <p>
|
||||
* This is done as part of bean refresh.
|
||||
*/
|
||||
public void reset(EntityBean ownerBean, String propertyName);
|
||||
|
||||
/**
|
||||
* Return true if the collection is empty and untouched. Used to detect if a
|
||||
* collection was 'cleared' deliberately or just un-initialised.
|
||||
@@ -47,14 +54,6 @@ public interface BeanCollection<E> extends Serializable {
|
||||
*/
|
||||
public String getPropertyName();
|
||||
|
||||
/**
|
||||
* Return the index position of this collection in the lazy/query loader.
|
||||
* <p>
|
||||
* Used for batch loading of collections.
|
||||
* </p>
|
||||
*/
|
||||
public int getLoaderIndex();
|
||||
|
||||
/**
|
||||
* Check after the lazy load that the underlying collection is not null
|
||||
* (handle case where join to many not outer).
|
||||
@@ -108,11 +107,6 @@ public interface BeanCollection<E> extends Serializable {
|
||||
*/
|
||||
public void internalAdd(Object bean);
|
||||
|
||||
/**
|
||||
* Returns the underlying List Set or Map object.
|
||||
*/
|
||||
public Object getActualCollection();
|
||||
|
||||
/**
|
||||
* Return the number of elements in the List Set or Map.
|
||||
*/
|
||||
|
||||
@@ -38,12 +38,12 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
/**
|
||||
* The owning bean (used for lazy fetch).
|
||||
*/
|
||||
protected final EntityBean ownerBean;
|
||||
protected EntityBean ownerBean;
|
||||
|
||||
/**
|
||||
* The name of this property in the owning bean (used for lazy fetch).
|
||||
*/
|
||||
protected final String propertyName;
|
||||
protected String propertyName;
|
||||
|
||||
protected ModifyHolder<E> modifyHolder;
|
||||
|
||||
@@ -62,8 +62,6 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
* Constructor not non-lazy loading collection.
|
||||
*/
|
||||
public AbstractBeanCollection() {
|
||||
this.ownerBean = null;
|
||||
this.propertyName = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,10 +83,6 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
public int getLoaderIndex() {
|
||||
return loaderIndex;
|
||||
}
|
||||
|
||||
public ExpressionList<?> getFilterMany() {
|
||||
return filterMany;
|
||||
}
|
||||
|
||||
@@ -46,6 +46,14 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
super(loader, ownerBean, propertyName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(EntityBean ownerBean, String propertyName) {
|
||||
this.ownerBean = ownerBean;
|
||||
this.propertyName = propertyName;
|
||||
this.list = null;
|
||||
this.touched = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmptyAndUntouched() {
|
||||
return !touched && (list == null || list.isEmpty());
|
||||
@@ -130,13 +138,6 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying list.
|
||||
*/
|
||||
public Object getActualCollection() {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the underlying list is populated.
|
||||
*/
|
||||
|
||||
@@ -39,7 +39,15 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
public BeanMap(BeanCollectionLoader ebeanServer, EntityBean ownerBean, String propertyName) {
|
||||
super(ebeanServer, ownerBean, propertyName);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void reset(EntityBean ownerBean, String propertyName) {
|
||||
this.ownerBean = ownerBean;
|
||||
this.propertyName = propertyName;
|
||||
this.map = null;
|
||||
this.touched = false;
|
||||
}
|
||||
|
||||
public boolean isEmptyAndUntouched() {
|
||||
return !touched && (map == null || map.isEmpty());
|
||||
}
|
||||
@@ -146,15 +154,8 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying map.
|
||||
*/
|
||||
public Object getActualCollection() {
|
||||
return map;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer(50);
|
||||
StringBuilder sb = new StringBuilder(50);
|
||||
sb.append("BeanMap ");
|
||||
if (isReadOnly()) {
|
||||
sb.append("readOnly ");
|
||||
|
||||
@@ -40,6 +40,14 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
super(loader, ownerBean, propertyName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(EntityBean ownerBean, String propertyName) {
|
||||
this.ownerBean = ownerBean;
|
||||
this.propertyName = propertyName;
|
||||
this.set = null;
|
||||
this.touched = false;
|
||||
}
|
||||
|
||||
public boolean isEmptyAndUntouched() {
|
||||
return !touched && (set == null || set.isEmpty());
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Provides some base implementation for NamingConventions.
|
||||
*
|
||||
*
|
||||
* @author emcgreal
|
||||
*/
|
||||
public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
@@ -41,7 +41,7 @@ public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
/** Used to trim off extra prefix for M2M. */
|
||||
protected int rhsPrefixLength = 3;
|
||||
|
||||
protected boolean useForeignKeyPrefix = true;
|
||||
protected boolean useForeignKeyPrefix;
|
||||
|
||||
/**
|
||||
* Construct with a sequence format and useForeignKeyPrefix setting.
|
||||
@@ -53,12 +53,12 @@ public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
|
||||
/**
|
||||
* Construct with a sequence format.
|
||||
*
|
||||
* @param sequenceFormat
|
||||
* the sequence format
|
||||
*
|
||||
* @param sequenceFormat the sequence format
|
||||
*/
|
||||
public AbstractNamingConvention(String sequenceFormat) {
|
||||
this.sequenceFormat = sequenceFormat;
|
||||
this.useForeignKeyPrefix = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,10 +125,9 @@ public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
* The format should include "{table}". When generating the sequence name
|
||||
* {table} is replaced with the actual table name.
|
||||
* </p>
|
||||
*
|
||||
* @param sequenceFormat
|
||||
* string containing "{table}" which is replaced with the actual
|
||||
* table name to generate the sequence name.
|
||||
*
|
||||
* @param sequenceFormat string containing "{table}" which is replaced with the actual
|
||||
* table name to generate the sequence name.
|
||||
*/
|
||||
public void setSequenceFormat(String sequenceFormat) {
|
||||
this.sequenceFormat = sequenceFormat;
|
||||
@@ -173,7 +172,7 @@ public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
* This first checks for the @Table annotation and if not present uses the
|
||||
* naming convention to define the table name.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @see #getTableNameFromAnnotation(Class)
|
||||
* @see #getTableNameByConvention(Class)
|
||||
*/
|
||||
@@ -240,8 +239,7 @@ public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
if (t != null && !isEmpty(t.name())) {
|
||||
// Note: empty catalog and schema are converted to null
|
||||
// Only need to convert quoted identifiers from annotations
|
||||
return new TableName(quoteIdentifiers(t.catalog()), quoteIdentifiers(t.schema()),
|
||||
quoteIdentifiers(t.name()));
|
||||
return new TableName(quoteIdentifiers(t.catalog()), quoteIdentifiers(t.schema()), quoteIdentifiers(t.name()));
|
||||
}
|
||||
|
||||
// No annotation
|
||||
@@ -279,4 +277,16 @@ public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load settings from properties.
|
||||
*/
|
||||
@Override
|
||||
public void loadFromProperties(PropertiesWrapper properties) {
|
||||
|
||||
useForeignKeyPrefix = properties.getBoolean("namingConvention.useForeignKeyPrefix", useForeignKeyPrefix);
|
||||
sequenceFormat = properties.get("namingConvention.sequenceFormat", sequenceFormat);
|
||||
schema = properties.get("namingConvention.schema", schema);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -155,14 +155,6 @@ public class AutofetchConfig {
|
||||
return logDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the log directory substituting any expressions such as
|
||||
* ${catalina.base} etc.
|
||||
*/
|
||||
public String getLogDirectoryWithEval() {
|
||||
return GlobalProperties.evaluateExpressions(logDirectory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the directory to put the autofetch log in.
|
||||
*/
|
||||
@@ -234,22 +226,20 @@ public class AutofetchConfig {
|
||||
/**
|
||||
* Load the settings from the properties file.
|
||||
*/
|
||||
public void loadSettings(GlobalProperties.PropertySource p) {
|
||||
public void loadSettings(PropertiesWrapper p) {
|
||||
|
||||
logDirectory = p.get("autofetch.logDirectory", null);
|
||||
queryTuning = p.getBoolean("autofetch.querytuning", false);
|
||||
queryTuningAddVersion = p.getBoolean("autofetch.queryTuningAddVersion", false);
|
||||
garbageCollectionOnShutdown = p.getBoolean("autofetch.garbageCollectionOnShutdown", false);
|
||||
logDirectory = p.get("autofetch.logDirectory", logDirectory);
|
||||
queryTuning = p.getBoolean("autofetch.querytuning", queryTuning);
|
||||
queryTuningAddVersion = p.getBoolean("autofetch.queryTuningAddVersion", queryTuningAddVersion);
|
||||
garbageCollectionOnShutdown = p.getBoolean("autofetch.garbageCollectionOnShutdown", garbageCollectionOnShutdown);
|
||||
|
||||
profiling = p.getBoolean("autofetch.profiling", false);
|
||||
mode = p.getEnum(AutofetchMode.class, "autofetch.implicitmode", AutofetchMode.DEFAULT_ONIFEMPTY);
|
||||
profiling = p.getBoolean("autofetch.profiling", profiling);
|
||||
mode = p.getEnum(AutofetchMode.class, "autofetch.implicitmode", mode);
|
||||
|
||||
profilingMin = p.getInt("autofetch.profiling.min", 1);
|
||||
profilingBase = p.getInt("autofetch.profiling.base", 10);
|
||||
profilingMin = p.getInt("autofetch.profiling.min", profilingMin);
|
||||
profilingBase = p.getInt("autofetch.profiling.base", profilingBase);
|
||||
|
||||
String rate = p.get("autofetch.profiling.rate", "0.05");
|
||||
profilingRate = Double.parseDouble(rate);
|
||||
|
||||
profileUpdateFrequency = p.getInt("autofetch.profiling.updatefrequency", 60);
|
||||
profilingRate = p.getDouble("autofetch.profiling.rate", profilingRate);
|
||||
profileUpdateFrequency = p.getInt("autofetch.profiling.updatefrequency", profileUpdateFrequency);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties.PropertySource;
|
||||
|
||||
/**
|
||||
* Helper to read server specific properties from ebean.properties.
|
||||
*/
|
||||
class ConfigPropertyMap implements PropertySource {
|
||||
|
||||
private final String serverName;
|
||||
|
||||
public ConfigPropertyMap(String serverName) {
|
||||
this.serverName = serverName;
|
||||
}
|
||||
|
||||
public String getServerName() {
|
||||
return serverName;
|
||||
}
|
||||
|
||||
public String get(String key, String defaultValue) {
|
||||
String namedKey = "ebean." + serverName + "." + key;
|
||||
String inheritKey = "ebean." + key;
|
||||
String value = GlobalProperties.get(namedKey, null);
|
||||
if (value == null) {
|
||||
value = GlobalProperties.get(inheritKey, null);
|
||||
}
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public int getInt(String key, int defaultValue) {
|
||||
|
||||
String value = get(key, String.valueOf(defaultValue));
|
||||
return Integer.parseInt(value);
|
||||
}
|
||||
|
||||
public boolean getBoolean(String key, boolean defaultValue) {
|
||||
|
||||
String value = get(key, String.valueOf(defaultValue));
|
||||
return Boolean.parseBoolean(value);
|
||||
}
|
||||
|
||||
public <T extends Enum<T>> T getEnum(Class<T> enumType, String key, T defaultValue) {
|
||||
String level = get(key, defaultValue.name());
|
||||
return Enum.valueOf(enumType, level.toUpperCase());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,464 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Configuration for the container that holds the EbeanServer instances.
|
||||
* <p>
|
||||
* Provides configuration for cluster communication (if clustering is used). The cluster communication is
|
||||
* used to invalidate appropriate parts of the L2 cache across the cluster.
|
||||
*/
|
||||
public class ContainerConfig {
|
||||
|
||||
/**
|
||||
* Communication mode used for clustering.
|
||||
*/
|
||||
public enum ClusterMode {
|
||||
|
||||
/**
|
||||
* No clustering.
|
||||
*/
|
||||
NONE,
|
||||
|
||||
/**
|
||||
* Use Multicast networking for cluster wide communication.
|
||||
*/
|
||||
MULTICAST,
|
||||
|
||||
/**
|
||||
* Use TCP Sockets for cluster wide communication.
|
||||
*/
|
||||
SOCKET
|
||||
}
|
||||
|
||||
/**
|
||||
* The cluster mode to use.
|
||||
*/
|
||||
ClusterMode mode = ClusterMode.NONE;
|
||||
|
||||
/**
|
||||
* Configuration if using TCP sockets for clustering communication.
|
||||
*/
|
||||
SocketConfig socketConfig = new SocketConfig();
|
||||
|
||||
/**
|
||||
* Configuration if using Multicast for clustering communication.
|
||||
*/
|
||||
MulticastConfig multicastConfig = new MulticastConfig();
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// MulticastConfig
|
||||
|
||||
/**
|
||||
* The configuration for clustering using Multicast networking.
|
||||
*/
|
||||
public static class MulticastConfig {
|
||||
|
||||
int managerSleepMillis = 80;
|
||||
int lastSendTimeFreqSecs = 300;//5mins
|
||||
int lastStatusTimeFreqSecs = 600;//10mins
|
||||
int maxResendOutgoingAttempts = 200;
|
||||
int maxResendIncomingRequests = 50;
|
||||
|
||||
int listenPort;
|
||||
String listenAddress;
|
||||
int sendPort;
|
||||
String sendAddress;
|
||||
|
||||
// Note 1500 is Ethernet MTU and this must be less than UDP max packet size of 65507
|
||||
int maxSendPacketSize = 1500;
|
||||
|
||||
// Whether to send packets even when there are no other members online
|
||||
boolean sendWithNoMembers = true;
|
||||
|
||||
// When multiple instances are on same box you need to broadcast back locally
|
||||
boolean disableLoopback;
|
||||
int listenTimeToLive = -1;
|
||||
int listenTimeout = 1000;
|
||||
int listenBufferSize = 65500;
|
||||
// For multihomed environment the address the listener should bind to
|
||||
String listenBindAddress;
|
||||
|
||||
/**
|
||||
* Return the manager sleep millis.
|
||||
*/
|
||||
public int getManagerSleepMillis() {
|
||||
return managerSleepMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the manager sleep millis.
|
||||
*/
|
||||
public void setManagerSleepMillis(int managerSleepMillis) {
|
||||
this.managerSleepMillis = managerSleepMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last send time frequency.
|
||||
*/
|
||||
public int getLastSendTimeFreqSecs() {
|
||||
return lastSendTimeFreqSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the last send time frequency.
|
||||
*/
|
||||
public void setLastSendTimeFreqSecs(int lastSendTimeFreqSecs) {
|
||||
this.lastSendTimeFreqSecs = lastSendTimeFreqSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last status time frequency.
|
||||
*/
|
||||
public int getLastStatusTimeFreqSecs() {
|
||||
return lastStatusTimeFreqSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the last status time frequency.
|
||||
*/
|
||||
public void setLastStatusTimeFreqSecs(int lastStatusTimeFreqSecs) {
|
||||
this.lastStatusTimeFreqSecs = lastStatusTimeFreqSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum number of times we will try to re-send a given packet before giving up sending
|
||||
*/
|
||||
public int getMaxResendOutgoingAttempts() {
|
||||
return maxResendOutgoingAttempts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum retry attempts for outgoing messages.
|
||||
*/
|
||||
public void setMaxResendOutgoingAttempts(int maxResendOutgoingAttempts) {
|
||||
this.maxResendOutgoingAttempts = maxResendOutgoingAttempts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum number of times we will ask for a packet to be resent to us before giving up asking.
|
||||
*/
|
||||
public int getMaxResendIncomingRequests() {
|
||||
return maxResendIncomingRequests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum retry attempts for incoming messages.
|
||||
*/
|
||||
public void setMaxResendIncomingRequests(int maxResendIncomingRequests) {
|
||||
this.maxResendIncomingRequests = maxResendIncomingRequests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the listen port.
|
||||
*/
|
||||
public int getListenPort() {
|
||||
return listenPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the listen port.
|
||||
*/
|
||||
public void setListenPort(int port) {
|
||||
this.listenPort = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the listen address.
|
||||
*/
|
||||
public String getListenAddress() {
|
||||
return listenAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the listen address.
|
||||
*/
|
||||
public void setListenAddress(String listenAddress) {
|
||||
this.listenAddress = listenAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the send port.
|
||||
*/
|
||||
public int getSendPort() {
|
||||
return sendPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the send port.
|
||||
*/
|
||||
public void setSendPort(int sendPort) {
|
||||
this.sendPort = sendPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the send address.
|
||||
*/
|
||||
public String getSendAddress() {
|
||||
return sendAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the send address.
|
||||
*/
|
||||
public void setSendAddress(String sendAddress) {
|
||||
this.sendAddress = sendAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum send packet size.
|
||||
*/
|
||||
public int getMaxSendPacketSize() {
|
||||
return maxSendPacketSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum send packet size. Note 1500 is Ethernet MTU and this must be less than UDP max packet size of 65507.
|
||||
*/
|
||||
public void setMaxSendPacketSize(int maxSendPacketSize) {
|
||||
this.maxSendPacketSize = maxSendPacketSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if send messages when no other members in the cluster are up.
|
||||
*/
|
||||
public boolean isSendWithNoMembers() {
|
||||
return sendWithNoMembers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set true if send messages when no other members in the cluster are up.
|
||||
*/
|
||||
public void setSendWithNoMembers(boolean sendWithNoMembers) {
|
||||
this.sendWithNoMembers = sendWithNoMembers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if loopback is disabled. When multiple instances are on same box you need to broadcast back locally.
|
||||
*/
|
||||
public boolean isDisableLoopback() {
|
||||
return disableLoopback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if loopback is disabled. When multiple instances are on same box you need to broadcast back locally.
|
||||
*/
|
||||
public void setDisableLoopback(boolean disableLoopback) {
|
||||
this.disableLoopback = disableLoopback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the listen time to live.
|
||||
*/
|
||||
public int getListenTimeToLive() {
|
||||
return listenTimeToLive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the listen time to live.
|
||||
*/
|
||||
public void setListenTimeToLive(int listenTimeToLive) {
|
||||
this.listenTimeToLive = listenTimeToLive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the listen timeout.
|
||||
*/
|
||||
public int getListenTimeout() {
|
||||
return listenTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the listen timeout.
|
||||
*/
|
||||
public void setListenTimeout(int listenTimeout) {
|
||||
this.listenTimeout = listenTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the listen buffer size.
|
||||
*/
|
||||
public int getListenBufferSize() {
|
||||
return listenBufferSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the listen buffer size.
|
||||
*/
|
||||
public void setListenBufferSize(int listenBufferSize) {
|
||||
this.listenBufferSize = listenBufferSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the listener bind address (optional). For multihomed environment the address the listener should bind to.
|
||||
*/
|
||||
public String getListenBindAddress() {
|
||||
return listenBindAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the listener bind address (optional). For multihomed environment the address the listener should bind to.
|
||||
*/
|
||||
public void setListenBindAddress(String listenBindAddress) {
|
||||
this.listenBindAddress = listenBindAddress;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// SocketConfig
|
||||
|
||||
/**
|
||||
* Configuration for clustering using TCP sockets.
|
||||
* <p>
|
||||
* This is good for when there are relatively small number of cluster members.
|
||||
*/
|
||||
public static class SocketConfig {
|
||||
|
||||
/**
|
||||
* This local server in host:port format.
|
||||
*/
|
||||
String localHostPort;
|
||||
|
||||
/**
|
||||
* All the cluster members in host:port format.
|
||||
*/
|
||||
List<String> members = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* core threads for the associated thread pool.
|
||||
*/
|
||||
int coreThreads = 2;
|
||||
|
||||
/**
|
||||
* Max threads for the associated thread pool.
|
||||
*/
|
||||
int maxThreads = 16;
|
||||
|
||||
String threadPoolName = "EbeanCluster";
|
||||
|
||||
/**
|
||||
* Return the host and port for this server instance.
|
||||
*/
|
||||
public String getLocalHostPort() {
|
||||
return localHostPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the host and port for this server instance.
|
||||
*/
|
||||
public void setLocalHostPort(String localHostPort) {
|
||||
this.localHostPort = localHostPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the host and port for all the members of the cluster.
|
||||
*/
|
||||
public List<String> getMembers() {
|
||||
return members;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all the host and port for all the members of the cluster.
|
||||
*/
|
||||
public void setMembers(List<String> members) {
|
||||
this.members = members;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of core threads to use.
|
||||
*/
|
||||
public int getCoreThreads() {
|
||||
return coreThreads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of core threads to use.
|
||||
*/
|
||||
public void setCoreThreads(int coreThreads) {
|
||||
this.coreThreads = coreThreads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of max threads to use.
|
||||
*/
|
||||
public int getMaxThreads() {
|
||||
return maxThreads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of max threads to use.
|
||||
*/
|
||||
public void setMaxThreads(int maxThreads) {
|
||||
this.maxThreads = maxThreads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the thread pool name.
|
||||
*/
|
||||
public String getThreadPoolName() {
|
||||
return threadPoolName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the thread pool name.
|
||||
*/
|
||||
public void setThreadPoolName(String threadPoolName) {
|
||||
this.threadPoolName = threadPoolName;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// Members
|
||||
|
||||
/**
|
||||
* Load the settings from properties.
|
||||
*/
|
||||
public void loadFromProperties(Properties properties) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cluster mode.
|
||||
*/
|
||||
public ClusterMode getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cluster mode.
|
||||
*/
|
||||
public void setMode(ClusterMode mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the socket communication configuration.
|
||||
*/
|
||||
public SocketConfig getSocketConfig() {
|
||||
return socketConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the socket communication configuration.
|
||||
*/
|
||||
public void setSocketConfig(SocketConfig socketConfig) {
|
||||
this.socketConfig = socketConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the multicast communication configuration.
|
||||
*/
|
||||
public MulticastConfig getMulticastConfig() {
|
||||
return multicastConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the multicast communication configuration.
|
||||
*/
|
||||
public void setMulticastConfig(MulticastConfig multicastConfig) {
|
||||
this.multicastConfig = multicastConfig;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.avaje.ebean.config;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.util.StringHelper;
|
||||
@@ -448,48 +449,63 @@ public class DataSourceConfig {
|
||||
this.customProperties = customProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the settings by reading the ebean.properties file.
|
||||
*
|
||||
* @param serverName name of the server
|
||||
*/
|
||||
public void loadSettings(String serverName) {
|
||||
loadSettingsCustomPrefix("datasource." + serverName + ".", new GlobalProperties.DelegatedGlobalPropertySource(serverName));
|
||||
loadSettings(new PropertiesWrapper("datasource", serverName, PropertyMap.defaultProperties()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the settings from ebean.properties.
|
||||
* Load the settings from the properties supplied.
|
||||
* <p>
|
||||
* You can use this when you have your own properties to use for configuration.
|
||||
* </p>
|
||||
*
|
||||
* @param properties the properties to configure the datasource
|
||||
* @param serverName the name of the specific datasource (optional)
|
||||
*/
|
||||
public void loadSettingsCustomPrefix(String prefix, GlobalProperties.PropertySource properties) {
|
||||
public void loadSettings(Properties properties, String serverName) {
|
||||
PropertiesWrapper dbProps = new PropertiesWrapper("datasource", serverName, properties);
|
||||
loadSettings(dbProps);
|
||||
}
|
||||
|
||||
this.username = properties.get(prefix + "username", null);
|
||||
this.password = properties.get(prefix + "password", null);
|
||||
/**
|
||||
* Load the settings from the PropertiesWrapper.
|
||||
*/
|
||||
public void loadSettings(PropertiesWrapper properties) {
|
||||
|
||||
String dbDriver = properties.get(prefix + "databaseDriver", null);
|
||||
this.driver = properties.get(prefix + "driver", dbDriver);
|
||||
username = properties.get("username", username);
|
||||
password = properties.get("password", password);
|
||||
driver = properties.get("driver", properties.get("databaseDriver", driver));
|
||||
url = properties.get("url", properties.get("databaseUrl", url));
|
||||
|
||||
String dbUrl = properties.get(prefix + "databaseUrl", null);
|
||||
this.url = properties.get(prefix + "url", dbUrl);
|
||||
autoCommit = properties.getBoolean("autoCommit", autoCommit);
|
||||
captureStackTrace = properties.getBoolean("captureStackTrace", captureStackTrace);
|
||||
maxStackTraceSize = properties.getInt("maxStackTraceSize", maxStackTraceSize);
|
||||
leakTimeMinutes = properties.getInt("leakTimeMinutes", leakTimeMinutes);
|
||||
maxInactiveTimeSecs = properties.getInt("maxInactiveTimeSecs", maxInactiveTimeSecs);
|
||||
trimPoolFreqSecs = properties.getInt("trimPoolFreqSecs", trimPoolFreqSecs);
|
||||
maxAgeMinutes = properties.getInt("maxAgeMinutes", maxAgeMinutes);
|
||||
|
||||
this.autoCommit = properties.getBoolean(prefix + "autoCommit", false);
|
||||
this.captureStackTrace = properties.getBoolean(prefix + "captureStackTrace", false);
|
||||
this.maxStackTraceSize = properties.getInt(prefix + "maxStackTraceSize", 5);
|
||||
this.leakTimeMinutes = properties.getInt(prefix + "leakTimeMinutes", 30);
|
||||
this.maxInactiveTimeSecs = properties.getInt(prefix + "maxInactiveTimeSecs", 720);
|
||||
this.trimPoolFreqSecs = properties.getInt(prefix + "trimPoolFreqSecs", 59);
|
||||
this.maxAgeMinutes = properties.getInt(prefix + "maxAgeMinutes", 0);
|
||||
minConnections = properties.getInt("minConnections", minConnections);
|
||||
maxConnections = properties.getInt("maxConnections", maxConnections);
|
||||
pstmtCacheSize = properties.getInt("pstmtCacheSize", pstmtCacheSize);
|
||||
cstmtCacheSize = properties.getInt("cstmtCacheSize", cstmtCacheSize);
|
||||
|
||||
this.minConnections = properties.getInt(prefix + "minConnections", 0);
|
||||
this.maxConnections = properties.getInt(prefix + "maxConnections", 20);
|
||||
this.pstmtCacheSize = properties.getInt(prefix + "pstmtCacheSize", 20);
|
||||
this.cstmtCacheSize = properties.getInt(prefix + "cstmtCacheSize", 20);
|
||||
waitTimeoutMillis = properties.getInt("waitTimeout", waitTimeoutMillis);
|
||||
|
||||
this.waitTimeoutMillis = properties.getInt(prefix + "waitTimeout", 1000);
|
||||
heartbeatSql = properties.get("heartbeatSql", heartbeatSql);
|
||||
heartbeatTimeoutSeconds = properties.getInt("heartbeatTimeoutSeconds", heartbeatTimeoutSeconds);
|
||||
poolListener = properties.get("poolListener", poolListener);
|
||||
offline = properties.getBoolean("offline", offline);
|
||||
|
||||
this.heartbeatSql = properties.get(prefix + "heartbeatSql", null);
|
||||
this.heartbeatTimeoutSeconds = properties.getInt(prefix + "heartbeatTimeoutSeconds", 3);
|
||||
this.poolListener = properties.get(prefix + "poolListener", null);
|
||||
this.offline = properties.getBoolean(prefix + "offline", false);
|
||||
|
||||
String isoLevel = properties.get(prefix + "isolationlevel", "READ_COMMITTED");
|
||||
String isoLevel = properties.get("isolationlevel", getTransactionIsolationLevel(isolationLevel));
|
||||
this.isolationLevel = getTransactionIsolationLevel(isoLevel);
|
||||
|
||||
String customProperties = properties.get(prefix + "customProperties", null);
|
||||
String customProperties = properties.get("customProperties", null);
|
||||
if (customProperties != null && customProperties.length() > 0) {
|
||||
Map<String, String> custProps = StringHelper.delimitedToMap(customProperties, ";", "=");
|
||||
this.customProperties = custProps;
|
||||
@@ -498,7 +514,21 @@ public class DataSourceConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* return the isolation level for a given string description.
|
||||
* Return the isolation level description from the associated Connection int value.
|
||||
*/
|
||||
public String getTransactionIsolationLevel(int level) {
|
||||
switch (level) {
|
||||
case Connection.TRANSACTION_NONE : return "NONE";
|
||||
case Connection.TRANSACTION_READ_COMMITTED : return "READ_COMMITTED";
|
||||
case Connection.TRANSACTION_READ_UNCOMMITTED : return "READ_UNCOMMITTED";
|
||||
case Connection.TRANSACTION_REPEATABLE_READ : return "REPEATABLE_READ";
|
||||
case Connection.TRANSACTION_SERIALIZABLE : return "SERIALIZABLE";
|
||||
default: throw new RuntimeException("Transaction Isolation level [" + level + "] is not known.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the isolation level for a given string description.
|
||||
*/
|
||||
public int getTransactionIsolationLevel(String level) {
|
||||
level = level.toUpperCase();
|
||||
@@ -522,6 +552,6 @@ public class DataSourceConfig {
|
||||
return Connection.TRANSACTION_SERIALIZABLE;
|
||||
}
|
||||
|
||||
throw new RuntimeException("Transaction Isolaction level [" + level + "] is not known.");
|
||||
throw new RuntimeException("Transaction Isolation level [" + level + "] is not known.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,211 +0,0 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import com.avaje.ebean.util.ClassUtil;
|
||||
|
||||
/**
|
||||
* Provides access to properties loaded from the ebean.properties file.
|
||||
*/
|
||||
public final class GlobalProperties {
|
||||
|
||||
private static volatile PropertyMap globalMap;
|
||||
|
||||
private static boolean skipPrimaryServer;
|
||||
|
||||
/**
|
||||
* Set whether to skip automatically creating the primary server.
|
||||
*/
|
||||
public static synchronized void setSkipPrimaryServer(boolean skip) {
|
||||
skipPrimaryServer = skip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true to skip automatically creating the primary server.
|
||||
*/
|
||||
public static synchronized boolean isSkipPrimaryServer() {
|
||||
return skipPrimaryServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the string replacing any expressions like ${catalina.base}.
|
||||
* <p>
|
||||
* This will evaluate expressions using first environment variables, than java
|
||||
* system variables and lastly properties in ebean.properties - in that order.
|
||||
* </p>
|
||||
* <p>
|
||||
* Expressions start with "${" and end with "}".
|
||||
* </p>
|
||||
*/
|
||||
public static String evaluateExpressions(String val) {
|
||||
return getPropertyMap().eval(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and evaluate any expressions that have not already been evaluated.
|
||||
*/
|
||||
public static synchronized void evaluateExpressions() {
|
||||
getPropertyMap().evaluateProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* In a servlet container environment this will additionally look in WEB-INF
|
||||
* for the ebean.properties file.
|
||||
*/
|
||||
public static synchronized void setServletContext(ServletContext servletContext) {
|
||||
|
||||
PropertyMapLoader.setServletContext(servletContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ServletContext (if setup in a servlet container environment).
|
||||
*/
|
||||
public static synchronized ServletContext getServletContext() {
|
||||
|
||||
return PropertyMapLoader.getServletContext();
|
||||
}
|
||||
|
||||
private static void initPropertyMap() {
|
||||
|
||||
String fileName = System.getenv("EBEAN_PROPS_FILE");
|
||||
if (fileName == null) {
|
||||
fileName = System.getProperty("ebean.props.file");
|
||||
if (fileName == null) {
|
||||
fileName = "ebean.properties";
|
||||
}
|
||||
}
|
||||
|
||||
globalMap = PropertyMapLoader.load(null, fileName);
|
||||
if (globalMap == null) {
|
||||
// ebean.properties file was not found... but that
|
||||
// is ok because we are likely doing programmatic config
|
||||
globalMap = new PropertyMap();
|
||||
}
|
||||
|
||||
String loaderCn = globalMap.get("ebean.properties.loader");
|
||||
if (loaderCn != null) {
|
||||
// a Runnable that can be used to customise the initialisation
|
||||
// of the GlobalProperties
|
||||
try {
|
||||
Runnable r = (Runnable) ClassUtil.newInstance(loaderCn);
|
||||
r.run();
|
||||
} catch (Exception e) {
|
||||
String m = "Error creating or running properties loader " + loaderCn;
|
||||
throw new RuntimeException(m, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property map loading it if required.
|
||||
*/
|
||||
private static synchronized PropertyMap getPropertyMap() {
|
||||
|
||||
if (globalMap == null) {
|
||||
initPropertyMap();
|
||||
}
|
||||
|
||||
return globalMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a String property with a default value.
|
||||
*/
|
||||
public static synchronized String get(String key, String defaultValue) {
|
||||
return getPropertyMap().get(key, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a int property with a default value.
|
||||
*/
|
||||
public static synchronized int getInt(String key, int defaultValue) {
|
||||
return getPropertyMap().getInt(key, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a boolean property with a default value.
|
||||
*/
|
||||
public static synchronized boolean getBoolean(String key, boolean defaultValue) {
|
||||
return getPropertyMap().getBoolean(key, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a property return the previous value. This will evaluate any
|
||||
* expressions in the value.
|
||||
*/
|
||||
public static synchronized String put(String key, String value) {
|
||||
return getPropertyMap().putEval(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a Map of key value properties.
|
||||
*/
|
||||
public static synchronized void putAll(Map<String, String> keyValueMap) {
|
||||
for (Entry<String, String> e : keyValueMap.entrySet()) {
|
||||
getPropertyMap().putEval(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
public static PropertySource getPropertySource(String name) {
|
||||
return new ConfigPropertyMap(name);
|
||||
}
|
||||
|
||||
public static interface PropertySource {
|
||||
|
||||
/**
|
||||
* Return the name of the server. This is also the dataSource name.
|
||||
*/
|
||||
public String getServerName();
|
||||
|
||||
/**
|
||||
* Get a property. This will prepend "ebean" and the server name to lookup
|
||||
* the value.
|
||||
*/
|
||||
public String get(String key, String defaultValue);
|
||||
|
||||
public int getInt(String key, int defaultValue);
|
||||
|
||||
public boolean getBoolean(String key, boolean defaultValue);
|
||||
|
||||
public <T extends Enum<T>> T getEnum(Class<T> enumType, String key, T defaultValue);
|
||||
|
||||
}
|
||||
|
||||
public static class DelegatedGlobalPropertySource implements PropertySource {
|
||||
|
||||
private String serverName;
|
||||
|
||||
public DelegatedGlobalPropertySource(String serverName) {
|
||||
this.serverName = serverName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerName() {
|
||||
return serverName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String key, String defaultValue) {
|
||||
return GlobalProperties.get(key, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(String key, int defaultValue) {
|
||||
return GlobalProperties.getInt(key, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean(String key, boolean defaultValue) {
|
||||
return GlobalProperties.getBoolean(key, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Enum<T>> T getEnum(Class<T> enumType, String key, T defaultValue) {
|
||||
String level = get(key, defaultValue.name());
|
||||
return Enum.valueOf(enumType, level.toUpperCase());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Configuration for JSON features.
|
||||
*/
|
||||
public abstract class JsonConfig {
|
||||
|
||||
/**
|
||||
* Defined the format used for DateTime types.
|
||||
*/
|
||||
public enum DateTime {
|
||||
|
||||
/**
|
||||
* Format as epoch millis.
|
||||
*/
|
||||
MILLIS,
|
||||
|
||||
/**
|
||||
* Format as epoch with nanos.
|
||||
*/
|
||||
NANOS,
|
||||
|
||||
/**
|
||||
* Format as ISO-8601 date format.
|
||||
*/
|
||||
ISO8601
|
||||
}
|
||||
|
||||
}
|
||||
@@ -112,4 +112,9 @@ public interface NamingConvention {
|
||||
*/
|
||||
public boolean isUseForeignKeyPrefix();
|
||||
|
||||
/**
|
||||
* Load setting from properties.
|
||||
*/
|
||||
public void loadFromProperties(PropertiesWrapper properties);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
public class PropertiesWrapper {
|
||||
|
||||
protected final Properties properties;
|
||||
|
||||
protected final String prefix;
|
||||
|
||||
protected final String serverName;
|
||||
|
||||
protected final PropertyMap propertyMap;
|
||||
|
||||
/**
|
||||
* Construct with a prefix, serverName and properties.
|
||||
*/
|
||||
public PropertiesWrapper(String prefix, String serverName, Properties properties) {
|
||||
this.serverName = serverName;
|
||||
this.prefix = prefix;
|
||||
this.propertyMap = PropertyMapLoader.load(null, properties);
|
||||
this.properties = propertyMap.asProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct without prefix of serverName.
|
||||
*/
|
||||
public PropertiesWrapper(Properties properties) {
|
||||
this(null, null, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal copy constructor when changing prefix.
|
||||
*/
|
||||
protected PropertiesWrapper(String prefix, String serverName, PropertyMap propertyMap, Properties properties) {
|
||||
this.serverName = serverName;
|
||||
this.prefix = prefix;
|
||||
this.propertyMap = propertyMap;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a PropertiesWrapper instance with a different prefix but same underlying properties.
|
||||
* <p/>
|
||||
* Used when wanting to use "datasource" as the prefix rather than "ebean".
|
||||
* <p/>
|
||||
* The returning instance should only be used in a read only fashion.
|
||||
*/
|
||||
public PropertiesWrapper withPrefix(String prefix) {
|
||||
return new PropertiesWrapper(prefix, serverName, propertyMap, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the serverName (optional).
|
||||
*/
|
||||
public String getServerName() {
|
||||
return serverName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return as Properties with lower case keys and after evaluation and additional properties loading has occurred.
|
||||
* <p>
|
||||
* Ebean has historically ignored the case of keys hence returning the Properties with all the keys lower cased.
|
||||
* </p>
|
||||
*/
|
||||
public Properties asPropertiesLowerCase() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a property with no default value.
|
||||
*/
|
||||
public String get(String key) {
|
||||
return get(key, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a property with a default value.
|
||||
* <p>
|
||||
* This performs a search using the prefix and server name (if supplied) to search for the property
|
||||
* value in order based on:
|
||||
* <pre>{@code
|
||||
* prefix.serverName.key
|
||||
* prefix.key
|
||||
* key
|
||||
* }</pre>
|
||||
* </p>
|
||||
*/
|
||||
public String get(String key, String defaultValue) {
|
||||
|
||||
String value = null;
|
||||
if (serverName != null && prefix != null) {
|
||||
value = propertyMap.get(prefix + "." + serverName + "." + key, null);
|
||||
}
|
||||
if (value == null && prefix != null) {
|
||||
value = propertyMap.get(prefix + "." + key, null);
|
||||
}
|
||||
if (value == null) {
|
||||
value = propertyMap.get(key, null);
|
||||
}
|
||||
return value == null ? defaultValue : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a double property value.
|
||||
*/
|
||||
public double getDouble(String key, double defaultValue) {
|
||||
|
||||
String value = get(key, String.valueOf(defaultValue));
|
||||
return Double.parseDouble(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an int property value.
|
||||
*/
|
||||
public int getInt(String key, int defaultValue) {
|
||||
|
||||
String value = get(key, String.valueOf(defaultValue));
|
||||
return Integer.parseInt(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a long property value.
|
||||
*/
|
||||
public long getLong(String key, long defaultValue) {
|
||||
|
||||
String value = get(key, String.valueOf(defaultValue));
|
||||
return Long.parseLong(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a boolean property value.
|
||||
*/
|
||||
public boolean getBoolean(String key, boolean defaultValue) {
|
||||
|
||||
String value = get(key, String.valueOf(defaultValue));
|
||||
return Boolean.parseBoolean(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Enum property value.
|
||||
*/
|
||||
public <T extends Enum<T>> T getEnum(Class<T> enumType, String key, T defaultValue) {
|
||||
String level = get(key, defaultValue.name());
|
||||
return Enum.valueOf(enumType, level.toUpperCase());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,21 +4,40 @@ import java.io.Serializable;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A map like structure of properties.
|
||||
* <p/>
|
||||
* Handles evaluation of expressions like ${home} and provides convenience methods for int, long and boolean.
|
||||
*/
|
||||
final class PropertyMap implements Serializable {
|
||||
public final class PropertyMap implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
|
||||
|
||||
public static Properties defaultProperties() {
|
||||
PropertyMap propertyMap = PropertyMapLoader.loadGlobalProperties();
|
||||
return (propertyMap == null) ? new Properties() : propertyMap.asProperties();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return map.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return as standard Properties.
|
||||
*/
|
||||
public Properties asProperties() {
|
||||
Properties properties = new Properties();
|
||||
for (Entry<String, String> e : entrySet()) {
|
||||
properties.put(e.getKey(), e.getValue());
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Go through all the properties and evaluate any expressions that have not
|
||||
* been resolved.
|
||||
@@ -35,10 +54,16 @@ final class PropertyMap implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value with expressions like ${home} evaluated using system properties and environment variables.
|
||||
*/
|
||||
public synchronized String eval(String val) {
|
||||
return PropertyExpression.eval(val, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the boolean property value with a given default.
|
||||
*/
|
||||
public synchronized boolean getBoolean(String key, boolean defaultValue) {
|
||||
String value = get(key);
|
||||
if (value == null) {
|
||||
@@ -48,6 +73,9 @@ final class PropertyMap implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the int property value with a given default.
|
||||
*/
|
||||
public synchronized int getInt(String key, int defaultValue) {
|
||||
String value = get(key);
|
||||
if (value == null) {
|
||||
@@ -57,36 +85,69 @@ final class PropertyMap implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the long property value with a given default.
|
||||
*/
|
||||
public synchronized long getLong(String key, long defaultValue) {
|
||||
String value = get(key);
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
} else {
|
||||
return Long.parseLong(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the string property value with a given default.
|
||||
*/
|
||||
public synchronized String get(String key, String defaultValue) {
|
||||
String value = map.get(key.toLowerCase());
|
||||
return value == null ? defaultValue : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property value returning null if there is no value defined.
|
||||
*/
|
||||
public synchronized String get(String key) {
|
||||
return map.get(key.toLowerCase());
|
||||
}
|
||||
|
||||
synchronized void putAll(Map<String, String> keyValueMap) {
|
||||
/**
|
||||
* Put all evaluating any expressions in the values.
|
||||
*/
|
||||
public synchronized void putEvalAll(Map<String, String> keyValueMap) {
|
||||
|
||||
for (Map.Entry<String, String> entry : keyValueMap.entrySet()) {
|
||||
put(entry.getKey(), entry.getValue());
|
||||
putEval(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
synchronized String putEval(String key, String value) {
|
||||
/**
|
||||
* Put a single key value evaluating any expressions in the value.
|
||||
*/
|
||||
public synchronized String putEval(String key, String value) {
|
||||
value = PropertyExpression.eval(value, this);
|
||||
return map.put(key.toLowerCase(), value);
|
||||
}
|
||||
|
||||
synchronized String put(String key, String value) {
|
||||
/**
|
||||
* Put a single key value with no expression evaluation.
|
||||
*/
|
||||
public synchronized String put(String key, String value) {
|
||||
return map.put(key.toLowerCase(), value);
|
||||
}
|
||||
|
||||
synchronized String remove(String key) {
|
||||
/**
|
||||
* Remove an entry.
|
||||
*/
|
||||
public synchronized String remove(String key) {
|
||||
return map.remove(key.toLowerCase());
|
||||
}
|
||||
|
||||
synchronized Set<Entry<String, String>> entrySet() {
|
||||
/**
|
||||
* Return the entries.
|
||||
*/
|
||||
public synchronized Set<Entry<String, String>> entrySet() {
|
||||
return map.entrySet();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,40 +1,30 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Helper used to load the PropertyMap.
|
||||
* Helper used to load the ebean.properties into a PropertyMap.
|
||||
*/
|
||||
final class PropertyMapLoader {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PropertyMapLoader.class);
|
||||
|
||||
private static ServletContext servletContext;
|
||||
public static PropertyMap loadGlobalProperties() {
|
||||
|
||||
/**
|
||||
* Return the servlet context when in a web environment.
|
||||
*/
|
||||
public static ServletContext getServletContext() {
|
||||
return servletContext;
|
||||
}
|
||||
String fileName = System.getenv("EBEAN_PROPS_FILE");
|
||||
if (fileName == null) {
|
||||
fileName = System.getProperty("ebean.props.file");
|
||||
if (fileName == null) {
|
||||
fileName = "ebean.properties";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ServletContext for when ebean.properties is in WEB-INF in a web
|
||||
* application environment.
|
||||
*/
|
||||
public static void setServletContext(ServletContext servletContext) {
|
||||
PropertyMapLoader.servletContext = servletContext;
|
||||
return load(null, fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,15 +54,20 @@ final class PropertyMapLoader {
|
||||
* @param in
|
||||
* the InputStream of the properties file to load.
|
||||
*/
|
||||
private static PropertyMap load(PropertyMap p, InputStream in) {
|
||||
public static PropertyMap load(PropertyMap p, InputStream in) {
|
||||
|
||||
Properties props = new Properties();
|
||||
try {
|
||||
props.load(in);
|
||||
in.close();
|
||||
return load(p, props);
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static PropertyMap load(PropertyMap p, Properties props) {
|
||||
|
||||
if (p == null) {
|
||||
p = new PropertyMap();
|
||||
@@ -117,18 +112,6 @@ final class PropertyMapLoader {
|
||||
throw new NullPointerException("fileName is null?");
|
||||
}
|
||||
|
||||
if (servletContext == null) {
|
||||
logger.debug("No servletContext so not looking in WEB-INF for " + fileName);
|
||||
|
||||
} else {
|
||||
// first look in WEB-INF ...
|
||||
InputStream in = servletContext.getResourceAsStream("/WEB-INF/" + fileName);
|
||||
if (in != null) {
|
||||
logger.debug(fileName + " found in WEB-INF");
|
||||
return in;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
File f = new File(fileName);
|
||||
|
||||
|
||||
@@ -1,27 +1,22 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.avaje.ebean.EbeanServerFactory;
|
||||
import com.avaje.ebean.PersistenceContextScope;
|
||||
import com.avaje.ebean.annotation.Encrypted;
|
||||
import com.avaje.ebean.cache.ServerCacheFactory;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.GlobalProperties.PropertySource;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.config.dbplatform.DbEncrypt;
|
||||
import com.avaje.ebean.event.BeanPersistController;
|
||||
import com.avaje.ebean.event.BeanPersistListener;
|
||||
import com.avaje.ebean.event.BeanQueryAdapter;
|
||||
import com.avaje.ebean.event.BulkTableEventListener;
|
||||
import com.avaje.ebean.event.ServerConfigStartup;
|
||||
import com.avaje.ebean.event.TransactionEventListener;
|
||||
import com.avaje.ebean.event.*;
|
||||
import com.avaje.ebean.meta.MetaInfoManager;
|
||||
import com.avaje.ebean.util.ClassUtil;
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* The configuration used for creating a EbeanServer.
|
||||
* <p>
|
||||
@@ -35,9 +30,9 @@ import com.fasterxml.jackson.core.JsonFactory;
|
||||
* classes and listeners etc.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
* ServerConfig c = new ServerConfig();
|
||||
* c.setName("ordh2");
|
||||
* c.setName("ordh2");
|
||||
*
|
||||
* // read the ebean.properties and load
|
||||
* // those settings into this serverConfig object
|
||||
@@ -48,18 +43,18 @@ import com.fasterxml.jackson.core.JsonFactory;
|
||||
* c.setDdlRun(true);
|
||||
*
|
||||
* // add any classes found in the app.data package
|
||||
* c.addPackage("app.data");
|
||||
* c.addPackage("app.data");
|
||||
*
|
||||
* // add the names of Jars that contain entities
|
||||
* c.addJar("myJarContainingEntities.jar");
|
||||
* c.addJar("someOtherJarContainingEntities.jar");
|
||||
* c.addJar("myJarContainingEntities.jar");
|
||||
* c.addJar("someOtherJarContainingEntities.jar");
|
||||
*
|
||||
* // register as the 'Default' server
|
||||
* c.setDefaultServer(true);
|
||||
*
|
||||
* EbeanServer server = EbeanServerFactory.create(c);
|
||||
*
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* @see EbeanServerFactory
|
||||
*
|
||||
@@ -67,27 +62,19 @@ import com.fasterxml.jackson.core.JsonFactory;
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class ServerConfig {
|
||||
|
||||
/**
|
||||
* The Constant DEFAULT_QUERY_BATCH_SIZE. Default: 100
|
||||
*/
|
||||
private final static int DEFAULT_QUERY_BATCH_SIZE = 100;
|
||||
|
||||
/**
|
||||
* The EbeanServer name.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
private ContainerConfig containerConfig;
|
||||
|
||||
/**
|
||||
* The resource directory.
|
||||
*/
|
||||
private String resourceDirectory;
|
||||
|
||||
/**
|
||||
* The enhance log level. Used with subclass generation.
|
||||
*/
|
||||
private int enhanceLogLevel;
|
||||
|
||||
/**
|
||||
* Set to true to register this EbeanServer with the Ebean singleton.
|
||||
*/
|
||||
@@ -116,11 +103,21 @@ public class ServerConfig {
|
||||
*/
|
||||
private List<String> searchJars = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* Class name of a classPathReader implementation.
|
||||
*/
|
||||
private String classPathReaderClassName;
|
||||
|
||||
/**
|
||||
* Config controlling the autofetch behaviour.
|
||||
*/
|
||||
private AutofetchConfig autofetchConfig = new AutofetchConfig();
|
||||
|
||||
/**
|
||||
* The JSON format used for DateTime types. Default to millis.
|
||||
*/
|
||||
private JsonConfig.DateTime jsonDateTime = JsonConfig.DateTime.MILLIS;
|
||||
|
||||
/**
|
||||
* The database platform name. Used to imply a DatabasePlatform to use.
|
||||
*/
|
||||
@@ -143,12 +140,14 @@ public class ServerConfig {
|
||||
/**
|
||||
* The default batch size for lazy loading
|
||||
*/
|
||||
private int lazyLoadBatchSize = 1;
|
||||
private int lazyLoadBatchSize = 10;
|
||||
|
||||
/**
|
||||
* The query batch size.
|
||||
* The default batch size for 'query joins'.
|
||||
*/
|
||||
private int queryBatchSize = -1;
|
||||
private int queryBatchSize = 100;
|
||||
|
||||
private boolean eagerFetchLobs;
|
||||
|
||||
private boolean ddlGenerate;
|
||||
|
||||
@@ -201,7 +200,7 @@ public class ServerConfig {
|
||||
/**
|
||||
* The naming convention.
|
||||
*/
|
||||
private NamingConvention namingConvention;
|
||||
private NamingConvention namingConvention = new UnderscoreNamingConvention();
|
||||
|
||||
/**
|
||||
* Behaviour of update to include on the change properties.
|
||||
@@ -217,10 +216,10 @@ public class ServerConfig {
|
||||
* Setting to indicate if UUID should be stored as binary(16) or varchar(40).
|
||||
*/
|
||||
private boolean uuidStoreAsBinary;
|
||||
|
||||
|
||||
|
||||
private List<BeanPersistController> persistControllers = new ArrayList<BeanPersistController>();
|
||||
private List<BeanPersistListener<?>> persistListeners = new ArrayList<BeanPersistListener<?>>();
|
||||
private List<BeanPersistListener> persistListeners = new ArrayList<BeanPersistListener>();
|
||||
private List<BeanQueryAdapter> queryAdapters = new ArrayList<BeanQueryAdapter>();
|
||||
private List<BulkTableEventListener> bulkTableEventListeners = new ArrayList<BulkTableEventListener>();
|
||||
private List<ServerConfigStartup> configStartupListeners = new ArrayList<ServerConfigStartup>();
|
||||
@@ -238,15 +237,50 @@ public class ServerConfig {
|
||||
|
||||
private ServerCacheManager serverCacheManager;
|
||||
|
||||
private boolean collectQueryStatsByNode;
|
||||
private boolean collectQueryStatsByNode = true;
|
||||
|
||||
private boolean collectQueryOrigins;
|
||||
|
||||
private JsonFactory jsonFactory;
|
||||
private boolean collectQueryOrigins = true;
|
||||
|
||||
/**
|
||||
* Construct a Server Configuration for programmatically creating an
|
||||
* EbeanServer.
|
||||
* The default PersistenceContextScope used if one is not explicitly set on a query.
|
||||
*/
|
||||
private PersistenceContextScope persistenceContextScope = PersistenceContextScope.TRANSACTION;
|
||||
|
||||
private JsonFactory jsonFactory;
|
||||
|
||||
private boolean localTimeWithNanos;
|
||||
|
||||
private boolean durationWithNanos;
|
||||
|
||||
private int maxCallStack = 5;
|
||||
|
||||
private boolean transactionRollbackOnChecked = true;
|
||||
|
||||
private boolean registerJmxMBeans = true;
|
||||
|
||||
// configuration for the background executor service (thread pool)
|
||||
|
||||
private int backgroundExecutorSchedulePoolSize = 1;
|
||||
private int backgroundExecutorCorePoolSize = 1;
|
||||
private int backgroundExecutorMaxPoolSize = 8;
|
||||
private int backgroundExecutorIdleSecs = 60;
|
||||
private int backgroundExecutorShutdownSecs = 30;
|
||||
|
||||
// defaults for the L2 bean caching
|
||||
|
||||
private int cacheWarmingDelay = 30;
|
||||
private int cacheMaxSize = 10000;
|
||||
private int cacheMaxIdleTime = 600;
|
||||
private int cacheMaxTimeToLive = 60*60*6;
|
||||
|
||||
// defaults for the L2 query caching
|
||||
|
||||
private int queryCacheMaxSize = 1000;
|
||||
private int queryCacheMaxIdleTime = 600;
|
||||
private int queryCacheMaxTimeToLive = 60*60*6;
|
||||
|
||||
/**
|
||||
* Construct a Server Configuration for programmatically creating an EbeanServer.
|
||||
*/
|
||||
public ServerConfig() {
|
||||
|
||||
@@ -270,6 +304,20 @@ public class ServerConfig {
|
||||
this.jsonFactory = jsonFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JSON format used for DateTime types.
|
||||
*/
|
||||
public JsonConfig.DateTime getJsonDateTime() {
|
||||
return jsonDateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JSON format to use for DateTime types.
|
||||
*/
|
||||
public void setJsonDateTime(JsonConfig.DateTime jsonDateTime) {
|
||||
this.jsonDateTime = jsonDateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the EbeanServer.
|
||||
*/
|
||||
@@ -284,6 +332,26 @@ public class ServerConfig {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the container / clustering configuration.
|
||||
* <p/>
|
||||
* The container holds all the EbeanServer instances and provides clustering communication
|
||||
* services to all the EbeanServer instances.
|
||||
*/
|
||||
public ContainerConfig getContainerConfig() {
|
||||
return containerConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the container / clustering configuration.
|
||||
* <p/>
|
||||
* The container holds all the EbeanServer instances and provides clustering communication
|
||||
* services to all the EbeanServer instances.
|
||||
*/
|
||||
public void setContainerConfig(ContainerConfig containerConfig) {
|
||||
this.containerConfig = containerConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this server should be registered with the Ebean singleton
|
||||
* when it is created.
|
||||
@@ -340,15 +408,6 @@ public class ServerConfig {
|
||||
return persistBatching;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use isPersistBatching() instead.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public boolean isUsePersistBatching() {
|
||||
return persistBatching;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if you what to use JDBC batching for persisting and deleting
|
||||
* beans.
|
||||
@@ -497,17 +556,231 @@ public class ServerConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the log level used for "subclassing" enhancement.
|
||||
* Return true if LOB's should default to fetch eager.
|
||||
* By default this is set to false and LOB's must be explicitly fetched.
|
||||
*/
|
||||
public int getEnhanceLogLevel() {
|
||||
return enhanceLogLevel;
|
||||
public boolean isEagerFetchLobs() {
|
||||
return eagerFetchLobs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the log level used for "subclassing" enhancement.
|
||||
* Set to true if you want LOB's to be fetch eager by default.
|
||||
* By default this is set to false and LOB's must be explicitly fetched.
|
||||
*/
|
||||
public void setEnhanceLogLevel(int enhanceLogLevel) {
|
||||
this.enhanceLogLevel = enhanceLogLevel;
|
||||
public void setEagerFetchLobs(boolean eagerFetchLobs) {
|
||||
this.eagerFetchLobs = eagerFetchLobs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the max call stack to use for origin location.
|
||||
*/
|
||||
public int getMaxCallStack() {
|
||||
return maxCallStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the max call stack to use for origin location.
|
||||
*/
|
||||
public void setMaxCallStack(int maxCallStack) {
|
||||
this.maxCallStack = maxCallStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if transactions should rollback on checked exceptions.
|
||||
*/
|
||||
public boolean isTransactionRollbackOnChecked() {
|
||||
return transactionRollbackOnChecked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if transactions should by default rollback on checked exceptions.
|
||||
*/
|
||||
public void setTransactionRollbackOnChecked(boolean transactionRollbackOnChecked) {
|
||||
this.transactionRollbackOnChecked = transactionRollbackOnChecked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the server should register JMX MBeans.
|
||||
*/
|
||||
public boolean isRegisterJmxMBeans() {
|
||||
return registerJmxMBeans;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if the server should register JMX MBeans.
|
||||
*/
|
||||
public void setRegisterJmxMBeans(boolean registerJmxMBeans) {
|
||||
this.registerJmxMBeans = registerJmxMBeans;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Background executor schedule pool size. Defaults to 1.
|
||||
*/
|
||||
public int getBackgroundExecutorSchedulePoolSize() {
|
||||
return backgroundExecutorSchedulePoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Background executor schedule pool size.
|
||||
*/
|
||||
public void setBackgroundExecutorSchedulePoolSize(int backgroundExecutorSchedulePoolSize) {
|
||||
this.backgroundExecutorSchedulePoolSize = backgroundExecutorSchedulePoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Background executor core pool size.
|
||||
*/
|
||||
public int getBackgroundExecutorCorePoolSize() {
|
||||
return backgroundExecutorCorePoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Background executor core pool size.
|
||||
*/
|
||||
public void setBackgroundExecutorCorePoolSize(int backgroundExecutorCorePoolSize) {
|
||||
this.backgroundExecutorCorePoolSize = backgroundExecutorCorePoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Background executor max pool size.
|
||||
*/
|
||||
public int getBackgroundExecutorMaxPoolSize() {
|
||||
return backgroundExecutorMaxPoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Background executor max pool size.
|
||||
*/
|
||||
public void setBackgroundExecutorMaxPoolSize(int backgroundExecutorMaxPoolSize) {
|
||||
this.backgroundExecutorMaxPoolSize = backgroundExecutorMaxPoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Background executor idle seconds.
|
||||
*/
|
||||
public int getBackgroundExecutorIdleSecs() {
|
||||
return backgroundExecutorIdleSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Background executor idle seconds.
|
||||
*/
|
||||
public void setBackgroundExecutorIdleSecs(int backgroundExecutorIdleSecs) {
|
||||
this.backgroundExecutorIdleSecs = backgroundExecutorIdleSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Background executor shutdown seconds. This is the time allowed for the pool to shutdown nicely
|
||||
* before it is forced shutdown.
|
||||
*/
|
||||
public int getBackgroundExecutorShutdownSecs() {
|
||||
return backgroundExecutorShutdownSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Background executor shutdown seconds. This is the time allowed for the pool to shutdown nicely
|
||||
* before it is forced shutdown.
|
||||
*/
|
||||
public void setBackgroundExecutorShutdownSecs(int backgroundExecutorShutdownSecs) {
|
||||
this.backgroundExecutorShutdownSecs = backgroundExecutorShutdownSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cache warming delay in seconds.
|
||||
*/
|
||||
public int getCacheWarmingDelay() {
|
||||
return cacheWarmingDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cache warming delay in seconds.
|
||||
*/
|
||||
public void setCacheWarmingDelay(int cacheWarmingDelay) {
|
||||
this.cacheWarmingDelay = cacheWarmingDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the L2 cache default max size.
|
||||
*/
|
||||
public int getCacheMaxSize() {
|
||||
return cacheMaxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the L2 cache default max size.
|
||||
*/
|
||||
public void setCacheMaxSize(int cacheMaxSize) {
|
||||
this.cacheMaxSize = cacheMaxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the L2 cache default max idle time in seconds.
|
||||
*/
|
||||
public int getCacheMaxIdleTime() {
|
||||
return cacheMaxIdleTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the L2 cache default max idle time in seconds.
|
||||
*/
|
||||
public void setCacheMaxIdleTime(int cacheMaxIdleTime) {
|
||||
this.cacheMaxIdleTime = cacheMaxIdleTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the L2 cache default max time to live in seconds.
|
||||
*/
|
||||
public int getCacheMaxTimeToLive() {
|
||||
return cacheMaxTimeToLive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the L2 cache default max time to live in seconds.
|
||||
*/
|
||||
public void setCacheMaxTimeToLive(int cacheMaxTimeToLive) {
|
||||
this.cacheMaxTimeToLive = cacheMaxTimeToLive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the L2 query cache default max size.
|
||||
*/
|
||||
public int getQueryCacheMaxSize() {
|
||||
return queryCacheMaxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the L2 query cache default max size.
|
||||
*/
|
||||
public void setQueryCacheMaxSize(int queryCacheMaxSize) {
|
||||
this.queryCacheMaxSize = queryCacheMaxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the L2 query cache default max idle time in seconds.
|
||||
*/
|
||||
public int getQueryCacheMaxIdleTime() {
|
||||
return queryCacheMaxIdleTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the L2 query cache default max idle time in seconds.
|
||||
*/
|
||||
public void setQueryCacheMaxIdleTime(int queryCacheMaxIdleTime) {
|
||||
this.queryCacheMaxIdleTime = queryCacheMaxIdleTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the L2 query cache default max time to live in seconds.
|
||||
*/
|
||||
public int getQueryCacheMaxTimeToLive() {
|
||||
return queryCacheMaxTimeToLive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the L2 query cache default max time to live in seconds.
|
||||
*/
|
||||
public void setQueryCacheMaxTimeToLive(int queryCacheMaxTimeToLive) {
|
||||
this.queryCacheMaxTimeToLive = queryCacheMaxTimeToLive;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -859,6 +1132,43 @@ public class ServerConfig {
|
||||
this.uuidStoreAsBinary = uuidStoreAsBinary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if LocalTime should be persisted with nanos precision.
|
||||
*/
|
||||
public boolean isLocalTimeWithNanos() {
|
||||
return localTimeWithNanos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if LocalTime should be persisted with nanos precision.
|
||||
* <p>
|
||||
* Otherwise it is persisted using java.sql.Time which is seconds precision.
|
||||
* </p>
|
||||
*/
|
||||
public void setLocalTimeWithNanos(boolean localTimeWithNanos) {
|
||||
this.localTimeWithNanos = localTimeWithNanos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if Duration should be persisted with nanos precision (SQL DECIMAL).
|
||||
* <p>
|
||||
* Otherwise it is persisted with second precision (SQL INTEGER).
|
||||
* </p>
|
||||
*/
|
||||
public boolean isDurationWithNanos() {
|
||||
return durationWithNanos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if Duration should be persisted with nanos precision (SQL DECIMAL).
|
||||
* <p>
|
||||
* Otherwise it is persisted with second precision (SQL INTEGER).
|
||||
* </p>
|
||||
*/
|
||||
public void setDurationWithNanos(boolean durationWithNanos) {
|
||||
this.durationWithNanos = durationWithNanos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to run the DDL generation on startup.
|
||||
*/
|
||||
@@ -990,6 +1300,23 @@ public class ServerConfig {
|
||||
this.searchJars = searchJars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the class name of a classPathReader implementation.
|
||||
*/
|
||||
public String getClassPathReaderClassName() {
|
||||
return classPathReaderClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the class name of a classPathReader implementation.
|
||||
*
|
||||
* Refer to server.util.ClassPathReader, this should really by a plugin but doing this for now
|
||||
* to be relatively compatible with current implementation.
|
||||
*/
|
||||
public void setClassPathReaderClassName(String classPathReaderClassName) {
|
||||
this.classPathReaderClassName = classPathReaderClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the list of classes (entities, listeners, scalarTypes etc) that should
|
||||
* be used for this server.
|
||||
@@ -1195,14 +1522,14 @@ public class ServerConfig {
|
||||
* all the BeanPersistListener instances.
|
||||
* </p>
|
||||
*/
|
||||
public void add(BeanPersistListener<?> beanPersistListener) {
|
||||
public void add(BeanPersistListener beanPersistListener) {
|
||||
persistListeners.add(beanPersistListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanPersistListener instances.
|
||||
*/
|
||||
public List<BeanPersistListener<?>> getPersistListeners() {
|
||||
public List<BeanPersistListener> getPersistListeners() {
|
||||
return persistListeners;
|
||||
}
|
||||
|
||||
@@ -1241,49 +1568,60 @@ public class ServerConfig {
|
||||
* BeanPersistListener instances one at a time.
|
||||
* </p>
|
||||
*/
|
||||
public void setPersistListeners(List<BeanPersistListener<?>> persistListeners) {
|
||||
public void setPersistListeners(List<BeanPersistListener> persistListeners) {
|
||||
this.persistListeners = persistListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the settings from the ebean.properties file.
|
||||
* Return the default PersistenceContextScope to be used if one is not explicitly set on a query.
|
||||
* <p/>
|
||||
* The PersistenceContextScope can specified on each query via {@link com.avaje.ebean
|
||||
* .Query#setPersistenceContextScope(com.avaje.ebean.PersistenceContextScope)}. If it
|
||||
* is not set on the query this default scope is used.
|
||||
*
|
||||
* @see com.avaje.ebean.Query#setPersistenceContextScope(com.avaje.ebean.PersistenceContextScope)
|
||||
*/
|
||||
public PersistenceContextScope getPersistenceContextScope() {
|
||||
// if somehow null return TRANSACTION scope
|
||||
return persistenceContextScope == null ? PersistenceContextScope.TRANSACTION : persistenceContextScope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the PersistenceContext scope to be used if one is not explicitly set on a query.
|
||||
* <p/>
|
||||
* This defaults to {@link PersistenceContextScope#TRANSACTION}.
|
||||
* <p/>
|
||||
* The PersistenceContextScope can specified on each query via {@link com.avaje.ebean
|
||||
* .Query#setPersistenceContextScope(com.avaje.ebean.PersistenceContextScope)}. If it
|
||||
* is not set on the query this scope is used.
|
||||
*
|
||||
* @see com.avaje.ebean.Query#setPersistenceContextScope(com.avaje.ebean.PersistenceContextScope)
|
||||
*/
|
||||
public void setPersistenceContextScope(PersistenceContextScope persistenceContextScope) {
|
||||
this.persistenceContextScope = persistenceContextScope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load settings from ebean.properties.
|
||||
*/
|
||||
public void loadFromProperties() {
|
||||
ConfigPropertyMap p = new ConfigPropertyMap(name);
|
||||
loadFromProperties(PropertyMap.defaultProperties());
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the settings from the given properties
|
||||
*/
|
||||
public void loadFromProperties(Properties properties) {
|
||||
PropertiesWrapper p = new PropertiesWrapper("ebean", name, properties);
|
||||
loadSettings(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a PropertySource for this server.
|
||||
*/
|
||||
public PropertySource getPropertySource() {
|
||||
return GlobalProperties.getPropertySource(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a configuration property using a default value.
|
||||
*/
|
||||
public String getProperty(String propertyName, String defaultValue) {
|
||||
PropertySource p = new ConfigPropertyMap(name);
|
||||
return p.get(propertyName, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a configuration property.
|
||||
*/
|
||||
public String getProperty(String propertyName) {
|
||||
return getProperty(propertyName, null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T createInstance(PropertySource p, Class<T> type, String key) {
|
||||
private <T> T createInstance(PropertiesWrapper p, Class<T> pluginType, String key) {
|
||||
|
||||
String classname = p.get(key, null);
|
||||
if (classname == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (T) ClassUtil.newInstance(classname);
|
||||
return classname == null ? null : (T) ClassUtil.newInstance(classname);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1293,38 +1631,37 @@ public class ServerConfig {
|
||||
*
|
||||
* @param p - The defined property source passed to load settings
|
||||
*/
|
||||
protected void loadDataSourceSettings(PropertySource p) {
|
||||
dataSourceConfig.loadSettings(p.getServerName());
|
||||
protected void loadDataSourceSettings(PropertiesWrapper p) {
|
||||
dataSourceConfig.loadSettings(p.withPrefix("datasource"));
|
||||
}
|
||||
|
||||
/**
|
||||
* This is broken out for the same reason as above - preserve existing behaviour but let it be overridden.
|
||||
*
|
||||
* @param p
|
||||
*/
|
||||
protected void loadAutofetchConfig(PropertySource p) {
|
||||
protected void loadAutofetchSettings(PropertiesWrapper p) {
|
||||
autofetchConfig.loadSettings(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the configuration settings from the properties file.
|
||||
*/
|
||||
protected void loadSettings(PropertySource p) {
|
||||
protected void loadSettings(PropertiesWrapper p) {
|
||||
|
||||
if (namingConvention != null) {
|
||||
namingConvention.loadFromProperties(p);
|
||||
}
|
||||
if (autofetchConfig == null) {
|
||||
autofetchConfig = new AutofetchConfig();
|
||||
}
|
||||
|
||||
loadAutofetchConfig(p);
|
||||
loadAutofetchSettings(p);
|
||||
|
||||
if (dataSourceConfig == null) {
|
||||
dataSourceConfig = new DataSourceConfig();
|
||||
}
|
||||
|
||||
loadDataSourceSettings(p);
|
||||
|
||||
autoCommitMode = p.getBoolean("autoCommitMode", false);
|
||||
useJtaTransactionManager = p.getBoolean("useJtaTransactionManager", false);
|
||||
autoCommitMode = p.getBoolean("autoCommitMode", autoCommitMode);
|
||||
useJtaTransactionManager = p.getBoolean("useJtaTransactionManager", useJtaTransactionManager);
|
||||
namingConvention = createNamingConvention(p);
|
||||
databasePlatform = createInstance(p, DatabasePlatform.class, "databasePlatform");
|
||||
encryptKeyManager = createInstance(p, EncryptKeyManager.class, "encryptKeyManager");
|
||||
@@ -1339,56 +1676,66 @@ public class ServerConfig {
|
||||
searchJars = getSearchJarsPackages(jarsProp);
|
||||
}
|
||||
|
||||
String packagesProp = p.get("search.packages", p.get("packages", null));
|
||||
if (packages != null) {
|
||||
String packagesProp = p.get("search.packages", p.get("packages", null));
|
||||
packages = getSearchJarsPackages(packagesProp);
|
||||
}
|
||||
|
||||
collectQueryStatsByNode = p.getBoolean("collectQueryStatsByNode", true);
|
||||
collectQueryOrigins = p.getBoolean("collectQueryOrigins", true);
|
||||
collectQueryStatsByNode = p.getBoolean("collectQueryStatsByNode", collectQueryStatsByNode);
|
||||
collectQueryOrigins = p.getBoolean("collectQueryOrigins", collectQueryOrigins);
|
||||
|
||||
updateChangesOnly = p.getBoolean("updateChangesOnly", true);
|
||||
updateChangesOnly = p.getBoolean("updateChangesOnly", updateChangesOnly);
|
||||
|
||||
boolean defaultDeleteMissingChildren = p.getBoolean("defaultDeleteMissingChildren", true);
|
||||
boolean defaultDeleteMissingChildren = p.getBoolean("defaultDeleteMissingChildren", updatesDeleteMissingChildren);
|
||||
updatesDeleteMissingChildren = p.getBoolean("updatesDeleteMissingChildren", defaultDeleteMissingChildren);
|
||||
|
||||
boolean batchMode = p.getBoolean("batch.mode", false);
|
||||
boolean batchMode = p.getBoolean("batch.mode", persistBatching);
|
||||
persistBatching = p.getBoolean("persistBatching", batchMode);
|
||||
|
||||
int batchSize = p.getInt("batch.size", 20);
|
||||
int batchSize = p.getInt("batch.size", persistBatchSize);
|
||||
persistBatchSize = p.getInt("persistBatchSize", batchSize);
|
||||
|
||||
dataSourceJndiName = p.get("dataSourceJndiName", null);
|
||||
databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", 20);
|
||||
databaseBooleanTrue = p.get("databaseBooleanTrue", null);
|
||||
databaseBooleanFalse = p.get("databaseBooleanFalse", null);
|
||||
databasePlatformName = p.get("databasePlatformName", null);
|
||||
uuidStoreAsBinary = p.getBoolean("uuidStoreAsBinary", false);
|
||||
persistenceContextScope = PersistenceContextScope.valueOf(p.get("persistenceContextScope","TRANSACTION"));
|
||||
|
||||
lazyLoadBatchSize = p.getInt("lazyLoadBatchSize", 1);
|
||||
queryBatchSize = p.getInt("queryBatchSize", DEFAULT_QUERY_BATCH_SIZE);
|
||||
dataSourceJndiName = p.get("dataSourceJndiName", dataSourceJndiName);
|
||||
databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize);
|
||||
databaseBooleanTrue = p.get("databaseBooleanTrue", databaseBooleanTrue);
|
||||
databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse);
|
||||
databasePlatformName = p.get("databasePlatformName", databasePlatformName);
|
||||
uuidStoreAsBinary = p.getBoolean("uuidStoreAsBinary", uuidStoreAsBinary);
|
||||
localTimeWithNanos = p.getBoolean("localTimeWithNanos", localTimeWithNanos);
|
||||
|
||||
ddlGenerate = p.getBoolean("ddl.generate", false);
|
||||
ddlRun = p.getBoolean("ddl.run", false);
|
||||
lazyLoadBatchSize = p.getInt("lazyLoadBatchSize", lazyLoadBatchSize);
|
||||
queryBatchSize = p.getInt("queryBatchSize", queryBatchSize);
|
||||
|
||||
String jsonDateTimeFormat = p.get("jsonDateTime", null);
|
||||
if (jsonDateTimeFormat != null) {
|
||||
jsonDateTime = JsonConfig.DateTime.valueOf(jsonDateTimeFormat);
|
||||
} else {
|
||||
jsonDateTime = JsonConfig.DateTime.MILLIS;
|
||||
}
|
||||
|
||||
ddlGenerate = p.getBoolean("ddl.generate", ddlGenerate);
|
||||
ddlRun = p.getBoolean("ddl.run", ddlRun);
|
||||
|
||||
classes = getClasses(p);
|
||||
}
|
||||
|
||||
private NamingConvention createNamingConvention(PropertySource p) {
|
||||
private NamingConvention createNamingConvention(PropertiesWrapper properties) {
|
||||
|
||||
NamingConvention nc = createInstance(p, NamingConvention.class, "namingconvention");
|
||||
NamingConvention nc = createInstance(properties, NamingConvention.class, "namingconvention");
|
||||
if (nc == null) {
|
||||
return null;
|
||||
}
|
||||
if (nc instanceof AbstractNamingConvention) {
|
||||
AbstractNamingConvention anc = (AbstractNamingConvention) nc;
|
||||
String v = p.get("namingConvention.useForeignKeyPrefix", null);
|
||||
String v = properties.get("namingConvention.useForeignKeyPrefix", null);
|
||||
if (v != null) {
|
||||
boolean useForeignKeyPrefix = Boolean.valueOf(v);
|
||||
anc.setUseForeignKeyPrefix(useForeignKeyPrefix);
|
||||
}
|
||||
|
||||
String sequenceFormat = p.get("namingConvention.sequenceFormat", null);
|
||||
String sequenceFormat = properties.get("namingConvention.sequenceFormat", null);
|
||||
if (sequenceFormat != null) {
|
||||
anc.setSequenceFormat(sequenceFormat);
|
||||
}
|
||||
@@ -1399,20 +1746,20 @@ public class ServerConfig {
|
||||
/**
|
||||
* Build the list of classes from the comma delimited string.
|
||||
*
|
||||
* @param p
|
||||
* the p
|
||||
* @param properties
|
||||
* the properties
|
||||
*
|
||||
* @return the classes
|
||||
*/
|
||||
private ArrayList<Class<?>> getClasses(PropertySource p) {
|
||||
private List<Class<?>> getClasses(PropertiesWrapper properties) {
|
||||
|
||||
String classNames = p.get("classes", null);
|
||||
String classNames = properties.get("classes", null);
|
||||
if (classNames == null) {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayList<Class<?>> classes = new ArrayList<Class<?>>();
|
||||
List<Class<?>> classes = new ArrayList<Class<?>>();
|
||||
|
||||
String[] split = classNames.split("[ ,;]");
|
||||
for (int i = 0; i < split.length; i++) {
|
||||
@@ -1442,5 +1789,4 @@ public class ServerConfig {
|
||||
}
|
||||
return hitList;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -72,6 +72,10 @@ public class DatabasePlatform {
|
||||
*/
|
||||
protected String name = "generic";
|
||||
|
||||
protected String columnAliasPrefix = "c";
|
||||
|
||||
protected String tableAliasPlaceHolder = "${ta}";
|
||||
|
||||
/**
|
||||
* Use a BackTick ` at the beginning and end of table or column names that you
|
||||
* want to use quoted identifiers for. The backticks get converted to the
|
||||
@@ -166,6 +170,34 @@ public class DatabasePlatform {
|
||||
return dbDdlSyntax;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the column alias prefix.
|
||||
*/
|
||||
public String getColumnAliasPrefix() {
|
||||
return columnAliasPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the column alias prefix.
|
||||
*/
|
||||
public void setColumnAliasPrefix(String columnAliasPrefix) {
|
||||
this.columnAliasPrefix = columnAliasPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the table alias placeholder.
|
||||
*/
|
||||
public String getTableAliasPlaceHolder() {
|
||||
return tableAliasPlaceHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the table alias placeholder.
|
||||
*/
|
||||
public void setTableAliasPlaceHolder(String tableAliasPlaceHolder) {
|
||||
this.tableAliasPlaceHolder = tableAliasPlaceHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the close quote for quoted identifiers.
|
||||
*
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@@ -14,15 +13,13 @@ public class H2Platform extends DatabasePlatform {
|
||||
super();
|
||||
this.name = "h2";
|
||||
this.dbEncrypt = new H2DbEncrypt();
|
||||
this.likeClause = "like ? escape''";
|
||||
// like ? escape'' not working in the latest version H2 so just using no
|
||||
// escape clause for now noting that backslash is an escape char for like in H2
|
||||
this.likeClause = "like ?";
|
||||
|
||||
// only support getGeneratedKeys with non-batch JDBC
|
||||
// so generally use SEQUENCE instead of IDENTITY for H2
|
||||
boolean useIdentity = GlobalProperties.getBoolean("ebean.h2platform.useIdentity", false);
|
||||
|
||||
IdType idType = useIdentity ? IdType.IDENTITY : IdType.SEQUENCE;
|
||||
this.dbIdentity.setIdType(idType);
|
||||
|
||||
this.dbIdentity.setIdType(IdType.SEQUENCE);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
this.dbIdentity.setSupportsIdentity(true);
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import java.sql.Types;
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* H2 specific platform.
|
||||
@@ -16,14 +14,7 @@ public class HsqldbPlatform extends DatabasePlatform {
|
||||
super();
|
||||
this.name = "hsqldb";
|
||||
this.dbEncrypt = new H2DbEncrypt();
|
||||
|
||||
// only support getGeneratedKeys with non-batch JDBC
|
||||
// so generally use SEQUENCE instead of IDENTITY for H2
|
||||
boolean useIdentity = GlobalProperties.getBoolean("ebean.hsqldb.useIdentity", true);
|
||||
|
||||
IdType idType = useIdentity ? IdType.IDENTITY : IdType.SEQUENCE;
|
||||
this.dbIdentity.setIdType(idType);
|
||||
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
this.dbIdentity.setSupportsIdentity(true);
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
|
||||
/**
|
||||
* Oracle encryption support.
|
||||
*
|
||||
@@ -48,12 +46,19 @@ import com.avaje.ebean.config.GlobalProperties;
|
||||
public class Oracle10DbEncrypt extends AbstractDbEncrypt {
|
||||
|
||||
/**
|
||||
* Constructs the Oracle10DbEncrypt.
|
||||
* Constructs the Oracle10DbEncrypt with default encrypt and decrypt stored procedures.
|
||||
*/
|
||||
public Oracle10DbEncrypt() {
|
||||
this("eb_encrypt", "eb_decrypt");
|
||||
}
|
||||
|
||||
String encryptfunction = GlobalProperties.get("ebean.oracle.encryptfunction", "eb_encrypt");
|
||||
String decryptfunction = GlobalProperties.get("ebean.oracle.decryptfunction", "eb_decrypt");
|
||||
/**
|
||||
* Constructs the Oracle10DbEncrypt specifying encrypt and decrypt stored procedures.
|
||||
*
|
||||
* @param encryptfunction the encrypt stored procedure
|
||||
* @param decryptfunction the decrypt stored procedure
|
||||
*/
|
||||
public Oracle10DbEncrypt(String encryptfunction, String decryptfunction) {
|
||||
|
||||
this.varcharEncryptFunction = new OraVarcharFunction(encryptfunction, decryptfunction);
|
||||
this.dateEncryptFunction = new OraDateFunction(encryptfunction, decryptfunction);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Types;
|
||||
@@ -27,12 +26,7 @@ public class Postgres8Platform extends DatabasePlatform {
|
||||
this.dbIdentity.setIdType(IdType.SEQUENCE);
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
|
||||
String colAlias = GlobalProperties.get("ebean.columnAliasPrefix", null);
|
||||
if (colAlias == null) {
|
||||
// Postgres requires the "as" keyword for column alias
|
||||
GlobalProperties.put("ebean.columnAliasPrefix", "as c");
|
||||
}
|
||||
|
||||
this.columnAliasPrefix = "as c";
|
||||
this.openQuote = "\"";
|
||||
this.closeQuote = "\"";
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
@@ -38,11 +36,7 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
|
||||
String colAlias = GlobalProperties.get("ebean.columnAliasPrefix", null);
|
||||
if (colAlias == null) {
|
||||
// Postgres requires the "as" keyword for column alias
|
||||
GlobalProperties.put("ebean.columnAliasPrefix", "as c");
|
||||
}
|
||||
this.columnAliasPrefix = "as c";
|
||||
|
||||
this.openQuote = "\"";
|
||||
this.closeQuote = "\"";
|
||||
|
||||
@@ -40,7 +40,7 @@ public abstract class SequenceIdGenerator implements IdGenerator {
|
||||
|
||||
protected final BackgroundExecutor backgroundExecutor;
|
||||
|
||||
protected final ArrayList<Integer> idList = new ArrayList<Integer>(50);
|
||||
protected final ArrayList<Long> idList = new ArrayList<Long>(50);
|
||||
|
||||
protected int batchSize;
|
||||
|
||||
@@ -117,7 +117,7 @@ public abstract class SequenceIdGenerator implements IdGenerator {
|
||||
if (idList.size() == 0) {
|
||||
loadMoreIds(batchSize, t);
|
||||
}
|
||||
Integer nextId = idList.remove(0);
|
||||
Long nextId = idList.remove(0);
|
||||
|
||||
if (batchSize > 1) {
|
||||
if (idList.size() <= batchSize / 2) {
|
||||
@@ -158,7 +158,7 @@ public abstract class SequenceIdGenerator implements IdGenerator {
|
||||
|
||||
protected void loadMoreIds(final int numberToLoad, Transaction t) {
|
||||
|
||||
ArrayList<Integer> newIds = getMoreIds(numberToLoad, t);
|
||||
ArrayList<Long> newIds = getMoreIds(numberToLoad, t);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("... seq:" + seqName + " loaded:" + numberToLoad + " ids:" + newIds);
|
||||
@@ -174,11 +174,11 @@ public abstract class SequenceIdGenerator implements IdGenerator {
|
||||
/**
|
||||
* Get more Id's by executing a query and reading the Id's returned.
|
||||
*/
|
||||
protected ArrayList<Integer> getMoreIds(int loadSize, Transaction t) {
|
||||
protected ArrayList<Long> getMoreIds(int loadSize, Transaction t) {
|
||||
|
||||
String sql = getSql(loadSize);
|
||||
|
||||
ArrayList<Integer> newIds = new ArrayList<Integer>(loadSize);
|
||||
ArrayList<Long> newIds = new ArrayList<Long>(loadSize);
|
||||
|
||||
boolean useTxnConnection = t != null;
|
||||
|
||||
@@ -191,12 +191,10 @@ public abstract class SequenceIdGenerator implements IdGenerator {
|
||||
pstmt = c.prepareStatement(sql);
|
||||
rset = pstmt.executeQuery();
|
||||
while (rset.next()) {
|
||||
int val = rset.getInt(1);
|
||||
newIds.add(Integer.valueOf(val));
|
||||
newIds.add(rset.getLong(1));
|
||||
}
|
||||
if (newIds.size() == 0) {
|
||||
String m = "Always expecting more than 1 row from " + sql;
|
||||
throw new PersistenceException(m);
|
||||
throw new PersistenceException("Always expecting more than 1 row from " + sql);
|
||||
}
|
||||
|
||||
return newIds;
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.avaje.ebean.event;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Provides a base implementation of BeanPersistListener.
|
||||
* <p>
|
||||
* Objects extending this should override the methods then are interested in.
|
||||
* The default inserted() updated() and deleted() methods return false and as such
|
||||
* means other servers in the cluster are not notified.
|
||||
* </p>
|
||||
*/
|
||||
public abstract class AbstractBeanPersistListener implements BeanPersistListener {
|
||||
|
||||
/**
|
||||
* Notified that a bean has been inserted locally. Return true if you want the
|
||||
* cluster to be notified of the event.
|
||||
*
|
||||
* @param bean The bean that was inserted.
|
||||
*/
|
||||
@Override
|
||||
public boolean inserted(Object bean) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notified that a bean has been updated locally. Return true if you want the
|
||||
* cluster to be notified of the event.
|
||||
*
|
||||
* @param bean The bean that was updated.
|
||||
* @param updatedProperties The properties that were modified by this update.
|
||||
*/
|
||||
@Override
|
||||
public boolean updated(Object bean, Set<String> updatedProperties) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notified that a bean has been deleted locally. Return true if you want the
|
||||
* cluster to be notified of the event.
|
||||
*
|
||||
* @param bean The bean that was deleted.
|
||||
*/
|
||||
@Override
|
||||
public boolean deleted(Object bean) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify that a bean was inserted on another node of the cluster.
|
||||
*
|
||||
* @param id the id value of the inserted bean
|
||||
*/
|
||||
@Override
|
||||
public void remoteInsert(Object id) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify that a bean was updated on another node of the cluster.
|
||||
*
|
||||
* @param id the id value of the updated bean.
|
||||
*/
|
||||
@Override
|
||||
public void remoteUpdate(Object id) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify that a bean was deleted on another node of the cluster.
|
||||
*
|
||||
* @param id the id value of the deleted bean.
|
||||
*/
|
||||
@Override
|
||||
public void remoteDelete(Object id) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
@@ -33,11 +33,17 @@ import com.avaje.ebean.config.ServerConfig;
|
||||
* </p>
|
||||
* <p>
|
||||
* A BeanPersistListener is either found automatically via class path search or
|
||||
* can be added programmatically via {@link ServerConfig#add(BeanPersistListener)}.
|
||||
* can be added programmatically via {@link ServerConfig#add(BeanPersistListener<?>)}}.
|
||||
* </p>
|
||||
* @see ServerConfig#add(BeanPersistListener)
|
||||
*/
|
||||
public interface BeanPersistListener<T> {
|
||||
public interface BeanPersistListener {
|
||||
|
||||
/**
|
||||
* Return true if this BeanPersistListener should be registered for events
|
||||
* on this entity type.
|
||||
*/
|
||||
public boolean isRegisterFor(Class<?> cls);
|
||||
|
||||
/**
|
||||
* Notified that a bean has been inserted locally. Return true if you want the
|
||||
@@ -46,7 +52,7 @@ public interface BeanPersistListener<T> {
|
||||
* @param bean
|
||||
* The bean that was inserted.
|
||||
*/
|
||||
public boolean inserted(T bean);
|
||||
public boolean inserted(Object bean);
|
||||
|
||||
/**
|
||||
* Notified that a bean has been updated locally. Return true if you want the
|
||||
@@ -57,7 +63,7 @@ public interface BeanPersistListener<T> {
|
||||
* @param updatedProperties
|
||||
* The properties that were modified by this update.
|
||||
*/
|
||||
public boolean updated(T bean, Set<String> updatedProperties);
|
||||
public boolean updated(Object bean, Set<String> updatedProperties);
|
||||
|
||||
/**
|
||||
* Notified that a bean has been deleted locally. Return true if you want the
|
||||
@@ -66,7 +72,7 @@ public interface BeanPersistListener<T> {
|
||||
* @param bean
|
||||
* The bean that was deleted.
|
||||
*/
|
||||
public boolean deleted(T bean);
|
||||
public boolean deleted(Object bean);
|
||||
|
||||
/**
|
||||
* Notify that a bean was inserted on another node of the cluster.
|
||||
|
||||
@@ -19,9 +19,6 @@ import com.avaje.ebean.Query;
|
||||
* properties and applying that to both what to fetch (ORM query) and what to
|
||||
* render (JAX-RS JSON / XML).
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
*/
|
||||
public class PathProperties {
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
import java.io.IOException;
|
||||
import com.avaje.ebean.text.PathProperties;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
|
||||
/**
|
||||
* Converts objects to and from JSON format.
|
||||
*/
|
||||
@@ -16,70 +16,113 @@ public interface JsonContext {
|
||||
|
||||
/**
|
||||
* Convert json string input into a Bean of a specific type.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
public <T> T toBean(Class<T> rootType, String json) throws IOException;
|
||||
public <T> T toBean(Class<T> rootType, String json) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Convert json reader input into a Bean of a specific type.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
public <T> T toBean(Class<T> rootType, Reader json) throws IOException;
|
||||
public <T> T toBean(Class<T> rootType, Reader json) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Convert json string input into a list of beans of a specific type.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
public <T> List<T> toList(Class<T> rootType, String json) throws IOException;
|
||||
public <T> List<T> toList(Class<T> rootType, String json) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Convert json reader input into a list of beans of a specific type.
|
||||
* @throws IOException
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
public <T> List<T> toList(Class<T> rootType, Reader json) throws IOException;
|
||||
public <T> List<T> toList(Class<T> rootType, Reader json) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Use the genericType to determine if this should be converted into a List or
|
||||
* bean.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
public Object toObject(Type genericType, Reader json) throws IOException;
|
||||
public Object toObject(Type genericType, Reader json) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Use the genericType to determine if this should be converted into a List or
|
||||
* bean.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
public Object toObject(Type genericType, String json) throws IOException;
|
||||
public Object toObject(Type genericType, String json) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Write the bean or collection in JSON format to the writer with default
|
||||
* options.
|
||||
*
|
||||
* @param value
|
||||
* the bean or collection of beans to write
|
||||
* @param writer
|
||||
* used to write the json output to
|
||||
* Return the bean or collection as JSON string.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
public void toJson(Object value, Writer writer) throws IOException;
|
||||
public String toJson(Object value) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* With additional options to specify JsonValueAdapter and
|
||||
* JsonWriteBeanVisitor's.
|
||||
*
|
||||
* @param value
|
||||
* the bean or collection of beans to write
|
||||
* @param writer
|
||||
* used to write the json output to
|
||||
* @param options
|
||||
* additional options to control the JSON output
|
||||
* Write the bean or collection in JSON format to the writer.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
public void toJson(Object value, Writer writer, JsonWriteOptions options) throws IOException;
|
||||
public void toJson(Object value, Writer writer) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Convert a bean or collection to json string using default options.
|
||||
* Write the bean or collection to the JsonGenerator.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
public String toJson(Object value) throws IOException;
|
||||
public void toJson(Object value, JsonGenerator generator) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Return the bean or collection as JSON string using PathProperties.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
public String toJson(Object value, PathProperties pathProperties) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Write the bean or collection as json to the writer using the PathProperties.
|
||||
*/
|
||||
public void toJson(Object value, Writer writer, PathProperties pathProperties) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Write the bean or collection to the JsonGenerator using the PathProperties.
|
||||
*/
|
||||
public void toJson(Object value, JsonGenerator generator, PathProperties pathProperties) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Deprecated in favour of using PathProperties by itself.
|
||||
* Write json to the JsonGenerator using the JsonWriteOptions.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public void toJson(Object value, JsonGenerator generator, JsonWriteOptions options) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Deprecated in favour of using PathProperties by itself.
|
||||
* With additional options.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public void toJson(Object value, Writer writer, JsonWriteOptions options) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Deprecated in favour of using PathProperties by itself.
|
||||
* Convert a bean or collection to json string.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public String toJson(Object value, JsonWriteOptions options) throws IOException;
|
||||
public String toJson(Object value, JsonWriteOptions options) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Return true if the type is known as an Entity bean or a List Set or
|
||||
@@ -89,11 +132,15 @@ public interface JsonContext {
|
||||
|
||||
/**
|
||||
* Create and return a new JsonGenerator for the given writer.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
public JsonGenerator createGenerator(Writer writer) throws IOException;
|
||||
|
||||
public JsonGenerator createGenerator(Writer writer) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Create and return a new JsonParser for the given reader.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
public JsonParser createParser(Reader reader) throws IOException;
|
||||
public JsonParser createParser(Reader reader) throws JsonIOException;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
/**
|
||||
* Unchecked exception thrown when an IOException occurs in json processing.
|
||||
* <p>
|
||||
* Typically wraps the checked IOException.
|
||||
* </p>
|
||||
*/
|
||||
public class JsonIOException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Construct with an underlying cause.
|
||||
*/
|
||||
public JsonIOException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with a message.
|
||||
*/
|
||||
public JsonIOException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -3,18 +3,14 @@ package com.avaje.ebean.text.json;
|
||||
import com.avaje.ebean.text.PathProperties;
|
||||
|
||||
/**
|
||||
* Deprecated in favour of just using PathProperties.
|
||||
*
|
||||
* Provides options for customising the JSON write process.
|
||||
* <p>
|
||||
* You can explicitly state which properties to include in the JSON output for
|
||||
* the root level and each path.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
|
||||
* // output as a JSON string with pretty formatting
|
||||
* String s = json.toJson(list, true, writeOptions);
|
||||
*
|
||||
* </pre>
|
||||
* @deprecated
|
||||
*/
|
||||
public class JsonWriteOptions {
|
||||
|
||||
@@ -24,12 +20,20 @@ public class JsonWriteOptions {
|
||||
* Parse and return a PathProperties from nested string format like
|
||||
* (a,b,c(d,e),f(g)) where "c" is a path containing "d" and "e" and "f" is a
|
||||
* path containing "g" and the root path contains "a","b","c" and "f".
|
||||
*
|
||||
* @see com.avaje.ebean.text.PathProperties#parse(String)
|
||||
*/
|
||||
public static JsonWriteOptions parsePath(String pathProperties) {
|
||||
|
||||
PathProperties p = PathProperties.parse(pathProperties);
|
||||
return pathProperties(PathProperties.parse(pathProperties));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct JsonWriteOptions with the given pathProperties.
|
||||
*/
|
||||
public static JsonWriteOptions pathProperties(PathProperties pathProperties) {
|
||||
JsonWriteOptions o = new JsonWriteOptions();
|
||||
o.setPathProperties(p);
|
||||
o.setPathProperties(pathProperties);
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,12 @@ public class BindParams implements Serializable {
|
||||
*/
|
||||
private String preparedSql;
|
||||
|
||||
/**
|
||||
* Bind hash and count used to detect when the bind values have changed such
|
||||
* that the generated SQL (with named parameters) needs to be recalculated.
|
||||
*/
|
||||
private int[] bindHash;
|
||||
|
||||
public BindParams() {
|
||||
}
|
||||
|
||||
@@ -51,20 +57,33 @@ public class BindParams implements Serializable {
|
||||
* </p>
|
||||
*/
|
||||
public void buildQueryPlanHash(HashQueryPlanBuilder builder) {
|
||||
int[] vals = calcQueryPlanHash();
|
||||
builder.add(vals[0]).bind(vals[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate and return a query plan bind hash with total bind count.
|
||||
*/
|
||||
public int[] calcQueryPlanHash() {
|
||||
int tempBindCount;
|
||||
int bc = 0;
|
||||
int hc = 31;
|
||||
for (Param param : positionedParameters) {
|
||||
hc = hc * 31 + param.queryBindCount();
|
||||
tempBindCount = param.queryBindCount();
|
||||
bc += tempBindCount;
|
||||
hc = hc * 31 + tempBindCount;
|
||||
}
|
||||
|
||||
for (Map.Entry<String, Param> entry : namedParameters.entrySet()) {
|
||||
tempBindCount = entry.getValue().queryBindCount();
|
||||
bc += tempBindCount;
|
||||
hc = hc * 31 + entry.getKey().hashCode();
|
||||
hc = hc * 31 + entry.getValue().queryBindCount();
|
||||
hc = hc * 31 + tempBindCount;
|
||||
}
|
||||
|
||||
int bindCount = positionedParameters.size() + namedParameters.size();
|
||||
builder.add(hc).bind(bindCount);
|
||||
return new int[]{hc, bc};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a deep copy of the BindParams.
|
||||
*/
|
||||
@@ -110,7 +129,7 @@ public class BindParams implements Serializable {
|
||||
* parameters ordered.
|
||||
*/
|
||||
public boolean requiresNamedParamsPrepare() {
|
||||
return !namedParameters.isEmpty() && positionedParameters.isEmpty();
|
||||
return !namedParameters.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,7 +169,7 @@ public class BindParams implements Serializable {
|
||||
}
|
||||
|
||||
private Param getParam(String name) {
|
||||
Param p = (Param) namedParameters.get(name);
|
||||
Param p = namedParameters.get(name);
|
||||
if (p == null) {
|
||||
p = new Param();
|
||||
namedParameters.put(name, p);
|
||||
@@ -165,7 +184,7 @@ public class BindParams implements Serializable {
|
||||
positionedParameters.add(new Param());
|
||||
}
|
||||
}
|
||||
return (Param) positionedParameters.get(position - 1);
|
||||
return positionedParameters.get(position - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -253,7 +272,29 @@ public class BindParams implements Serializable {
|
||||
return preparedSql;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Return true if the bind hash and count has not changed.
|
||||
*/
|
||||
public boolean isSameBindHash() {
|
||||
|
||||
if (bindHash == null) {
|
||||
bindHash = calcQueryPlanHash();
|
||||
return false;
|
||||
}
|
||||
int[] oldPlan = bindHash;
|
||||
bindHash = calcQueryPlanHash();
|
||||
return bindHash[0] == oldPlan[0] && bindHash[1] == oldPlan[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new positioned parameters orderedList.
|
||||
*/
|
||||
public OrderedList createOrderedList() {
|
||||
positionedParameters.clear();
|
||||
return new OrderedList(positionedParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* The bind parameters in the correct binding order.
|
||||
* <p>
|
||||
* This is the result of converting sql with named parameters
|
||||
@@ -327,8 +368,6 @@ public class BindParams implements Serializable {
|
||||
|
||||
private Object outValue;
|
||||
|
||||
private int textLocation;
|
||||
|
||||
/**
|
||||
* Construct a Parameter.
|
||||
*/
|
||||
@@ -368,17 +407,8 @@ public class BindParams implements Serializable {
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (o == null) {
|
||||
return false;
|
||||
}
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
if (o instanceof Param) {
|
||||
return hashCode() == o.hashCode();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return o != null && (o == this || (o instanceof Param) && hashCode() == o.hashCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is an In parameter that needs to be bound before
|
||||
@@ -463,21 +493,6 @@ public class BindParams implements Serializable {
|
||||
this.outValue = out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the location this parameter was found in the sql text.
|
||||
*/
|
||||
public int getTextLocation() {
|
||||
return textLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the location in the sql text this parameter was located. This is
|
||||
* used to control order for named parameters.
|
||||
*/
|
||||
public void setTextLocation(int textLocation) {
|
||||
this.textLocation = textLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* If true do not include this value in a transaction log.
|
||||
*/
|
||||
|
||||
@@ -11,6 +11,8 @@ import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
*/
|
||||
public interface LoadBeanBuffer {
|
||||
|
||||
public int getBatchSize();
|
||||
|
||||
public List<EntityBeanIntercept> getBatch();
|
||||
|
||||
public BeanDescriptor<?> getBeanDescriptor();
|
||||
|
||||
@@ -59,4 +59,7 @@ public class LoadBeanRequest extends LoadRequest {
|
||||
return lazyLoadProperty;
|
||||
}
|
||||
|
||||
public int getBatchSize() {
|
||||
return getLoadContext().getBatchSize();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,16 +11,16 @@ import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
*/
|
||||
public interface LoadContext {
|
||||
|
||||
/**
|
||||
* Return the minimum batch size when using QueryIterator with query joins.
|
||||
*/
|
||||
public int getSecondaryQueriesMinBatchSize(OrmQueryRequest<?> parentRequest, int defaultQueryBatch);
|
||||
/**
|
||||
* Return the minimum batch size when using QueryIterator with query joins.
|
||||
*/
|
||||
public int getSecondaryQueriesMinBatchSize(OrmQueryRequest<?> parentRequest, int defaultQueryBatch);
|
||||
|
||||
/**
|
||||
* Execute any secondary (+query) queries if there are any defined.
|
||||
* @param parentRequest the originating query request
|
||||
*/
|
||||
public void executeSecondaryQueries(OrmQueryRequest<?> parentRequest, int defaultQueryBatch);
|
||||
public void executeSecondaryQueries(OrmQueryRequest<?> parentRequest);
|
||||
|
||||
/**
|
||||
* Register any secondary queries (+query or +lazy) with their
|
||||
|
||||
@@ -13,6 +13,8 @@ import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
*/
|
||||
public interface LoadManyBuffer {
|
||||
|
||||
public int getBatchSize();
|
||||
|
||||
public List<BeanCollection<?>> getBatch();
|
||||
|
||||
public BeanPropertyAssocMany<?> getBeanProperty();
|
||||
|
||||
@@ -18,12 +18,11 @@ public class LoadManyRequest extends LoadRequest {
|
||||
|
||||
private final boolean loadCache;
|
||||
|
||||
public LoadManyRequest(LoadManyBuffer loadContext, int batchSize, boolean lazy,boolean onlyIds, boolean loadCache) {
|
||||
this(loadContext, null, batchSize, lazy, onlyIds, loadCache);
|
||||
public LoadManyRequest(LoadManyBuffer loadContext, boolean lazy, boolean onlyIds, boolean loadCache) {
|
||||
this(loadContext, null, lazy, onlyIds, loadCache);
|
||||
}
|
||||
|
||||
public LoadManyRequest(LoadManyBuffer loadContext, OrmQueryRequest<?> parentRequest, int batchSize, boolean lazy,
|
||||
boolean onlyIds, boolean loadCache) {
|
||||
public LoadManyRequest(LoadManyBuffer loadContext, OrmQueryRequest<?> parentRequest, boolean lazy, boolean onlyIds, boolean loadCache) {
|
||||
|
||||
super(parentRequest, lazy);
|
||||
this.loadContext = loadContext;
|
||||
@@ -69,4 +68,10 @@ public class LoadManyRequest extends LoadRequest {
|
||||
return loadCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch size used for this load context.
|
||||
*/
|
||||
public int getBatchSize() {
|
||||
return loadContext.getBatchSize();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,6 @@ public interface LoadSecondaryQuery {
|
||||
|
||||
/**
|
||||
* Execute the secondary query with a given batch size.
|
||||
*
|
||||
* @param parentRequest
|
||||
* the originating query request
|
||||
*/
|
||||
public void loadSecondaryQuery(OrmQueryRequest<?> parentRequest, int requestedBatchSize, boolean all);
|
||||
public void loadSecondaryQuery(OrmQueryRequest<?> parentRequest);
|
||||
}
|
||||
|
||||
@@ -2,10 +2,7 @@ package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.TxScope;
|
||||
import com.avaje.ebean.*;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.BeanLoader;
|
||||
import com.avaje.ebean.bean.CallStack;
|
||||
@@ -63,6 +60,11 @@ public interface SpiEbeanServer extends EbeanServer, BeanLoader, BeanCollectionL
|
||||
*/
|
||||
public CallStack createCallStack();
|
||||
|
||||
/**
|
||||
* Return the PersistenceContextScope to use defined at query or server level.
|
||||
*/
|
||||
public PersistenceContextScope getPersistenceContextScope(SpiQuery<?> query);
|
||||
|
||||
/**
|
||||
* Return the DDL generator.
|
||||
*/
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.util.List;
|
||||
|
||||
import com.avaje.ebean.ExpressionList;
|
||||
import com.avaje.ebean.OrderBy;
|
||||
import com.avaje.ebean.PersistenceContextScope;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.bean.BeanCollectionTouched;
|
||||
import com.avaje.ebean.bean.CallStack;
|
||||
@@ -26,7 +27,7 @@ import com.avaje.ebeaninternal.server.querydefn.OrmQueryProperties;
|
||||
*/
|
||||
public interface SpiQuery<T> extends Query<T> {
|
||||
|
||||
public enum Mode {
|
||||
public enum Mode {
|
||||
NORMAL(false), LAZYLOAD_MANY(false), LAZYLOAD_BEAN(true), REFRESH_BEAN(true);
|
||||
Mode(boolean loadContextBean) {
|
||||
this.loadContextBean = loadContextBean;
|
||||
@@ -79,7 +80,20 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
*/
|
||||
SUBQUERY
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the PersistenceContextScope that this query should use.
|
||||
* <p>
|
||||
* This can be null and in that case use the default scope.
|
||||
* </p>
|
||||
*/
|
||||
public PersistenceContextScope getPersistenceContextScope();
|
||||
|
||||
/**
|
||||
* Return the default lazy load batch size.
|
||||
*/
|
||||
public int getLazyLoadBatchSize();
|
||||
|
||||
/**
|
||||
* Return true if select all properties was used to ensure the property
|
||||
* invoking a lazy load was included in the query.
|
||||
|
||||
@@ -5,4 +5,6 @@ import com.avaje.ebean.SqlUpdate;
|
||||
public interface SpiSqlUpdate extends SqlUpdate {
|
||||
|
||||
public BindParams getBindParams();
|
||||
|
||||
public void setGeneratedSql(String sql);
|
||||
}
|
||||
|
||||
@@ -19,179 +19,179 @@ public interface SpiTransaction extends Transaction {
|
||||
* End the transaction when had query only use.
|
||||
*/
|
||||
public void endQueryOnly();
|
||||
|
||||
|
||||
/**
|
||||
* Return the string prefix with the transactin id and label used in logging.
|
||||
*/
|
||||
public String getLogPrefix();
|
||||
|
||||
/**
|
||||
* Return true if generated SQL and Bind values should be logged to the
|
||||
* transaction log.
|
||||
*/
|
||||
public boolean isLogSql();
|
||||
|
||||
/**
|
||||
* Return true if summary level events should be logged to the transaction
|
||||
* log.
|
||||
*/
|
||||
public boolean isLogSummary();
|
||||
/**
|
||||
* Return true if generated SQL and Bind values should be logged to the
|
||||
* transaction log.
|
||||
*/
|
||||
public boolean isLogSql();
|
||||
|
||||
/**
|
||||
* Log a message to the SQL logger.
|
||||
*/
|
||||
public void logSql(String msg);
|
||||
/**
|
||||
* Return true if summary level events should be logged to the transaction
|
||||
* log.
|
||||
*/
|
||||
public boolean isLogSummary();
|
||||
|
||||
/**
|
||||
* Log a message to the SUMMARY logger.
|
||||
*/
|
||||
public void logSummary(String msg);
|
||||
/**
|
||||
* Log a message to the SQL logger.
|
||||
*/
|
||||
public void logSql(String msg);
|
||||
|
||||
/**
|
||||
* Register a "Derived Relationship" (that requires an additional update).
|
||||
*/
|
||||
public void registerDerivedRelationship(DerivedRelationshipData assocBean);
|
||||
/**
|
||||
* Log a message to the SUMMARY logger.
|
||||
*/
|
||||
public void logSummary(String msg);
|
||||
|
||||
/**
|
||||
* Return the list of "Derived Relationships" that must be maintained after
|
||||
* insert.
|
||||
*/
|
||||
public List<DerivedRelationshipData> getDerivedRelationship(Object bean);
|
||||
/**
|
||||
* Register a "Derived Relationship" (that requires an additional update).
|
||||
*/
|
||||
public void registerDerivedRelationship(DerivedRelationshipData assocBean);
|
||||
|
||||
/**
|
||||
* Add a deleting bean to the registered list.
|
||||
* <p>
|
||||
* This is to handle bi-directional relationships where both sides Cascade.
|
||||
* </p>
|
||||
*/
|
||||
public void registerDeleteBean(Integer hash);
|
||||
/**
|
||||
* Return the list of "Derived Relationships" that must be maintained after
|
||||
* insert.
|
||||
*/
|
||||
public List<DerivedRelationshipData> getDerivedRelationship(Object bean);
|
||||
|
||||
/**
|
||||
* Unregister the hash of the bean.
|
||||
*/
|
||||
public void unregisterDeleteBean(Integer hash);
|
||||
/**
|
||||
* Add a deleting bean to the registered list.
|
||||
* <p>
|
||||
* This is to handle bi-directional relationships where both sides Cascade.
|
||||
* </p>
|
||||
*/
|
||||
public void registerDeleteBean(Integer hash);
|
||||
|
||||
/**
|
||||
* Return true if this is a bean that has already been saved/deleted.
|
||||
*/
|
||||
public boolean isRegisteredDeleteBean(Integer hash);
|
||||
/**
|
||||
* Unregister the hash of the bean.
|
||||
*/
|
||||
public void unregisterDeleteBean(Integer hash);
|
||||
|
||||
/**
|
||||
* Unregister the persisted bean.
|
||||
*/
|
||||
public void unregisterBean(Object bean);
|
||||
/**
|
||||
* Return true if this is a bean that has already been saved/deleted.
|
||||
*/
|
||||
public boolean isRegisteredDeleteBean(Integer hash);
|
||||
|
||||
/**
|
||||
* Return true if this is a bean that has already been persisted in the
|
||||
* current recursive save request. The goal is to stop recursively saving
|
||||
* the bean when cascade persist is on both sides of a relationship).
|
||||
* <p>
|
||||
* This will register the bean if it is not already.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isRegisteredBean(Object bean);
|
||||
/**
|
||||
* Unregister the persisted bean.
|
||||
*/
|
||||
public void unregisterBean(Object bean);
|
||||
|
||||
/**
|
||||
* Returns a String used to identify the transaction. This id is used for
|
||||
* Transaction logging.
|
||||
*/
|
||||
public String getId();
|
||||
/**
|
||||
* Return true if this is a bean that has already been persisted in the
|
||||
* current recursive save request. The goal is to stop recursively saving
|
||||
* the bean when cascade persist is on both sides of a relationship).
|
||||
* <p>
|
||||
* This will register the bean if it is not already.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isRegisteredBean(Object bean);
|
||||
|
||||
/**
|
||||
* Return the batchSize specifically set for this transaction or 0.
|
||||
* <p>
|
||||
* Returning 0 implies to use the system wide default batch size.
|
||||
* </p>
|
||||
*/
|
||||
public int getBatchSize();
|
||||
/**
|
||||
* Returns a String used to identify the transaction. This id is used for
|
||||
* Transaction logging.
|
||||
*/
|
||||
public String getId();
|
||||
|
||||
/**
|
||||
* Modify and return the current 'depth' of the transaction.
|
||||
* <p>
|
||||
* As we cascade save or delete we traverse the object graph tree. Going up
|
||||
* to Assoc Ones the depth decreases and going down to Assoc Manys the depth
|
||||
* increases.
|
||||
* </p>
|
||||
* <p>
|
||||
* The depth is used for ordering batching statements. The lowest depth get
|
||||
* executed first during save.
|
||||
* </p>
|
||||
*/
|
||||
public int depth(int diff);
|
||||
/**
|
||||
* Return the batchSize specifically set for this transaction or 0.
|
||||
* <p>
|
||||
* Returning 0 implies to use the system wide default batch size.
|
||||
* </p>
|
||||
*/
|
||||
public int getBatchSize();
|
||||
|
||||
/**
|
||||
* Return true if this transaction was created explicitly via
|
||||
* <code>Ebean.beginTransaction()</code>.
|
||||
*/
|
||||
public boolean isExplicit();
|
||||
/**
|
||||
* Modify and return the current 'depth' of the transaction.
|
||||
* <p>
|
||||
* As we cascade save or delete we traverse the object graph tree. Going up
|
||||
* to Assoc Ones the depth decreases and going down to Assoc Manys the depth
|
||||
* increases.
|
||||
* </p>
|
||||
* <p>
|
||||
* The depth is used for ordering batching statements. The lowest depth get
|
||||
* executed first during save.
|
||||
* </p>
|
||||
*/
|
||||
public int depth(int diff);
|
||||
|
||||
/**
|
||||
* Get the object that holds the event details.
|
||||
* <p>
|
||||
* This information is used maintain the table state, cache and text
|
||||
* indexes. On commit the Table modifications this generates is broadcast
|
||||
* around the cluster (if you have a cluster).
|
||||
* </p>
|
||||
*/
|
||||
public TransactionEvent getEvent();
|
||||
/**
|
||||
* Return true if this transaction was created explicitly via
|
||||
* <code>Ebean.beginTransaction()</code>.
|
||||
*/
|
||||
public boolean isExplicit();
|
||||
|
||||
/**
|
||||
* Whether persistCascade is on for save and delete.
|
||||
*/
|
||||
public boolean isPersistCascade();
|
||||
/**
|
||||
* Get the object that holds the event details.
|
||||
* <p>
|
||||
* This information is used maintain the table state, cache and text
|
||||
* indexes. On commit the Table modifications this generates is broadcast
|
||||
* around the cluster (if you have a cluster).
|
||||
* </p>
|
||||
*/
|
||||
public TransactionEvent getEvent();
|
||||
|
||||
/**
|
||||
* Return true if this request should be batched. Conversely returns false
|
||||
* if this request should be executed immediately.
|
||||
*/
|
||||
public boolean isBatchThisRequest();
|
||||
/**
|
||||
* Whether persistCascade is on for save and delete.
|
||||
*/
|
||||
public boolean isPersistCascade();
|
||||
|
||||
/**
|
||||
* Return the queue used to batch up persist requests.
|
||||
*/
|
||||
public BatchControl getBatchControl();
|
||||
/**
|
||||
* Return true if this request should be batched. Conversely returns false
|
||||
* if this request should be executed immediately.
|
||||
*/
|
||||
public boolean isBatchThisRequest();
|
||||
|
||||
/**
|
||||
* Set the queue used to batch up persist requests. There should only be one
|
||||
* PersistQueue set per transaction.
|
||||
*/
|
||||
public void setBatchControl(BatchControl control);
|
||||
/**
|
||||
* Return the queue used to batch up persist requests.
|
||||
*/
|
||||
public BatchControl getBatchControl();
|
||||
|
||||
/**
|
||||
* Return the persistence context associated with this transaction.
|
||||
* <p>
|
||||
* You may wish to hold onto this and set it against another transaction
|
||||
* later. This is along the lines of 'extended persistence context'
|
||||
* behaviour.
|
||||
* </p>
|
||||
*/
|
||||
public PersistenceContext getPersistenceContext();
|
||||
/**
|
||||
* Set the queue used to batch up persist requests. There should only be one
|
||||
* PersistQueue set per transaction.
|
||||
*/
|
||||
public void setBatchControl(BatchControl control);
|
||||
|
||||
/**
|
||||
* Set the persistence context to this transaction.
|
||||
* <p>
|
||||
* This could be considered similar to 'EJB3 Extended Persistence Context'.
|
||||
* In that you can get the PersistenceContext from a transaction, hold onto
|
||||
* it, and then set it back later to a second transaction. In general there
|
||||
* is one PersistenceContext per Transaction. The getPersistenceContext()
|
||||
* and setPersistenceContext() enable a developer to reuse a single
|
||||
* PersistenceContext with multiple transactions.
|
||||
* </p>
|
||||
*/
|
||||
public void setPersistenceContext(PersistenceContext context);
|
||||
/**
|
||||
* Return the persistence context associated with this transaction.
|
||||
* <p>
|
||||
* You may wish to hold onto this and set it against another transaction
|
||||
* later. This is along the lines of 'extended persistence context'
|
||||
* behaviour.
|
||||
* </p>
|
||||
*/
|
||||
public PersistenceContext getPersistenceContext();
|
||||
|
||||
/**
|
||||
* Return the underlying Connection for internal use.
|
||||
* <p>
|
||||
* If the connection is made public from Transaction and the user code calls
|
||||
* that method we can no longer trust the query only status of a
|
||||
* Transaction.
|
||||
* </p>
|
||||
*/
|
||||
public Connection getInternalConnection();
|
||||
/**
|
||||
* Set the persistence context to this transaction.
|
||||
* <p>
|
||||
* This could be considered similar to 'EJB3 Extended Persistence Context'.
|
||||
* In that you can get the PersistenceContext from a transaction, hold onto
|
||||
* it, and then set it back later to a second transaction. In general there
|
||||
* is one PersistenceContext per Transaction. The getPersistenceContext()
|
||||
* and setPersistenceContext() enable a developer to reuse a single
|
||||
* PersistenceContext with multiple transactions.
|
||||
* </p>
|
||||
*/
|
||||
public void setPersistenceContext(PersistenceContext context);
|
||||
|
||||
/**
|
||||
* Return true if the manyToMany intersection should be persisted for this particular relationship direction.
|
||||
*/
|
||||
/**
|
||||
* Return the underlying Connection for internal use.
|
||||
* <p>
|
||||
* If the connection is made public from Transaction and the user code calls
|
||||
* that method we can no longer trust the query only status of a
|
||||
* Transaction.
|
||||
* </p>
|
||||
*/
|
||||
public Connection getInternalConnection();
|
||||
|
||||
/**
|
||||
* Return true if the manyToMany intersection should be persisted for this particular relationship direction.
|
||||
*/
|
||||
public boolean isSaveAssocManyIntersection(String intersectionTable, String beanName);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.transaction.BeanDelta;
|
||||
import com.avaje.ebeaninternal.server.transaction.DeleteByIdMap;
|
||||
import com.avaje.ebeaninternal.server.transaction.IndexInvalidate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Holds information for a transaction. There is one TransactionEvent instance
|
||||
@@ -25,180 +17,107 @@ import org.slf4j.LoggerFactory;
|
||||
*/
|
||||
public class TransactionEvent implements Serializable {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(TransactionEvent.class);
|
||||
|
||||
private static final long serialVersionUID = 7230903304106097120L;
|
||||
private static final long serialVersionUID = 7230903304106097120L;
|
||||
|
||||
/**
|
||||
* Flag indicating this is a local transaction (not from another server in
|
||||
* the cluster).
|
||||
*/
|
||||
private transient boolean local;
|
||||
/**
|
||||
* Flag indicating this is a local transaction (not from another server in
|
||||
* the cluster).
|
||||
*/
|
||||
private transient boolean local;
|
||||
|
||||
private boolean invalidateAll;
|
||||
private TransactionEventTable eventTables;
|
||||
|
||||
private TransactionEventTable eventTables;
|
||||
|
||||
private transient TransactionEventBeans eventBeans;
|
||||
private transient TransactionEventBeans eventBeans;
|
||||
|
||||
private transient List<BeanDelta> beanDeltas;
|
||||
private transient DeleteByIdMap deleteByIdMap;
|
||||
|
||||
private transient DeleteByIdMap deleteByIdMap;
|
||||
|
||||
private transient Set<IndexInvalidate> indexInvalidations;
|
||||
|
||||
private transient Set<String> pauseIndexInvalidate;
|
||||
|
||||
/**
|
||||
* Create the TransactionEvent, one per Transaction.
|
||||
*/
|
||||
public TransactionEvent() {
|
||||
this.local = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this to true to invalidate all table dependent cached objects.
|
||||
*/
|
||||
public void setInvalidateAll(boolean isInvalidateAll) {
|
||||
this.invalidateAll = isInvalidateAll;
|
||||
}
|
||||
/**
|
||||
* Create the TransactionEvent, one per Transaction.
|
||||
*/
|
||||
public TransactionEvent() {
|
||||
this.local = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if all table states should be invalidated. This will cause
|
||||
* all cached objects to be invalidated.
|
||||
*/
|
||||
public boolean isInvalidateAll() {
|
||||
return invalidateAll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporarily pause/ignore any index invalidation for this bean type.
|
||||
*/
|
||||
public void pauseIndexInvalidate(Class<?> beanType) {
|
||||
if (pauseIndexInvalidate == null){
|
||||
pauseIndexInvalidate = new HashSet<String>();
|
||||
}
|
||||
pauseIndexInvalidate.add(beanType.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume listening for index invalidation for this bean type.
|
||||
*/
|
||||
public void resumeIndexInvalidate(Class<?> beanType) {
|
||||
if (pauseIndexInvalidate != null){
|
||||
pauseIndexInvalidate.remove(beanType.getName());
|
||||
}
|
||||
public void addDeleteById(BeanDescriptor<?> desc, Object id) {
|
||||
if (deleteByIdMap == null) {
|
||||
deleteByIdMap = new DeleteByIdMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an IndexInvalidation notices to the transaction.
|
||||
*/
|
||||
public void addIndexInvalidate(IndexInvalidate indexEvent){
|
||||
if (pauseIndexInvalidate != null && pauseIndexInvalidate.contains(indexEvent.getIndexName())){
|
||||
logger.debug("--- IGNORE Invalidate on "+indexEvent.getIndexName());
|
||||
return;
|
||||
}
|
||||
if (indexInvalidations == null){
|
||||
indexInvalidations = new HashSet<IndexInvalidate>();
|
||||
}
|
||||
indexInvalidations.add(indexEvent);
|
||||
}
|
||||
|
||||
public void addDeleteById(BeanDescriptor<?> desc, Object id){
|
||||
if (deleteByIdMap == null){
|
||||
deleteByIdMap = new DeleteByIdMap();
|
||||
}
|
||||
deleteByIdMap.add(desc, id);
|
||||
}
|
||||
|
||||
public void addDeleteByIdList(BeanDescriptor<?> desc, List<Object> idList) {
|
||||
if (deleteByIdMap == null) {
|
||||
deleteByIdMap = new DeleteByIdMap();
|
||||
}
|
||||
deleteByIdMap.addList(desc, idList);
|
||||
deleteByIdMap.add(desc, id);
|
||||
}
|
||||
|
||||
public void addDeleteByIdList(BeanDescriptor<?> desc, List<Object> idList) {
|
||||
if (deleteByIdMap == null) {
|
||||
deleteByIdMap = new DeleteByIdMap();
|
||||
}
|
||||
|
||||
public DeleteByIdMap getDeleteByIdMap() {
|
||||
return deleteByIdMap;
|
||||
deleteByIdMap.addList(desc, idList);
|
||||
}
|
||||
|
||||
public DeleteByIdMap getDeleteByIdMap() {
|
||||
return deleteByIdMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this was a local transaction. Returns false if this
|
||||
* transaction originated on another server in the cluster.
|
||||
*/
|
||||
public boolean isLocal() {
|
||||
return local;
|
||||
}
|
||||
|
||||
/**
|
||||
* For BeanListeners the requests they are interested in.
|
||||
*/
|
||||
public TransactionEventBeans getEventBeans() {
|
||||
return eventBeans;
|
||||
}
|
||||
|
||||
public TransactionEventTable getEventTables() {
|
||||
return eventTables;
|
||||
}
|
||||
|
||||
public void add(String tableName, boolean inserts, boolean updates, boolean deletes) {
|
||||
if (eventTables == null) {
|
||||
eventTables = new TransactionEventTable();
|
||||
}
|
||||
eventTables.add(tableName, inserts, updates, deletes);
|
||||
}
|
||||
|
||||
public void addBeanDelta(BeanDelta delta) {
|
||||
if (beanDeltas == null) {
|
||||
beanDeltas = new ArrayList<BeanDelta>();
|
||||
}
|
||||
beanDeltas.add(delta);
|
||||
public void add(TransactionEventTable table) {
|
||||
if (eventTables == null) {
|
||||
eventTables = new TransactionEventTable();
|
||||
}
|
||||
eventTables.add(table);
|
||||
}
|
||||
|
||||
public List<BeanDelta> getBeanDeltas() {
|
||||
return beanDeltas;
|
||||
/**
|
||||
* Add a inserted updated or deleted bean to the event.
|
||||
*/
|
||||
public void add(PersistRequestBean<?> request) {
|
||||
|
||||
if (request.isNotify(this)) {
|
||||
// either a BeanListener or Cache is interested
|
||||
if (eventBeans == null) {
|
||||
eventBeans = new TransactionEventBeans();
|
||||
}
|
||||
eventBeans.add(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this was a local transaction. Returns false if this
|
||||
* transaction originated on another server in the cluster.
|
||||
*/
|
||||
public boolean isLocal() {
|
||||
return local;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For BeanListeners the requests they are interested in.
|
||||
*/
|
||||
public TransactionEventBeans getEventBeans() {
|
||||
return eventBeans;
|
||||
}
|
||||
|
||||
public TransactionEventTable getEventTables() {
|
||||
return eventTables;
|
||||
}
|
||||
|
||||
public Set<IndexInvalidate> getIndexInvalidations() {
|
||||
return indexInvalidations;
|
||||
/**
|
||||
* Notify the cache of bean changes.
|
||||
* <p>
|
||||
* This returns the TransactionEventTable so that if any
|
||||
* general table changes can also be used to invalidate
|
||||
* parts of the cache.
|
||||
* </p>
|
||||
*/
|
||||
public void notifyCache() {
|
||||
if (eventBeans != null) {
|
||||
eventBeans.notifyCache();
|
||||
}
|
||||
|
||||
public void add(String tableName, boolean inserts, boolean updates, boolean deletes){
|
||||
if (eventTables == null){
|
||||
eventTables = new TransactionEventTable();
|
||||
}
|
||||
eventTables.add(tableName, inserts, updates, deletes);
|
||||
}
|
||||
|
||||
public void add(TransactionEventTable table){
|
||||
if (eventTables == null){
|
||||
eventTables = new TransactionEventTable();
|
||||
}
|
||||
eventTables.add(table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a inserted updated or deleted bean to the event.
|
||||
*/
|
||||
public void add(PersistRequestBean<?> request) {
|
||||
|
||||
if (request.isNotify(this)){
|
||||
// either a BeanListener or Cache is interested
|
||||
if (eventBeans == null) {
|
||||
eventBeans = new TransactionEventBeans();
|
||||
}
|
||||
eventBeans.add(request);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the cache of bean changes.
|
||||
* <p>
|
||||
* This returns the TransactionEventTable so that if any
|
||||
* general table changes can also be used to invalidate
|
||||
* parts of the cache.
|
||||
* </p>
|
||||
*/
|
||||
public void notifyCache(){
|
||||
if (eventBeans != null){
|
||||
eventBeans.notifyCache();
|
||||
}
|
||||
if (deleteByIdMap != null) {
|
||||
deleteByIdMap.notifyCache();
|
||||
}
|
||||
}
|
||||
if (deleteByIdMap != null) {
|
||||
deleteByIdMap.notifyCache();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ public final class TransactionEventTable implements Serializable {
|
||||
private boolean update;
|
||||
private boolean delete;
|
||||
|
||||
private TableIUD(String table, boolean insert, boolean update, boolean delete){
|
||||
public TableIUD(String table, boolean insert, boolean update, boolean delete){
|
||||
this.table = table;
|
||||
this.insert = insert;
|
||||
this.update = update;
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
package com.avaje.ebeaninternal.server.autofetch;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.resource.ResourceManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
|
||||
public class AutoFetchManagerFactory {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AutoFetchManagerFactory.class);
|
||||
@@ -37,7 +35,7 @@ public class AutoFetchManagerFactory {
|
||||
|
||||
AutoFetchManager autoFetchManager = null;
|
||||
|
||||
boolean readFile = GlobalProperties.getBoolean("autofetch.readfromfile", true);
|
||||
boolean readFile = !"false".equalsIgnoreCase(System.getProperty("autofetch.readfromfile"));
|
||||
if (readFile) {
|
||||
autoFetchManager = deserializeAutoFetch(autoFetchFile);
|
||||
}
|
||||
|
||||
+14
-10
@@ -22,6 +22,8 @@ import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.querydefn.OrmQueryDetail;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The manager of all the usage/query statistics as well as the tuned fetch
|
||||
@@ -29,6 +31,8 @@ import com.avaje.ebeaninternal.server.querydefn.OrmQueryDetail;
|
||||
*/
|
||||
public class DefaultAutoFetchManager implements AutoFetchManager, Serializable {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultAutoFetchManager.class);
|
||||
|
||||
private static final long serialVersionUID = -6826119882781771722L;
|
||||
|
||||
private final String statisticsMonitor = new String();
|
||||
@@ -551,16 +555,16 @@ public class DefaultAutoFetchManager implements AutoFetchManager, Serializable {
|
||||
|
||||
Statistics stats = getQueryPointStats(origin);
|
||||
|
||||
if (logging.isTraceUsageCollection()){
|
||||
System.out.println("... NodeUsageCollector "+usageCollector);
|
||||
}
|
||||
|
||||
stats.collectUsageInfo(usageCollector);
|
||||
|
||||
if (logging.isTraceUsageCollection()){
|
||||
System.out.println("stats\n"+stats);
|
||||
}
|
||||
}
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("... NodeUsageCollector " + usageCollector);
|
||||
}
|
||||
|
||||
stats.collectUsageInfo(usageCollector);
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("stats\n" + stats);
|
||||
}
|
||||
}
|
||||
|
||||
private Statistics getQueryPointStats(ObjectGraphOrigin originQueryPoint) {
|
||||
synchronized (statisticsMonitor) {
|
||||
|
||||
+5
-15
@@ -1,14 +1,12 @@
|
||||
package com.avaje.ebeaninternal.server.autofetch;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.querydefn.OrmQueryDetail;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Handles the logging aspects for the DefaultAutoFetchListener.
|
||||
@@ -23,15 +21,12 @@ public class DefaultAutoFetchManagerLogging {
|
||||
|
||||
private final DefaultAutoFetchManager manager;
|
||||
|
||||
private final boolean traceUsageCollection;
|
||||
|
||||
private final int updateFreqInSecs;
|
||||
|
||||
public DefaultAutoFetchManagerLogging(ServerConfig serverConfig, DefaultAutoFetchManager profileListener) {
|
||||
|
||||
this.manager = profileListener;
|
||||
this.traceUsageCollection = GlobalProperties.getBoolean("ebean.autofetch.traceUsageCollection", false);
|
||||
this.updateFreqInSecs = serverConfig.getAutofetchConfig().getProfileUpdateFrequency();
|
||||
this.updateFreqInSecs = serverConfig.getAutofetchConfig().getProfileUpdateFrequency();
|
||||
}
|
||||
|
||||
public void init(SpiEbeanServer ebeanServer) {
|
||||
@@ -69,9 +64,4 @@ public class DefaultAutoFetchManagerLogging {
|
||||
String msg = tunedFetch.getLogOutput(null);
|
||||
logger.debug(msg);
|
||||
}
|
||||
|
||||
public boolean isTraceUsageCollection() {
|
||||
return traceUsageCollection;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-4
@@ -40,10 +40,13 @@ public class DefaultServerCacheManager implements ServerCacheManager {
|
||||
cacheFactory.init(server);
|
||||
this.ebeanServer = (SpiEbeanServer)server;
|
||||
}
|
||||
|
||||
public void setCaching(Class<?> beanType, boolean useCache) {
|
||||
ebeanServer.getBeanDescriptor(beanType).getCacheOptions().setUseCache(useCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set bean caching on or off for a given bean type.
|
||||
*/
|
||||
public void setCaching(Class<?> beanType, boolean useCache) {
|
||||
ebeanServer.getBeanDescriptor(beanType).setUseCache(useCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear both the bean cache and the query cache for a
|
||||
|
||||
@@ -17,9 +17,6 @@ import java.io.DataOutputStream;
|
||||
* be common for many Ack, Resend and Control messages to all be contained in a
|
||||
* single packet.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
*/
|
||||
public class BinaryMessage {
|
||||
|
||||
@@ -28,8 +25,7 @@ public class BinaryMessage {
|
||||
public static final int TYPE_TABLEIUD = 2;
|
||||
public static final int TYPE_BEANDELTA = 3;
|
||||
public static final int TYPE_BEANPATHUPDATE = 4;
|
||||
public static final int TYPE_INDEX_INVALIDATE = 6;
|
||||
public static final int TYPE_INDEX = 7;
|
||||
|
||||
public static final int TYPE_MSGACK = 8;
|
||||
public static final int TYPE_MSGRESEND = 9;
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@ package com.avaje.ebeaninternal.server.cluster;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
import com.avaje.ebean.config.ContainerConfig;
|
||||
import com.avaje.ebeaninternal.server.cluster.mcast.McastClusterManager;
|
||||
import com.avaje.ebeaninternal.server.cluster.socket.SocketClusterBroadcast;
|
||||
import com.avaje.ebeaninternal.server.transaction.RemoteTransactionEvent;
|
||||
@@ -26,41 +25,36 @@ public class ClusterManager {
|
||||
|
||||
private boolean started;
|
||||
|
||||
public ClusterManager() {
|
||||
public ClusterManager(ContainerConfig containerConfig) {
|
||||
|
||||
String clusterType = GlobalProperties.get("ebean.cluster.type", null);
|
||||
if (clusterType == null || clusterType.trim().length() == 0) {
|
||||
// not clustering this instance
|
||||
this.broadcast = null;
|
||||
|
||||
} else {
|
||||
|
||||
try {
|
||||
if ("mcast".equalsIgnoreCase(clusterType)) {
|
||||
this.broadcast = new McastClusterManager();
|
||||
|
||||
} else if ("socket".equalsIgnoreCase(clusterType)) {
|
||||
this.broadcast = new SocketClusterBroadcast();
|
||||
|
||||
} else {
|
||||
logger.info("Clustering using [" + clusterType + "]");
|
||||
this.broadcast = (ClusterBroadcast) ClassUtil.newInstance(clusterType);
|
||||
ContainerConfig.ClusterMode mode = containerConfig.getMode();
|
||||
try {
|
||||
switch (mode) {
|
||||
case SOCKET: {
|
||||
this.broadcast = new SocketClusterBroadcast(containerConfig);
|
||||
break;
|
||||
}
|
||||
case MULTICAST: {
|
||||
this.broadcast = new McastClusterManager(containerConfig);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
this.broadcast = null;
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
String msg = "Error initialising ClusterManager type [" + clusterType + "]";
|
||||
logger.error(msg, e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Error initialising ClusterManager type [" + mode + "]", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerServer(EbeanServer server) {
|
||||
synchronized (monitor) {
|
||||
serverMap.put(server.getName(), server);
|
||||
if (!started) {
|
||||
startup();
|
||||
}
|
||||
serverMap.put(server.getName(), server);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.TransactionEventTable.TableIUD;
|
||||
import com.avaje.ebeaninternal.server.transaction.BeanDelta;
|
||||
import com.avaje.ebeaninternal.server.transaction.BeanPersistIds;
|
||||
import com.avaje.ebeaninternal.server.transaction.IndexEvent;
|
||||
import com.avaje.ebeaninternal.server.transaction.RemoteTransactionEvent;
|
||||
|
||||
/**
|
||||
@@ -16,7 +15,6 @@ import com.avaje.ebeaninternal.server.transaction.RemoteTransactionEvent;
|
||||
* Due to the hard limit for UDP packet sizes a RemoteTransactionEvent
|
||||
* is actually broken up into smaller messages.
|
||||
* </p>
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class PacketTransactionEvent extends Packet {
|
||||
|
||||
@@ -63,10 +61,6 @@ public class PacketTransactionEvent extends Packet {
|
||||
event.addBeanDelta(BeanDelta.readBinaryMessage(server, dataInput));
|
||||
break;
|
||||
|
||||
case BinaryMessage.TYPE_INDEX:
|
||||
event.addIndexEvent(IndexEvent.readBinaryMessage(dataInput));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Invalid Transaction msgType "+msgType);
|
||||
}
|
||||
|
||||
+41
-36
@@ -7,49 +7,54 @@ import java.util.List;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.transaction.RemoteTransactionEvent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Mechanism to convert RemoteTransactionEvent to/from byte[] content.
|
||||
*/
|
||||
public abstract class SerialiseTransactionHelper {
|
||||
|
||||
private final PacketWriter packetWriter;
|
||||
private static final Logger logger = LoggerFactory.getLogger(SerialiseTransactionHelper.class);
|
||||
|
||||
public SerialiseTransactionHelper() {
|
||||
packetWriter = new PacketWriter(Integer.MAX_VALUE);
|
||||
private final PacketWriter packetWriter;
|
||||
|
||||
public SerialiseTransactionHelper() {
|
||||
packetWriter = new PacketWriter(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
public abstract SpiEbeanServer getEbeanServer(String serverName);
|
||||
|
||||
/**
|
||||
* Convert the RemoteTransactionEvent to byte[] content.
|
||||
*/
|
||||
public DataHolder createDataHolder(RemoteTransactionEvent transEvent) throws IOException {
|
||||
|
||||
List<Packet> packetList = packetWriter.write(transEvent);
|
||||
if (packetList.size() != 1) {
|
||||
throw new RuntimeException("Always expecting 1 Packet but got " + packetList.size());
|
||||
}
|
||||
byte[] data = packetList.get(0).getBytes();
|
||||
return new DataHolder(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the byte[] content to RemoteTransactionEvent.
|
||||
*/
|
||||
public RemoteTransactionEvent read(DataHolder dataHolder) throws IOException {
|
||||
|
||||
ByteArrayInputStream bi = new ByteArrayInputStream(dataHolder.getData());
|
||||
DataInputStream dataInput = new DataInputStream(bi);
|
||||
|
||||
Packet header = Packet.readHeader(dataInput);
|
||||
|
||||
SpiEbeanServer server = getEbeanServer(header.getServerName());
|
||||
if (server == null) {
|
||||
logger.error("server [{}] not found/registered?", header.getServerName());
|
||||
}
|
||||
|
||||
public abstract SpiEbeanServer getEbeanServer(String serverName);
|
||||
|
||||
/**
|
||||
* Convert the RemoteTransactionEvent to byte[] content.
|
||||
*/
|
||||
public DataHolder createDataHolder(RemoteTransactionEvent transEvent) throws IOException {
|
||||
|
||||
List<Packet> packetList = packetWriter.write(transEvent);
|
||||
if (packetList.size() != 1) {
|
||||
throw new RuntimeException("Always expecting 1 Packet but got " + packetList.size());
|
||||
}
|
||||
byte[] data = packetList.get(0).getBytes();
|
||||
return new DataHolder(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the byte[] content to RemoteTransactionEvent.
|
||||
*/
|
||||
public RemoteTransactionEvent read(DataHolder dataHolder) throws IOException {
|
||||
|
||||
ByteArrayInputStream bi = new ByteArrayInputStream(dataHolder.getData());
|
||||
DataInputStream dataInput = new DataInputStream(bi);
|
||||
|
||||
Packet header = Packet.readHeader(dataInput);
|
||||
|
||||
SpiEbeanServer server = getEbeanServer(header.getServerName());
|
||||
|
||||
PacketTransactionEvent tranEventPacket = PacketTransactionEvent.forRead(header, server);
|
||||
tranEventPacket.read(dataInput);
|
||||
|
||||
return tranEventPacket.getEvent();
|
||||
|
||||
}
|
||||
PacketTransactionEvent tranEventPacket = PacketTransactionEvent.forRead(header, server);
|
||||
tranEventPacket.read(dataInput);
|
||||
return tranEventPacket.getEvent();
|
||||
}
|
||||
}
|
||||
|
||||
+494
-515
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,12 @@
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.cluster.Packet;
|
||||
import com.avaje.ebeaninternal.server.cluster.PacketTransactionEvent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataInputStream;
|
||||
@@ -28,13 +34,6 @@ import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.MulticastSocket;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.cluster.Packet;
|
||||
import com.avaje.ebeaninternal.server.cluster.PacketTransactionEvent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Listens for Incoming packets.
|
||||
*
|
||||
@@ -56,8 +55,6 @@ public class McastListener implements Runnable {
|
||||
|
||||
private final InetAddress group;
|
||||
|
||||
private final boolean debugIgnore;
|
||||
|
||||
private DatagramPacket pack;
|
||||
|
||||
private byte[] receiveBuffer;
|
||||
@@ -73,8 +70,6 @@ public class McastListener implements Runnable {
|
||||
int bufferSize, int timeout, String localSenderHostPort,
|
||||
boolean disableLoopback, int ttl, InetAddress mcastBindAddress) {
|
||||
|
||||
this.debugIgnore = GlobalProperties.getBoolean("ebean.debug.mcast.ignore", false);
|
||||
|
||||
this.owner = owner;
|
||||
this.packetControl = packetControl;
|
||||
this.localSenderHostPort = localSenderHostPort;
|
||||
@@ -96,7 +91,7 @@ public class McastListener implements Runnable {
|
||||
this.sock.setSoTimeout(timeout);
|
||||
|
||||
if (disableLoopback){
|
||||
sock.setLoopbackMode(disableLoopback);
|
||||
sock.setLoopbackMode(true);
|
||||
}
|
||||
|
||||
if (mcastBindAddress != null) {
|
||||
@@ -173,7 +168,7 @@ public class McastListener implements Runnable {
|
||||
String senderHostPort = senderAddr.getAddress().getHostAddress()+":"+senderAddr.getPort();
|
||||
|
||||
if (senderHostPort.equals(localSenderHostPort)){
|
||||
if (debugIgnore || logger.isDebugEnabled()){
|
||||
if (logger.isTraceEnabled()){
|
||||
logger.info("Ignoring message as sent by localSender: "+localSenderHostPort);
|
||||
}
|
||||
} else {
|
||||
@@ -195,7 +190,7 @@ public class McastListener implements Runnable {
|
||||
boolean processThisPacket = ackMsg || packetControl.isProcessPacket(senderHostPort, header.getPacketId());
|
||||
|
||||
if (!processThisPacket){
|
||||
if (debugIgnore || logger.isDebugEnabled()){
|
||||
if (logger.isTraceEnabled()){
|
||||
logger.info("Already processed packet: "+header.getPacketId()+" type:"+header.getPacketType()+" len:"+data.length);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -21,15 +21,18 @@ class RequestProcessor implements Runnable {
|
||||
private final Socket clientSocket;
|
||||
|
||||
private final SocketClusterBroadcast owner;
|
||||
|
||||
/**
|
||||
|
||||
private final String hostPort;
|
||||
|
||||
/**
|
||||
* Create including the Listener (used to lookup the Request Handler) and
|
||||
* the socket itself.
|
||||
*/
|
||||
public RequestProcessor(SocketClusterBroadcast owner, Socket clientSocket) {
|
||||
this.clientSocket = clientSocket;
|
||||
this.owner = owner;
|
||||
}
|
||||
this.hostPort = owner.getHostPort();
|
||||
}
|
||||
|
||||
/**
|
||||
* This will parse out the command. Lookup the appropriate Handler and
|
||||
@@ -39,22 +42,20 @@ class RequestProcessor implements Runnable {
|
||||
*/
|
||||
public void run() {
|
||||
try {
|
||||
SocketConnection sc = new SocketConnection(clientSocket);
|
||||
|
||||
while(true){
|
||||
if (owner.process(sc)) {
|
||||
// got the offline message or timeout
|
||||
break;
|
||||
}
|
||||
}
|
||||
sc.disconnect();
|
||||
|
||||
} catch (IOException e) {
|
||||
logger.error(null, e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
logger.error(null, e);
|
||||
logger.trace("start listening for cluster messages");
|
||||
SocketConnection sc = new SocketConnection(clientSocket);
|
||||
while (true) {
|
||||
if (owner.process(sc)) {
|
||||
// got the offline message or timeout
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.trace("disconnecting: {}", hostPort);
|
||||
sc.disconnect();
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Error listening for messages - "+owner.getHostPort(), e);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
@@ -35,6 +35,10 @@ class SocketClient {
|
||||
this.hostPort = address.getHostName()+":"+address.getPort();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return address.toString();
|
||||
}
|
||||
|
||||
public String getHostPort() {
|
||||
return hostPort;
|
||||
}
|
||||
|
||||
+217
-209
@@ -1,248 +1,256 @@
|
||||
package com.avaje.ebeaninternal.server.cluster.socket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebean.config.ContainerConfig;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.cluster.ClusterBroadcast;
|
||||
import com.avaje.ebeaninternal.server.cluster.ClusterManager;
|
||||
import com.avaje.ebeaninternal.server.cluster.DataHolder;
|
||||
import com.avaje.ebeaninternal.server.cluster.SerialiseTransactionHelper;
|
||||
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
||||
import com.avaje.ebeaninternal.server.transaction.RemoteTransactionEvent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Broadcast messages across the cluster using sockets.
|
||||
* Broadcast messages across the cluster using sockets.
|
||||
*/
|
||||
public class SocketClusterBroadcast implements ClusterBroadcast {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SocketClusterBroadcast.class);
|
||||
|
||||
private final SocketClient local;
|
||||
|
||||
private final HashMap<String,SocketClient> clientMap;
|
||||
|
||||
private final SocketClusterListener listener;
|
||||
|
||||
private SocketClient[] members;
|
||||
private static final Logger logger = LoggerFactory.getLogger(SocketClusterBroadcast.class);
|
||||
|
||||
private ClusterManager clusterManager;
|
||||
private final SocketClient local;
|
||||
|
||||
private final TxnSerialiseHelper txnSerialiseHelper = new TxnSerialiseHelper();
|
||||
|
||||
private final AtomicInteger txnOutgoing = new AtomicInteger();
|
||||
private final AtomicInteger txnIncoming = new AtomicInteger();
|
||||
|
||||
|
||||
public SocketClusterBroadcast( ){
|
||||
|
||||
String localHostPort = GlobalProperties.get("ebean.cluster.local", null);
|
||||
String members = GlobalProperties.get("ebean.cluster.members", null);
|
||||
private final HashMap<String, SocketClient> clientMap;
|
||||
|
||||
logger.info("Clustering using Sockets local["+localHostPort+"] members["+members+"]");
|
||||
|
||||
this.local = new SocketClient(parseFullName(localHostPort));
|
||||
this.clientMap = new HashMap<String, SocketClient>();
|
||||
|
||||
String[] memArray = StringHelper.delimitedToArray(members, ",", false);
|
||||
for (int i = 0; i < memArray.length; i++) {
|
||||
InetSocketAddress member = parseFullName(memArray[i]);
|
||||
SocketClient client = new SocketClient(member);
|
||||
if (!local.getHostPort().equalsIgnoreCase(client.getHostPort())) {
|
||||
// don't add the local one ...
|
||||
clientMap.put(client.getHostPort(), client);
|
||||
}
|
||||
}
|
||||
|
||||
this.members = clientMap.values().toArray(new SocketClient[clientMap.size()]);
|
||||
this.listener = new SocketClusterListener(this, local.getPort());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current status of this instance.
|
||||
*/
|
||||
public SocketClusterStatus getStatus() {
|
||||
|
||||
// count of online members
|
||||
int currentGroupSize = 0;
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
if (members[i].isOnline()) {
|
||||
++currentGroupSize;
|
||||
}
|
||||
}
|
||||
int txnIn = txnIncoming.get();
|
||||
int txnOut = txnOutgoing.get();
|
||||
|
||||
return new SocketClusterStatus(currentGroupSize, txnIn, txnOut);
|
||||
}
|
||||
|
||||
public void startup(ClusterManager clusterManager) {
|
||||
|
||||
this.clusterManager = clusterManager;
|
||||
try {
|
||||
listener.startListening();
|
||||
register();
|
||||
private final SocketClusterListener listener;
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new PersistenceException(e);
|
||||
}
|
||||
private SocketClient[] members;
|
||||
|
||||
private ClusterManager clusterManager;
|
||||
|
||||
private final TxnSerialiseHelper txnSerialiseHelper = new TxnSerialiseHelper();
|
||||
|
||||
private final AtomicInteger txnOutgoing = new AtomicInteger();
|
||||
private final AtomicInteger txnIncoming = new AtomicInteger();
|
||||
|
||||
public SocketClusterBroadcast(ContainerConfig containerConfig) {
|
||||
|
||||
ContainerConfig.SocketConfig socketConfig = containerConfig.getSocketConfig();
|
||||
|
||||
String localHostPort = socketConfig.getLocalHostPort();
|
||||
List<String> members = socketConfig.getMembers();
|
||||
|
||||
logger.info("Clustering using Sockets local[" + localHostPort + "] members[" + members + "]");
|
||||
|
||||
this.local = new SocketClient(parseFullName(localHostPort));
|
||||
this.clientMap = new HashMap<String, SocketClient>();
|
||||
|
||||
for (String memberHostPort : members) {
|
||||
InetSocketAddress member = parseFullName(memberHostPort);
|
||||
SocketClient client = new SocketClient(member);
|
||||
if (!local.getHostPort().equalsIgnoreCase(client.getHostPort())) {
|
||||
// don't add the local one ...
|
||||
clientMap.put(client.getHostPort(), client);
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
deregister();
|
||||
listener.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register with all the other members of the Cluster.
|
||||
*/
|
||||
private void register() {
|
||||
this.members = clientMap.values().toArray(new SocketClient[clientMap.size()]);
|
||||
this.listener = new SocketClusterListener(this, local.getPort(), socketConfig.getCoreThreads(), socketConfig.getMaxThreads(), socketConfig.getThreadPoolName());
|
||||
}
|
||||
|
||||
SocketClusterMessage h = SocketClusterMessage.register(local.getHostPort(), true);
|
||||
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
boolean online = members[i].register(h);
|
||||
|
||||
String msg = "Cluster Member ["+members[i].getHostPort()+"] online["+online+"]";
|
||||
logger.info(msg);
|
||||
}
|
||||
public String getHostPort() {
|
||||
return local.getHostPort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current status of this instance.
|
||||
*/
|
||||
public SocketClusterStatus getStatus() {
|
||||
|
||||
// count of online members
|
||||
int currentGroupSize = 0;
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
if (members[i].isOnline()) {
|
||||
++currentGroupSize;
|
||||
}
|
||||
}
|
||||
int txnIn = txnIncoming.get();
|
||||
int txnOut = txnOutgoing.get();
|
||||
|
||||
protected void setMemberOnline(String fullName, boolean online) throws IOException {
|
||||
synchronized (clientMap) {
|
||||
String msg = "Cluster Member ["+fullName+"] online["+online+"]";
|
||||
logger.info(msg);
|
||||
SocketClient member = clientMap.get(fullName);
|
||||
member.setOnline(online);
|
||||
}
|
||||
return new SocketClusterStatus(currentGroupSize, txnIn, txnOut);
|
||||
}
|
||||
|
||||
public void startup(ClusterManager clusterManager) {
|
||||
|
||||
this.clusterManager = clusterManager;
|
||||
try {
|
||||
listener.startListening();
|
||||
register();
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new PersistenceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void send(SocketClient client, SocketClusterMessage msg) {
|
||||
public void shutdown() {
|
||||
deregister();
|
||||
listener.shutdown();
|
||||
}
|
||||
|
||||
try {
|
||||
// alternative would be to connect/disconnect here
|
||||
// but prefer to use keepalive
|
||||
client.send(msg);
|
||||
|
||||
} catch (Exception ex){
|
||||
logger.error("Error sending message", ex);
|
||||
try {
|
||||
client.reconnect();
|
||||
} catch (IOException e) {
|
||||
logger.error("Error trying to reconnect", ex);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Register with all the other members of the Cluster.
|
||||
*/
|
||||
private void register() {
|
||||
|
||||
SocketClusterMessage h = SocketClusterMessage.register(local.getHostPort(), true);
|
||||
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
boolean online = members[i].register(h);
|
||||
logger.info("Cluster Member [{}] online[{}]", members[i].getHostPort(), online);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the payload to all the members of the cluster.
|
||||
*/
|
||||
public void broadcast(RemoteTransactionEvent remoteTransEvent) {
|
||||
try {
|
||||
|
||||
txnOutgoing.incrementAndGet();
|
||||
DataHolder dataHolder = txnSerialiseHelper.createDataHolder(remoteTransEvent);
|
||||
SocketClusterMessage msg = SocketClusterMessage.transEvent(dataHolder);
|
||||
broadcast(msg);
|
||||
} catch (Exception e){
|
||||
String msg = "Error sending RemoteTransactionEvent "+remoteTransEvent+" to cluster members.";
|
||||
logger.error(msg, e);
|
||||
}
|
||||
protected void setMemberOnline(String fullName, boolean online) throws IOException {
|
||||
synchronized (clientMap) {
|
||||
logger.info("Cluster Member [{}] online[{}]", fullName, online);
|
||||
SocketClient member = clientMap.get(fullName);
|
||||
member.setOnline(online);
|
||||
}
|
||||
}
|
||||
|
||||
protected void broadcast(SocketClusterMessage msg) {
|
||||
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
send(members[i], msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Leave the cluster.
|
||||
*/
|
||||
private void deregister() {
|
||||
|
||||
SocketClusterMessage h = SocketClusterMessage.register(local.getHostPort(), false);
|
||||
broadcast(h);
|
||||
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
members[i].disconnect();
|
||||
}
|
||||
}
|
||||
private void send(SocketClient client, SocketClusterMessage msg) {
|
||||
|
||||
/**
|
||||
* Process a Cluster message.
|
||||
*/
|
||||
protected boolean process(SocketConnection request) throws IOException, ClassNotFoundException {
|
||||
try {
|
||||
// alternative would be to connect/disconnect here but prefer to use keepalive
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("... send to member {} broadcast msg: {}", client, msg);
|
||||
}
|
||||
client.send(msg);
|
||||
|
||||
try {
|
||||
SocketClusterMessage h = (SocketClusterMessage)request.readObject();
|
||||
|
||||
if (h.isRegisterEvent()){
|
||||
setMemberOnline(h.getRegisterHost(), h.isRegister());
|
||||
|
||||
} else {
|
||||
txnIncoming.incrementAndGet();
|
||||
DataHolder dataHolder = h.getDataHolder();
|
||||
RemoteTransactionEvent transEvent = txnSerialiseHelper.read(dataHolder);
|
||||
transEvent.run();
|
||||
}
|
||||
|
||||
if (h.isRegisterEvent() && !h.isRegister()){
|
||||
// instance shutting down
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (InterruptedIOException e) {
|
||||
String msg = "Timeout waiting for message";
|
||||
logger.info(msg, e);
|
||||
try {
|
||||
request.disconnect();
|
||||
} catch (IOException ex){
|
||||
logger.info("Error disconnecting after timeout", ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.error("Error sending message", ex);
|
||||
try {
|
||||
client.reconnect();
|
||||
} catch (IOException e) {
|
||||
logger.error("Error trying to reconnect", ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a host:port into a InetSocketAddress.
|
||||
*/
|
||||
private InetSocketAddress parseFullName(String hostAndPort) {
|
||||
|
||||
try {
|
||||
hostAndPort = hostAndPort.trim();
|
||||
int colonPos = hostAndPort.indexOf(":");
|
||||
if (colonPos == -1) {
|
||||
String msg = "No colon \":\" in "+hostAndPort;
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
String host = hostAndPort.substring(0, colonPos);
|
||||
String sPort = hostAndPort.substring(colonPos + 1, hostAndPort.length());
|
||||
int port = Integer.parseInt(sPort);
|
||||
|
||||
return new InetSocketAddress(host, port);
|
||||
|
||||
} catch (Exception ex){
|
||||
throw new RuntimeException("Error parsing ["+hostAndPort+"] for the form [host:port]", ex);
|
||||
}
|
||||
/**
|
||||
* Send the payload to all the members of the cluster.
|
||||
*/
|
||||
public void broadcast(RemoteTransactionEvent remoteTransEvent) {
|
||||
try {
|
||||
txnOutgoing.incrementAndGet();
|
||||
DataHolder dataHolder = txnSerialiseHelper.createDataHolder(remoteTransEvent);
|
||||
SocketClusterMessage msg = SocketClusterMessage.transEvent(dataHolder);
|
||||
broadcast(msg);
|
||||
} catch (Exception e) {
|
||||
logger.error("Error sending RemoteTransactionEvent " + remoteTransEvent + " to cluster members.", e);
|
||||
}
|
||||
|
||||
class TxnSerialiseHelper extends SerialiseTransactionHelper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpiEbeanServer getEbeanServer(String serverName) {
|
||||
return (SpiEbeanServer)clusterManager.getServer(serverName);
|
||||
}
|
||||
protected void broadcast(SocketClusterMessage msg) {
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("... broadcast msg: "+msg);
|
||||
}
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
send(members[i], msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Leave the cluster.
|
||||
*/
|
||||
private void deregister() {
|
||||
|
||||
SocketClusterMessage h = SocketClusterMessage.register(local.getHostPort(), false);
|
||||
broadcast(h);
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
members[i].disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an incoming Cluster message.
|
||||
*/
|
||||
protected boolean process(SocketConnection request) throws IOException, ClassNotFoundException {
|
||||
|
||||
try {
|
||||
SocketClusterMessage h = (SocketClusterMessage) request.readObject();
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("... received msg: {}", h);
|
||||
}
|
||||
|
||||
if (h.isRegisterEvent()) {
|
||||
setMemberOnline(h.getRegisterHost(), h.isRegister());
|
||||
|
||||
} else {
|
||||
txnIncoming.incrementAndGet();
|
||||
DataHolder dataHolder = h.getDataHolder();
|
||||
RemoteTransactionEvent transEvent = txnSerialiseHelper.read(dataHolder);
|
||||
transEvent.run();
|
||||
}
|
||||
|
||||
// instance shutting down
|
||||
return h.isRegisterEvent() && !h.isRegister();
|
||||
|
||||
} catch (InterruptedIOException e) {
|
||||
logger.info("Timeout waiting for message", e);
|
||||
try {
|
||||
request.disconnect();
|
||||
} catch (IOException ex) {
|
||||
logger.info("Error disconnecting after timeout", ex);
|
||||
}
|
||||
return true;
|
||||
|
||||
} catch (EOFException e) {
|
||||
logger.info("EOF disconnecting");
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
logger.info("IO Error waiting/reading message", e);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a host:port into a InetSocketAddress.
|
||||
*/
|
||||
private InetSocketAddress parseFullName(String hostAndPort) {
|
||||
|
||||
try {
|
||||
hostAndPort = hostAndPort.trim();
|
||||
int colonPos = hostAndPort.indexOf(":");
|
||||
if (colonPos == -1) {
|
||||
String msg = "No colon \":\" in " + hostAndPort;
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
String host = hostAndPort.substring(0, colonPos);
|
||||
String sPort = hostAndPort.substring(colonPos + 1, hostAndPort.length());
|
||||
int port = Integer.parseInt(sPort);
|
||||
|
||||
return new InetSocketAddress(host, port);
|
||||
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("Error parsing [" + hostAndPort + "] for the form [host:port]", ex);
|
||||
}
|
||||
}
|
||||
|
||||
class TxnSerialiseHelper extends SerialiseTransactionHelper {
|
||||
|
||||
@Override
|
||||
public SpiEbeanServer getEbeanServer(String serverName) {
|
||||
return (SpiEbeanServer) clusterManager.getServer(serverName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+99
-122
@@ -6,10 +6,10 @@ import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
|
||||
import com.avaje.ebeaninternal.server.lib.DaemonThreadPool;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebeaninternal.server.lib.thread.ThreadPool;
|
||||
|
||||
/**
|
||||
* Serverside multithreaded socket listener. Accepts connections and dispatches
|
||||
@@ -26,141 +26,118 @@ import com.avaje.ebeaninternal.server.lib.thread.ThreadPool;
|
||||
*/
|
||||
class SocketClusterListener implements Runnable {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SocketClusterListener.class);
|
||||
|
||||
/**
|
||||
* The port the SocketListener uses.
|
||||
*/
|
||||
private final int port;
|
||||
private static final Logger logger = LoggerFactory.getLogger(SocketClusterListener.class);
|
||||
|
||||
/**
|
||||
* The length of the socket accept timeout.
|
||||
*/
|
||||
private final int listenTimeout = 60000;
|
||||
/**
|
||||
* The server socket used to listen for requests.
|
||||
*/
|
||||
private final ServerSocket serverListenSocket;
|
||||
|
||||
/**
|
||||
* The server socket used to listen for requests.
|
||||
*/
|
||||
private final ServerSocket serverListenSocket;
|
||||
/**
|
||||
* The listening thread.
|
||||
*/
|
||||
private final Thread listenerThread;
|
||||
|
||||
/**
|
||||
* The listening thread.
|
||||
*/
|
||||
private final Thread listenerThread;
|
||||
/**
|
||||
* The pool of threads that actually do the parsing execution of requests.
|
||||
*/
|
||||
private final DaemonThreadPool threadPool;
|
||||
|
||||
/**
|
||||
* The pool of threads that actually do the parsing execution of requests.
|
||||
*/
|
||||
private final ThreadPool threadPool;
|
||||
private final SocketClusterBroadcast owner;
|
||||
|
||||
private final SocketClusterBroadcast owner;
|
||||
/**
|
||||
* shutting down flag.
|
||||
*/
|
||||
boolean doingShutdown;
|
||||
|
||||
/**
|
||||
* shutting down flag.
|
||||
*/
|
||||
boolean doingShutdown;
|
||||
/**
|
||||
* Whether the listening thread is busy assigning a request to a thread.
|
||||
*/
|
||||
boolean isActive;
|
||||
|
||||
/**
|
||||
* Whether the listening thread is busy assigning a request to a thread.
|
||||
*/
|
||||
boolean isActive;
|
||||
/**
|
||||
* Construct with a given thread pool name.
|
||||
*/
|
||||
public SocketClusterListener(SocketClusterBroadcast owner, int port, int coreThreads, int maxThreads, String poolName) {
|
||||
this.owner = owner;
|
||||
this.threadPool = new DaemonThreadPool(coreThreads, maxThreads, 60, 30, poolName);
|
||||
try {
|
||||
this.serverListenSocket = new ServerSocket(port);
|
||||
this.serverListenSocket.setSoTimeout(60000);
|
||||
this.listenerThread = new Thread(this, "EbeanClusterListener");
|
||||
|
||||
/**
|
||||
* Construct with a given thread pool name.
|
||||
*/
|
||||
public SocketClusterListener(SocketClusterBroadcast owner, int port) {
|
||||
this.owner = owner;
|
||||
this.threadPool = ThreadPool.createThreadPool("EbeanCluster");
|
||||
this.port = port;
|
||||
|
||||
try {
|
||||
this.serverListenSocket = new ServerSocket(port);
|
||||
this.serverListenSocket.setSoTimeout(listenTimeout);
|
||||
this.listenerThread = new Thread(this, "EbeanClusterListener");
|
||||
|
||||
} catch (IOException e){
|
||||
String msg = "Error starting cluster socket listener on port "+port;
|
||||
throw new RuntimeException(msg,e);
|
||||
} catch (IOException e) {
|
||||
String msg = "Error starting cluster socket listener on port " + port;
|
||||
throw new RuntimeException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start listening for requests.
|
||||
*/
|
||||
public void startListening() throws IOException {
|
||||
logger.trace("... startListening()");
|
||||
this.listenerThread.setDaemon(true);
|
||||
this.listenerThread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown this listener.
|
||||
*/
|
||||
public void shutdown() {
|
||||
doingShutdown = true;
|
||||
try {
|
||||
if (isActive) {
|
||||
synchronized (listenerThread) {
|
||||
try {
|
||||
listenerThread.wait(1000);
|
||||
} catch (InterruptedException e) {
|
||||
// OK to ignore as expected to Interrupt for shutdown.
|
||||
}
|
||||
}
|
||||
}
|
||||
listenerThread.interrupt();
|
||||
serverListenSocket.close();
|
||||
} catch (IOException e) {
|
||||
logger.error("Error shutting down listener", e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the port the listener is using.
|
||||
*/
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
threadPool.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start listening for requests.
|
||||
*/
|
||||
public void startListening() throws IOException {
|
||||
this.listenerThread.setDaemon(true);
|
||||
this.listenerThread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown this listener.
|
||||
*/
|
||||
public void shutdown() {
|
||||
doingShutdown = true;
|
||||
try {
|
||||
if (isActive) {
|
||||
synchronized (listenerThread) {
|
||||
try {
|
||||
listenerThread.wait(1000);
|
||||
} catch (InterruptedException e) {
|
||||
// OK to ignore as expected to Interrupt for shutdown.
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
listenerThread.interrupt();
|
||||
serverListenSocket.close();
|
||||
} catch (IOException e) {
|
||||
logger.error("Error shutting down listener", e);
|
||||
/**
|
||||
* This is a runnable and so this must be public. Don't call this externally
|
||||
* but rather call the startListening() method.
|
||||
*/
|
||||
public void run() {
|
||||
// run in loop until doingShutdown is true...
|
||||
while (!doingShutdown) {
|
||||
try {
|
||||
synchronized (listenerThread) {
|
||||
Socket clientSocket = serverListenSocket.accept();
|
||||
isActive = true;
|
||||
|
||||
Runnable request = new RequestProcessor(owner, clientSocket);
|
||||
threadPool.execute(request);
|
||||
|
||||
isActive = false;
|
||||
}
|
||||
|
||||
threadPool.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a runnable and so this must be public. Don't call this externally
|
||||
* but rather call the startListening() method.
|
||||
*/
|
||||
public void run() {
|
||||
// run in loop until doingShutdown is true...
|
||||
while (!doingShutdown) {
|
||||
try {
|
||||
synchronized (listenerThread) {
|
||||
Socket clientSocket = serverListenSocket.accept();
|
||||
|
||||
isActive = true;
|
||||
|
||||
Runnable request = new RequestProcessor(owner, clientSocket);
|
||||
threadPool.assign(request, true);
|
||||
|
||||
isActive = false;
|
||||
}
|
||||
} catch (SocketException e) {
|
||||
if (doingShutdown) {
|
||||
String msg = "doingShutdown and accept threw:"+ e.getMessage();
|
||||
logger.info(msg);
|
||||
|
||||
} else {
|
||||
logger.error(null, e);
|
||||
}
|
||||
|
||||
} catch (InterruptedIOException e) {
|
||||
// this will happen when the server is very quiet.
|
||||
// that is, no requests
|
||||
logger.debug("Possibly expected due to accept timeout?" + e.getMessage());
|
||||
|
||||
} catch (IOException e) {
|
||||
// log it and continue in the loop...
|
||||
logger.error(null, e);
|
||||
}
|
||||
} catch (SocketException e) {
|
||||
if (doingShutdown) {
|
||||
logger.info("doingShutdown and accept threw:" + e.getMessage());
|
||||
} else {
|
||||
logger.error("Error while listening", e);
|
||||
}
|
||||
} catch (InterruptedIOException e) {
|
||||
// this will happen when the server is very quiet.
|
||||
// that is, no requests
|
||||
logger.debug("Possibly expected due to accept timeout? {}", e.getMessage());
|
||||
|
||||
} catch (IOException e) {
|
||||
// log it and continue in the loop...
|
||||
logger.error("IOException processing cluster message", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebeaninternal.server.util.ClassPathSearch;
|
||||
import com.avaje.ebeaninternal.server.util.ClassPathSearchFilter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Searches for interesting classes such as Entities, Embedded and ScalarTypes.
|
||||
*/
|
||||
@@ -20,17 +20,21 @@ public class BootupClassPathSearch {
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
private final List<String> packages;
|
||||
private final List<String> jars;
|
||||
|
||||
private final List<String> jars;
|
||||
|
||||
private BootupClasses bootupClasses;
|
||||
|
||||
private final String classPathReaderClassName;
|
||||
|
||||
/**
|
||||
* Construct and search for interesting classes.
|
||||
*/
|
||||
public BootupClassPathSearch(ClassLoader classLoader, List<String> packages, List<String> jars) {
|
||||
public BootupClassPathSearch(ClassLoader classLoader, List<String> packages, List<String> jars, String classPathReaderClassName) {
|
||||
this.classLoader = (classLoader == null) ? getClass().getClassLoader() : classLoader;
|
||||
this.packages = packages;
|
||||
this.jars = jars;
|
||||
this.classPathReaderClassName = classPathReaderClassName;
|
||||
}
|
||||
|
||||
public BootupClasses getBootupClasses() {
|
||||
@@ -57,7 +61,7 @@ public class BootupClassPathSearch {
|
||||
|
||||
ClassPathSearchFilter filter = createFilter();
|
||||
|
||||
ClassPathSearch finder = new ClassPathSearch(classLoader, filter, bc);
|
||||
ClassPathSearch finder = new ClassPathSearch(classLoader, filter, bc, classPathReaderClassName);
|
||||
|
||||
finder.findClasses();
|
||||
Set<String> jars = finder.getJarHits();
|
||||
|
||||
@@ -56,7 +56,7 @@ public class BootupClasses implements ClassPathSearchMatcher {
|
||||
private ArrayList<ServerConfigStartup> serverConfigStartupInstances = new ArrayList<ServerConfigStartup>();
|
||||
|
||||
private List<BeanPersistController> persistControllerInstances = new ArrayList<BeanPersistController>();
|
||||
private List<BeanPersistListener<?>> persistListenerInstances = new ArrayList<BeanPersistListener<?>>();
|
||||
private List<BeanPersistListener> persistListenerInstances = new ArrayList<BeanPersistListener>();
|
||||
private List<BeanQueryAdapter> queryAdapterInstances = new ArrayList<BeanQueryAdapter>();
|
||||
private List<TransactionEventListener> transactionEventListenerInstances = new ArrayList<TransactionEventListener>();
|
||||
|
||||
@@ -145,9 +145,9 @@ public class BootupClasses implements ClassPathSearchMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
public void addPersistListeners(List<BeanPersistListener<?>> listenerInstances) {
|
||||
public void addPersistListeners(List<BeanPersistListener> listenerInstances) {
|
||||
if (listenerInstances != null) {
|
||||
for (BeanPersistListener<?> l : listenerInstances) {
|
||||
for (BeanPersistListener l : listenerInstances) {
|
||||
this.persistListenerInstances.add(l);
|
||||
// don't automatically instantiate
|
||||
this.beanListenerList.remove(l.getClass());
|
||||
@@ -181,12 +181,12 @@ public class BootupClasses implements ClassPathSearchMatcher {
|
||||
return queryAdapterInstances;
|
||||
}
|
||||
|
||||
public List<BeanPersistListener<?>> getBeanPersistListeners() {
|
||||
public List<BeanPersistListener> getBeanPersistListeners() {
|
||||
// add class registered BeanPersistController to the
|
||||
// already created instances
|
||||
for (Class<?> cls : beanListenerList) {
|
||||
try {
|
||||
BeanPersistListener<?> newInstance = (BeanPersistListener<?>) cls.newInstance();
|
||||
BeanPersistListener newInstance = (BeanPersistListener) cls.newInstance();
|
||||
persistListenerInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanPersistController " + cls;
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
|
||||
|
||||
/**
|
||||
* Build a ServerConfig from ebean.properties.
|
||||
*/
|
||||
public class ConfigBuilder {
|
||||
|
||||
/**
|
||||
* Create a ServerConfig and load it from ebean.properties.
|
||||
*/
|
||||
public ServerConfig build(String serverName) {
|
||||
|
||||
ServerConfig config = new ServerConfig();
|
||||
config.setName(serverName);
|
||||
|
||||
config.loadFromProperties();
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -8,8 +8,6 @@ import com.avaje.ebeaninternal.server.lib.DaemonThreadPool;
|
||||
|
||||
/**
|
||||
* The default implementation of the BackgroundExecutor.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class DefaultBackgroundExecutor implements SpiBackgroundExecutor {
|
||||
|
||||
@@ -17,19 +15,21 @@ public class DefaultBackgroundExecutor implements SpiBackgroundExecutor {
|
||||
|
||||
private final DaemonScheduleThreadPool schedulePool;
|
||||
|
||||
/**
|
||||
* Construct the default implementation of BackgroundExecutor.
|
||||
*
|
||||
* @param mainPoolSize
|
||||
* the core size of the thread pool.
|
||||
* @param keepAliveSecs
|
||||
* the time in seconds idle threads are keep alive
|
||||
* @param shutdownWaitSeconds
|
||||
* the time in seconds allowed for the pool to shutdown nicely.
|
||||
* After this the pool is forced to shutdown.
|
||||
*/
|
||||
public DefaultBackgroundExecutor(int schedulePoolSize, int corePoolSize, long keepAliveSecs,int shutdownWaitSeconds, String namePrefix) {
|
||||
this.pool = new DaemonThreadPool(corePoolSize, keepAliveSecs, shutdownWaitSeconds, namePrefix);
|
||||
/**
|
||||
* Construct the default implementation of BackgroundExecutor.
|
||||
*
|
||||
* @param corePoolSize
|
||||
* the core size of the thread pool.
|
||||
* @param maximumPoolSize
|
||||
* the maximum pool size before jobs are queued
|
||||
* @param keepAliveSecs
|
||||
* the time in seconds idle threads are keep alive
|
||||
* @param shutdownWaitSeconds
|
||||
* the time in seconds allowed for the pool to shutdown nicely.
|
||||
* After this the pool is forced to shutdown.
|
||||
*/
|
||||
public DefaultBackgroundExecutor(int schedulePoolSize, int corePoolSize, int maximumPoolSize, long keepAliveSecs,int shutdownWaitSeconds, String namePrefix) {
|
||||
this.pool = new DaemonThreadPool(corePoolSize, maximumPoolSize, keepAliveSecs, shutdownWaitSeconds, namePrefix);
|
||||
this.schedulePool = new DaemonScheduleThreadPool(schedulePoolSize, shutdownWaitSeconds, namePrefix+"-periodic-");
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ public class DefaultBeanLoader {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Return a batch size that might be less than the requestedBatchSize.
|
||||
* <p>
|
||||
* This means we can have large and variable requestedBatchSizes.
|
||||
@@ -51,7 +51,7 @@ public class DefaultBeanLoader {
|
||||
* </p>
|
||||
*/
|
||||
private int getBatchSize(int batchSize) {
|
||||
|
||||
|
||||
if (batchSize == 1) {
|
||||
// there is only one bean/collection to load
|
||||
return 1;
|
||||
@@ -74,10 +74,10 @@ public class DefaultBeanLoader {
|
||||
}
|
||||
return batchSize;
|
||||
}
|
||||
|
||||
public void refreshMany(EntityBean parentBean, String propertyName) {
|
||||
refreshMany(parentBean, propertyName, null);
|
||||
}
|
||||
|
||||
public void refreshMany(EntityBean parentBean, String propertyName) {
|
||||
refreshMany(parentBean, propertyName, null);
|
||||
}
|
||||
|
||||
public void loadMany(LoadManyRequest loadRequest) {
|
||||
|
||||
@@ -113,7 +113,7 @@ public class DefaultBeanLoader {
|
||||
if (orderBy != null) {
|
||||
query.orderBy(orderBy);
|
||||
}
|
||||
|
||||
|
||||
String extraWhere = many.getExtraWhere();
|
||||
if (extraWhere != null) {
|
||||
// replace special ${ta} placeholder with the base table alias
|
||||
@@ -121,7 +121,7 @@ public class DefaultBeanLoader {
|
||||
String ew = StringHelper.replaceString(extraWhere, "${ta}", "t0");
|
||||
query.where().raw(ew);
|
||||
}
|
||||
|
||||
|
||||
query.setLazyLoadForParents(idList, many);
|
||||
many.addWhereParentIdIn(query, idList);
|
||||
|
||||
@@ -130,6 +130,11 @@ public class DefaultBeanLoader {
|
||||
String mode = loadRequest.isLazy() ? "+lazy" : "+query";
|
||||
query.setLoadDescription(mode, loadRequest.getDescription());
|
||||
|
||||
if (loadRequest.isLazy()) {
|
||||
// cascade the batch size (if set) for further lazy loading
|
||||
query.setLazyLoadBatchSize(loadRequest.getBatchSize());
|
||||
}
|
||||
|
||||
// potentially changes the joins and selected properties
|
||||
ctx.configureQuery(query);
|
||||
|
||||
@@ -153,7 +158,7 @@ public class DefaultBeanLoader {
|
||||
desc.cacheManyPropPut(many, bc, parentId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// log the query (for testing secondary queries)
|
||||
loadRequest.logSecondaryQuery(query);
|
||||
}
|
||||
@@ -163,18 +168,17 @@ public class DefaultBeanLoader {
|
||||
EntityBean parentBean = bc.getOwnerBean();
|
||||
String propertyName = bc.getPropertyName();
|
||||
|
||||
//ObjectGraphNode node = ctx == null ? null : ctx.getObjectGraphNode();
|
||||
|
||||
loadManyInternal(parentBean, propertyName, null, false, null, onlyIds);
|
||||
}
|
||||
|
||||
public void refreshMany(EntityBean parentBean, String propertyName, Transaction t) {
|
||||
loadManyInternal(parentBean, propertyName, t, true, null, false);
|
||||
}
|
||||
public void refreshMany(EntityBean parentBean, String propertyName, Transaction t) {
|
||||
loadManyInternal(parentBean, propertyName, t, true, null, false);
|
||||
}
|
||||
|
||||
private void loadManyInternal(EntityBean parentBean, String propertyName, Transaction t, boolean refresh, ObjectGraphNode node, boolean onlyIds) {
|
||||
private void loadManyInternal(EntityBean parentBean, String propertyName, Transaction t, boolean refresh,
|
||||
ObjectGraphNode node, boolean onlyIds) {
|
||||
|
||||
EntityBeanIntercept ebi = ((EntityBean) parentBean)._ebean_getIntercept();
|
||||
EntityBeanIntercept ebi = parentBean._ebean_getIntercept();
|
||||
PersistenceContext pc = ebi.getPersistenceContext();
|
||||
|
||||
BeanDescriptor<?> parentDesc = server.getBeanDescriptor(parentBean.getClass());
|
||||
@@ -182,7 +186,7 @@ public class DefaultBeanLoader {
|
||||
|
||||
BeanCollection<?> beanCollection = null;
|
||||
ExpressionList<?> filterMany = null;
|
||||
|
||||
|
||||
Object currentValue = many.getValue(parentBean);
|
||||
if (currentValue instanceof BeanCollection<?>) {
|
||||
beanCollection = (BeanCollection<?>) currentValue;
|
||||
@@ -199,7 +203,7 @@ public class DefaultBeanLoader {
|
||||
boolean useManyIdCache = beanCollection != null && parentDesc.isManyPropCaching();
|
||||
if (useManyIdCache) {
|
||||
Boolean readOnly = null;
|
||||
if (ebi != null && ebi.isReadOnly()) {
|
||||
if (ebi.isReadOnly()) {
|
||||
readOnly = Boolean.TRUE;
|
||||
}
|
||||
if (parentDesc.cacheManyPropLoad(many, beanCollection, parentId, readOnly)) {
|
||||
@@ -211,7 +215,7 @@ public class DefaultBeanLoader {
|
||||
|
||||
if (refresh) {
|
||||
// populate a new collection
|
||||
Object emptyCollection = many.createEmpty(false);
|
||||
BeanCollection<?> emptyCollection = many.createEmpty(parentBean);
|
||||
many.setValue(parentBean, emptyCollection);
|
||||
query.setLoadDescription("+refresh", null);
|
||||
} else {
|
||||
@@ -241,10 +245,8 @@ public class DefaultBeanLoader {
|
||||
query.setLazyLoadManyPath(many.getName());
|
||||
query.setPersistenceContext(pc);
|
||||
|
||||
if (ebi != null) {
|
||||
if (ebi.isReadOnly()) {
|
||||
query.setReadOnly(true);
|
||||
}
|
||||
if (ebi.isReadOnly()) {
|
||||
query.setReadOnly(true);
|
||||
}
|
||||
|
||||
server.findUnique(query, t);
|
||||
@@ -315,6 +317,11 @@ public class DefaultBeanLoader {
|
||||
String mode = loadRequest.isLazy() ? "+lazy" : "+query";
|
||||
query.setLoadDescription(mode, loadRequest.getDescription());
|
||||
|
||||
if (loadRequest.isLazy()) {
|
||||
// cascade the batch size (if set) for further lazy loading
|
||||
query.setLazyLoadBatchSize(loadRequest.getBatchSize());
|
||||
}
|
||||
|
||||
ctx.configureQuery(query, loadRequest.getLazyLoadProperty());
|
||||
|
||||
// make sure the query doesn't use the cache
|
||||
@@ -329,7 +336,7 @@ public class DefaultBeanLoader {
|
||||
|
||||
if (loadRequest.isLoadCache()) {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
desc.cacheBeanPutData((EntityBean)list.get(i));
|
||||
desc.cacheBeanPutData((EntityBean) list.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,48 +345,50 @@ public class DefaultBeanLoader {
|
||||
// necessary but allow processing to continue until it is accessed by client code
|
||||
ebis[i].checkLazyLoadFailure();
|
||||
}
|
||||
|
||||
|
||||
// log the query (for testing secondary queries)
|
||||
loadRequest.logSecondaryQuery(query);
|
||||
}
|
||||
|
||||
public void refresh(EntityBean bean) {
|
||||
refreshBeanInternal(bean, SpiQuery.Mode.REFRESH_BEAN, -1);
|
||||
}
|
||||
|
||||
public void loadBean(EntityBeanIntercept ebi) {
|
||||
refreshBeanInternal(ebi.getOwner(), SpiQuery.Mode.LAZYLOAD_BEAN, -1);
|
||||
}
|
||||
public void refresh(EntityBean bean) {
|
||||
refreshBeanInternal(bean, SpiQuery.Mode.REFRESH_BEAN, -1);
|
||||
}
|
||||
|
||||
public void loadBean(EntityBeanIntercept ebi) {
|
||||
refreshBeanInternal(ebi.getOwner(), SpiQuery.Mode.LAZYLOAD_BEAN, -1);
|
||||
}
|
||||
|
||||
private void refreshBeanInternal(EntityBean bean, SpiQuery.Mode mode, int embeddedOwnerIndex) {
|
||||
|
||||
EntityBeanIntercept ebi = ((EntityBean) bean)._ebean_getIntercept();;
|
||||
EntityBeanIntercept ebi = bean._ebean_getIntercept();
|
||||
PersistenceContext pc = ebi.getPersistenceContext();
|
||||
if (Mode.REFRESH_BEAN == mode) {
|
||||
// need a new PersistenceContext for REFRESH
|
||||
pc = null;
|
||||
}
|
||||
|
||||
BeanDescriptor<?> desc = server.getBeanDescriptor(bean.getClass());
|
||||
if (EntityType.EMBEDDED == desc.getEntityType()) {
|
||||
// lazy loading on an embedded bean property
|
||||
EntityBean embeddedOwner = (EntityBean)ebi.getEmbeddedOwner();
|
||||
EntityBean embeddedOwner = (EntityBean) ebi.getEmbeddedOwner();
|
||||
int ownerIndex = ebi.getEmbeddedOwnerIndex();
|
||||
|
||||
refreshBeanInternal(embeddedOwner, mode, ownerIndex);
|
||||
}
|
||||
|
||||
|
||||
Object id = desc.getId(bean);
|
||||
|
||||
if (pc == null) {
|
||||
// a reference with no existing persistenceContext
|
||||
pc = new DefaultPersistenceContext();
|
||||
pc.put(id, bean);
|
||||
if (ebi != null) {
|
||||
ebi.setPersistenceContext(pc);
|
||||
}
|
||||
ebi.setPersistenceContext(pc);
|
||||
}
|
||||
|
||||
if (embeddedOwnerIndex == -1) {
|
||||
if (SpiQuery.Mode.LAZYLOAD_BEAN.equals(mode) && desc.isBeanCaching()) {
|
||||
// lazy loading and the bean cache is active
|
||||
if (desc.cacheBeanLoad((EntityBean)bean, ebi, id)) {
|
||||
if (desc.cacheBeanLoad(bean, ebi, id)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -389,15 +398,13 @@ public class DefaultBeanLoader {
|
||||
}
|
||||
|
||||
SpiQuery<?> query = (SpiQuery<?>) server.createQuery(desc.getBeanType());
|
||||
if (ebi != null) {
|
||||
query.setLazyLoadProperty(ebi.getLazyLoadProperty());
|
||||
}
|
||||
query.setLazyLoadProperty(ebi.getLazyLoadProperty());
|
||||
|
||||
if (embeddedOwnerIndex > -1) {
|
||||
String embeddedBeanPropertyName = ebi.getProperty(embeddedOwnerIndex);
|
||||
query.select("id,"+embeddedBeanPropertyName);
|
||||
query.select("id," + embeddedBeanPropertyName);
|
||||
}
|
||||
|
||||
|
||||
// don't collect autoFetch usage profiling information
|
||||
// as we just copy the data out of these fetched beans
|
||||
// and put the data into the original bean
|
||||
@@ -415,7 +422,7 @@ public class DefaultBeanLoader {
|
||||
if (ebi.isReadOnly()) {
|
||||
query.setReadOnly(true);
|
||||
}
|
||||
|
||||
|
||||
if (SpiQuery.Mode.REFRESH_BEAN.equals(mode)) {
|
||||
// explicitly state to load all properties on REFRESH.
|
||||
// Lobs default to fetch lazy so this forces lobs to be
|
||||
@@ -429,5 +436,7 @@ public class DefaultBeanLoader {
|
||||
throw new EntityNotFoundException(msg);
|
||||
}
|
||||
|
||||
desc.resetManyProperties(dbBean);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,62 +1,10 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
import javax.management.InstanceAlreadyExistsException;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.ObjectName;
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.AdminAutofetch;
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.BeanState;
|
||||
import com.avaje.ebean.CallableSql;
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.ExpressionFactory;
|
||||
import com.avaje.ebean.Filter;
|
||||
import com.avaje.ebean.FutureIds;
|
||||
import com.avaje.ebean.FutureList;
|
||||
import com.avaje.ebean.FutureRowCount;
|
||||
import com.avaje.ebean.PagedList;
|
||||
import com.avaje.ebean.PagingList;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.QueryResultVisitor;
|
||||
import com.avaje.ebean.SqlFutureList;
|
||||
import com.avaje.ebean.SqlQuery;
|
||||
import com.avaje.ebean.SqlRow;
|
||||
import com.avaje.ebean.SqlUpdate;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.TxCallable;
|
||||
import com.avaje.ebean.TxIsolation;
|
||||
import com.avaje.ebean.TxRunnable;
|
||||
import com.avaje.ebean.TxScope;
|
||||
import com.avaje.ebean.TxType;
|
||||
import com.avaje.ebean.Update;
|
||||
import com.avaje.ebean.ValuePair;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.CallStack;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebean.*;
|
||||
import com.avaje.ebean.bean.*;
|
||||
import com.avaje.ebean.bean.PersistenceContext.WithOption;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.EncryptKeyManager;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.event.BeanPersistController;
|
||||
@@ -65,43 +13,16 @@ import com.avaje.ebean.meta.MetaBeanInfo;
|
||||
import com.avaje.ebean.meta.MetaInfoManager;
|
||||
import com.avaje.ebean.text.csv.CsvReader;
|
||||
import com.avaje.ebean.text.json.JsonContext;
|
||||
import com.avaje.ebeaninternal.api.LoadBeanRequest;
|
||||
import com.avaje.ebeaninternal.api.LoadManyRequest;
|
||||
import com.avaje.ebeaninternal.api.ScopeTrans;
|
||||
import com.avaje.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanPlugin;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.api.*;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery.Mode;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery.Type;
|
||||
import com.avaje.ebeaninternal.api.SpiSqlQuery;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.api.TransactionEventTable;
|
||||
import com.avaje.ebeaninternal.server.autofetch.AutoFetchManager;
|
||||
import com.avaje.ebeaninternal.server.ddl.DdlGenerator;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.DNativeQuery;
|
||||
import com.avaje.ebeaninternal.server.deploy.DeployNamedQuery;
|
||||
import com.avaje.ebeaninternal.server.deploy.DeployNamedUpdate;
|
||||
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.*;
|
||||
import com.avaje.ebeaninternal.server.el.ElFilter;
|
||||
import com.avaje.ebeaninternal.server.jmx.MAdminAutofetch;
|
||||
import com.avaje.ebeaninternal.server.lib.ShutdownManager;
|
||||
import com.avaje.ebeaninternal.server.query.CQuery;
|
||||
import com.avaje.ebeaninternal.server.query.CQueryEngine;
|
||||
import com.avaje.ebeaninternal.server.query.CallableQueryIds;
|
||||
import com.avaje.ebeaninternal.server.query.CallableQueryList;
|
||||
import com.avaje.ebeaninternal.server.query.CallableQueryRowCount;
|
||||
import com.avaje.ebeaninternal.server.query.CallableSqlQueryList;
|
||||
import com.avaje.ebeaninternal.server.query.LimitOffsetPagedList;
|
||||
import com.avaje.ebeaninternal.server.query.LimitOffsetPagingQuery;
|
||||
import com.avaje.ebeaninternal.server.query.QueryFutureIds;
|
||||
import com.avaje.ebeaninternal.server.query.QueryFutureList;
|
||||
import com.avaje.ebeaninternal.server.query.QueryFutureRowCount;
|
||||
import com.avaje.ebeaninternal.server.query.SqlQueryFutureList;
|
||||
import com.avaje.ebeaninternal.server.query.*;
|
||||
import com.avaje.ebeaninternal.server.querydefn.DefaultOrmQuery;
|
||||
import com.avaje.ebeaninternal.server.querydefn.DefaultOrmUpdate;
|
||||
import com.avaje.ebeaninternal.server.querydefn.DefaultRelationalQuery;
|
||||
@@ -112,6 +33,16 @@ import com.avaje.ebeaninternal.server.transaction.TransactionManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.TransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.util.ParamTypeHelper;
|
||||
import com.avaje.ebeaninternal.util.ParamTypeHelper.TypeInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.management.InstanceAlreadyExistsException;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.ObjectName;
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
/**
|
||||
* The default server side implementation of EbeanServer.
|
||||
@@ -163,7 +94,6 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
|
||||
private final CQueryEngine cqueryEngine;
|
||||
|
||||
//@Deprecated
|
||||
private DdlGenerator ddlGenerator;
|
||||
|
||||
private final ExpressionFactory expressionFactory;
|
||||
@@ -183,6 +113,11 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
*/
|
||||
private String mbeanName;
|
||||
|
||||
/**
|
||||
* The default PersistenceContextScope used if it is not explicitly set on a query.
|
||||
*/
|
||||
private final PersistenceContextScope defaultPersistenceContextScope;
|
||||
|
||||
/**
|
||||
* The MBeanServer Ebean is registered with.
|
||||
*/
|
||||
@@ -241,15 +176,16 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
this.cqueryEngine = config.getCQueryEngine();
|
||||
this.expressionFactory = config.getExpressionFactory();
|
||||
this.encryptKeyManager = serverConfig.getEncryptKeyManager();
|
||||
this.defaultPersistenceContextScope = serverConfig.getPersistenceContextScope();
|
||||
|
||||
this.beanDescriptorManager = config.getBeanDescriptorManager();
|
||||
beanDescriptorManager.setEbeanServer(this);
|
||||
|
||||
this.collectQueryOrigins = serverConfig.isCollectQueryOrigins();
|
||||
this.collectQueryStatsByNode = serverConfig.isCollectQueryStatsByNode();
|
||||
this.maxCallStack = GlobalProperties.getInt("ebean.maxCallStack", 5);
|
||||
this.maxCallStack = serverConfig.getMaxCallStack();
|
||||
|
||||
this.rollbackOnChecked = GlobalProperties.getBoolean("ebean.transaction.rollbackOnChecked", true);
|
||||
this.rollbackOnChecked = serverConfig.isTransactionRollbackOnChecked();
|
||||
this.transactionManager = config.getTransactionManager();
|
||||
this.transactionScopeManager = config.getTransactionScopeManager();
|
||||
|
||||
@@ -273,17 +209,14 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
|
||||
List<SpiEbeanPlugin> spiPlugins = new ArrayList<SpiEbeanPlugin>();
|
||||
|
||||
final Iterator<SpiEbeanPlugin> plugins = ServiceLoader.load(SpiEbeanPlugin.class).iterator();
|
||||
|
||||
while (plugins.hasNext()) {
|
||||
SpiEbeanPlugin plugin = plugins.next();
|
||||
for (SpiEbeanPlugin plugin : ServiceLoader.load(SpiEbeanPlugin.class)) {
|
||||
spiPlugins.add(plugin);
|
||||
plugin.setup(this, this.getDatabasePlatform(), config.getServerConfig());
|
||||
|
||||
if (plugin instanceof DdlGenerator) {
|
||||
// backwards compatible
|
||||
ddlGenerator = (DdlGenerator)plugin;
|
||||
}
|
||||
ddlGenerator = (DdlGenerator) plugin;
|
||||
}
|
||||
}
|
||||
|
||||
if (ddlGenerator == null) {
|
||||
@@ -677,6 +610,15 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
return (T) ref;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(TransactionCallback transactionCallback) {
|
||||
Transaction transaction = currentTransaction();
|
||||
if (transaction == null) {
|
||||
throw new PersistenceException("Not currently active transaction when trying to register transactionCallback");
|
||||
}
|
||||
transaction.register(transactionCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Transaction that is NOT stored in TransactionThreadLocal. Use
|
||||
* this when you want a thread to have a second independent transaction.
|
||||
@@ -1160,8 +1102,8 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
t = getCurrentServerTransaction();
|
||||
}
|
||||
PersistenceContext context = null;
|
||||
if (t != null) {
|
||||
// first look in the persistence context
|
||||
if (t != null && useTransactionPersistenceContext(query)) {
|
||||
// first look in the transaction scoped persistence context
|
||||
context = t.getPersistenceContext();
|
||||
if (context != null) {
|
||||
WithOption o = context.getWithOption(beanDescriptor.getBeanType(), query.getId());
|
||||
@@ -1184,7 +1126,22 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
// Hit the L2 bean cache
|
||||
return beanDescriptor.cacheBeanGet(query, context);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if transactions PersistenceContext should be used.
|
||||
*/
|
||||
private <T> boolean useTransactionPersistenceContext(SpiQuery<T> query) {
|
||||
return PersistenceContextScope.TRANSACTION.equals(getPersistenceContextScope(query));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the PersistenceContextScope to use defined at query or server level.
|
||||
*/
|
||||
public PersistenceContextScope getPersistenceContextScope(SpiQuery<?> query) {
|
||||
PersistenceContextScope scope = query.getPersistenceContextScope();
|
||||
return (scope != null) ? scope : defaultPersistenceContextScope;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T findId(Query<T> query, Transaction t) {
|
||||
|
||||
@@ -1360,49 +1317,17 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
SpiQuery<T> spiQuery = (SpiQuery<T>) query;
|
||||
spiQuery.setFutureFetch(true);
|
||||
|
||||
// transfer the persistence content from the transaction
|
||||
if (spiQuery.getPersistenceContext() == null) {
|
||||
if (t != null) {
|
||||
spiQuery.setPersistenceContext(((SpiTransaction) t).getPersistenceContext());
|
||||
} else {
|
||||
SpiTransaction st = getCurrentServerTransaction();
|
||||
if (st != null) {
|
||||
spiQuery.setPersistenceContext(st.getPersistenceContext());
|
||||
}
|
||||
}
|
||||
}
|
||||
// FutureList query always run in it's own persistence content
|
||||
spiQuery.setPersistenceContext(new DefaultPersistenceContext());
|
||||
|
||||
// Create a new transaction solely to execute the findList() at some future time
|
||||
Transaction newTxn = createTransaction();
|
||||
CallableQueryList<T> call = new CallableQueryList<T>(this, spiQuery, newTxn);
|
||||
QueryFutureList<T> queryFuture = new QueryFutureList<T>(call);
|
||||
backgroundExecutor.execute(queryFuture.getFutureTask());
|
||||
|
||||
return queryFuture;
|
||||
}
|
||||
|
||||
public <T> PagingList<T> findPagingList(Query<T> query, Transaction t, int pageSize) {
|
||||
|
||||
SpiQuery<T> spiQuery = (SpiQuery<T>) query;
|
||||
|
||||
// we want to use a single PersistenceContext to be used
|
||||
// for all the paging queries so we make sure there is a
|
||||
// PersistenceContext on the query
|
||||
PersistenceContext pc = spiQuery.getPersistenceContext();
|
||||
if (pc == null) {
|
||||
SpiTransaction currentTransaction = getCurrentServerTransaction();
|
||||
if (currentTransaction != null) {
|
||||
pc = currentTransaction.getPersistenceContext();
|
||||
}
|
||||
if (pc == null) {
|
||||
pc = new DefaultPersistenceContext();
|
||||
}
|
||||
spiQuery.setPersistenceContext(pc);
|
||||
}
|
||||
|
||||
return new LimitOffsetPagingQuery<T>(this, spiQuery, pageSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> PagedList<T> findPagedList(Query<T> query, Transaction transaction, int pageIndex, int pageSize) {
|
||||
|
||||
@@ -1413,12 +1338,27 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.LIST, query, t);
|
||||
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
request.findVisit(visitor);
|
||||
} finally {
|
||||
// do nothing - findVisit garuntee's cleanup of the transaction if required
|
||||
}
|
||||
request.initTransIfRequired();
|
||||
request.findVisit(visitor);
|
||||
// no try finally - findVisit guarantee's cleanup of the transaction if required
|
||||
}
|
||||
|
||||
public <T> void findEach(Query<T> query, QueryEachConsumer<T> consumer, Transaction t) {
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.LIST, query, t);
|
||||
|
||||
request.initTransIfRequired();
|
||||
request.findEach(consumer);
|
||||
// no try finally - findVisit guarantee's cleanup of the transaction if required
|
||||
}
|
||||
|
||||
public <T> void findEachWhile(Query<T> query, QueryEachWhileConsumer<T> consumer, Transaction t) {
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.LIST, query, t);
|
||||
|
||||
request.initTransIfRequired();
|
||||
request.findEachWhile(consumer);
|
||||
// no try finally - findVisit guarantee's cleanup of the transaction if required
|
||||
}
|
||||
|
||||
public <T> QueryIterator<T> findIterate(Query<T> query, Transaction t) {
|
||||
@@ -1542,7 +1482,7 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
|
||||
@Override
|
||||
public void markAsDirty(Object bean) {
|
||||
if (bean instanceof EntityBean == false) {
|
||||
if (!(bean instanceof EntityBean)) {
|
||||
throw new IllegalArgumentException("This bean is not an EntityBean?");
|
||||
}
|
||||
// mark the bean as dirty (so that an update will not get skipped)
|
||||
@@ -1650,7 +1590,7 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
if (bean == null) {
|
||||
throw new IllegalArgumentException(Message.msg("bean.isnull"));
|
||||
}
|
||||
if (bean instanceof EntityBean == false) {
|
||||
if (!(bean instanceof EntityBean)) {
|
||||
throw new IllegalArgumentException("Was expecting an EntityBean but got a "+bean.getClass());
|
||||
}
|
||||
return (EntityBean)bean;
|
||||
@@ -1959,10 +1899,7 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
public boolean isSupportedType(java.lang.reflect.Type genericType) {
|
||||
|
||||
TypeInfo typeInfo = ParamTypeHelper.getTypeInfo(genericType);
|
||||
if (typeInfo == null) {
|
||||
return false;
|
||||
}
|
||||
return getBeanDescriptor(typeInfo.getBeanType()) != null;
|
||||
return typeInfo != null && getBeanDescriptor(typeInfo.getBeanType()) != null;
|
||||
}
|
||||
|
||||
public Object getBeanId(Object bean) {
|
||||
@@ -2069,9 +2006,7 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
|
||||
// create the 'interesting' part of the stackTrace
|
||||
StackTraceElement[] finalTrace = new StackTraceElement[stackLength];
|
||||
for (int i = 0; i < stackLength; i++) {
|
||||
finalTrace[i] = stackTrace[i + startIndex];
|
||||
}
|
||||
System.arraycopy(stackTrace, 0 + startIndex, finalTrace, 0, stackLength);
|
||||
|
||||
if (stackLength < 1) {
|
||||
// this should not really happen
|
||||
|
||||
@@ -2,10 +2,7 @@ package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
@@ -13,6 +10,7 @@ import javax.management.MBeanServerFactory;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.avaje.ebean.config.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -21,11 +19,6 @@ import com.avaje.ebean.cache.ServerCacheFactory;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.cache.ServerCacheOptions;
|
||||
import com.avaje.ebean.common.BootupEbeanManager;
|
||||
import com.avaje.ebean.config.DataSourceConfig;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebean.config.PstmtDelegate;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.UnderscoreNamingConvention;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
@@ -38,7 +31,6 @@ import com.avaje.ebeaninternal.server.lib.ShutdownManager;
|
||||
import com.avaje.ebeaninternal.server.lib.sql.DataSourceAlert;
|
||||
import com.avaje.ebeaninternal.server.lib.sql.DataSourcePool;
|
||||
import com.avaje.ebeaninternal.server.lib.sql.SimpleDataSourceAlert;
|
||||
import com.avaje.ebeaninternal.server.lib.thread.ThreadPool;
|
||||
|
||||
/**
|
||||
* Default Server side implementation of ServerFactory.
|
||||
@@ -51,46 +43,18 @@ public class DefaultServerFactory implements BootupEbeanManager {
|
||||
|
||||
private final JndiDataSourceLookup jndiDataSourceFactory;
|
||||
|
||||
private final BootupClassPathSearch bootupClassSearch;
|
||||
|
||||
private final AtomicInteger serverId = new AtomicInteger(1);
|
||||
|
||||
private final XmlConfigLoader xmlConfigLoader;
|
||||
public DefaultServerFactory(ContainerConfig containerConfig) {
|
||||
|
||||
private final XmlConfig xmlConfig;
|
||||
|
||||
public DefaultServerFactory() {
|
||||
|
||||
this.clusterManager = new ClusterManager();
|
||||
this.clusterManager = new ClusterManager(containerConfig);
|
||||
this.jndiDataSourceFactory = new JndiDataSourceLookup();
|
||||
|
||||
List<String> packages = getSearchJarsPackages(GlobalProperties.get("ebean.search.packages", null));
|
||||
List<String> jars = getSearchJarsPackages(GlobalProperties.get("ebean.search.jars", null));
|
||||
|
||||
this.bootupClassSearch = new BootupClassPathSearch(null, packages, jars);
|
||||
this.xmlConfigLoader = new XmlConfigLoader(null);
|
||||
|
||||
this.xmlConfig = xmlConfigLoader.load();
|
||||
|
||||
// register so that we can shutdown any Ebean wide
|
||||
// resources such as clustering
|
||||
ShutdownManager.registerServerFactory(this);
|
||||
}
|
||||
|
||||
private List<String> getSearchJarsPackages(String searchPackages) {
|
||||
|
||||
List<String> hitList = new ArrayList<String>();
|
||||
|
||||
if (searchPackages != null) {
|
||||
|
||||
String[] entries = searchPackages.split("[ ,;]");
|
||||
for (int i = 0; i < entries.length; i++) {
|
||||
hitList.add(entries[i].trim());
|
||||
}
|
||||
}
|
||||
return hitList;
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
clusterManager.shutdown();
|
||||
}
|
||||
@@ -100,35 +64,26 @@ public class DefaultServerFactory implements BootupEbeanManager {
|
||||
*/
|
||||
public SpiEbeanServer createServer(String name) {
|
||||
|
||||
ConfigBuilder b = new ConfigBuilder();
|
||||
ServerConfig config = b.build(name);
|
||||
ServerConfig config = new ServerConfig();
|
||||
config.setName(name);
|
||||
|
||||
Properties prop = PropertyMap.defaultProperties();
|
||||
config.loadFromProperties(prop);
|
||||
|
||||
return createServer(config);
|
||||
}
|
||||
|
||||
private SpiBackgroundExecutor createBackgroundExecutor(ServerConfig serverConfig, int uniqueServerId) {
|
||||
private SpiBackgroundExecutor createBackgroundExecutor(ServerConfig serverConfig) {
|
||||
|
||||
String namePrefix = "Ebean-" + serverConfig.getName();
|
||||
String namePrefix = "ebean-" + serverConfig.getName();
|
||||
|
||||
// the size of the pool for executing periodic tasks (such as cache flushing)
|
||||
int schedulePoolSize = GlobalProperties.getInt("backgroundExecutor.schedulePoolsize", 1);
|
||||
int schedulePoolSize = serverConfig.getBackgroundExecutorSchedulePoolSize();
|
||||
int corePoolSize = serverConfig.getBackgroundExecutorCorePoolSize();
|
||||
int maxPoolSize = serverConfig.getBackgroundExecutorMaxPoolSize();
|
||||
int idleSecs = serverConfig.getBackgroundExecutorIdleSecs();
|
||||
int shutdownSecs = serverConfig.getBackgroundExecutorShutdownSecs();
|
||||
|
||||
// the side of the main pool for immediate background task execution
|
||||
int minPoolSize = GlobalProperties.getInt("backgroundExecutor.minPoolSize", 0);
|
||||
int poolSize = GlobalProperties.getInt("backgroundExecutor.poolsize", 20);
|
||||
int maxPoolSize = GlobalProperties.getInt("backgroundExecutor.maxPoolSize", poolSize);
|
||||
|
||||
int idleSecs = GlobalProperties.getInt("backgroundExecutor.idlesecs", 120);
|
||||
int shutdownSecs = GlobalProperties.getInt("backgroundExecutor.shutdownSecs", 30);
|
||||
|
||||
boolean useTrad = GlobalProperties.getBoolean("backgroundExecutor.traditional", true);
|
||||
if (useTrad) {
|
||||
// this pool will use Idle seconds to maintain the thread count between min and max
|
||||
ThreadPool pool = new ThreadPool(namePrefix, true, null, minPoolSize, maxPoolSize, idleSecs*1000);
|
||||
return new TraditionalBackgroundExecutor(pool, schedulePoolSize, shutdownSecs, namePrefix);
|
||||
} else {
|
||||
return new DefaultBackgroundExecutor(schedulePoolSize, maxPoolSize, idleSecs, shutdownSecs, namePrefix);
|
||||
}
|
||||
return new DefaultBackgroundExecutor(schedulePoolSize, corePoolSize, maxPoolSize, idleSecs, shutdownSecs, namePrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -163,8 +118,7 @@ public class DefaultServerFactory implements BootupEbeanManager {
|
||||
pstmtDelegate = getOraclePstmtDelegate(serverConfig.getDataSource());
|
||||
}
|
||||
if (pstmtDelegate != null) {
|
||||
// We can support JDBC batching with Oracle
|
||||
// via OraclePreparedStatement
|
||||
// We can support JDBC batching with Oracle via OraclePreparedStatement
|
||||
pstmtBatch = new OraclePstmtBatch(pstmtDelegate);
|
||||
}
|
||||
if (pstmtBatch == null) {
|
||||
@@ -180,27 +134,30 @@ public class DefaultServerFactory implements BootupEbeanManager {
|
||||
ServerCacheManager cacheManager = getCacheManager(serverConfig);
|
||||
|
||||
int uniqueServerId = serverId.incrementAndGet();
|
||||
SpiBackgroundExecutor bgExecutor = createBackgroundExecutor(serverConfig, uniqueServerId);
|
||||
SpiBackgroundExecutor bgExecutor = createBackgroundExecutor(serverConfig);
|
||||
|
||||
InternalConfiguration c = new InternalConfiguration(xmlConfig, clusterManager, cacheManager, bgExecutor, serverConfig, bootupClasses,
|
||||
pstmtBatch);
|
||||
XmlConfigLoader xmlConfigLoader = new XmlConfigLoader(null);
|
||||
XmlConfig xmlConfig = xmlConfigLoader.load();
|
||||
|
||||
InternalConfiguration c = new InternalConfiguration(xmlConfig, clusterManager, cacheManager, bgExecutor, serverConfig, bootupClasses, pstmtBatch);
|
||||
|
||||
DefaultServer server = new DefaultServer(c, cacheManager);
|
||||
|
||||
cacheManager.init(server);
|
||||
|
||||
MBeanServer mbeanServer;
|
||||
ArrayList<?> list = MBeanServerFactory.findMBeanServer(null);
|
||||
if (list.size() == 0) {
|
||||
// probably not running in a server
|
||||
mbeanServer = MBeanServerFactory.createMBeanServer();
|
||||
} else {
|
||||
// use the first MBeanServer
|
||||
mbeanServer = (MBeanServer) list.get(0);
|
||||
if (serverConfig.isRegisterJmxMBeans()) {
|
||||
MBeanServer mbeanServer;
|
||||
ArrayList<?> list = MBeanServerFactory.findMBeanServer(null);
|
||||
if (list.size() == 0) {
|
||||
// probably not running in a server
|
||||
mbeanServer = MBeanServerFactory.createMBeanServer();
|
||||
} else {
|
||||
// use the first MBeanServer
|
||||
mbeanServer = (MBeanServer) list.get(0);
|
||||
}
|
||||
server.registerMBeans(mbeanServer, uniqueServerId);
|
||||
}
|
||||
|
||||
server.registerMBeans(mbeanServer, uniqueServerId);
|
||||
|
||||
// generate and run DDL if required
|
||||
// if there are any other tasks requiring action in their plugins, do them as well
|
||||
server.executePlugins(online);
|
||||
@@ -215,9 +172,7 @@ public class DefaultServerFactory implements BootupEbeanManager {
|
||||
}
|
||||
|
||||
// warm the cache in 30 seconds
|
||||
int delaySecs = GlobalProperties.getInt("ebean.cacheWarmingDelay", 30);
|
||||
long sleepMillis = 1000 * delaySecs;
|
||||
|
||||
long sleepMillis = 1000 * serverConfig.getCacheWarmingDelay();
|
||||
if (sleepMillis > 0) {
|
||||
Timer t = new Timer("EbeanCacheWarmer", true);
|
||||
t.schedule(new CacheWarmer(server), sleepMillis);
|
||||
@@ -252,19 +207,15 @@ public class DefaultServerFactory implements BootupEbeanManager {
|
||||
|
||||
// reasonable default settings are for a cache per bean type
|
||||
ServerCacheOptions beanOptions = new ServerCacheOptions();
|
||||
beanOptions.setMaxSize(GlobalProperties.getInt("cache.maxSize", 1000));
|
||||
// maxIdleTime 10 minutes
|
||||
beanOptions.setMaxIdleSecs(GlobalProperties.getInt("cache.maxIdleTime", 60 * 10));
|
||||
// maxTimeToLive 6 hrs
|
||||
beanOptions.setMaxSecsToLive(GlobalProperties.getInt("cache.maxTimeToLive", 60 * 60 * 6));
|
||||
beanOptions.setMaxSize(serverConfig.getCacheMaxSize());
|
||||
beanOptions.setMaxIdleSecs(serverConfig.getCacheMaxIdleTime());
|
||||
beanOptions.setMaxSecsToLive(serverConfig.getCacheMaxTimeToLive());
|
||||
|
||||
// reasonable default settings for the query cache per bean type
|
||||
ServerCacheOptions queryOptions = new ServerCacheOptions();
|
||||
queryOptions.setMaxSize(GlobalProperties.getInt("querycache.maxSize", 100));
|
||||
// maxIdleTime 10 minutes
|
||||
queryOptions.setMaxIdleSecs(GlobalProperties.getInt("querycache.maxIdleTime", 60 * 10));
|
||||
// maxTimeToLive 6 hours
|
||||
queryOptions.setMaxSecsToLive(GlobalProperties.getInt("querycache.maxTimeToLive", 60 * 60 * 6));
|
||||
queryOptions.setMaxSize(serverConfig.getQueryCacheMaxSize());
|
||||
queryOptions.setMaxIdleSecs(serverConfig.getQueryCacheMaxIdleTime());
|
||||
queryOptions.setMaxSecsToLive(serverConfig.getQueryCacheMaxTimeToLive());
|
||||
|
||||
ServerCacheFactory cacheFactory = serverConfig.getServerCacheFactory();
|
||||
if (cacheFactory == null) {
|
||||
@@ -303,17 +254,8 @@ public class DefaultServerFactory implements BootupEbeanManager {
|
||||
return new BootupClasses(serverConfig.getClasses());
|
||||
}
|
||||
|
||||
List<String> jars = serverConfig.getJars();
|
||||
List<String> packages = serverConfig.getPackages();
|
||||
|
||||
if ((packages != null && !packages.isEmpty()) || (jars != null && !jars.isEmpty())) {
|
||||
// filter by package name
|
||||
BootupClassPathSearch search = new BootupClassPathSearch(null, packages, jars);
|
||||
return search.getBootupClasses();
|
||||
}
|
||||
|
||||
// just use classes we can find via class path search
|
||||
return bootupClassSearch.getBootupClasses().createCopy();
|
||||
BootupClassPathSearch search = new BootupClassPathSearch(null, serverConfig.getPackages(), serverConfig.getJars(), serverConfig.getClassPathReaderClassName());
|
||||
return search.getBootupClasses();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -323,22 +265,6 @@ public class DefaultServerFactory implements BootupEbeanManager {
|
||||
if (config.getNamingConvention() == null) {
|
||||
UnderscoreNamingConvention nc = new UnderscoreNamingConvention();
|
||||
config.setNamingConvention(nc);
|
||||
|
||||
String v = config.getProperty("namingConvention.useForeignKeyPrefix");
|
||||
if (v != null) {
|
||||
boolean useForeignKeyPrefix = Boolean.valueOf(v);
|
||||
nc.setUseForeignKeyPrefix(useForeignKeyPrefix);
|
||||
}
|
||||
|
||||
String sequenceFormat = config.getProperty("namingConvention.sequenceFormat");
|
||||
if (sequenceFormat != null) {
|
||||
nc.setSequenceFormat(sequenceFormat);
|
||||
}
|
||||
|
||||
String schema = config.getProperty("namingConvention.schema");
|
||||
if (schema != null) {
|
||||
nc.setSchema(schema);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -351,7 +277,6 @@ public class DefaultServerFactory implements BootupEbeanManager {
|
||||
if (dbPlatform == null) {
|
||||
|
||||
DatabasePlatformFactory factory = new DatabasePlatformFactory();
|
||||
|
||||
DatabasePlatform db = factory.create(config);
|
||||
config.setDatabasePlatform(db);
|
||||
logger.info("DatabasePlatform name:" + config.getName() + " platform:" + db.getName());
|
||||
@@ -370,7 +295,7 @@ public class DefaultServerFactory implements BootupEbeanManager {
|
||||
|
||||
private DataSource getDataSourceFromConfig(ServerConfig config) {
|
||||
|
||||
DataSource ds = null;
|
||||
DataSource ds;
|
||||
|
||||
if (config.getDataSourceJndiName() != null) {
|
||||
ds = jndiDataSourceFactory.lookup(config.getDataSourceJndiName());
|
||||
|
||||
@@ -93,6 +93,11 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
|
||||
*/
|
||||
private final String sql;
|
||||
|
||||
/**
|
||||
* The actual sql with named parameters converted.
|
||||
*/
|
||||
private String generatedSql;
|
||||
|
||||
/**
|
||||
* Some descriptive text that can be put into the transaction log.
|
||||
*/
|
||||
@@ -170,7 +175,16 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getSql() {
|
||||
public String getGeneratedSql() {
|
||||
return generatedSql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGeneratedSql(String generatedSql) {
|
||||
this.generatedSql = generatedSql;
|
||||
}
|
||||
|
||||
public String getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,266 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.ExpressionFactory;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.ExternalTransactionManager;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.text.json.JsonContext;
|
||||
import com.avaje.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.autofetch.AutoFetchManager;
|
||||
import com.avaje.ebeaninternal.server.autofetch.AutoFetchManagerFactory;
|
||||
import com.avaje.ebeaninternal.server.cluster.ClusterManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.DeployOrmXml;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployCreateProperties;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployInherit;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployUtil;
|
||||
import com.avaje.ebeaninternal.server.expression.DefaultExpressionFactory;
|
||||
import com.avaje.ebeaninternal.server.lib.sql.DataSourcePool;
|
||||
import com.avaje.ebeaninternal.server.persist.Binder;
|
||||
import com.avaje.ebeaninternal.server.persist.DefaultPersister;
|
||||
import com.avaje.ebeaninternal.server.query.CQueryEngine;
|
||||
import com.avaje.ebeaninternal.server.query.DefaultOrmQueryEngine;
|
||||
import com.avaje.ebeaninternal.server.query.DefaultRelationalQueryEngine;
|
||||
import com.avaje.ebeaninternal.server.resource.ResourceManager;
|
||||
import com.avaje.ebeaninternal.server.resource.ResourceManagerFactory;
|
||||
import com.avaje.ebeaninternal.server.text.json.DJsonContext;
|
||||
<<<<<<< HEAD
|
||||
import com.avaje.ebeaninternal.server.text.json.DefaultJsonValueAdapter;
|
||||
import com.avaje.ebeaninternal.server.transaction.AutoCommitTransactionManager;
|
||||
=======
|
||||
>>>>>>> json-refactor
|
||||
import com.avaje.ebeaninternal.server.transaction.DefaultTransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.ExternalTransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.JtaTransactionManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.TransactionManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.TransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.server.type.DefaultTypeManager;
|
||||
import com.avaje.ebeaninternal.server.type.TypeManager;
|
||||
|
||||
/**
|
||||
* Used to extend the ServerConfig with additional objects used to configure and
|
||||
* construct an EbeanServer.
|
||||
*/
|
||||
public class InternalConfiguration {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(InternalConfiguration.class);
|
||||
|
||||
private final ServerConfig serverConfig;
|
||||
|
||||
private final BootupClasses bootupClasses;
|
||||
|
||||
private final DeployInherit deployInherit;
|
||||
|
||||
private final ResourceManager resourceManager;
|
||||
|
||||
private final DeployOrmXml deployOrmXml;
|
||||
|
||||
private final TypeManager typeManager;
|
||||
|
||||
private final Binder binder;
|
||||
|
||||
private final DeployCreateProperties deployCreateProperties;
|
||||
|
||||
private final DeployUtil deployUtil;
|
||||
|
||||
private final BeanDescriptorManager beanDescriptorManager;
|
||||
|
||||
private final TransactionManager transactionManager;
|
||||
|
||||
private final TransactionScopeManager transactionScopeManager;
|
||||
|
||||
private final CQueryEngine cQueryEngine;
|
||||
|
||||
private final ClusterManager clusterManager;
|
||||
|
||||
private final ServerCacheManager cacheManager;
|
||||
|
||||
private final ExpressionFactory expressionFactory;
|
||||
|
||||
private final SpiBackgroundExecutor backgroundExecutor;
|
||||
|
||||
private final PstmtBatch pstmtBatch;
|
||||
|
||||
private final XmlConfig xmlConfig;
|
||||
|
||||
public InternalConfiguration(XmlConfig xmlConfig, ClusterManager clusterManager,
|
||||
ServerCacheManager cacheManager, SpiBackgroundExecutor backgroundExecutor,
|
||||
ServerConfig serverConfig, BootupClasses bootupClasses, PstmtBatch pstmtBatch) {
|
||||
|
||||
this.xmlConfig = xmlConfig;
|
||||
this.pstmtBatch = pstmtBatch;
|
||||
this.clusterManager = clusterManager;
|
||||
this.backgroundExecutor = backgroundExecutor;
|
||||
this.cacheManager = cacheManager;
|
||||
this.serverConfig = serverConfig;
|
||||
this.bootupClasses = bootupClasses;
|
||||
this.expressionFactory = new DefaultExpressionFactory();
|
||||
|
||||
this.typeManager = new DefaultTypeManager(serverConfig, bootupClasses);
|
||||
this.binder = new Binder(typeManager);
|
||||
|
||||
this.resourceManager = ResourceManagerFactory.createResourceManager(serverConfig);
|
||||
this.deployOrmXml = new DeployOrmXml(resourceManager.getResourceSource());
|
||||
this.deployInherit = new DeployInherit(bootupClasses);
|
||||
|
||||
this.deployCreateProperties = new DeployCreateProperties(typeManager);
|
||||
this.deployUtil = new DeployUtil(typeManager, serverConfig);
|
||||
|
||||
this.beanDescriptorManager = new BeanDescriptorManager(this);
|
||||
beanDescriptorManager.deploy();
|
||||
|
||||
this.transactionManager = createTransactionManager();
|
||||
|
||||
this.cQueryEngine = new CQueryEngine(serverConfig.getDatabasePlatform(), binder);
|
||||
|
||||
ExternalTransactionManager externalTransactionManager = serverConfig.getExternalTransactionManager();
|
||||
if (externalTransactionManager == null && serverConfig.isUseJtaTransactionManager()) {
|
||||
externalTransactionManager = new JtaTransactionManager();
|
||||
}
|
||||
if (externalTransactionManager != null) {
|
||||
externalTransactionManager.setTransactionManager(transactionManager);
|
||||
this.transactionScopeManager = new ExternalTransactionScopeManager(transactionManager, externalTransactionManager);
|
||||
logger.info("Using Transaction Manager [" + externalTransactionManager.getClass() + "]");
|
||||
} else {
|
||||
this.transactionScopeManager = new DefaultTransactionScopeManager(transactionManager);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the TransactionManager taking into account autoCommit mode.
|
||||
*/
|
||||
private TransactionManager createTransactionManager() {
|
||||
|
||||
if (isAutoCommitMode()) {
|
||||
return new AutoCommitTransactionManager(clusterManager, backgroundExecutor, serverConfig, beanDescriptorManager, this.getBootupClasses());
|
||||
}
|
||||
|
||||
return new TransactionManager(clusterManager, backgroundExecutor, serverConfig, beanDescriptorManager, this.getBootupClasses());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if autoCommit mode is on.
|
||||
*/
|
||||
private boolean isAutoCommitMode() {
|
||||
if (serverConfig.isAutoCommitMode()) {
|
||||
// explicitly set
|
||||
return true;
|
||||
}
|
||||
DataSource dataSource = serverConfig.getDataSource();
|
||||
if (dataSource instanceof DataSourcePool && ((DataSourcePool)dataSource).getAutoCommit()) {
|
||||
// We know the DataSourcePool is using autoCommit
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public JsonContext createJsonContext(SpiEbeanServer server) {
|
||||
|
||||
return new DJsonContext(server);
|
||||
}
|
||||
|
||||
public XmlConfig getXmlConfig() {
|
||||
return xmlConfig;
|
||||
}
|
||||
|
||||
public AutoFetchManager createAutoFetchManager(SpiEbeanServer server) {
|
||||
return AutoFetchManagerFactory.create(server, serverConfig, resourceManager);
|
||||
}
|
||||
|
||||
public RelationalQueryEngine createRelationalQueryEngine() {
|
||||
return new DefaultRelationalQueryEngine(binder, serverConfig.getDatabaseBooleanTrue());
|
||||
}
|
||||
|
||||
public OrmQueryEngine createOrmQueryEngine() {
|
||||
return new DefaultOrmQueryEngine(beanDescriptorManager, cQueryEngine);
|
||||
}
|
||||
|
||||
public Persister createPersister(SpiEbeanServer server) {
|
||||
return new DefaultPersister(server, binder, beanDescriptorManager, pstmtBatch);
|
||||
}
|
||||
|
||||
public PstmtBatch getPstmtBatch() {
|
||||
return pstmtBatch;
|
||||
}
|
||||
|
||||
public ServerCacheManager getCacheManager() {
|
||||
return cacheManager;
|
||||
}
|
||||
|
||||
public BootupClasses getBootupClasses() {
|
||||
return bootupClasses;
|
||||
}
|
||||
|
||||
public DatabasePlatform getDatabasePlatform() {
|
||||
return serverConfig.getDatabasePlatform();
|
||||
}
|
||||
|
||||
public ServerConfig getServerConfig() {
|
||||
return serverConfig;
|
||||
}
|
||||
|
||||
public ExpressionFactory getExpressionFactory() {
|
||||
return expressionFactory;
|
||||
}
|
||||
|
||||
public TypeManager getTypeManager() {
|
||||
return typeManager;
|
||||
}
|
||||
|
||||
public Binder getBinder() {
|
||||
return binder;
|
||||
}
|
||||
|
||||
public BeanDescriptorManager getBeanDescriptorManager() {
|
||||
return beanDescriptorManager;
|
||||
}
|
||||
|
||||
public DeployInherit getDeployInherit() {
|
||||
return deployInherit;
|
||||
}
|
||||
|
||||
public ResourceManager getResourceManager() {
|
||||
return resourceManager;
|
||||
}
|
||||
|
||||
public DeployOrmXml getDeployOrmXml() {
|
||||
return deployOrmXml;
|
||||
}
|
||||
|
||||
public DeployCreateProperties getDeployCreateProperties() {
|
||||
return deployCreateProperties;
|
||||
}
|
||||
|
||||
public DeployUtil getDeployUtil() {
|
||||
return deployUtil;
|
||||
}
|
||||
|
||||
public TransactionManager getTransactionManager() {
|
||||
return transactionManager;
|
||||
}
|
||||
|
||||
public TransactionScopeManager getTransactionScopeManager() {
|
||||
return transactionScopeManager;
|
||||
}
|
||||
|
||||
public CQueryEngine getCQueryEngine() {
|
||||
return cQueryEngine;
|
||||
}
|
||||
|
||||
public ClusterManager getClusterManager() {
|
||||
return clusterManager;
|
||||
}
|
||||
|
||||
public SpiBackgroundExecutor getBackgroundExecutor() {
|
||||
return backgroundExecutor;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,9 +6,6 @@ import javax.naming.NamingException;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
|
||||
|
||||
/**
|
||||
* Helper to lookup a DataSource from JNDI.
|
||||
*/
|
||||
@@ -16,8 +13,6 @@ public class JndiDataSourceLookup {
|
||||
|
||||
private static final String DEFAULT_PREFIX = "java:comp/env/jdbc/";
|
||||
|
||||
String jndiPrefix = GlobalProperties.get("ebean.datasource.jndi.prefix", DEFAULT_PREFIX);
|
||||
|
||||
public JndiDataSourceLookup() {
|
||||
}
|
||||
|
||||
@@ -32,7 +27,7 @@ public class JndiDataSourceLookup {
|
||||
try {
|
||||
|
||||
if (!jndiName.startsWith("java:")){
|
||||
jndiName = jndiPrefix + jndiName;
|
||||
jndiName = DEFAULT_PREFIX + jndiName;
|
||||
}
|
||||
|
||||
Context ctx = new InitialContext();
|
||||
|
||||
@@ -6,9 +6,7 @@ import java.util.Set;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.QueryResultVisitor;
|
||||
import com.avaje.ebean.RawSql;
|
||||
import com.avaje.ebean.*;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebean.event.BeanFinder;
|
||||
@@ -55,7 +53,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
private HashQuery cacheKey;
|
||||
|
||||
private HashQueryPlan queryPlanHash;
|
||||
|
||||
|
||||
/**
|
||||
* Create the InternalQueryRequest.
|
||||
*/
|
||||
@@ -71,7 +69,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
this.readOnly = query.isReadOnly();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Return the database platform like clause.
|
||||
*/
|
||||
@@ -80,8 +78,8 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
return ebeanServer.getDatabasePlatform().getLikeClause();
|
||||
}
|
||||
|
||||
public void executeSecondaryQueries(int defaultQueryBatch) {
|
||||
loadContext.executeSecondaryQueries(this, defaultQueryBatch);
|
||||
public void executeSecondaryQueries() {
|
||||
loadContext.executeSecondaryQueries(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,18 +183,21 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
persistenceContext = new DefaultPersistenceContext();
|
||||
loadContext.setPersistenceContext(persistenceContext);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the TransactionContext either explicitly set on the query or
|
||||
* transaction scoped.
|
||||
*/
|
||||
private PersistenceContext getPersistenceContext(SpiQuery<?> query, SpiTransaction t) {
|
||||
|
||||
// check if there is already a persistence context set which is the case
|
||||
// when lazy loading or query joins are executed
|
||||
PersistenceContext ctx = query.getPersistenceContext();
|
||||
if (ctx == null) {
|
||||
ctx = t.getPersistenceContext();
|
||||
}
|
||||
return ctx;
|
||||
if (ctx != null) return ctx;
|
||||
|
||||
// determine the scope (from the query and then server)
|
||||
PersistenceContextScope scope = ebeanServer.getPersistenceContextScope(query);
|
||||
return (scope == PersistenceContextScope.QUERY) ? new DefaultPersistenceContext() : t.getPersistenceContext();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -234,6 +235,30 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
return idList.getIdList();
|
||||
}
|
||||
|
||||
public void findEach(QueryEachConsumer<T> consumer) {
|
||||
QueryIterator<T> it = queryEngine.findIterate(this);
|
||||
try {
|
||||
while (it.hasNext()) {
|
||||
consumer.accept(it.next());
|
||||
}
|
||||
} finally {
|
||||
it.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void findEachWhile(QueryEachWhileConsumer<T> consumer) {
|
||||
QueryIterator<T> it = queryEngine.findIterate(this);
|
||||
try {
|
||||
while (it.hasNext()) {
|
||||
if (!consumer.accept(it.next())) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
it.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void findVisit(QueryResultVisitor<T> visitor) {
|
||||
QueryIterator<T> it = queryEngine.findIterate(this);
|
||||
try {
|
||||
@@ -379,4 +404,12 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
return query.isLogSecondaryQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch size for lazy loading on this bean query request.
|
||||
*/
|
||||
public int getLazyLoadBatchSize() {
|
||||
|
||||
int batchSize = query.getLazyLoadBatchSize();
|
||||
return (batchSize > 0) ? batchSize : ebeanServer.getLazyLoadBatchSize();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
|
||||
private final BeanDescriptor<T> beanDescriptor;
|
||||
|
||||
private final BeanPersistListener<T> beanPersistListener;
|
||||
private final BeanPersistListener beanPersistListener;
|
||||
|
||||
/**
|
||||
* For per post insert update delete control.
|
||||
@@ -91,6 +91,12 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
*/
|
||||
private List<BeanPropertyAssocMany<?>> updatedManys;
|
||||
|
||||
/**
|
||||
* Need to get and store the updated properties because the persist listener is notified
|
||||
* later on a different thread and the bean has been reset at that point.
|
||||
*/
|
||||
private Set<String> updatedProperties;
|
||||
|
||||
public PersistRequestBean(SpiEbeanServer server, T bean, Object parentBean, BeanManager<T> mgr, SpiTransaction t,
|
||||
PersistExecute persistExecute, PersistRequest.Type type, boolean saveRecurse) {
|
||||
|
||||
@@ -188,7 +194,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
return beanPersistListener.inserted(bean);
|
||||
|
||||
case UPDATE:
|
||||
return beanPersistListener.updated(bean, intercept.getDirtyPropertyNames());
|
||||
return beanPersistListener.updated(bean, updatedProperties);
|
||||
|
||||
case DELETE:
|
||||
return beanPersistListener.deleted(bean);
|
||||
@@ -372,6 +378,10 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
return -1;
|
||||
|
||||
case UPDATE:
|
||||
if (beanPersistListener != null) {
|
||||
// store the updated properties for sending later
|
||||
updatedProperties = getUpdatedProperties();
|
||||
}
|
||||
persistExecute.executeUpdateBean(this);
|
||||
return -1;
|
||||
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebeaninternal.server.lib.ShutdownManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.ServletContextEvent;
|
||||
|
||||
/**
|
||||
* Listens for webserver server starting and stopping events.
|
||||
@@ -19,8 +14,6 @@ import org.slf4j.LoggerFactory;
|
||||
*/
|
||||
public class ServletContextListener implements javax.servlet.ServletContextListener {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ServletContextListener.class);
|
||||
|
||||
/**
|
||||
* The servlet container is stopping.
|
||||
*/
|
||||
@@ -29,29 +22,10 @@ public class ServletContextListener implements javax.servlet.ServletContextListe
|
||||
}
|
||||
|
||||
/**
|
||||
* The servlet container is starting.
|
||||
* <p>
|
||||
* Initialise the properties file using SystemProperties.initWebapp();
|
||||
* and start Ebean.
|
||||
* </p>
|
||||
* Do nothing on startup.
|
||||
*/
|
||||
public void contextInitialized(ServletContextEvent event) {
|
||||
|
||||
try {
|
||||
ServletContext servletContext = event.getServletContext();
|
||||
GlobalProperties.setServletContext(servletContext);
|
||||
|
||||
if (servletContext != null) {
|
||||
String servletRealPath = servletContext.getRealPath("");
|
||||
GlobalProperties.put("servlet.realpath", servletRealPath);
|
||||
logger.info("servlet.realpath=[" + servletRealPath + "]");
|
||||
}
|
||||
|
||||
Ebean.getServer(null);
|
||||
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.QueryEachConsumer;
|
||||
import com.avaje.ebean.QueryEachWhileConsumer;
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.QueryResultVisitor;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
@@ -65,7 +67,17 @@ public interface SpiOrmQueryRequest<T> {
|
||||
*/
|
||||
public void findVisit(QueryResultVisitor<T> visitor);
|
||||
|
||||
/**
|
||||
/**
|
||||
* Execute the find returning a QueryIterator and visitor pattern.
|
||||
*/
|
||||
public void findEach(QueryEachConsumer<T> consumer);
|
||||
|
||||
/**
|
||||
* Execute the find returning a QueryIterator and visitor pattern.
|
||||
*/
|
||||
public void findEachWhile(QueryEachWhileConsumer<T> consumer);
|
||||
|
||||
/**
|
||||
* Execute the find returning a QueryIterator.
|
||||
*/
|
||||
public QueryIterator<T> findIterate();
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import com.avaje.ebeaninternal.server.lib.DaemonScheduleThreadPool;
|
||||
import com.avaje.ebeaninternal.server.lib.thread.ThreadPool;
|
||||
|
||||
/**
|
||||
* BackgroundExecutor using my traditional ThreadPool that will grow and trim.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class TraditionalBackgroundExecutor implements SpiBackgroundExecutor {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(TraditionalBackgroundExecutor.class);
|
||||
|
||||
private final ThreadPool pool;
|
||||
|
||||
private final DaemonScheduleThreadPool schedulePool;
|
||||
|
||||
/**
|
||||
* Construct the default implementation of BackgroundExecutor.
|
||||
*/
|
||||
public TraditionalBackgroundExecutor(ThreadPool pool, int schedulePoolSize, int shutdownWaitSeconds, String namePrefix) {
|
||||
this.pool = pool;
|
||||
this.schedulePool = new DaemonScheduleThreadPool(schedulePoolSize, shutdownWaitSeconds, namePrefix+"-periodic-");
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a Runnable using a background thread.
|
||||
*/
|
||||
public void execute(Runnable r) {
|
||||
pool.assign(r, true);
|
||||
}
|
||||
|
||||
public void executePeriodically(Runnable r, long delay, TimeUnit unit) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Registering for executePeriodically {} delay:{} {}",r, delay, unit);
|
||||
}
|
||||
schedulePool.scheduleWithFixedDelay(r, delay, delay, unit);
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Shutting down");
|
||||
}
|
||||
pool.shutdown();
|
||||
schedulePool.shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +1,5 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.Transaction;
|
||||
@@ -12,6 +9,8 @@ import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.text.json.WriteJson;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Helper functions for performing tasks on Lists Sets or Maps.
|
||||
*/
|
||||
@@ -30,15 +29,15 @@ public interface BeanCollectionHelp<T> {
|
||||
*/
|
||||
public BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey);
|
||||
|
||||
/**
|
||||
* Create an empty collection of the correct type without a parent bean.
|
||||
*/
|
||||
public BeanCollection<T> createEmptyNoParent();
|
||||
|
||||
/**
|
||||
* Create an empty collection of the correct type.
|
||||
*/
|
||||
public Object createEmpty(boolean vanilla);
|
||||
|
||||
/**
|
||||
* Create an iterator for reading the entries.
|
||||
*/
|
||||
public Iterator<?> getIterator(Object collection);
|
||||
public BeanCollection<T> createEmpty(EntityBean bean);
|
||||
|
||||
/**
|
||||
* Add a bean to the List Set or Map.
|
||||
@@ -48,7 +47,7 @@ public interface BeanCollectionHelp<T> {
|
||||
/**
|
||||
* Create a lazy loading proxy for a List Set or Map.
|
||||
*/
|
||||
public BeanCollection<T> createReference(EntityBean parentBean, String propertyName);
|
||||
public BeanCollection<T> createReference(EntityBean parentBean);
|
||||
|
||||
/**
|
||||
* Refresh the List Set or Map.
|
||||
|
||||
@@ -9,6 +9,10 @@ import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
*/
|
||||
public class BeanCollectionHelpFactory {
|
||||
|
||||
static final BeanListHelp LIST_HELP = new BeanListHelp();
|
||||
|
||||
static final BeanSetHelp SET_HELP = new BeanSetHelp();
|
||||
|
||||
/**
|
||||
* Create the helper based on the many property.
|
||||
*/
|
||||
@@ -33,10 +37,10 @@ public class BeanCollectionHelpFactory {
|
||||
SpiQuery.Type manyType = request.getQuery().getType();
|
||||
|
||||
if (manyType.equals(SpiQuery.Type.LIST)){
|
||||
return new BeanListHelp<T>();
|
||||
return LIST_HELP;
|
||||
|
||||
} else if (manyType.equals(SpiQuery.Type.SET)) {
|
||||
return new BeanSetHelp<T>();
|
||||
return SET_HELP;
|
||||
|
||||
} else {
|
||||
BeanDescriptor<T> target = request.getBeanDescriptor();
|
||||
|
||||
@@ -134,11 +134,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
|
||||
private final CompoundUniqueContraint[] compoundUniqueConstraints;
|
||||
|
||||
/**
|
||||
* Extra deployment attributes.
|
||||
*/
|
||||
private final Map<String, String> extraAttrMap;
|
||||
|
||||
/**
|
||||
* The base database table.
|
||||
*/
|
||||
@@ -175,7 +170,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
/**
|
||||
* Listens for post commit insert update and delete events.
|
||||
*/
|
||||
private volatile BeanPersistListener<T> persistListener;
|
||||
private volatile BeanPersistListener persistListener;
|
||||
|
||||
private volatile BeanQueryAdapter queryAdapter;
|
||||
|
||||
@@ -225,17 +220,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
|
||||
private final BeanPropertyAssocOne<?> unidirectional;
|
||||
|
||||
/**
|
||||
* A hashcode of all the many property names. This is used to efficiently
|
||||
* create sets of loaded property names (for partial objects).
|
||||
*/
|
||||
private final int namesOfManyPropsHash;
|
||||
|
||||
/**
|
||||
* The set of names of the many properties.
|
||||
*/
|
||||
private final Set<String> namesOfManyProps;
|
||||
|
||||
/**
|
||||
* list of properties that are Lists/Sets/Maps (Derived).
|
||||
*/
|
||||
@@ -376,8 +360,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
this.dependantTables = deploy.getDependantTables();
|
||||
this.compoundUniqueConstraints = deploy.getCompoundUniqueConstraints();
|
||||
|
||||
this.extraAttrMap = deploy.getExtraAttributeMap();
|
||||
|
||||
this.baseTable = InternString.intern(deploy.getBaseTable());
|
||||
|
||||
this.autoFetchTunable = EntityType.ORM.equals(entityType) && (beanFinder == null);
|
||||
@@ -411,9 +393,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
this.propertiesManyDelete = listHelper.getManyDelete();
|
||||
this.propertiesManyToMany = listHelper.getManyToMany();
|
||||
|
||||
this.namesOfManyProps = deriveManyPropNames();
|
||||
this.namesOfManyPropsHash = namesOfManyProps.hashCode();
|
||||
|
||||
this.derivedTableJoins = listHelper.getTableJoin();
|
||||
|
||||
boolean noRelationships = propertiesOne.length + propertiesMany.length == 0;
|
||||
@@ -518,48 +497,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the concurrency mode based on the existence of a non-null version
|
||||
* property value.
|
||||
*/
|
||||
public ConcurrencyMode determineConcurrencyMode(EntityBean bean) {
|
||||
|
||||
if (versionProperty == null) {
|
||||
return ConcurrencyMode.NONE;
|
||||
}
|
||||
Object v = versionProperty.getValue(bean);
|
||||
return (v == null) ? ConcurrencyMode.NONE : ConcurrencyMode.VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Set of embedded beans that have changed.
|
||||
*/
|
||||
public Set<String> getDirtyEmbeddedProperties(EntityBean bean) {
|
||||
|
||||
HashSet<String> dirtyProperties = null;
|
||||
|
||||
for (int i = 0; i < propertiesEmbedded.length; i++) {
|
||||
Object embValue = propertiesEmbedded[i].getValue(bean);
|
||||
if (embValue instanceof EntityBean) {
|
||||
if (((EntityBean) embValue)._ebean_getIntercept().isDirty()) {
|
||||
// this embedded is dirty so should be included in an update
|
||||
if (dirtyProperties == null) {
|
||||
dirtyProperties = new HashSet<String>();
|
||||
}
|
||||
dirtyProperties.add(propertiesEmbedded[i].getName());
|
||||
}
|
||||
} else {
|
||||
// must assume it is dirty
|
||||
if (dirtyProperties == null) {
|
||||
dirtyProperties = new HashSet<String>();
|
||||
}
|
||||
dirtyProperties.add(propertiesEmbedded[i].getName());
|
||||
}
|
||||
}
|
||||
|
||||
return dirtyProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the EbeanServer instance that owns this BeanDescriptor.
|
||||
*/
|
||||
@@ -667,10 +604,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
cacheHelp.initialise();
|
||||
}
|
||||
|
||||
protected boolean hasInheritance() {
|
||||
return inheritInfo != null;
|
||||
}
|
||||
|
||||
public SqlUpdate deleteById(Object id, List<Object> idList) {
|
||||
if (id != null) {
|
||||
return deleteById(id);
|
||||
@@ -792,6 +725,13 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
return inheritInfo == null || inheritInfo.isRoot();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bean caching on or off.
|
||||
*/
|
||||
public void setUseCache(boolean useCache) {
|
||||
cacheHelp.setUseCache(useCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is currently query caching for this type of bean.
|
||||
*/
|
||||
@@ -838,8 +778,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
cacheHelp.queryCachePut(id, query);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Try to load the beanCollection from cache return true if successful.
|
||||
*/
|
||||
@@ -1030,11 +968,10 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
/**
|
||||
* Execute the postLoad if a BeanPersistController exists for this bean.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void postLoad(Object bean, Set<String> includedProperties) {
|
||||
BeanPersistController c = persistController;
|
||||
if (c != null) {
|
||||
c.postLoad((T) bean, includedProperties);
|
||||
c.postLoad(bean, includedProperties);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1060,13 +997,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
updatePlanCache.put(key, plan);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the TypeManager.
|
||||
*/
|
||||
public TypeManager getTypeManager() {
|
||||
return typeManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if updates should only include changed properties. Otherwise
|
||||
* all loaded properties are included in the update.
|
||||
@@ -1194,7 +1124,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
public T createReference(Boolean readOnly, Object id) {
|
||||
|
||||
if (cacheSharableBeans && !Boolean.FALSE.equals(readOnly)) {
|
||||
CachedBeanData d = (CachedBeanData) cacheHelp.beanCacheGetData(id);
|
||||
CachedBeanData d = cacheHelp.beanCacheGetData(id);
|
||||
if (d != null) {
|
||||
Object shareableBean = d.getSharableBean();
|
||||
if (shareableBean != null) {
|
||||
@@ -1220,13 +1150,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanProperty for the given deployment name.
|
||||
*/
|
||||
public BeanProperty getBeanPropertyFromDbColumn(String dbColumn) {
|
||||
return propMapByDbColumn.get(dbColumn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean property traversing the object graph and taking into
|
||||
* account inheritance.
|
||||
@@ -1355,14 +1278,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
return (idProperty == null) ? null : idProperty.getValue(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return false if the id is a simple scalar and false if it is embedded or
|
||||
* concatenated.
|
||||
*/
|
||||
public boolean isComplexId() {
|
||||
return idBinder.isComplexId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default order by that may need to be added if a many property is
|
||||
* included in the query.
|
||||
@@ -1393,7 +1308,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
* Get a BeanProperty by its name.
|
||||
*/
|
||||
public BeanProperty getBeanProperty(String propName) {
|
||||
return (BeanProperty) propMap.get(propName);
|
||||
return propMap.get(propName);
|
||||
}
|
||||
|
||||
public void sort(List<T> list, String sortByClause) {
|
||||
@@ -1572,11 +1487,15 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
return prop;
|
||||
}
|
||||
|
||||
protected Object getBeanPropertyWithInheritance(EntityBean bean, String propName) {
|
||||
/**
|
||||
* Reset the many properties to empty state ready for reloading.
|
||||
*/
|
||||
public void resetManyProperties(Object dbBean) {
|
||||
|
||||
BeanDescriptor<?> desc = getBeanDescriptor(bean.getClass());
|
||||
BeanProperty beanProperty = desc.findBeanProperty(propName);
|
||||
return beanProperty.getValue(bean);
|
||||
EntityBean bean = (EntityBean)dbBean;
|
||||
for (int i = 0; i < propertiesMany.length; i++) {
|
||||
propertiesMany[i].resetMany(bean);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1619,17 +1538,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
return EntityType.EMBEDDED.equals(entityType);
|
||||
}
|
||||
|
||||
public boolean isBaseTableType() {
|
||||
return EntityType.ORM.equals(entityType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the concurrency mode used for beans of this type.
|
||||
*/
|
||||
public ConcurrencyMode getConcurrencyMode() {
|
||||
return concurrencyMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the tables this bean is dependent on. This implies that if any of
|
||||
* these tables are modified then cached beans may be invalidated.
|
||||
@@ -1648,7 +1556,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
/**
|
||||
* Return the beanListener.
|
||||
*/
|
||||
public BeanPersistListener<T> getPersistListener() {
|
||||
public BeanPersistListener getPersistListener() {
|
||||
return persistListener;
|
||||
}
|
||||
|
||||
@@ -1670,16 +1578,16 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
* De-register the BeanPersistListener.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void deregister(BeanPersistListener<?> listener) {
|
||||
public void deregister(BeanPersistListener listener) {
|
||||
// volatile read...
|
||||
BeanPersistListener<T> currListener = persistListener;
|
||||
BeanPersistListener currListener = persistListener;
|
||||
if (currListener == null) {
|
||||
// nothing to deregister
|
||||
} else {
|
||||
BeanPersistListener<T> deregListener = (BeanPersistListener<T>) listener;
|
||||
if (currListener instanceof ChainedBeanPersistListener<?>) {
|
||||
BeanPersistListener deregListener = listener;
|
||||
if (currListener instanceof ChainedBeanPersistListener) {
|
||||
// remove it from the existing chain
|
||||
persistListener = ((ChainedBeanPersistListener<T>) currListener).deregister(deregListener);
|
||||
persistListener = ((ChainedBeanPersistListener) currListener).deregister(deregListener);
|
||||
} else if (currListener.equals(deregListener)) {
|
||||
persistListener = null;
|
||||
}
|
||||
@@ -1692,9 +1600,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
public void deregister(BeanPersistController controller) {
|
||||
// volatile read...
|
||||
BeanPersistController c = persistController;
|
||||
if (c == null) {
|
||||
// nothing to deregister
|
||||
} else {
|
||||
if (c != null) {
|
||||
if (c instanceof ChainedBeanPersistController) {
|
||||
// remove it from the existing chain
|
||||
persistController = ((ChainedBeanPersistController) c).deregister(controller);
|
||||
@@ -1708,23 +1614,20 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
* Register the new BeanPersistController.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void register(BeanPersistListener<?> newPersistListener) {
|
||||
public void register(BeanPersistListener newPersistListener) {
|
||||
|
||||
if (!PersistListenerManager.isRegisterFor(beanType, newPersistListener)) {
|
||||
// skip
|
||||
} else {
|
||||
BeanPersistListener<T> newListener = (BeanPersistListener<T>) newPersistListener;
|
||||
if (newPersistListener.isRegisterFor(beanType)) {
|
||||
// volatile read...
|
||||
BeanPersistListener<T> currListener = persistListener;
|
||||
BeanPersistListener currListener = persistListener;
|
||||
if (currListener == null) {
|
||||
persistListener = newListener;
|
||||
persistListener = newPersistListener;
|
||||
} else {
|
||||
if (currListener instanceof ChainedBeanPersistListener<?>) {
|
||||
if (currListener instanceof ChainedBeanPersistListener) {
|
||||
// add it to the existing chain
|
||||
persistListener = ((ChainedBeanPersistListener<T>) currListener).register(newListener);
|
||||
persistListener = ((ChainedBeanPersistListener) currListener).register(newPersistListener);
|
||||
} else {
|
||||
// build new chain of the 2
|
||||
persistListener = new ChainedBeanPersistListener<T>(currListener, newListener);
|
||||
persistListener = new ChainedBeanPersistListener(currListener, newPersistListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1735,9 +1638,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
*/
|
||||
public void register(BeanPersistController newController) {
|
||||
|
||||
if (!newController.isRegisterFor(beanType)) {
|
||||
// skip
|
||||
} else {
|
||||
if (newController.isRegisterFor(beanType)) {
|
||||
// volatile read...
|
||||
BeanPersistController c = persistController;
|
||||
if (c == null) {
|
||||
@@ -1781,13 +1682,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
return baseTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a named extra attribute.
|
||||
*/
|
||||
public String getExtraAttribute(String key) {
|
||||
return (String) extraAttrMap.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the identity generation type.
|
||||
*/
|
||||
@@ -1906,17 +1800,11 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
}
|
||||
|
||||
public boolean hasIdProperty(EntityBeanIntercept ebi) {
|
||||
if (idPropertyIndex > -1) {
|
||||
return ebi.isLoadedProperty(idPropertyIndex);
|
||||
}
|
||||
return false;
|
||||
return idPropertyIndex > -1 && ebi.isLoadedProperty(idPropertyIndex);
|
||||
}
|
||||
|
||||
public boolean hasVersionProperty(EntityBeanIntercept ebi) {
|
||||
if (versionPropertyIndex > -1) {
|
||||
return ebi.isLoadedProperty(versionPropertyIndex);
|
||||
}
|
||||
return false;
|
||||
return versionPropertyIndex > -1 && ebi.isLoadedProperty(versionPropertyIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1979,16 +1867,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
return propertiesOneImportedDelete;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns OneToOnes that are on the exported side of a OneToOne.
|
||||
* <p>
|
||||
* These associations do not own the relationship.
|
||||
* </p>
|
||||
*/
|
||||
public BeanPropertyAssocOne<?>[] propertiesOneExported() {
|
||||
return propertiesOneExported;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exported assoc ones with cascade save.
|
||||
*/
|
||||
@@ -2003,32 +1881,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
return propertiesOneExportedDelete;
|
||||
}
|
||||
|
||||
private Set<String> deriveManyPropNames() {
|
||||
|
||||
LinkedHashSet<String> names = new LinkedHashSet<String>();
|
||||
for (int i = 0; i < propertiesMany.length; i++) {
|
||||
names.add(propertiesMany[i].getName());
|
||||
}
|
||||
|
||||
return Collections.unmodifiableSet(names);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a hash of the names of the many properties on this bean type. This
|
||||
* is used for efficient building of included properties sets for partial
|
||||
* objects.
|
||||
*/
|
||||
public int getNamesOfManyPropsHash() {
|
||||
return namesOfManyPropsHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of many property names for this bean type.
|
||||
*/
|
||||
public Set<String> getNamesOfManyProps() {
|
||||
return namesOfManyProps;
|
||||
}
|
||||
|
||||
/**
|
||||
* All Non Assoc Many's for this descriptor.
|
||||
*/
|
||||
@@ -2075,20 +1927,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
return versionProperty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is an Update (rather than insert) given that the bean
|
||||
* is involved in a stateless update.
|
||||
*/
|
||||
public boolean isStatelessUpdate(EntityBean bean) {
|
||||
if (versionProperty == null) {
|
||||
Object versionValue = getId(bean);
|
||||
return !DmlUtil.isNullOrZero(versionValue);
|
||||
} else {
|
||||
Object versionValue = versionProperty.getValue(bean);
|
||||
return !DmlUtil.isNullOrZero(versionValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scalar properties without the unique id or secondary table properties.
|
||||
*/
|
||||
|
||||
@@ -105,7 +105,16 @@ public final class BeanDescriptorCacheHelp<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setUseCache(boolean useCache) {
|
||||
if (useCache) {
|
||||
getBeanCache();
|
||||
} else {
|
||||
beanCacheClear();
|
||||
beanCache = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is currently query caching for this type of bean.
|
||||
*/
|
||||
|
||||
@@ -1,25 +1,5 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.persistence.Transient;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.Model;
|
||||
import com.avaje.ebean.RawSql;
|
||||
@@ -29,7 +9,6 @@ import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.EncryptKey;
|
||||
import com.avaje.ebean.config.EncryptKeyManager;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebean.config.NamingConvention;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.config.dbplatform.DbIdentity;
|
||||
@@ -38,35 +17,31 @@ import com.avaje.ebean.config.dbplatform.IdType;
|
||||
import com.avaje.ebean.event.BeanFinder;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.TransactionEventTable;
|
||||
import com.avaje.ebeaninternal.server.core.BootupClasses;
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
import com.avaje.ebeaninternal.server.core.InternalConfiguration;
|
||||
import com.avaje.ebeaninternal.server.core.Message;
|
||||
import com.avaje.ebeaninternal.server.core.XmlConfig;
|
||||
import com.avaje.ebeaninternal.server.core.*;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor.EntityType;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.IdBinderEmbedded;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.IdBinderFactory;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanTable;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoin;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployBeanInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployCreateProperties;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployInherit;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployUtil;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.ReadAnnotations;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.TransientProperties;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.*;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.*;
|
||||
import com.avaje.ebeaninternal.server.idgen.UuidIdGenerator;
|
||||
import com.avaje.ebeaninternal.server.lib.util.Dnode;
|
||||
import com.avaje.ebeaninternal.server.reflect.BeanReflect;
|
||||
import com.avaje.ebeaninternal.server.reflect.BeanReflectFactory;
|
||||
import com.avaje.ebeaninternal.server.reflect.BeanReflectProperties;
|
||||
import com.avaje.ebeaninternal.server.reflect.EnhanceBeanReflectFactory;
|
||||
import com.avaje.ebeaninternal.server.properties.BeanPropertiesReader;
|
||||
import com.avaje.ebeaninternal.server.properties.BeanPropertyInfo;
|
||||
import com.avaje.ebeaninternal.server.properties.BeanPropertyInfoFactory;
|
||||
import com.avaje.ebeaninternal.server.properties.EnhanceBeanPropertyInfoFactory;
|
||||
import com.avaje.ebeaninternal.server.type.TypeManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.persistence.Transient;
|
||||
import javax.sql.DataSource;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Creates BeanDescriptors.
|
||||
@@ -86,7 +61,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
*/
|
||||
private final DeployInherit deplyInherit;
|
||||
|
||||
private final BeanReflectFactory reflectFactory;
|
||||
private final BeanPropertyInfoFactory reflectFactory;
|
||||
|
||||
private final DeployUtil deployUtil;
|
||||
|
||||
@@ -153,6 +128,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
private final BeanLifecycleAdapterFactory beanLifecycleAdapterFactory;
|
||||
|
||||
private final boolean eagerFetchLobs;
|
||||
|
||||
/**
|
||||
* Create for a given database dbConfig.
|
||||
*/
|
||||
@@ -167,6 +144,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
this.encryptKeyManager = config.getServerConfig().getEncryptKeyManager();
|
||||
this.databasePlatform = config.getServerConfig().getDatabasePlatform();
|
||||
this.idBinderFactory = new IdBinderFactory(databasePlatform.isIdInExpandedForm());
|
||||
this.eagerFetchLobs = config.getServerConfig().isEagerFetchLobs();
|
||||
|
||||
this.bootupClasses = config.getBootupClasses();
|
||||
this.createProperties = config.getDeployCreateProperties();
|
||||
@@ -397,12 +375,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
String msg = "SERIOUS ERROR: The hashCode() and equals() methods *MUST* be implemented ";
|
||||
msg += "on Embedded bean " + idType + " as it is used as an Id for " + beanType;
|
||||
|
||||
if (GlobalProperties.getBoolean("ebean.strict", true)) {
|
||||
throw new PersistenceException(msg, source);
|
||||
} else {
|
||||
logger.error(msg, source);
|
||||
}
|
||||
throw new PersistenceException(msg, source);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1017,7 +990,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
DeployBeanInfo<T> info = new DeployBeanInfo<T>(deployUtil, desc);
|
||||
|
||||
readAnnotations.readInitial(info);
|
||||
readAnnotations.readInitial(info, eagerFetchLobs);
|
||||
return info;
|
||||
}
|
||||
|
||||
@@ -1274,9 +1247,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
}
|
||||
|
||||
private BeanReflectFactory createReflectionFactory() {
|
||||
private BeanPropertyInfoFactory createReflectionFactory() {
|
||||
|
||||
return new EnhanceBeanReflectFactory();
|
||||
return new EnhanceBeanPropertyInfoFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1295,9 +1268,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
Class<?> beanType = desc.getBeanType();
|
||||
|
||||
BeanReflectProperties reflectProps = new BeanReflectProperties(beanType);
|
||||
BeanPropertiesReader reflectProps = new BeanPropertiesReader(beanType);
|
||||
|
||||
BeanReflect beanReflect = reflectFactory.create(beanType);
|
||||
BeanPropertyInfo beanReflect = reflectFactory.create(beanType);
|
||||
desc.setBeanReflect(beanReflect);
|
||||
desc.setProperties(reflectProps.getProperties());
|
||||
|
||||
|
||||
@@ -22,29 +22,36 @@ public final class BeanListHelp<T> implements BeanCollectionHelp<T> {
|
||||
|
||||
private final BeanPropertyAssocMany<T> many;
|
||||
private final BeanDescriptor<T> targetDescriptor;
|
||||
private final String propertyName;
|
||||
|
||||
private BeanCollectionLoader loader;
|
||||
|
||||
public BeanListHelp(BeanPropertyAssocMany<T> many) {
|
||||
this.many = many;
|
||||
this.targetDescriptor = many.getTargetDescriptor();
|
||||
this.propertyName = many.getName();
|
||||
}
|
||||
|
||||
public BeanListHelp() {
|
||||
this.many = null;
|
||||
this.targetDescriptor = null;
|
||||
this.propertyName = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoader(BeanCollectionLoader loader) {
|
||||
this.loader = loader;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Internal add bypassing any modify listening.
|
||||
*/
|
||||
@Override
|
||||
public void add(BeanCollection<?> collection, EntityBean bean) {
|
||||
collection.internalAdd(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) {
|
||||
|
||||
if (bc instanceof BeanList<?>) {
|
||||
@@ -54,57 +61,42 @@ public final class BeanListHelp<T> implements BeanCollectionHelp<T> {
|
||||
bl.setActualList(new ArrayList<Object>());
|
||||
}
|
||||
return bl;
|
||||
} else if (bc instanceof List<?>) {
|
||||
return new VanillaAdd((List<?>) bc);
|
||||
|
||||
} else {
|
||||
throw new RuntimeException("Unhandled type " + bc);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static class VanillaAdd implements BeanCollectionAdd {
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private final List list;
|
||||
|
||||
private VanillaAdd(List<?> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
public void addBean(EntityBean bean) {
|
||||
list.add(bean);
|
||||
}
|
||||
@Override
|
||||
public BeanCollection<T> createEmptyNoParent() {
|
||||
return new BeanList<T>();
|
||||
}
|
||||
|
||||
public Iterator<?> getIterator(Object collection) {
|
||||
return ((List<?>) collection).iterator();
|
||||
}
|
||||
|
||||
public Object createEmpty(boolean vanilla) {
|
||||
if (vanilla) {
|
||||
return new ArrayList<T>();
|
||||
}
|
||||
BeanList<T> beanList = new BeanList<T>();
|
||||
@Override
|
||||
public BeanCollection<T> createEmpty(EntityBean parentBean) {
|
||||
BeanList<T> beanList = new BeanList<T>(loader, parentBean, propertyName);
|
||||
if (many != null) {
|
||||
beanList.setModifyListening(many.getModifyListenMode());
|
||||
}
|
||||
return beanList;
|
||||
}
|
||||
|
||||
public BeanCollection<T> createReference(EntityBean parentBean, String propertyName) {
|
||||
@Override
|
||||
public BeanCollection<T> createReference(EntityBean parentBean) {
|
||||
|
||||
BeanList<T> beanList = new BeanList<T>(loader, parentBean, propertyName);
|
||||
beanList.setModifyListening(many.getModifyListenMode());
|
||||
return beanList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(EbeanServer server, Query<?> query, Transaction t, EntityBean parentBean) {
|
||||
|
||||
BeanList<?> newBeanList = (BeanList<?>) server.findList(query, t);
|
||||
refresh(newBeanList, parentBean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(BeanCollection<?> bc, EntityBean parentBean) {
|
||||
|
||||
BeanList<?> newBeanList = (BeanList<?>) bc;
|
||||
@@ -129,6 +121,7 @@ public final class BeanListHelp<T> implements BeanCollectionHelp<T> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(WriteJson ctx, String name, Object collection, boolean explicitInclude) throws IOException {
|
||||
|
||||
List<?> list;
|
||||
@@ -150,7 +143,7 @@ public final class BeanListHelp<T> implements BeanCollectionHelp<T> {
|
||||
|
||||
ctx.writeStartArray(name);
|
||||
for (int j = 0; j < list.size(); j++) {
|
||||
targetDescriptor.jsonWrite(ctx, (EntityBean)list.get(j));
|
||||
targetDescriptor.jsonWrite(ctx, (EntityBean) list.get(j));
|
||||
}
|
||||
ctx.writeEndArray();
|
||||
}
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.Transaction;
|
||||
@@ -16,174 +10,175 @@ import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.common.BeanMap;
|
||||
import com.avaje.ebeaninternal.server.text.json.WriteJson;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* Helper specifically for dealing with Maps.
|
||||
*/
|
||||
public final class BeanMapHelp<T> implements BeanCollectionHelp<T> {
|
||||
|
||||
private final BeanPropertyAssocMany<T> many;
|
||||
private final BeanDescriptor<T> targetDescriptor;
|
||||
private final BeanProperty beanProperty;
|
||||
private BeanCollectionLoader loader;
|
||||
//private final String mapKey;
|
||||
|
||||
/**
|
||||
* When created for a given query that will return a map.
|
||||
*/
|
||||
public BeanMapHelp(BeanDescriptor<T> targetDescriptor, String mapKey) {
|
||||
this(null, targetDescriptor, mapKey);
|
||||
}
|
||||
private final BeanPropertyAssocMany<T> many;
|
||||
private final BeanDescriptor<T> targetDescriptor;
|
||||
private final String propertyName;
|
||||
private final BeanProperty beanProperty;
|
||||
private BeanCollectionLoader loader;
|
||||
|
||||
public BeanMapHelp(BeanPropertyAssocMany<T> many){
|
||||
this(many, many.getTargetDescriptor(), many.getMapKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* When help is attached to a specific many property.
|
||||
*/
|
||||
private BeanMapHelp(BeanPropertyAssocMany<T> many, BeanDescriptor<T> targetDescriptor, String mapKey){
|
||||
this.many = many;
|
||||
this.targetDescriptor = targetDescriptor;
|
||||
//this.mapKey = mapKey;
|
||||
this.beanProperty = targetDescriptor.getBeanProperty(mapKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an iterator of the values.
|
||||
*/
|
||||
public Iterator<?> getIterator(Object collection) {
|
||||
return ((Map<?,?>) collection).values().iterator();
|
||||
/**
|
||||
* When created for a given query that will return a map.
|
||||
*/
|
||||
public BeanMapHelp(BeanDescriptor<T> targetDescriptor, String mapKey) {
|
||||
this.targetDescriptor = targetDescriptor;
|
||||
this.beanProperty = targetDescriptor.getBeanProperty(mapKey);
|
||||
this.many = null;
|
||||
this.propertyName = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* When help is attached to a specific many property.
|
||||
*/ public BeanMapHelp(BeanPropertyAssocMany<T> many) {
|
||||
this.many = many;
|
||||
this.targetDescriptor = many.getTargetDescriptor();
|
||||
this.propertyName = many.getName();
|
||||
this.beanProperty = targetDescriptor.getBeanProperty(many.getMapKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoader(BeanCollectionLoader loader) {
|
||||
this.loader = loader;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) {
|
||||
|
||||
if (mapKey == null) {
|
||||
mapKey = many.getMapKey();
|
||||
}
|
||||
|
||||
public void setLoader(BeanCollectionLoader loader){
|
||||
this.loader = loader;
|
||||
}
|
||||
BeanProperty beanProp = targetDescriptor.getBeanProperty(mapKey);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) {
|
||||
|
||||
if(mapKey == null){
|
||||
mapKey = many.getMapKey();
|
||||
}
|
||||
BeanProperty beanProp = targetDescriptor.getBeanProperty(mapKey);
|
||||
|
||||
if (bc instanceof BeanMap<?,?>){
|
||||
BeanMap<Object, Object> bm = (BeanMap<Object, Object>)bc;
|
||||
Map<Object, Object> actualMap = bm.getActualMap();
|
||||
if (actualMap == null){
|
||||
actualMap = new LinkedHashMap<Object, Object>();
|
||||
bm.setActualMap(actualMap);
|
||||
}
|
||||
return new Adder(beanProp, actualMap);
|
||||
|
||||
} else if (bc instanceof Map<?,?>) {
|
||||
return new Adder(beanProp, (Map<Object, Object>)bc);
|
||||
|
||||
} else {
|
||||
throw new RuntimeException("Unhandled type "+bc);
|
||||
}
|
||||
}
|
||||
if (bc instanceof BeanMap<?, ?>) {
|
||||
BeanMap<Object, Object> bm = (BeanMap<Object, Object>) bc;
|
||||
Map<Object, Object> actualMap = bm.getActualMap();
|
||||
if (actualMap == null) {
|
||||
actualMap = new LinkedHashMap<Object, Object>();
|
||||
bm.setActualMap(actualMap);
|
||||
}
|
||||
return new Adder(beanProp, actualMap);
|
||||
|
||||
static class Adder implements BeanCollectionAdd {
|
||||
|
||||
private final BeanProperty beanProperty;
|
||||
|
||||
private final Map<Object, Object> map;
|
||||
|
||||
Adder(BeanProperty beanProperty, Map<Object, Object> map) {
|
||||
this.beanProperty = beanProperty;
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
public void addBean(EntityBean bean) {
|
||||
Object keyValue = beanProperty.getValue(bean);
|
||||
map.put(keyValue, bean);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("Unhandled type " + bc);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public Object createEmpty(boolean vanilla) {
|
||||
if (vanilla) {
|
||||
return new LinkedHashMap();
|
||||
}
|
||||
BeanMap beanMap = new BeanMap();
|
||||
if (many != null) {
|
||||
beanMap.setModifyListening(many.getModifyListenMode());
|
||||
}
|
||||
return beanMap;
|
||||
}
|
||||
|
||||
public void add(BeanCollection<?> collection, EntityBean bean) {
|
||||
static class Adder implements BeanCollectionAdd {
|
||||
|
||||
Object keyValue = beanProperty.getValueIntercept(bean);
|
||||
private final BeanProperty beanProperty;
|
||||
|
||||
((BeanMap<?,?>) collection).internalPut(keyValue, bean);
|
||||
}
|
||||
private final Map<Object, Object> map;
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public BeanCollection<T> createReference(EntityBean parentBean, String propertyName) {
|
||||
Adder(BeanProperty beanProperty, Map<Object, Object> map) {
|
||||
this.beanProperty = beanProperty;
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
BeanMap beanMap = new BeanMap(loader, parentBean, propertyName);
|
||||
public void addBean(EntityBean bean) {
|
||||
Object keyValue = beanProperty.getValue(bean);
|
||||
map.put(keyValue, bean);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanCollection<T> createEmptyNoParent() {
|
||||
return new BeanMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public BeanCollection<T> createEmpty(EntityBean ownerBean) {
|
||||
|
||||
BeanMap beanMap = new BeanMap(loader, ownerBean, propertyName);
|
||||
if (many != null) {
|
||||
beanMap.setModifyListening(many.getModifyListenMode());
|
||||
}
|
||||
return beanMap;
|
||||
}
|
||||
}
|
||||
|
||||
public void refresh(EbeanServer server, Query<?> query, Transaction t, EntityBean parentBean) {
|
||||
BeanMap<?, ?> newBeanMap = (BeanMap<?, ?>) server.findMap(query, t);
|
||||
refresh(newBeanMap, parentBean);
|
||||
}
|
||||
|
||||
public void refresh(BeanCollection<?> bc, EntityBean parentBean) {
|
||||
@Override
|
||||
public void add(BeanCollection<?> collection, EntityBean bean) {
|
||||
|
||||
BeanMap<?, ?> newBeanMap = (BeanMap<?, ?>) bc;
|
||||
Map<?, ?> current = (Map<?, ?>) many.getValue(parentBean);
|
||||
Object keyValue = beanProperty.getValueIntercept(bean);
|
||||
((BeanMap<?, ?>) collection).internalPut(keyValue, bean);
|
||||
}
|
||||
|
||||
newBeanMap.setModifyListening(many.getModifyListenMode());
|
||||
if (current == null) {
|
||||
// the currentMap is null? Not really expecting this...
|
||||
many.setValue(parentBean, newBeanMap);
|
||||
@Override
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public BeanCollection<T> createReference(EntityBean parentBean) {
|
||||
|
||||
} else if (current instanceof BeanMap<?,?>) {
|
||||
// normally this case, replace just the underlying list
|
||||
BeanMap<?, ?> currentBeanMap = (BeanMap<?, ?>) current;
|
||||
currentBeanMap.setActualMap(newBeanMap.getActualMap());
|
||||
currentBeanMap.setModifyListening(many.getModifyListenMode());
|
||||
BeanMap beanMap = new BeanMap(loader, parentBean, propertyName);
|
||||
if (many != null) {
|
||||
beanMap.setModifyListening(many.getModifyListenMode());
|
||||
}
|
||||
return beanMap;
|
||||
}
|
||||
|
||||
} else {
|
||||
// replace the entire set
|
||||
many.setValue(parentBean, newBeanMap);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void refresh(EbeanServer server, Query<?> query, Transaction t, EntityBean parentBean) {
|
||||
BeanMap<?, ?> newBeanMap = (BeanMap<?, ?>) server.findMap(query, t);
|
||||
refresh(newBeanMap, parentBean);
|
||||
}
|
||||
|
||||
public void jsonWrite(WriteJson ctx, String name, Object collection, boolean explicitInclude) throws IOException {
|
||||
|
||||
Map<?,?> map;
|
||||
if (collection instanceof BeanCollection<?>){
|
||||
BeanMap<?,?> bc = (BeanMap<?,?>)collection;
|
||||
if (!bc.isPopulated()){
|
||||
if (explicitInclude){
|
||||
// invoke lazy loading as collection
|
||||
// is explicitly included in the output
|
||||
bc.size();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
map = bc.getActualMap();
|
||||
@Override
|
||||
public void refresh(BeanCollection<?> bc, EntityBean parentBean) {
|
||||
|
||||
BeanMap<?, ?> newBeanMap = (BeanMap<?, ?>) bc;
|
||||
Map<?, ?> current = (Map<?, ?>) many.getValue(parentBean);
|
||||
|
||||
newBeanMap.setModifyListening(many.getModifyListenMode());
|
||||
if (current == null) {
|
||||
// the currentMap is null? Not really expecting this...
|
||||
many.setValue(parentBean, newBeanMap);
|
||||
|
||||
} else if (current instanceof BeanMap<?, ?>) {
|
||||
// normally this case, replace just the underlying list
|
||||
BeanMap<?, ?> currentBeanMap = (BeanMap<?, ?>) current;
|
||||
currentBeanMap.setActualMap(newBeanMap.getActualMap());
|
||||
currentBeanMap.setModifyListening(many.getModifyListenMode());
|
||||
|
||||
} else {
|
||||
// replace the entire set
|
||||
many.setValue(parentBean, newBeanMap);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(WriteJson ctx, String name, Object collection, boolean explicitInclude) throws IOException {
|
||||
|
||||
Map<?, ?> map;
|
||||
if (collection instanceof BeanCollection<?>) {
|
||||
BeanMap<?, ?> bc = (BeanMap<?, ?>) collection;
|
||||
if (!bc.isPopulated()) {
|
||||
if (explicitInclude) {
|
||||
// invoke lazy loading as collection
|
||||
// is explicitly included in the output
|
||||
bc.size();
|
||||
} else {
|
||||
map = (Map<?,?>)collection;
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.writeStartArray(name);
|
||||
Iterator<?> it = map.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Entry<?, ?> entry = (Entry<?, ?>)it.next();
|
||||
//FIXME: json write map key ...
|
||||
targetDescriptor.jsonWrite(ctx, (EntityBean) entry.getValue());
|
||||
}
|
||||
ctx.writeEndArray();
|
||||
}
|
||||
map = bc.getActualMap();
|
||||
} else {
|
||||
map = (Map<?, ?>) collection;
|
||||
}
|
||||
|
||||
ctx.writeStartArray(name);
|
||||
for (Entry<?, ?> entry : map.entrySet()) {
|
||||
//FIXME: json write map key ...
|
||||
targetDescriptor.jsonWrite(ctx, (EntityBean) entry.getValue());
|
||||
}
|
||||
ctx.writeEndArray();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ import com.avaje.ebeaninternal.server.el.ElPropertyValue;
|
||||
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
||||
import com.avaje.ebeaninternal.server.query.SqlBeanLoad;
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
import com.avaje.ebeaninternal.server.reflect.BeanReflectGetter;
|
||||
import com.avaje.ebeaninternal.server.reflect.BeanReflectSetter;
|
||||
import com.avaje.ebeaninternal.server.properties.BeanPropertyGetter;
|
||||
import com.avaje.ebeaninternal.server.properties.BeanPropertySetter;
|
||||
import com.avaje.ebeaninternal.server.text.json.WriteJson;
|
||||
import com.avaje.ebeaninternal.server.type.DataBind;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
@@ -41,29 +41,6 @@ import com.fasterxml.jackson.core.JsonToken;
|
||||
*/
|
||||
public class BeanProperty implements ElPropertyValue {
|
||||
|
||||
/**
|
||||
* Advanced bean deployment. To exclude this property from update where
|
||||
* clause.
|
||||
*/
|
||||
public static final String EXCLUDE_FROM_UPDATE_WHERE = "EXCLUDE_FROM_UPDATE_WHERE";
|
||||
|
||||
/**
|
||||
* Advanced bean deployment. To exclude this property from delete where
|
||||
* clause.
|
||||
*/
|
||||
public static final String EXCLUDE_FROM_DELETE_WHERE = "EXCLUDE_FROM_DELETE_WHERE";
|
||||
|
||||
/**
|
||||
* Advanced bean deployment. To exclude this property from insert.
|
||||
*/
|
||||
public static final String EXCLUDE_FROM_INSERT = "EXCLUDE_FROM_INSERT";
|
||||
|
||||
/**
|
||||
* Advanced bean deployment. To exclude this property from update set
|
||||
* clause.
|
||||
*/
|
||||
public static final String EXCLUDE_FROM_UPDATE = "EXCLUDE_FROM_UPDATE";
|
||||
|
||||
/**
|
||||
* Flag to mark this at part of the unique id.
|
||||
*/
|
||||
@@ -219,9 +196,9 @@ public class BeanProperty implements ElPropertyValue {
|
||||
*/
|
||||
final GeneratedProperty generatedProperty;
|
||||
|
||||
final BeanReflectGetter getter;
|
||||
final BeanPropertyGetter getter;
|
||||
|
||||
final BeanReflectSetter setter;
|
||||
final BeanPropertySetter setter;
|
||||
|
||||
final BeanDescriptor<?> descriptor;
|
||||
|
||||
@@ -488,15 +465,7 @@ public class BeanProperty implements ElPropertyValue {
|
||||
* Return true if the underlying type is mutable.
|
||||
*/
|
||||
public boolean isMutableScalarType() {
|
||||
if (scalarType == null) {
|
||||
return false;
|
||||
}
|
||||
return scalarType.isMutable();
|
||||
}
|
||||
|
||||
public void copyProperty(EntityBean sourceBean, EntityBean destBean) {
|
||||
Object value = getValue(sourceBean);
|
||||
setValue(destBean, value);
|
||||
return scalarType != null && scalarType.isMutable();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -506,10 +475,6 @@ public class BeanProperty implements ElPropertyValue {
|
||||
return descriptor.getEncryptKey(this);
|
||||
}
|
||||
|
||||
public String getDecryptProperty() {
|
||||
return dbEncryptFunction.getDecryptSql(this.getName());
|
||||
}
|
||||
|
||||
public String getDecryptProperty(String propertyName) {
|
||||
return dbEncryptFunction.getDecryptSql(propertyName);
|
||||
}
|
||||
@@ -575,24 +540,6 @@ public class BeanProperty implements ElPropertyValue {
|
||||
return owningType.isAssignableFrom(type);
|
||||
}
|
||||
|
||||
public Object readSetOwning(DbReadContext ctx, EntityBean bean, Class<?> type) throws SQLException {
|
||||
|
||||
try {
|
||||
Object value = scalarType.read(ctx.getDataReader());
|
||||
if (value == null || bean == null) {
|
||||
// not setting the value...
|
||||
} else {
|
||||
if (owningType.equals(type)) {
|
||||
setValue(bean, value);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
} catch (Exception e) {
|
||||
String msg = "Error readSet on " + descriptor + "." + name;
|
||||
throw new PersistenceException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void loadIgnore(DbReadContext ctx) {
|
||||
scalarType.loadIgnore(ctx.getDataReader());
|
||||
}
|
||||
@@ -616,16 +563,13 @@ public class BeanProperty implements ElPropertyValue {
|
||||
public Object readSet(DbReadContext ctx, EntityBean bean, Class<?> type) throws SQLException {
|
||||
|
||||
try {
|
||||
Object value = scalarType.read(ctx.getDataReader());
|
||||
if (bean == null || (type != null && !owningType.isAssignableFrom(type))) {
|
||||
// not setting the value...
|
||||
} else {
|
||||
setValue(bean, value);
|
||||
}
|
||||
return value;
|
||||
Object value = scalarType.read(ctx.getDataReader());
|
||||
if (bean != null && ((type == null || owningType.isAssignableFrom(type)))) {
|
||||
setValue(bean, value);
|
||||
}
|
||||
return value;
|
||||
} catch (Exception e) {
|
||||
String msg = "Error readSet on " + descriptor + "." + name;
|
||||
throw new PersistenceException(msg, e);
|
||||
throw new PersistenceException("Error readSet on " + descriptor + "." + name, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -653,21 +597,6 @@ public class BeanProperty implements ElPropertyValue {
|
||||
return scalarType.readData(dataInput);
|
||||
}
|
||||
|
||||
public boolean isCascadeValidate() {
|
||||
return cascadeValidate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if a bean is a reference (will be lazy loaded) or a
|
||||
* BeanCollection that has not yet been populated.
|
||||
* <p>
|
||||
* For base types this returns true.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isValueLoaded(Object value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public BeanProperty getBeanProperty() {
|
||||
return this;
|
||||
}
|
||||
@@ -737,16 +666,21 @@ public class BeanProperty implements ElPropertyValue {
|
||||
}
|
||||
}
|
||||
|
||||
private static Object[] NO_ARGS = new Object[0];
|
||||
|
||||
public Object getCacheDataValue(EntityBean bean) {
|
||||
return getValue(bean);
|
||||
}
|
||||
}
|
||||
|
||||
public void setCacheDataValue(EntityBean bean, Object cacheData) {
|
||||
setValue(bean, cacheData);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the property value from a compound value type.
|
||||
*/
|
||||
public Object getValueObject(Object bean) {
|
||||
throw new RuntimeException("Expected to be called only on BeanPropertyCompoundScalar");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value of the property method.
|
||||
*/
|
||||
@@ -759,19 +693,6 @@ public class BeanProperty implements ElPropertyValue {
|
||||
throw new RuntimeException(msg, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Explicitly use reflection to get value.
|
||||
*/
|
||||
public Object getValueViaReflection(Object bean) {
|
||||
try {
|
||||
return readMethod.invoke(bean, NO_ARGS);
|
||||
} catch (Exception ex) {
|
||||
String beanType = bean == null ? "null" : bean.getClass().getName();
|
||||
String msg = "get " + name + " on [" + descriptor + "] type[" + beanType + "] threw error.";
|
||||
throw new RuntimeException(msg, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public Object getValueIntercept(EntityBean bean) {
|
||||
try {
|
||||
@@ -826,13 +747,6 @@ public class BeanProperty implements ElPropertyValue {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a full ElGetValue.
|
||||
*/
|
||||
public boolean isDeployOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsFormulaWithJoin() {
|
||||
return formula && sqlFormulaJoin != null;
|
||||
@@ -902,7 +816,7 @@ public class BeanProperty implements ElPropertyValue {
|
||||
/**
|
||||
* Return the scalarType.
|
||||
*/
|
||||
public ScalarType<?> getScalarType() {
|
||||
public ScalarType<Object> getScalarType() {
|
||||
return scalarType;
|
||||
}
|
||||
|
||||
@@ -923,7 +837,7 @@ public class BeanProperty implements ElPropertyValue {
|
||||
}
|
||||
|
||||
public Object parseDateTime(long systemTimeMillis) {
|
||||
return scalarType.parseDateTime(systemTimeMillis);
|
||||
return scalarType.convertFromMillis(systemTimeMillis);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1031,10 +945,6 @@ public class BeanProperty implements ElPropertyValue {
|
||||
return version;
|
||||
}
|
||||
|
||||
public String getDeployProperty() {
|
||||
return dbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* The database column name this is mapped to.
|
||||
*/
|
||||
@@ -1168,13 +1078,6 @@ public class BeanProperty implements ElPropertyValue {
|
||||
return embedded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an extra attribute set on this property.
|
||||
*/
|
||||
public String getExtraAttribute(String key) {
|
||||
return extraAttributeMap.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default value.
|
||||
*/
|
||||
|
||||
@@ -174,7 +174,7 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
|
||||
public void addBeanToCollectionWithCreate(EntityBean parentBean, EntityBean detailBean) {
|
||||
BeanCollection<?> bc = (BeanCollection<?>) super.getValue(parentBean);
|
||||
if (bc == null) {
|
||||
bc = (BeanCollection<?>) help.createEmpty(false);
|
||||
bc = help.createEmpty(parentBean);
|
||||
setValue(parentBean, bc);
|
||||
}
|
||||
help.add(bc, detailBean);
|
||||
@@ -185,6 +185,22 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
|
||||
return val == null || (val instanceof BeanCollection<?>) && ((BeanCollection<?>) val).isEmptyAndUntouched();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the many properties to be empty and ready for reloading.
|
||||
* <p>
|
||||
* Used in bean refresh.
|
||||
*/
|
||||
public void resetMany(EntityBean bean) {
|
||||
Object value = getValue(bean);
|
||||
if (value == null) {
|
||||
// not expecting this - set an empty reference
|
||||
createReference(bean);
|
||||
} else {
|
||||
// reset the collection back to empty
|
||||
((BeanCollection)value).reset(bean, name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(EntityBean bean) {
|
||||
return super.getValue(bean);
|
||||
@@ -385,12 +401,6 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isValueLoaded(Object value) {
|
||||
return !(value instanceof BeanCollection<?>) || ((BeanCollection<?>) value).isPopulated();
|
||||
}
|
||||
|
||||
public void add(BeanCollection<?> collection, EntityBean bean) {
|
||||
help.add(collection, bean);
|
||||
}
|
||||
@@ -532,13 +542,13 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
|
||||
|
||||
public BeanCollection<?> createReference(EntityBean parentBean) {
|
||||
|
||||
BeanCollection<?> ref = help.createReference(parentBean, name);
|
||||
BeanCollection<?> ref = help.createReference(parentBean);
|
||||
setValue(parentBean, ref);
|
||||
return ref;
|
||||
}
|
||||
|
||||
public Object createEmpty(boolean vanilla) {
|
||||
return help.createEmpty(vanilla);
|
||||
public BeanCollection<T> createEmpty(EntityBean parentBean) {
|
||||
return help.createEmpty(parentBean);
|
||||
}
|
||||
|
||||
public BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) {
|
||||
|
||||
+2
-1
@@ -2,6 +2,7 @@ package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.BeanCollectionAdd;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
@@ -30,7 +31,7 @@ public class BeanPropertyAssocManyJsonHelp {
|
||||
throw new JsonParseException("Unexpected token " + event + " - expecting start_array ", parser.getCurrentLocation());
|
||||
}
|
||||
|
||||
Object collection = many.createEmpty(false);
|
||||
BeanCollection<?> collection = many.createEmpty(parentBean);
|
||||
BeanCollectionAdd add = many.getBeanCollectionAdd(collection, null);
|
||||
do {
|
||||
EntityBean detailBean = (EntityBean) many.targetDescriptor.jsonRead(parser, many.name);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user