mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
117
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f7199b586 | ||
|
|
721a50219d | ||
|
|
f0b8270e5e | ||
|
|
92232c2afb | ||
|
|
5e68b1a25e | ||
|
|
041324d177 | ||
|
|
7d02a42276 | ||
|
|
2a900165f0 | ||
|
|
e7c40e9552 | ||
|
|
0d92807308 | ||
|
|
16f7de30c6 | ||
|
|
3d250b0eca | ||
|
|
8403adac90 | ||
|
|
c006aa3f48 | ||
|
|
dcb7054248 | ||
|
|
12833bc918 | ||
|
|
71d805bc17 | ||
|
|
ab8704e2c9 | ||
|
|
327e2baae7 | ||
|
|
6e89c551d5 | ||
|
|
0a3941227f | ||
|
|
0013cb1a76 | ||
|
|
8fe91f66c0 | ||
|
|
053fdf4abb | ||
|
|
24be907dc5 | ||
|
|
6aa915b420 | ||
|
|
40d87af5b1 | ||
|
|
75082fe0c0 | ||
|
|
7d43f5a3d7 | ||
|
|
99203a35a2 | ||
|
|
67f427b83e | ||
|
|
f5a2cf8ff9 | ||
|
|
4e1cda691f | ||
|
|
64b01324d1 | ||
|
|
3cba238073 | ||
|
|
b5b4a4639f | ||
|
|
2d0a179c3b | ||
|
|
40f7a0088d | ||
|
|
6a02a8d69f | ||
|
|
ed18cbcabf | ||
|
|
3ce4f2fb35 | ||
|
|
962a27f838 | ||
|
|
2b583cf707 | ||
|
|
ef9ade4f5c | ||
|
|
b1b7774a23 | ||
|
|
c6632bbc25 | ||
|
|
8c12fc762c | ||
|
|
8cb0b13ccb | ||
|
|
c2faffb6f4 | ||
|
|
e17d823c17 | ||
|
|
9bf9338ba9 | ||
|
|
0da764ed0c | ||
|
|
43003f4a3a | ||
|
|
7081d3f54a | ||
|
|
cce2c2e28f | ||
|
|
61ecf16978 | ||
|
|
9ff4e63c32 | ||
|
|
a13fd55f64 | ||
|
|
a90d413e01 | ||
|
|
f2559f80ef | ||
|
|
23da6f3de8 | ||
|
|
bdf35646a6 | ||
|
|
f947a76fce | ||
|
|
88f144ec33 | ||
|
|
21c8dd524a | ||
|
|
624da4a34a | ||
|
|
e3cccfa9a3 | ||
|
|
3358ab16a7 | ||
|
|
4eaa6adf08 | ||
|
|
4143c0de26 | ||
|
|
726d3a0c38 | ||
|
|
8f12bbb6c4 | ||
|
|
89db75e8c5 | ||
|
|
dfb69e3cde | ||
|
|
39520e367d | ||
|
|
30d697d490 | ||
|
|
241a1236b8 | ||
|
|
ccada72323 | ||
|
|
c2ddab2ba0 | ||
|
|
27a0e93fda | ||
|
|
f306672c6c | ||
|
|
dc86b8b447 | ||
|
|
d63eb7abe1 | ||
|
|
cc200e8607 | ||
|
|
fffc684edd | ||
|
|
82471c2573 | ||
|
|
f7fa778e99 | ||
|
|
fc3e1083d7 | ||
|
|
819edb20e8 | ||
|
|
e669a86135 | ||
|
|
4f67d2be4e | ||
|
|
0356067d86 | ||
|
|
74c9c14838 | ||
|
|
fc53e281e8 | ||
|
|
0c5e092d16 | ||
|
|
1260edc8ed | ||
|
|
de372bfb89 | ||
|
|
2ed5e026e0 | ||
|
|
6c37dc494b | ||
|
|
6807499d01 | ||
|
|
cb6faa022b | ||
|
|
3b30388b35 | ||
|
|
db57404e18 | ||
|
|
bede89fe13 | ||
|
|
c9fb28b288 | ||
|
|
a192b0cdbf | ||
|
|
0a15cdd7b2 | ||
|
|
14c5a1328b | ||
|
|
cac6333c5e | ||
|
|
f7d1291a41 | ||
|
|
151e44ff67 | ||
|
|
4f24944ec4 | ||
|
|
c3ccb1afb5 | ||
|
|
ca8f529629 | ||
|
|
2e03452e2e | ||
|
|
f78f4ea64a | ||
|
|
81aeca5475 |
@@ -1,12 +1,22 @@
|
||||
[](https://waffle.io/ebean-orm/avaje-ebeanorm)
|
||||
avaje-ebeanorm
|
||||
Ebean ORM
|
||||
==============
|
||||
|
||||
Project Website
|
||||
----------------
|
||||
[http://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Website")
|
||||
|
||||
|
||||
Maven Dependency
|
||||
----------------
|
||||
<dependency>
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm</artifactId>
|
||||
<version>4.5.4</version>
|
||||
<version>4.7.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
[Maven central - avaje-ebeanorm](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.avaje.ebeanorm%22%20AND%20a%3A%22avaje-ebeanorm%22 "maven central ebeanorm")
|
||||
|
||||
[Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cavaje-ebeanorm "maven central ebeanorm")
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm</artifactId>
|
||||
<version>4.5.5</version>
|
||||
<version>4.7.2</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>avaje-ebeanorm</name>
|
||||
@@ -55,12 +55,21 @@
|
||||
<version>1.7.7</version>
|
||||
</dependency>
|
||||
|
||||
<!-- provided scope for JsonNode support -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.5.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson core used internally by Ebean -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>2.4.3</version>
|
||||
<version>2.5.3</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.transaction</groupId>
|
||||
<artifactId>jta</artifactId>
|
||||
@@ -68,6 +77,7 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- provided scope to read validation annotations Size etc -->
|
||||
<dependency>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
@@ -89,6 +99,14 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Provided scope for Postgres JSON/JSONB support -->
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>9.4-1201-jdbc41</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
@@ -124,13 +142,6 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>8.4-701.jdbc4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
@@ -228,6 +239,13 @@
|
||||
<include>**/*Test.java</include>
|
||||
<include>**/*Tests.java</include>
|
||||
</includes>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<!-- transfer datasource.default parameter -->
|
||||
<name>datasource.default</name>
|
||||
<value>${datasource.default}</value>
|
||||
</property>
|
||||
</systemProperties>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
@@ -247,8 +265,6 @@
|
||||
<configuration>
|
||||
<doctitle>Ebean 4</doctitle>
|
||||
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
|
||||
<!-- <excludePackageNames>com.avaje.ebeaninternal.*:com.avaje.ebean.util</excludePackageNames> -->
|
||||
<!--<additionalparam>-Xdoclint:none</additionalparam>-->
|
||||
<source>1.8</source>
|
||||
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
|
||||
<excludePackageNames>com.avaje.ebeaninternal.*:com.avaje.ebean.util</excludePackageNames>
|
||||
|
||||
@@ -8,28 +8,28 @@ public interface AdminAutofetch {
|
||||
/**
|
||||
* Return true if profiling is enabled.
|
||||
*/
|
||||
public boolean isProfiling();
|
||||
boolean isProfiling();
|
||||
|
||||
/**
|
||||
* Set to true to enable profiling.
|
||||
*/
|
||||
public void setProfiling(boolean enable);
|
||||
void setProfiling(boolean enable);
|
||||
|
||||
/**
|
||||
* Return true if autoFetch automatic query tuning is enabled.
|
||||
*/
|
||||
public boolean isQueryTuning();
|
||||
boolean isQueryTuning();
|
||||
|
||||
/**
|
||||
* Set to true to enable autoFetch automatic query tuning.
|
||||
*/
|
||||
public void setQueryTuning(boolean enable);
|
||||
void setQueryTuning(boolean enable);
|
||||
|
||||
/**
|
||||
* Returns the rate which profiling is collected. This is an int between 0 and
|
||||
* 100.
|
||||
*/
|
||||
public double getProfilingRate();
|
||||
double getProfilingRate();
|
||||
|
||||
/**
|
||||
* Set the rate at which profiling is collected after the base.
|
||||
@@ -37,13 +37,13 @@ public interface AdminAutofetch {
|
||||
* @param rate
|
||||
* a int between 0 and 100.
|
||||
*/
|
||||
public void setProfilingRate(double rate);
|
||||
void setProfilingRate(double rate);
|
||||
|
||||
/**
|
||||
* Return the number of queries profiled after which profiling is collected at
|
||||
* a percentage rate.
|
||||
*/
|
||||
public int getProfilingBase();
|
||||
int getProfilingBase();
|
||||
|
||||
/**
|
||||
* Set a base number of queries to profile per query point.
|
||||
@@ -52,7 +52,7 @@ public interface AdminAutofetch {
|
||||
* the Profiling Percentage rate.
|
||||
* </p>
|
||||
*/
|
||||
public void setProfilingBase(int profilingBase);
|
||||
void setProfilingBase(int profilingBase);
|
||||
|
||||
/**
|
||||
* Return the minimum number of queries profiled before autoFetch will start
|
||||
@@ -62,7 +62,7 @@ public interface AdminAutofetch {
|
||||
* profiling information is collected.
|
||||
* </p>
|
||||
*/
|
||||
public int getProfilingMin();
|
||||
int getProfilingMin();
|
||||
|
||||
/**
|
||||
* Set the minimum number of queries profiled per query point before autoFetch
|
||||
@@ -72,13 +72,13 @@ public interface AdminAutofetch {
|
||||
* autoFetch starts tuning the query.
|
||||
* </p>
|
||||
*/
|
||||
public void setProfilingMin(int autoFetchMinThreshold);
|
||||
void setProfilingMin(int autoFetchMinThreshold);
|
||||
|
||||
/**
|
||||
* Fire a garbage collection (hint to the JVM). Assuming garbage collection
|
||||
* fires this will gather the usage profiling information.
|
||||
*/
|
||||
public String collectUsageViaGC();
|
||||
String collectUsageViaGC();
|
||||
|
||||
/**
|
||||
* This will take the current profiling information and update the "tuned
|
||||
@@ -89,7 +89,7 @@ public interface AdminAutofetch {
|
||||
*
|
||||
* @return a summary of the updates that occurred
|
||||
*/
|
||||
public String updateTunedQueryInfo();
|
||||
String updateTunedQueryInfo();
|
||||
|
||||
/**
|
||||
* Clear all the tuned query info.
|
||||
@@ -99,7 +99,7 @@ public interface AdminAutofetch {
|
||||
*
|
||||
* @return the amount of tuned query information cleared.
|
||||
*/
|
||||
public int clearTunedQueryInfo();
|
||||
int clearTunedQueryInfo();
|
||||
|
||||
/**
|
||||
* Clear all the profiling information.
|
||||
@@ -112,26 +112,26 @@ public interface AdminAutofetch {
|
||||
*
|
||||
* @return the amount of profiled information cleared.
|
||||
*/
|
||||
public int clearProfilingInfo();
|
||||
int clearProfilingInfo();
|
||||
|
||||
/**
|
||||
* Clear the query execution statistics.
|
||||
*/
|
||||
public void clearQueryStatistics();
|
||||
void clearQueryStatistics();
|
||||
|
||||
/**
|
||||
* Return the number of queries tuned by AutoFetch.
|
||||
*/
|
||||
public int getTotalTunedQueryCount();
|
||||
int getTotalTunedQueryCount();
|
||||
|
||||
/**
|
||||
* Return the size of the TuneQuery map.
|
||||
*/
|
||||
public int getTotalTunedQuerySize();
|
||||
int getTotalTunedQuerySize();
|
||||
|
||||
/**
|
||||
* Return the size of the profile map.
|
||||
*/
|
||||
public int getTotalProfileSize();
|
||||
int getTotalProfileSize();
|
||||
|
||||
}
|
||||
@@ -1,40 +1,40 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Background thread pool service for executing of tasks asynchronously.
|
||||
* <p>
|
||||
* This service is used internally by Ebean for executing background tasks such
|
||||
* as the {@link Query#findFutureList()} and also for executing background tasks
|
||||
* periodically.
|
||||
* </p>
|
||||
* <p>
|
||||
* This service has been made available so you can use it for your application
|
||||
* code if you want. It can be useful for some server caching implementations
|
||||
* (background population and trimming of the cache etc).
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface BackgroundExecutor {
|
||||
|
||||
/**
|
||||
* Execute a task in the background.
|
||||
*/
|
||||
public void execute(Runnable r);
|
||||
|
||||
/**
|
||||
* Execute a task periodically with a fixed delay between each execution.
|
||||
* <p>
|
||||
* For example, execute a runnable every minute.
|
||||
* </p>
|
||||
* <p>
|
||||
* The delay is the time between executions no matter how long the task took.
|
||||
* That is, this method has the same behaviour characteristics as
|
||||
* {@link ScheduledExecutorService#scheduleWithFixedDelay(Runnable, long, long, TimeUnit)}
|
||||
* </p>
|
||||
*/
|
||||
public void executePeriodically(Runnable r, long delay, TimeUnit unit);
|
||||
}
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Background thread pool service for executing of tasks asynchronously.
|
||||
* <p>
|
||||
* This service is used internally by Ebean for executing background tasks such
|
||||
* as the {@link Query#findFutureList()} and also for executing background tasks
|
||||
* periodically.
|
||||
* </p>
|
||||
* <p>
|
||||
* This service has been made available so you can use it for your application
|
||||
* code if you want. It can be useful for some server caching implementations
|
||||
* (background population and trimming of the cache etc).
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface BackgroundExecutor {
|
||||
|
||||
/**
|
||||
* Execute a task in the background.
|
||||
*/
|
||||
void execute(Runnable r);
|
||||
|
||||
/**
|
||||
* Execute a task periodically with a fixed delay between each execution.
|
||||
* <p>
|
||||
* For example, execute a runnable every minute.
|
||||
* </p>
|
||||
* <p>
|
||||
* The delay is the time between executions no matter how long the task took.
|
||||
* That is, this method has the same behaviour characteristics as
|
||||
* {@link ScheduledExecutorService#scheduleWithFixedDelay(Runnable, long, long, TimeUnit)}
|
||||
* </p>
|
||||
*/
|
||||
void executePeriodically(Runnable r, long delay, TimeUnit unit);
|
||||
}
|
||||
|
||||
@@ -1,86 +1,86 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Provides access to the internal state of an entity bean.
|
||||
*/
|
||||
public interface BeanState {
|
||||
|
||||
/**
|
||||
* Return true if this is a lazy loading reference bean.
|
||||
* <p>
|
||||
* If so the this bean only holds the Id property and will invoke lazy loading
|
||||
* if any other property is get or set.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isReference();
|
||||
|
||||
/**
|
||||
* Return true if the bean is new (and not yet saved).
|
||||
*/
|
||||
public boolean isNew();
|
||||
|
||||
/**
|
||||
* Return true if the bean is new or dirty (and probably needs to be saved).
|
||||
*/
|
||||
public boolean isNewOrDirty();
|
||||
|
||||
/**
|
||||
* Return true if the bean has been changed but not yet saved.
|
||||
*/
|
||||
public boolean isDirty();
|
||||
|
||||
/**
|
||||
* For partially populated beans returns the properties that are loaded on the
|
||||
* bean.
|
||||
* <p>
|
||||
* Accessing another property will cause lazy loading to occur.
|
||||
* </p>
|
||||
*/
|
||||
public Set<String> getLoadedProps();
|
||||
|
||||
/**
|
||||
* Return the set of changed properties.
|
||||
*/
|
||||
public Set<String> getChangedProps();
|
||||
|
||||
/**
|
||||
* Return a map of the updated properties and their new and old values.
|
||||
*/
|
||||
public Map<String,ValuePair> getDirtyValues();
|
||||
|
||||
/**
|
||||
* Return true if the bean is readOnly.
|
||||
* <p>
|
||||
* If a setter is called on a readOnly bean it will throw an exception.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isReadOnly();
|
||||
|
||||
/**
|
||||
* Set the readOnly status for the bean.
|
||||
*/
|
||||
public void setReadOnly(boolean readOnly);
|
||||
|
||||
/**
|
||||
* Add a propertyChangeListener.
|
||||
*/
|
||||
public void addPropertyChangeListener(PropertyChangeListener listener);
|
||||
|
||||
/**
|
||||
* Remove a propertyChangeListener.
|
||||
*/
|
||||
public void removePropertyChangeListener(PropertyChangeListener listener);
|
||||
|
||||
/**
|
||||
* Advanced - Used to programmatically build a partially or fully loaded
|
||||
* entity bean. First create an entity bean via
|
||||
* {@link EbeanServer#createEntityBean(Class)}, then populate its properties
|
||||
* and then call this method specifying which properties where loaded or null
|
||||
* for a fully loaded entity bean.
|
||||
*/
|
||||
public void setLoaded();
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Provides access to the internal state of an entity bean.
|
||||
*/
|
||||
public interface BeanState {
|
||||
|
||||
/**
|
||||
* Return true if this is a lazy loading reference bean.
|
||||
* <p>
|
||||
* If so the this bean only holds the Id property and will invoke lazy loading
|
||||
* if any other property is get or set.
|
||||
* </p>
|
||||
*/
|
||||
boolean isReference();
|
||||
|
||||
/**
|
||||
* Return true if the bean is new (and not yet saved).
|
||||
*/
|
||||
boolean isNew();
|
||||
|
||||
/**
|
||||
* Return true if the bean is new or dirty (and probably needs to be saved).
|
||||
*/
|
||||
boolean isNewOrDirty();
|
||||
|
||||
/**
|
||||
* Return true if the bean has been changed but not yet saved.
|
||||
*/
|
||||
boolean isDirty();
|
||||
|
||||
/**
|
||||
* For partially populated beans returns the properties that are loaded on the
|
||||
* bean.
|
||||
* <p>
|
||||
* Accessing another property will cause lazy loading to occur.
|
||||
* </p>
|
||||
*/
|
||||
Set<String> getLoadedProps();
|
||||
|
||||
/**
|
||||
* Return the set of changed properties.
|
||||
*/
|
||||
Set<String> getChangedProps();
|
||||
|
||||
/**
|
||||
* Return a map of the updated properties and their new and old values.
|
||||
*/
|
||||
Map<String,ValuePair> getDirtyValues();
|
||||
|
||||
/**
|
||||
* Return true if the bean is readOnly.
|
||||
* <p>
|
||||
* If a setter is called on a readOnly bean it will throw an exception.
|
||||
* </p>
|
||||
*/
|
||||
boolean isReadOnly();
|
||||
|
||||
/**
|
||||
* Set the readOnly status for the bean.
|
||||
*/
|
||||
void setReadOnly(boolean readOnly);
|
||||
|
||||
/**
|
||||
* Add a propertyChangeListener.
|
||||
*/
|
||||
void addPropertyChangeListener(PropertyChangeListener listener);
|
||||
|
||||
/**
|
||||
* Remove a propertyChangeListener.
|
||||
*/
|
||||
void removePropertyChangeListener(PropertyChangeListener listener);
|
||||
|
||||
/**
|
||||
* Advanced - Used to programmatically build a partially or fully loaded
|
||||
* entity bean. First create an entity bean via
|
||||
* {@link EbeanServer#createEntityBean(Class)}, then populate its properties
|
||||
* and then call this method specifying which properties where loaded or null
|
||||
* for a fully loaded entity bean.
|
||||
*/
|
||||
void setLoaded();
|
||||
}
|
||||
@@ -85,17 +85,17 @@ public interface CallableSql {
|
||||
/**
|
||||
* Set the label that is put in the transaction log.
|
||||
*/
|
||||
public CallableSql setLabel(String label);
|
||||
CallableSql setLabel(String label);
|
||||
|
||||
/**
|
||||
* Return the statement execution timeout.
|
||||
*/
|
||||
public int getTimeout();
|
||||
int getTimeout();
|
||||
|
||||
/**
|
||||
* Return the callable sql.
|
||||
*/
|
||||
public String getSql();
|
||||
String getSql();
|
||||
|
||||
/**
|
||||
* Set the statement execution timeout. Zero implies unlimited time.
|
||||
@@ -103,12 +103,12 @@ public interface CallableSql {
|
||||
* This is set to the underlying CallableStatement.
|
||||
* </p>
|
||||
*/
|
||||
public CallableSql setTimeout(int secs);
|
||||
CallableSql setTimeout(int secs);
|
||||
|
||||
/**
|
||||
* Set the callable sql.
|
||||
*/
|
||||
public CallableSql setSql(String sql);
|
||||
CallableSql setSql(String sql);
|
||||
|
||||
/**
|
||||
* Bind a parameter that is bound as a IN parameter.
|
||||
@@ -125,7 +125,7 @@ public interface CallableSql {
|
||||
* @param value
|
||||
* the value of the parameter.
|
||||
*/
|
||||
public CallableSql bind(int position, Object value);
|
||||
CallableSql bind(int position, Object value);
|
||||
|
||||
/**
|
||||
* Bind a positioned parameter (same as bind method).
|
||||
@@ -135,7 +135,7 @@ public interface CallableSql {
|
||||
* @param value
|
||||
* the value of the parameter.
|
||||
*/
|
||||
public CallableSql setParameter(int position, Object value);
|
||||
CallableSql setParameter(int position, Object value);
|
||||
|
||||
/**
|
||||
* Register an OUT parameter.
|
||||
@@ -153,7 +153,7 @@ public interface CallableSql {
|
||||
* @param type
|
||||
* the jdbc type of the OUT parameter that will be read.
|
||||
*/
|
||||
public CallableSql registerOut(int position, int type);
|
||||
CallableSql registerOut(int position, int type);
|
||||
|
||||
/**
|
||||
* Return an OUT parameter value.
|
||||
@@ -165,7 +165,7 @@ public interface CallableSql {
|
||||
* in batch mode you effectively can't use this method.
|
||||
* </p>
|
||||
*/
|
||||
public Object getObject(int position);
|
||||
Object getObject(int position);
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -173,7 +173,7 @@ public interface CallableSql {
|
||||
* stored procedure calls. This would be the case when ResultSets are returned
|
||||
* etc.
|
||||
*/
|
||||
public boolean executeOverride(CallableStatement cstmt) throws SQLException;
|
||||
boolean executeOverride(CallableStatement cstmt) throws SQLException;
|
||||
|
||||
/**
|
||||
* Add table modification information to the TransactionEvent.
|
||||
@@ -188,7 +188,6 @@ public interface CallableSql {
|
||||
* delete.
|
||||
* </p>
|
||||
*/
|
||||
public CallableSql addModification(String tableName, boolean inserts, boolean updates,
|
||||
boolean deletes);
|
||||
CallableSql addModification(String tableName, boolean inserts, boolean updates, boolean deletes);
|
||||
|
||||
}
|
||||
+1504
-1441
File diff suppressed because it is too large
Load Diff
@@ -103,30 +103,30 @@ public interface EbeanServer {
|
||||
* if true then deregister the JDBC driver if it is the EbeanORM
|
||||
* DataSource implementation.
|
||||
*/
|
||||
public void shutdown(boolean shutdownDataSource, boolean deregisterDriver);
|
||||
void shutdown(boolean shutdownDataSource, boolean deregisterDriver);
|
||||
|
||||
/**
|
||||
* Return the AdminAutofetch which is used to control and configure the
|
||||
* Autofetch service at runtime.
|
||||
*/
|
||||
public AdminAutofetch getAdminAutofetch();
|
||||
AdminAutofetch getAdminAutofetch();
|
||||
|
||||
/**
|
||||
* Return the name. This is used with {@link Ebean#getServer(String)} to get a
|
||||
* EbeanServer that was registered with the Ebean singleton.
|
||||
*/
|
||||
public String getName();
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Return the ExpressionFactory for this server.
|
||||
*/
|
||||
public ExpressionFactory getExpressionFactory();
|
||||
ExpressionFactory getExpressionFactory();
|
||||
|
||||
/**
|
||||
* Return the MetaInfoManager which is used to get meta data from the EbeanServer
|
||||
* such as query execution statistics.
|
||||
*/
|
||||
public MetaInfoManager getMetaInfoManager();
|
||||
MetaInfoManager getMetaInfoManager();
|
||||
|
||||
/**
|
||||
* Return the BeanState for a given entity bean.
|
||||
@@ -134,12 +134,12 @@ public interface EbeanServer {
|
||||
* This will return null if the bean is not an enhanced entity bean.
|
||||
* </p>
|
||||
*/
|
||||
public BeanState getBeanState(Object bean);
|
||||
BeanState getBeanState(Object bean);
|
||||
|
||||
/**
|
||||
* Return the value of the Id property for a given bean.
|
||||
*/
|
||||
public Object getBeanId(Object bean);
|
||||
Object getBeanId(Object bean);
|
||||
|
||||
/**
|
||||
* Return a map of the differences between two objects of the same type.
|
||||
@@ -148,7 +148,7 @@ public interface EbeanServer {
|
||||
* difference comparison.
|
||||
* </p>
|
||||
*/
|
||||
public Map<String, ValuePair> diff(Object a, Object b);
|
||||
Map<String, ValuePair> diff(Object a, Object b);
|
||||
|
||||
/**
|
||||
* Create a new instance of T that is an EntityBean.
|
||||
@@ -157,12 +157,12 @@ public interface EbeanServer {
|
||||
* favour of always using enhancement).
|
||||
* </p>
|
||||
*/
|
||||
public <T> T createEntityBean(Class<T> type);
|
||||
<T> T createEntityBean(Class<T> type);
|
||||
|
||||
/**
|
||||
* Create a CsvReader for a given beanType.
|
||||
*/
|
||||
public <T> CsvReader<T> createCsvReader(Class<T> beanType);
|
||||
<T> CsvReader<T> createCsvReader(Class<T> beanType);
|
||||
|
||||
/**
|
||||
* Return a named Query that will have defined fetch paths, predicates etc.
|
||||
@@ -182,7 +182,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public <T> Query<T> createNamedQuery(Class<T> beanType, String namedQuery);
|
||||
<T> Query<T> createNamedQuery(Class<T> beanType, String namedQuery);
|
||||
|
||||
/**
|
||||
* Create a query using the query language.
|
||||
@@ -208,14 +208,14 @@ public interface EbeanServer {
|
||||
* @param query
|
||||
* the object query
|
||||
*/
|
||||
public <T> Query<T> createQuery(Class<T> beanType, String query);
|
||||
<T> Query<T> createQuery(Class<T> beanType, String query);
|
||||
|
||||
/**
|
||||
* Create a query for an entity bean and synonym for {@link #find(Class)}.
|
||||
*
|
||||
* @see #find(Class)
|
||||
*/
|
||||
public <T> Query<T> createQuery(Class<T> beanType);
|
||||
<T> Query<T> createQuery(Class<T> beanType);
|
||||
|
||||
/**
|
||||
* Create a query for a type of entity bean.
|
||||
@@ -257,7 +257,7 @@ public interface EbeanServer {
|
||||
* }</pre>
|
||||
*
|
||||
*/
|
||||
public <T> Query<T> find(Class<T> beanType);
|
||||
<T> Query<T> find(Class<T> beanType);
|
||||
|
||||
/**
|
||||
* Return the next unique identity value for a given bean type.
|
||||
@@ -271,7 +271,7 @@ public interface EbeanServer {
|
||||
* complex cases where it is useful to get an ID prior to some processing.
|
||||
* </p>
|
||||
*/
|
||||
public Object nextId(Class<?> beanType);
|
||||
Object nextId(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* Create a filter for sorting and filtering lists of entities locally without
|
||||
@@ -283,7 +283,7 @@ public interface EbeanServer {
|
||||
* Refer to {@link Filter} for an example of its use.
|
||||
* </p>
|
||||
*/
|
||||
public <T> Filter<T> filter(Class<T> beanType);
|
||||
<T> Filter<T> filter(Class<T> beanType);
|
||||
|
||||
/**
|
||||
* Sort the list in memory using the sortByClause which can contain a comma delimited
|
||||
@@ -327,7 +327,7 @@ public interface EbeanServer {
|
||||
* @param sortByClause
|
||||
* the properties to sort the list by
|
||||
*/
|
||||
public <T> void sort(List<T> list, String sortByClause);
|
||||
<T> void sort(List<T> list, String sortByClause);
|
||||
|
||||
/**
|
||||
* Create a named orm update. The update statement is specified via the
|
||||
@@ -383,7 +383,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public <T> Update<T> createNamedUpdate(Class<T> beanType, String namedUpdate);
|
||||
<T> Update<T> createNamedUpdate(Class<T> beanType, String namedUpdate);
|
||||
|
||||
/**
|
||||
* Create a orm update where you will supply the insert/update or delete
|
||||
@@ -414,7 +414,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public <T> Update<T> createUpdate(Class<T> beanType, String ormUpdate);
|
||||
<T> Update<T> createUpdate(Class<T> beanType, String ormUpdate);
|
||||
|
||||
/**
|
||||
* Create a SqlQuery for executing native sql
|
||||
@@ -424,7 +424,7 @@ public interface EbeanServer {
|
||||
* annotation for examples.
|
||||
* </p>
|
||||
*/
|
||||
public SqlQuery createSqlQuery(String sql);
|
||||
SqlQuery createSqlQuery(String sql);
|
||||
|
||||
/**
|
||||
* Create a named sql query.
|
||||
@@ -435,7 +435,7 @@ public interface EbeanServer {
|
||||
* @param namedQuery
|
||||
* the name of the query
|
||||
*/
|
||||
public SqlQuery createNamedSqlQuery(String namedQuery);
|
||||
SqlQuery createNamedSqlQuery(String namedQuery);
|
||||
|
||||
/**
|
||||
* Create a sql update for executing native dml statements.
|
||||
@@ -451,12 +451,12 @@ public interface EbeanServer {
|
||||
* xml file (named update) and use {@link #createNamedSqlUpdate(String)} .
|
||||
* </p>
|
||||
*/
|
||||
public SqlUpdate createSqlUpdate(String sql);
|
||||
SqlUpdate createSqlUpdate(String sql);
|
||||
|
||||
/**
|
||||
* Create a CallableSql to execute a given stored procedure.
|
||||
*/
|
||||
public CallableSql createCallableSql(String callableSql);
|
||||
CallableSql createCallableSql(String callableSql);
|
||||
|
||||
/**
|
||||
* Create a named sql update.
|
||||
@@ -477,7 +477,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public SqlUpdate createNamedSqlUpdate(String namedQuery);
|
||||
SqlUpdate createNamedSqlUpdate(String namedQuery);
|
||||
|
||||
/**
|
||||
* Register a TransactionCallback on the currently active transaction.
|
||||
@@ -488,7 +488,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* @throws PersistenceException If there is no currently active transaction
|
||||
*/
|
||||
public void register(TransactionCallback transactionCallback) throws PersistenceException;
|
||||
void register(TransactionCallback transactionCallback) throws PersistenceException;
|
||||
|
||||
/**
|
||||
* Create a new transaction that is not held in TransactionThreadLocal.
|
||||
@@ -498,7 +498,7 @@ public interface EbeanServer {
|
||||
* management.
|
||||
* </p>
|
||||
*/
|
||||
public Transaction createTransaction();
|
||||
Transaction createTransaction();
|
||||
|
||||
/**
|
||||
* Create a new transaction additionally specifying the isolation level.
|
||||
@@ -506,10 +506,13 @@ public interface EbeanServer {
|
||||
* Note that this transaction is NOT stored in a thread local.
|
||||
* </p>
|
||||
*/
|
||||
public Transaction createTransaction(TxIsolation isolation);
|
||||
Transaction createTransaction(TxIsolation isolation);
|
||||
|
||||
/**
|
||||
* Start a new explicit transaction putting it into a ThreadLocal.
|
||||
* Start a transaction with 'REQUIRED' semantics.
|
||||
* <p>
|
||||
* With REQUIRED semantics if an active transaction already exists that transaction will be used.
|
||||
* </p>
|
||||
* <p>
|
||||
* The transaction is stored in a ThreadLocal variable and typically you only
|
||||
* need to use the returned Transaction <em>IF</em> you wish to do things like
|
||||
@@ -579,27 +582,80 @@ public interface EbeanServer {
|
||||
* EbeanServer yourself.
|
||||
* </p>
|
||||
*/
|
||||
public Transaction beginTransaction();
|
||||
Transaction beginTransaction();
|
||||
|
||||
/**
|
||||
* Start a transaction additionally specifying the isolation level.
|
||||
*/
|
||||
public Transaction beginTransaction(TxIsolation isolation);
|
||||
Transaction beginTransaction(TxIsolation isolation);
|
||||
|
||||
/**
|
||||
* Start a transaction typically specifying REQUIRES_NEW or REQUIRED semantics.
|
||||
*
|
||||
* <p>
|
||||
* Note that this provides an try finally alternative to using {@link #execute(TxScope, TxCallable)} or
|
||||
* {@link #execute(TxScope, TxRunnable)}.
|
||||
* </p>
|
||||
*
|
||||
* <h3>REQUIRES_NEW example:</h3>
|
||||
* <pre>{@code
|
||||
* // Start a new transaction. If there is a current transaction
|
||||
* // suspend it until this transaction ends
|
||||
* Transaction txn = server.beginTransaction(TxScope.requiresNew());
|
||||
* try {
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* // commit the transaction
|
||||
* txn.commit();
|
||||
*
|
||||
* } finally {
|
||||
* // end this transaction which:
|
||||
* // A) will rollback transaction if it has not been committed already
|
||||
* // B) will restore a previously suspended transaction
|
||||
* txn.end();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>REQUIRED example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // start a new transaction if there is not a current transaction
|
||||
* Transaction txn = server.beginTransaction(TxScope.required());
|
||||
* try {
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* // commit the transaction if it was created or
|
||||
* // do nothing if there was already a current transaction
|
||||
* txn.commit();
|
||||
*
|
||||
* } finally {
|
||||
* // end this transaction which will rollback the transaction
|
||||
* // if it was created for this try finally scope and has not
|
||||
* // already been committed
|
||||
* txn.end();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
Transaction beginTransaction(TxScope scope);
|
||||
|
||||
/**
|
||||
* Returns the current transaction or null if there is no current transaction in scope.
|
||||
*/
|
||||
public Transaction currentTransaction();
|
||||
Transaction currentTransaction();
|
||||
|
||||
/**
|
||||
* Commit the current transaction.
|
||||
*/
|
||||
public void commitTransaction();
|
||||
void commitTransaction();
|
||||
|
||||
/**
|
||||
* Rollback the current transaction.
|
||||
*/
|
||||
public void rollbackTransaction();
|
||||
void rollbackTransaction();
|
||||
|
||||
/**
|
||||
* If the current transaction has already been committed do nothing otherwise
|
||||
@@ -630,7 +686,7 @@ public interface EbeanServer {
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public void endTransaction();
|
||||
void endTransaction();
|
||||
|
||||
/**
|
||||
* Refresh the values of a bean.
|
||||
@@ -639,7 +695,7 @@ public interface EbeanServer {
|
||||
* are accessed a lazy load will refresh the many property.
|
||||
* </p>
|
||||
*/
|
||||
public void refresh(Object bean);
|
||||
void refresh(Object bean);
|
||||
|
||||
/**
|
||||
* Refresh a many property of an entity bean.
|
||||
@@ -650,7 +706,7 @@ public interface EbeanServer {
|
||||
* the 'many' property to be refreshed
|
||||
*
|
||||
*/
|
||||
public void refreshMany(Object bean, String propertyName);
|
||||
void refreshMany(Object bean, String propertyName);
|
||||
|
||||
/**
|
||||
* Find a bean using its unique id.
|
||||
@@ -700,7 +756,7 @@ public interface EbeanServer {
|
||||
* @param id
|
||||
* the id value
|
||||
*/
|
||||
public <T> T find(Class<T> beanType, Object id);
|
||||
<T> T find(Class<T> beanType, Object id);
|
||||
|
||||
/**
|
||||
* Get a reference object.
|
||||
@@ -745,7 +801,7 @@ public interface EbeanServer {
|
||||
* @param id
|
||||
* the id value
|
||||
*/
|
||||
public <T> T getReference(Class<T> beanType, Object id);
|
||||
<T> T getReference(Class<T> beanType, Object id);
|
||||
|
||||
/**
|
||||
* Return the number of 'top level' or 'root' entities this query should
|
||||
@@ -754,14 +810,14 @@ public interface EbeanServer {
|
||||
* @see Query#findRowCount()
|
||||
* @see com.avaje.ebean.Query#findFutureRowCount()
|
||||
*/
|
||||
public <T> int findRowCount(Query<T> query, Transaction transaction);
|
||||
<T> int findRowCount(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Return the Id values of the query as a List.
|
||||
*
|
||||
* @see com.avaje.ebean.Query#findIds()
|
||||
*/
|
||||
public <T> List<Object> findIds(Query<T> query, Transaction transaction);
|
||||
<T> List<Object> findIds(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Return a QueryIterator for the query.
|
||||
@@ -779,7 +835,7 @@ public interface EbeanServer {
|
||||
* @see Query#findEach(QueryEachConsumer)
|
||||
* @see Query#findEachWhile(QueryEachWhileConsumer)
|
||||
*/
|
||||
public <T> QueryIterator<T> findIterate(Query<T> query, Transaction transaction);
|
||||
<T> QueryIterator<T> findIterate(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the query visiting the each bean one at a time.
|
||||
@@ -809,7 +865,7 @@ public interface EbeanServer {
|
||||
* @see Query#findEach(QueryEachConsumer)
|
||||
* @see Query#findEachWhile(QueryEachWhileConsumer)
|
||||
*/
|
||||
public <T> void findEach(Query<T> query, QueryEachConsumer<T> consumer, Transaction transaction);
|
||||
<T> void findEach(Query<T> query, QueryEachConsumer<T> consumer, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the query visiting the each bean one at a time.
|
||||
@@ -846,7 +902,7 @@ public interface EbeanServer {
|
||||
* @see Query#findEach(QueryEachConsumer)
|
||||
* @see Query#findEachWhile(QueryEachWhileConsumer)
|
||||
*/
|
||||
public <T> void findEachWhile(Query<T> query, QueryEachWhileConsumer<T> consumer, Transaction transaction);
|
||||
<T> void findEachWhile(Query<T> query, QueryEachWhileConsumer<T> consumer, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Deprecated in favor of #findEachWhile which is functionally exactly the same
|
||||
@@ -859,7 +915,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public <T> void findVisit(Query<T> query, QueryResultVisitor<T> visitor, Transaction transaction);
|
||||
<T> void findVisit(Query<T> query, QueryResultVisitor<T> visitor, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute a query returning a list of beans.
|
||||
@@ -888,7 +944,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* @see Query#findList()
|
||||
*/
|
||||
public <T> List<T> findList(Query<T> query, Transaction transaction);
|
||||
<T> List<T> findList(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute find row count query in a background thread.
|
||||
@@ -906,7 +962,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* @see com.avaje.ebean.Query#findFutureRowCount()
|
||||
*/
|
||||
public <T> FutureRowCount<T> findFutureRowCount(Query<T> query, Transaction transaction);
|
||||
<T> FutureRowCount<T> findFutureRowCount(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute find Id's query in a background thread.
|
||||
@@ -924,7 +980,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* @see com.avaje.ebean.Query#findFutureIds()
|
||||
*/
|
||||
public <T> FutureIds<T> findFutureIds(Query<T> query, Transaction transaction);
|
||||
<T> FutureIds<T> findFutureIds(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute find list query in a background thread returning a FutureList object.
|
||||
@@ -944,7 +1000,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* @see Query#findFutureList()
|
||||
*/
|
||||
public <T> FutureList<T> findFutureList(Query<T> query, Transaction transaction);
|
||||
<T> FutureList<T> findFutureList(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute find list SQL query in a background thread.
|
||||
@@ -960,7 +1016,7 @@ public interface EbeanServer {
|
||||
* the transaction (can be null).
|
||||
* @return a Future object for the list result of the query
|
||||
*/
|
||||
public SqlFutureList findFutureList(SqlQuery query, Transaction transaction);
|
||||
SqlFutureList findFutureList(SqlQuery query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Return a PagedList for this query.
|
||||
@@ -983,7 +1039,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* @see Query#findPagedList(int, int)
|
||||
*/
|
||||
public <T> PagedList<T> findPagedList(Query<T> query, Transaction transaction, int pageIndex, int pageSize);
|
||||
<T> PagedList<T> findPagedList(Query<T> query, Transaction transaction, int pageIndex, int pageSize);
|
||||
|
||||
/**
|
||||
* Execute the query returning a set of entity beans.
|
||||
@@ -1012,7 +1068,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* @see Query#findSet()
|
||||
*/
|
||||
public <T> Set<T> findSet(Query<T> query, Transaction transaction);
|
||||
<T> Set<T> findSet(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the query returning the entity beans in a Map.
|
||||
@@ -1032,7 +1088,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* @see Query#findMap()
|
||||
*/
|
||||
public <T> Map<?, T> findMap(Query<T> query, Transaction transaction);
|
||||
<T> Map<?, T> findMap(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the query returning at most one entity bean. This will throw a
|
||||
@@ -1053,7 +1109,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* @see Query#findUnique()
|
||||
*/
|
||||
public <T> T findUnique(Query<T> query, Transaction transaction);
|
||||
<T> T findUnique(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the sql query returning a list of MapBean.
|
||||
@@ -1071,7 +1127,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* @see SqlQuery#findList()
|
||||
*/
|
||||
public List<SqlRow> findList(SqlQuery query, Transaction transaction);
|
||||
List<SqlRow> findList(SqlQuery query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the sql query returning a set of MapBean.
|
||||
@@ -1089,7 +1145,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* @see SqlQuery#findSet()
|
||||
*/
|
||||
public Set<SqlRow> findSet(SqlQuery query, Transaction transaction);
|
||||
Set<SqlRow> findSet(SqlQuery query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the sql query returning a map of MapBean.
|
||||
@@ -1107,7 +1163,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* @see SqlQuery#findMap()
|
||||
*/
|
||||
public Map<?, SqlRow> findMap(SqlQuery query, Transaction transaction);
|
||||
Map<?, SqlRow> findMap(SqlQuery query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the sql query returning a single MapBean or null.
|
||||
@@ -1129,7 +1185,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* @see SqlQuery#findUnique()
|
||||
*/
|
||||
public SqlRow findUnique(SqlQuery query, Transaction transaction);
|
||||
SqlRow findUnique(SqlQuery query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Either Insert or Update the bean depending on its state.
|
||||
@@ -1164,17 +1220,17 @@ public interface EbeanServer {
|
||||
* will be set against each order detail when it is saved.
|
||||
* </p>
|
||||
*/
|
||||
public void save(Object bean) throws OptimisticLockException;
|
||||
void save(Object bean) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Save all the beans in the iterator.
|
||||
*/
|
||||
public int save(Iterator<?> it) throws OptimisticLockException;
|
||||
int save(Iterator<?> it) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Save all the beans in the collection.
|
||||
*/
|
||||
public int save(Collection<?> beans) throws OptimisticLockException;
|
||||
int save(Collection<?> beans) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Delete the bean.
|
||||
@@ -1183,38 +1239,38 @@ public interface EbeanServer {
|
||||
* you automatically.
|
||||
* </p>
|
||||
*/
|
||||
public void delete(Object bean) throws OptimisticLockException;
|
||||
void delete(Object bean) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Delete all the beans from an Iterator.
|
||||
*/
|
||||
public int delete(Iterator<?> it) throws OptimisticLockException;
|
||||
int delete(Iterator<?> it) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Delete all the beans in the collection.
|
||||
*/
|
||||
public int delete(Collection<?> c) throws OptimisticLockException;
|
||||
int delete(Collection<?> c) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Delete the bean given its type and id.
|
||||
*/
|
||||
public int delete(Class<?> beanType, Object id);
|
||||
int delete(Class<?> beanType, Object id);
|
||||
|
||||
/**
|
||||
* Delete the bean given its type and id with an explicit transaction.
|
||||
*/
|
||||
public int delete(Class<?> beanType, Object id, Transaction transaction);
|
||||
int delete(Class<?> beanType, Object id, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Delete several beans given their type and id values.
|
||||
*/
|
||||
public void delete(Class<?> beanType, Collection<?> ids);
|
||||
void delete(Class<?> beanType, Collection<?> ids);
|
||||
|
||||
/**
|
||||
* Delete several beans given their type and id values with an explicit
|
||||
* transaction.
|
||||
*/
|
||||
public void delete(Class<?> beanType, Collection<?> ids, Transaction transaction);
|
||||
void delete(Class<?> beanType, Collection<?> ids, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute a Sql Update Delete or Insert statement. This returns the number of
|
||||
@@ -1257,7 +1313,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* @see CallableSql
|
||||
*/
|
||||
public int execute(SqlUpdate sqlUpdate);
|
||||
int execute(SqlUpdate sqlUpdate);
|
||||
|
||||
/**
|
||||
* Execute a ORM insert update or delete statement using the current
|
||||
@@ -1266,13 +1322,13 @@ public interface EbeanServer {
|
||||
* This returns the number of rows that where inserted, updated or deleted.
|
||||
* </p>
|
||||
*/
|
||||
public int execute(Update<?> update);
|
||||
int execute(Update<?> update);
|
||||
|
||||
/**
|
||||
* Execute a ORM insert update or delete statement with an explicit
|
||||
* transaction.
|
||||
*/
|
||||
public int execute(Update<?> update, Transaction t);
|
||||
int execute(Update<?> update, Transaction t);
|
||||
|
||||
/**
|
||||
* For making calls to stored procedures.
|
||||
@@ -1299,7 +1355,7 @@ public interface EbeanServer {
|
||||
* @see CallableSql
|
||||
* @see Ebean#execute(SqlUpdate)
|
||||
*/
|
||||
public int execute(CallableSql callableSql);
|
||||
int execute(CallableSql callableSql);
|
||||
|
||||
/**
|
||||
* Inform Ebean that tables have been modified externally. These could be the
|
||||
@@ -1335,7 +1391,7 @@ public interface EbeanServer {
|
||||
* @param deleted
|
||||
* true if rows on the table where deleted
|
||||
*/
|
||||
public void externalModification(String tableName, boolean inserted, boolean updated, boolean deleted);
|
||||
void externalModification(String tableName, boolean inserted, boolean updated, boolean deleted);
|
||||
|
||||
/**
|
||||
* Find a entity bean with an explicit transaction.
|
||||
@@ -1349,22 +1405,22 @@ public interface EbeanServer {
|
||||
* @param transaction
|
||||
* the transaction to use (can be null)
|
||||
*/
|
||||
public <T> T find(Class<T> beanType, Object uid, Transaction transaction);
|
||||
<T> T find(Class<T> beanType, Object uid, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Insert or update a bean with an explicit transaction.
|
||||
*/
|
||||
public void save(Object bean, Transaction transaction) throws OptimisticLockException;
|
||||
void save(Object bean, Transaction transaction) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Save all the beans in the iterator with an explicit transaction.
|
||||
*/
|
||||
public int save(Iterator<?> it, Transaction transaction) throws OptimisticLockException;
|
||||
int save(Iterator<?> it, Transaction transaction) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Save all the beans in the collection with an explicit transaction.
|
||||
*/
|
||||
public int save(Collection<?> beans, Transaction transaction) throws OptimisticLockException;
|
||||
int save(Collection<?> beans, Transaction transaction) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Marks the entity bean as dirty.
|
||||
@@ -1386,7 +1442,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public void markAsDirty(Object bean);
|
||||
void markAsDirty(Object bean);
|
||||
|
||||
/**
|
||||
* Saves the bean using an update. If you know you are updating a bean then it is preferrable to
|
||||
@@ -1424,12 +1480,12 @@ public interface EbeanServer {
|
||||
* @see ServerConfig#setUpdatesDeleteMissingChildren(boolean)
|
||||
* @see ServerConfig#setUpdateChangesOnly(boolean)
|
||||
*/
|
||||
public void update(Object bean) throws OptimisticLockException;
|
||||
void update(Object bean) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Update a bean additionally specifying a transaction.
|
||||
*/
|
||||
public void update(Object bean, Transaction t) throws OptimisticLockException;
|
||||
void update(Object bean, Transaction t) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Update a bean additionally specifying a transaction and the deleteMissingChildren setting.
|
||||
@@ -1443,18 +1499,18 @@ public interface EbeanServer {
|
||||
* or ManyToMany to be automatically deleted.
|
||||
|
||||
*/
|
||||
public void update(Object bean, Transaction transaction, boolean deleteMissingChildren) throws OptimisticLockException;
|
||||
void update(Object bean, Transaction transaction, boolean deleteMissingChildren) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Update a collection of beans. If there is no current transaction one is created and used to
|
||||
* update all the beans in the collection.
|
||||
*/
|
||||
public void update(Collection<?> beans) throws OptimisticLockException;
|
||||
void update(Collection<?> beans) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Update a collection of beans with an explicit transaction.
|
||||
*/
|
||||
public void update(Collection<?> beans, Transaction transaction) throws OptimisticLockException;
|
||||
void update(Collection<?> beans, Transaction transaction) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Insert the bean.
|
||||
@@ -1464,23 +1520,23 @@ public interface EbeanServer {
|
||||
* and want to insert them into another database (and you want to explicitly insert them).
|
||||
* </p>
|
||||
*/
|
||||
public void insert(Object bean);
|
||||
void insert(Object bean);
|
||||
|
||||
/**
|
||||
* Insert the bean with a transaction.
|
||||
*/
|
||||
public void insert(Object bean, Transaction t);
|
||||
void insert(Object bean, Transaction t);
|
||||
|
||||
/**
|
||||
* Insert a collection of beans. If there is no current transaction one is created and used to
|
||||
* insert all the beans in the collection.
|
||||
*/
|
||||
public void insert(Collection<?> beans);
|
||||
void insert(Collection<?> beans);
|
||||
|
||||
/**
|
||||
* Insert a collection of beans with an explicit transaction.
|
||||
*/
|
||||
public void insert(Collection<?> beans, Transaction t);
|
||||
void insert(Collection<?> beans, Transaction t);
|
||||
|
||||
/**
|
||||
* Delete the associations (from the intersection table) of a ManyToMany given
|
||||
@@ -1492,7 +1548,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* @return the number of associations deleted (from the intersection table).
|
||||
*/
|
||||
public int deleteManyToManyAssociations(Object ownerBean, String propertyName);
|
||||
int deleteManyToManyAssociations(Object ownerBean, String propertyName);
|
||||
|
||||
/**
|
||||
* Delete the associations (from the intersection table) of a ManyToMany given
|
||||
@@ -1507,7 +1563,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* @return the number of associations deleted (from the intersection table).
|
||||
*/
|
||||
public int deleteManyToManyAssociations(Object ownerBean, String propertyName, Transaction t);
|
||||
int deleteManyToManyAssociations(Object ownerBean, String propertyName, Transaction t);
|
||||
|
||||
/**
|
||||
* Save the associations of a ManyToMany given the owner bean and the
|
||||
@@ -1518,7 +1574,7 @@ public interface EbeanServer {
|
||||
* way to invoke those insertions directly.
|
||||
* </p>
|
||||
*/
|
||||
public void saveManyToManyAssociations(Object ownerBean, String propertyName);
|
||||
void saveManyToManyAssociations(Object ownerBean, String propertyName);
|
||||
|
||||
/**
|
||||
* Save the associations of a ManyToMany given the owner bean and the
|
||||
@@ -1529,7 +1585,7 @@ public interface EbeanServer {
|
||||
* way to invoke those insertions directly.
|
||||
* </p>
|
||||
*/
|
||||
public void saveManyToManyAssociations(Object ownerBean, String propertyName, Transaction t);
|
||||
void saveManyToManyAssociations(Object ownerBean, String propertyName, Transaction t);
|
||||
|
||||
/**
|
||||
* Save the associated collection or bean given the property name.
|
||||
@@ -1547,7 +1603,7 @@ public interface EbeanServer {
|
||||
* @param propertyName
|
||||
* the property we want to save
|
||||
*/
|
||||
public void saveAssociation(Object ownerBean, String propertyName);
|
||||
void saveAssociation(Object ownerBean, String propertyName);
|
||||
|
||||
/**
|
||||
* Save the associated collection or bean given the property name with a
|
||||
@@ -1566,27 +1622,27 @@ public interface EbeanServer {
|
||||
* @param propertyName
|
||||
* the property we want to save
|
||||
*/
|
||||
public void saveAssociation(Object ownerBean, String propertyName, Transaction t);
|
||||
void saveAssociation(Object ownerBean, String propertyName, Transaction t);
|
||||
|
||||
/**
|
||||
* Delete the bean with an explicit transaction.
|
||||
*/
|
||||
public void delete(Object bean, Transaction t) throws OptimisticLockException;
|
||||
void delete(Object bean, Transaction t) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Delete all the beans from an iterator.
|
||||
*/
|
||||
public int delete(Iterator<?> it, Transaction t) throws OptimisticLockException;
|
||||
int delete(Iterator<?> it, Transaction t) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Execute explicitly passing a transaction.
|
||||
*/
|
||||
public int execute(SqlUpdate updSql, Transaction t);
|
||||
int execute(SqlUpdate updSql, Transaction t);
|
||||
|
||||
/**
|
||||
* Execute explicitly passing a transaction.
|
||||
*/
|
||||
public int execute(CallableSql callableSql, Transaction t);
|
||||
int execute(CallableSql callableSql, Transaction t);
|
||||
|
||||
/**
|
||||
* Execute a TxRunnable in a Transaction with an explicit scope.
|
||||
@@ -1609,7 +1665,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public void execute(TxScope scope, TxRunnable r);
|
||||
void execute(TxScope scope, TxRunnable r);
|
||||
|
||||
/**
|
||||
* Execute a TxRunnable in a Transaction with the default scope.
|
||||
@@ -1635,7 +1691,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public void execute(TxRunnable r);
|
||||
void execute(TxRunnable r);
|
||||
|
||||
/**
|
||||
* Execute a TxCallable in a Transaction with an explicit scope.
|
||||
@@ -1659,7 +1715,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public <T> T execute(TxScope scope, TxCallable<T> c);
|
||||
<T> T execute(TxScope scope, TxCallable<T> c);
|
||||
|
||||
/**
|
||||
* Execute a TxCallable in a Transaction with the default scope.
|
||||
@@ -1691,19 +1747,19 @@ public interface EbeanServer {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public <T> T execute(TxCallable<T> c);
|
||||
<T> T execute(TxCallable<T> c);
|
||||
|
||||
/**
|
||||
* Return the manager of the server cache ("L2" cache).
|
||||
*
|
||||
*/
|
||||
public ServerCacheManager getServerCacheManager();
|
||||
ServerCacheManager getServerCacheManager();
|
||||
|
||||
/**
|
||||
* Return the BackgroundExecutor service for asynchronous processing of
|
||||
* queries.
|
||||
*/
|
||||
public BackgroundExecutor getBackgroundExecutor();
|
||||
BackgroundExecutor getBackgroundExecutor();
|
||||
|
||||
/**
|
||||
* Run the cache warming queries on all bean types that have one defined.
|
||||
@@ -1711,7 +1767,7 @@ public interface EbeanServer {
|
||||
* A cache warming query can be defined via {@link CacheStrategy}.
|
||||
* </p>
|
||||
*/
|
||||
public void runCacheWarming();
|
||||
void runCacheWarming();
|
||||
|
||||
/**
|
||||
* Run the cache warming query for a specific bean type.
|
||||
@@ -1719,13 +1775,13 @@ public interface EbeanServer {
|
||||
* A cache warming query can be defined via {@link CacheStrategy}.
|
||||
* </p>
|
||||
*/
|
||||
public void runCacheWarming(Class<?> beanType);
|
||||
void runCacheWarming(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* Return the JsonContext for reading/writing JSON.
|
||||
* @deprecated Please use #json instead.
|
||||
*/
|
||||
public JsonContext createJsonContext();
|
||||
JsonContext createJsonContext();
|
||||
|
||||
/**
|
||||
* Return the JsonContext for reading/writing JSON.
|
||||
@@ -1765,6 +1821,6 @@ public interface EbeanServer {
|
||||
* @see com.avaje.ebean.text.PathProperties
|
||||
* @see Query#apply(com.avaje.ebean.text.PathProperties)
|
||||
*/
|
||||
public JsonContext json();
|
||||
JsonContext json();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,119 +1,148 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.common.BootupEbeanManager;
|
||||
import com.avaje.ebean.config.ContainerConfig;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Creates EbeanServer instances.
|
||||
* <p>
|
||||
* This uses either a ServerConfig or properties in the ebean.properties file to
|
||||
* configure and create a EbeanServer instance.
|
||||
* </p>
|
||||
* <p>
|
||||
* The EbeanServer instance can either be registered with the Ebean singleton or
|
||||
* not. The Ebean singleton effectively holds a map of EbeanServers by a name.
|
||||
* If the EbeanServer is registered with the Ebean singleton you can retrieve it
|
||||
* later via {@link Ebean#getServer(String)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* One EbeanServer can be nominated as the 'default/primary' EbeanServer. Many
|
||||
* methods on the Ebean singleton such as {@link Ebean#find(Class)} are just a
|
||||
* convenient way of using the 'default/primary' EbeanServer.
|
||||
* </p>
|
||||
*/
|
||||
public class EbeanServerFactory {
|
||||
|
||||
|
||||
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 synchronized EbeanServer create(String name) {
|
||||
|
||||
// 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 synchronized EbeanServer create(ServerConfig config) {
|
||||
|
||||
if (config.getName() == null) {
|
||||
throw new PersistenceException("The name is null (it is required)");
|
||||
}
|
||||
|
||||
EbeanServer server = createInternal(config);
|
||||
|
||||
if (config.isDefaultServer()) {
|
||||
PrimaryServer.setSkip(true);
|
||||
}
|
||||
if (config.isRegister()) {
|
||||
Ebean.register(server, config.isDefaultServer());
|
||||
}
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
Class<?> cls = Class.forName(implClassName);
|
||||
Constructor<?> constructor = cls.getConstructor(ContainerConfig.class);
|
||||
return (BootupEbeanManager) constructor.newInstance(containerConfig);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.common.SpiContainer;
|
||||
import com.avaje.ebean.config.ContainerConfig;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebeaninternal.server.lib.ShutdownManager;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Creates EbeanServer instances.
|
||||
* <p>
|
||||
* This uses either a ServerConfig or properties in the ebean.properties file to
|
||||
* configure and create a EbeanServer instance.
|
||||
* </p>
|
||||
* <p>
|
||||
* The EbeanServer instance can either be registered with the Ebean singleton or
|
||||
* not. The Ebean singleton effectively holds a map of EbeanServers by a name.
|
||||
* If the EbeanServer is registered with the Ebean singleton you can retrieve it
|
||||
* later via {@link Ebean#getServer(String)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* One EbeanServer can be nominated as the 'default/primary' EbeanServer. Many
|
||||
* methods on the Ebean singleton such as {@link Ebean#find(Class)} are just a
|
||||
* convenient way of using the 'default/primary' EbeanServer.
|
||||
* </p>
|
||||
*/
|
||||
public class EbeanServerFactory {
|
||||
|
||||
|
||||
private static final String DEFAULT_CONTAINER = "com.avaje.ebeaninternal.server.core.DefaultContainer";
|
||||
|
||||
private static SpiContainer container;
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
getContainer(containerConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using ebean.properties to configure the server.
|
||||
*/
|
||||
public static synchronized EbeanServer create(String name) {
|
||||
|
||||
// construct based on loading properties files
|
||||
// and if invoked by Ebean then it handles registration
|
||||
SpiContainer serverFactory = getContainer(null);
|
||||
return serverFactory.createServer(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using the ServerConfig object to configure the server.
|
||||
*/
|
||||
public static synchronized EbeanServer create(ServerConfig config) {
|
||||
|
||||
if (config.getName() == null) {
|
||||
throw new PersistenceException("The name is null (it is required)");
|
||||
}
|
||||
|
||||
EbeanServer server = createInternal(config);
|
||||
|
||||
if (config.isDefaultServer()) {
|
||||
PrimaryServer.setSkip(true);
|
||||
}
|
||||
if (config.isRegister()) {
|
||||
Ebean.register(server, config.isDefaultServer());
|
||||
}
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using the ServerConfig additionally specifying a classLoader to use as the context class loader.
|
||||
*/
|
||||
public static synchronized EbeanServer createWithContextClassLoader(ServerConfig config, ClassLoader classLoader) {
|
||||
|
||||
ClassLoader currentContextLoader = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(classLoader);
|
||||
try {
|
||||
return EbeanServerFactory.create(config);
|
||||
|
||||
} finally {
|
||||
// set the currentContextLoader back
|
||||
Thread.currentThread().setContextClassLoader(currentContextLoader);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown gracefully all EbeanServers cleaning up any resources as required.
|
||||
* <p>
|
||||
* This is typically invoked via JVM shutdown hook and not explicitly called.
|
||||
* </p>
|
||||
*/
|
||||
public static synchronized void shutdown() {
|
||||
ShutdownManager.shutdown();
|
||||
}
|
||||
|
||||
|
||||
private static EbeanServer createInternal(ServerConfig config) {
|
||||
|
||||
return getContainer(config.getContainerConfig()).createServer(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the EbeanContainer initialising it if necessary.
|
||||
*
|
||||
* @param containerConfig the configuration controlling clustering communication
|
||||
*/
|
||||
private static SpiContainer getContainer(ContainerConfig containerConfig) {
|
||||
|
||||
// thread safe in that all calling methods are synchronized
|
||||
if (container != null) {
|
||||
return container;
|
||||
}
|
||||
|
||||
if (containerConfig == null) {
|
||||
// effectively load configuration from ebean.properties
|
||||
Properties properties = PrimaryServer.getProperties();
|
||||
containerConfig = new ContainerConfig();
|
||||
containerConfig.loadFromProperties(properties);
|
||||
}
|
||||
container = createContainer(containerConfig);
|
||||
return container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the container instance using the configuration.
|
||||
*/
|
||||
private static SpiContainer createContainer(ContainerConfig containerConfig) {
|
||||
|
||||
String implClassName = System.getProperty("ebean.container", DEFAULT_CONTAINER);
|
||||
|
||||
try {
|
||||
Class<?> cls = Class.forName(implClassName);
|
||||
Constructor<?> constructor = cls.getConstructor(ContainerConfig.class);
|
||||
return (SpiContainer) constructor.newInstance(containerConfig);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,93 +1,93 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Query by Example expression.
|
||||
* <p>
|
||||
* Pass in an example entity and for each non-null scalar properties an
|
||||
* expression is added.
|
||||
* </p>
|
||||
* <p>
|
||||
* By Default this case sensitive, will ignore numeric zero values and will use
|
||||
* a Like for string values (you must put in your own wildcards).
|
||||
* </p>
|
||||
* <p>
|
||||
* To get control over the options you can create an ExampleExpression and set
|
||||
* those options such as case insensitive etc.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // create an example bean and set the properties
|
||||
* // with the query parameters you want
|
||||
* Customer example = new Customer();
|
||||
* example.setName("Rob%");
|
||||
* example.setNotes("%something%");
|
||||
*
|
||||
* List<Customer> list =
|
||||
* Ebean.find(Customer.class)
|
||||
* .where()
|
||||
* // pass the bean into the where() clause
|
||||
* .exampleLike(example)
|
||||
* // you can add other expressions to the same query
|
||||
* .gt("id", 2)
|
||||
* .findList();
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* Similarly you can create an ExampleExpression
|
||||
*
|
||||
* <pre>
|
||||
* Customer example = new Customer();
|
||||
* example.setName("Rob%");
|
||||
* example.setNotes("%something%");
|
||||
*
|
||||
* // create a ExampleExpression with more control
|
||||
* ExampleExpression qbe = new ExampleExpression(example, true, LikeType.EQUAL_TO)
|
||||
* .includeZeros();
|
||||
*
|
||||
* List<Customer> list =
|
||||
* Ebean.find(Customer.class)
|
||||
* .where()
|
||||
* .add(qbe)
|
||||
* .findList();
|
||||
* </pre>
|
||||
*
|
||||
* @author Rob Bygrave
|
||||
*/
|
||||
public interface ExampleExpression extends Expression {
|
||||
|
||||
/**
|
||||
* By calling this method zero value properties are going to be included in
|
||||
* the expression.
|
||||
* <p>
|
||||
* By default numeric zero values are excluded as they can result from
|
||||
* primitive int and long types.
|
||||
* </p>
|
||||
*/
|
||||
public ExampleExpression includeZeros();
|
||||
|
||||
/**
|
||||
* Set case insensitive to true.
|
||||
*/
|
||||
public ExampleExpression caseInsensitive();
|
||||
|
||||
/**
|
||||
* Use startsWith expression for string properties.
|
||||
*/
|
||||
public ExampleExpression useStartsWith();
|
||||
|
||||
/**
|
||||
* Use contains expression for string properties.
|
||||
*/
|
||||
public ExampleExpression useContains();
|
||||
|
||||
/**
|
||||
* Use endsWith expression for string properties.
|
||||
*/
|
||||
public ExampleExpression useEndsWith();
|
||||
|
||||
/**
|
||||
* Use equal to expression for string properties.
|
||||
*/
|
||||
public ExampleExpression useEqualTo();
|
||||
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Query by Example expression.
|
||||
* <p>
|
||||
* Pass in an example entity and for each non-null scalar properties an
|
||||
* expression is added.
|
||||
* </p>
|
||||
* <p>
|
||||
* By Default this case sensitive, will ignore numeric zero values and will use
|
||||
* a Like for string values (you must put in your own wildcards).
|
||||
* </p>
|
||||
* <p>
|
||||
* To get control over the options you can create an ExampleExpression and set
|
||||
* those options such as case insensitive etc.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // create an example bean and set the properties
|
||||
* // with the query parameters you want
|
||||
* Customer example = new Customer();
|
||||
* example.setName("Rob%");
|
||||
* example.setNotes("%something%");
|
||||
*
|
||||
* List<Customer> list =
|
||||
* Ebean.find(Customer.class)
|
||||
* .where()
|
||||
* // pass the bean into the where() clause
|
||||
* .exampleLike(example)
|
||||
* // you can add other expressions to the same query
|
||||
* .gt("id", 2)
|
||||
* .findList();
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* Similarly you can create an ExampleExpression
|
||||
*
|
||||
* <pre>
|
||||
* Customer example = new Customer();
|
||||
* example.setName("Rob%");
|
||||
* example.setNotes("%something%");
|
||||
*
|
||||
* // create a ExampleExpression with more control
|
||||
* ExampleExpression qbe = new ExampleExpression(example, true, LikeType.EQUAL_TO)
|
||||
* .includeZeros();
|
||||
*
|
||||
* List<Customer> list =
|
||||
* Ebean.find(Customer.class)
|
||||
* .where()
|
||||
* .add(qbe)
|
||||
* .findList();
|
||||
* </pre>
|
||||
*
|
||||
* @author Rob Bygrave
|
||||
*/
|
||||
public interface ExampleExpression extends Expression {
|
||||
|
||||
/**
|
||||
* By calling this method zero value properties are going to be included in
|
||||
* the expression.
|
||||
* <p>
|
||||
* By default numeric zero values are excluded as they can result from
|
||||
* primitive int and long types.
|
||||
* </p>
|
||||
*/
|
||||
ExampleExpression includeZeros();
|
||||
|
||||
/**
|
||||
* Set case insensitive to true.
|
||||
*/
|
||||
ExampleExpression caseInsensitive();
|
||||
|
||||
/**
|
||||
* Use startsWith expression for string properties.
|
||||
*/
|
||||
ExampleExpression useStartsWith();
|
||||
|
||||
/**
|
||||
* Use contains expression for string properties.
|
||||
*/
|
||||
ExampleExpression useContains();
|
||||
|
||||
/**
|
||||
* Use endsWith expression for string properties.
|
||||
*/
|
||||
ExampleExpression useEndsWith();
|
||||
|
||||
/**
|
||||
* Use equal to expression for string properties.
|
||||
*/
|
||||
ExampleExpression useEqualTo();
|
||||
|
||||
}
|
||||
@@ -1,322 +1,322 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Expression factory for creating standard expressions for WHERE and HAVING
|
||||
* clauses.
|
||||
* <p>
|
||||
* Generally you will only need to use this object for creating OR, JUNCTION or
|
||||
* CONJUNCTION expressions. To create simple expressions you will most likely
|
||||
* just use the methods on the ExpressionList object that is returned via
|
||||
* {@link Query#where()}.
|
||||
* </p>
|
||||
* <p>
|
||||
* This provides a convenient way to create expressions for the 'Default'
|
||||
* server. It is actually a short cut for using the ExpressionFactory of the
|
||||
* 'default' EbeanServer.
|
||||
* <p>
|
||||
* See also {@link Ebean#getExpressionFactory()}
|
||||
* </p>
|
||||
* <p>
|
||||
* Creates standard common expressions for using in a Query Where or Having
|
||||
* clause.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // Example: Using an Expr.or() method
|
||||
* Query<Order> query = Ebean.createQuery(Order.class);
|
||||
* query.where(
|
||||
* Expr.or(Expr.eq("status", Order.NEW),
|
||||
* Expr.gt("orderDate", lastWeek));
|
||||
*
|
||||
* List<Order> list = query.findList();
|
||||
* ...
|
||||
* </pre>
|
||||
*
|
||||
* @see Query#where()
|
||||
* @author Rob Bygrave
|
||||
*/
|
||||
public class Expr {
|
||||
|
||||
private Expr() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Equal To - property equal to the given value.
|
||||
*/
|
||||
public static Expression eq(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().eq(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not Equal To - property not equal to the given value.
|
||||
*/
|
||||
public static Expression ne(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().ne(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Case Insensitive Equal To - property equal to the given value (typically
|
||||
* using a lower() function to make it case insensitive).
|
||||
*/
|
||||
public static Expression ieq(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().ieq(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Between - property between the two given values.
|
||||
*/
|
||||
public static Expression between(String propertyName, Object value1, Object value2) {
|
||||
|
||||
return Ebean.getExpressionFactory().between(propertyName, value1, value2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Between - value between two given properties.
|
||||
*/
|
||||
public static Expression between(String lowProperty, String highProperty, Object value) {
|
||||
|
||||
return Ebean.getExpressionFactory().betweenProperties(lowProperty, highProperty, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Greater Than - property greater than the given value.
|
||||
*/
|
||||
public static Expression gt(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().gt(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Greater Than or Equal to - property greater than or equal to the given
|
||||
* value.
|
||||
*/
|
||||
public static Expression ge(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().ge(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Less Than - property less than the given value.
|
||||
*/
|
||||
public static Expression lt(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().lt(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Less Than or Equal to - property less than or equal to the given value.
|
||||
*/
|
||||
public static Expression le(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().le(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is Null - property is null.
|
||||
*/
|
||||
public static Expression isNull(String propertyName) {
|
||||
return Ebean.getExpressionFactory().isNull(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is Not Null - property is not null.
|
||||
*/
|
||||
public static Expression isNotNull(String propertyName) {
|
||||
return Ebean.getExpressionFactory().isNotNull(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Case insensitive {@link #exampleLike(Object)}
|
||||
*/
|
||||
public static ExampleExpression iexampleLike(Object example) {
|
||||
return Ebean.getExpressionFactory().iexampleLike(example);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the query by Example expression which is case sensitive and using
|
||||
* LikeType.RAW (you need to add you own wildcards % and _).
|
||||
*/
|
||||
public static ExampleExpression exampleLike(Object example) {
|
||||
return Ebean.getExpressionFactory().exampleLike(example);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the query by Example expression specifying more options.
|
||||
*/
|
||||
public static ExampleExpression exampleLike(Object example, boolean caseInsensitive,
|
||||
LikeType likeType) {
|
||||
return Ebean.getExpressionFactory().exampleLike(example, caseInsensitive, likeType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like - property like value where the value contains the SQL wild card
|
||||
* characters % (percentage) and _ (underscore).
|
||||
*/
|
||||
public static Expression like(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().like(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Case insensitive Like - property like value where the value contains the
|
||||
* SQL wild card characters % (percentage) and _ (underscore). Typically uses
|
||||
* a lower() function to make the expression case insensitive.
|
||||
*/
|
||||
public static Expression ilike(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().ilike(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts With - property like value%.
|
||||
*/
|
||||
public static Expression startsWith(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().startsWith(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Case insensitive Starts With - property like value%. Typically uses a
|
||||
* lower() function to make the expression case insensitive.
|
||||
*/
|
||||
public static Expression istartsWith(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().istartsWith(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends With - property like %value.
|
||||
*/
|
||||
public static Expression endsWith(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().endsWith(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Case insensitive Ends With - property like %value. Typically uses a lower()
|
||||
* function to make the expression case insensitive.
|
||||
*/
|
||||
public static Expression iendsWith(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().iendsWith(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains - property like %value%.
|
||||
*/
|
||||
public static Expression contains(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().contains(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Case insensitive Contains - property like %value%. Typically uses a lower()
|
||||
* function to make the expression case insensitive.
|
||||
*/
|
||||
public static Expression icontains(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().icontains(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* In - property has a value in the array of values.
|
||||
*/
|
||||
public static Expression in(String propertyName, Object[] values) {
|
||||
return Ebean.getExpressionFactory().in(propertyName, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* In - using a subQuery.
|
||||
*/
|
||||
public static Expression in(String propertyName, Query<?> subQuery) {
|
||||
return Ebean.getExpressionFactory().in(propertyName, subQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* In - property has a value in the collection of values.
|
||||
*/
|
||||
public static Expression in(String propertyName, Collection<?> values) {
|
||||
return Ebean.getExpressionFactory().in(propertyName, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Id Equal to - ID property is equal to the value.
|
||||
*/
|
||||
public static Expression idEq(Object value) {
|
||||
return Ebean.getExpressionFactory().idEq(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* All Equal - Map containing property names and their values.
|
||||
* <p>
|
||||
* Expression where all the property names in the map are equal to the
|
||||
* corresponding value.
|
||||
* </p>
|
||||
*
|
||||
* @param propertyMap
|
||||
* a map keyed by property names.
|
||||
*/
|
||||
public static Expression allEq(Map<String, Object> propertyMap) {
|
||||
return Ebean.getExpressionFactory().allEq(propertyMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add raw expression with a single parameter.
|
||||
* <p>
|
||||
* The raw expression should contain a single ? at the location of the
|
||||
* parameter.
|
||||
* </p>
|
||||
*/
|
||||
public static Expression raw(String raw, Object value) {
|
||||
return Ebean.getExpressionFactory().raw(raw, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add raw expression with an array of parameters.
|
||||
* <p>
|
||||
* The raw expression should contain the same number of ? as there are
|
||||
* parameters.
|
||||
* </p>
|
||||
*/
|
||||
public static Expression raw(String raw, Object[] values) {
|
||||
return Ebean.getExpressionFactory().raw(raw, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add raw expression with no parameters.
|
||||
*/
|
||||
public static Expression raw(String raw) {
|
||||
return Ebean.getExpressionFactory().raw(raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* And - join two expressions with a logical and.
|
||||
*/
|
||||
public static Expression and(Expression expOne, Expression expTwo) {
|
||||
|
||||
return Ebean.getExpressionFactory().and(expOne, expTwo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Or - join two expressions with a logical or.
|
||||
*/
|
||||
public static Expression or(Expression expOne, Expression expTwo) {
|
||||
|
||||
return Ebean.getExpressionFactory().or(expOne, expTwo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate the expression (prefix it with NOT).
|
||||
*/
|
||||
public static Expression not(Expression exp) {
|
||||
|
||||
return Ebean.getExpressionFactory().not(exp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by AND's.
|
||||
*/
|
||||
public static <T> Junction<T> conjunction(Query<T> query) {
|
||||
|
||||
return Ebean.getExpressionFactory().conjunction(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by OR's.
|
||||
*/
|
||||
public static <T> Junction<T> disjunction(Query<T> query) {
|
||||
|
||||
return Ebean.getExpressionFactory().disjunction(query);
|
||||
}
|
||||
}
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Expression factory for creating standard expressions for WHERE and HAVING
|
||||
* clauses.
|
||||
* <p>
|
||||
* Generally you will only need to use this object for creating OR, JUNCTION or
|
||||
* CONJUNCTION expressions. To create simple expressions you will most likely
|
||||
* just use the methods on the ExpressionList object that is returned via
|
||||
* {@link Query#where()}.
|
||||
* </p>
|
||||
* <p>
|
||||
* This provides a convenient way to create expressions for the 'Default'
|
||||
* server. It is actually a short cut for using the ExpressionFactory of the
|
||||
* 'default' EbeanServer.
|
||||
* <p>
|
||||
* See also {@link Ebean#getExpressionFactory()}
|
||||
* </p>
|
||||
* <p>
|
||||
* Creates standard common expressions for using in a Query Where or Having
|
||||
* clause.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // Example: Using an Expr.or() method
|
||||
* Query<Order> query = Ebean.createQuery(Order.class);
|
||||
* query.where(
|
||||
* Expr.or(Expr.eq("status", Order.NEW),
|
||||
* Expr.gt("orderDate", lastWeek));
|
||||
*
|
||||
* List<Order> list = query.findList();
|
||||
* ...
|
||||
* </pre>
|
||||
*
|
||||
* @see Query#where()
|
||||
* @author Rob Bygrave
|
||||
*/
|
||||
public class Expr {
|
||||
|
||||
private Expr() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Equal To - property equal to the given value.
|
||||
*/
|
||||
public static Expression eq(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().eq(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not Equal To - property not equal to the given value.
|
||||
*/
|
||||
public static Expression ne(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().ne(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Case Insensitive Equal To - property equal to the given value (typically
|
||||
* using a lower() function to make it case insensitive).
|
||||
*/
|
||||
public static Expression ieq(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().ieq(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Between - property between the two given values.
|
||||
*/
|
||||
public static Expression between(String propertyName, Object value1, Object value2) {
|
||||
|
||||
return Ebean.getExpressionFactory().between(propertyName, value1, value2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Between - value between two given properties.
|
||||
*/
|
||||
public static Expression between(String lowProperty, String highProperty, Object value) {
|
||||
|
||||
return Ebean.getExpressionFactory().betweenProperties(lowProperty, highProperty, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Greater Than - property greater than the given value.
|
||||
*/
|
||||
public static Expression gt(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().gt(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Greater Than or Equal to - property greater than or equal to the given
|
||||
* value.
|
||||
*/
|
||||
public static Expression ge(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().ge(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Less Than - property less than the given value.
|
||||
*/
|
||||
public static Expression lt(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().lt(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Less Than or Equal to - property less than or equal to the given value.
|
||||
*/
|
||||
public static Expression le(String propertyName, Object value) {
|
||||
return Ebean.getExpressionFactory().le(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is Null - property is null.
|
||||
*/
|
||||
public static Expression isNull(String propertyName) {
|
||||
return Ebean.getExpressionFactory().isNull(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is Not Null - property is not null.
|
||||
*/
|
||||
public static Expression isNotNull(String propertyName) {
|
||||
return Ebean.getExpressionFactory().isNotNull(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Case insensitive {@link #exampleLike(Object)}
|
||||
*/
|
||||
public static ExampleExpression iexampleLike(Object example) {
|
||||
return Ebean.getExpressionFactory().iexampleLike(example);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the query by Example expression which is case sensitive and using
|
||||
* LikeType.RAW (you need to add you own wildcards % and _).
|
||||
*/
|
||||
public static ExampleExpression exampleLike(Object example) {
|
||||
return Ebean.getExpressionFactory().exampleLike(example);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the query by Example expression specifying more options.
|
||||
*/
|
||||
public static ExampleExpression exampleLike(Object example, boolean caseInsensitive,
|
||||
LikeType likeType) {
|
||||
return Ebean.getExpressionFactory().exampleLike(example, caseInsensitive, likeType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like - property like value where the value contains the SQL wild card
|
||||
* characters % (percentage) and _ (underscore).
|
||||
*/
|
||||
public static Expression like(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().like(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Case insensitive Like - property like value where the value contains the
|
||||
* SQL wild card characters % (percentage) and _ (underscore). Typically uses
|
||||
* a lower() function to make the expression case insensitive.
|
||||
*/
|
||||
public static Expression ilike(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().ilike(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts With - property like value%.
|
||||
*/
|
||||
public static Expression startsWith(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().startsWith(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Case insensitive Starts With - property like value%. Typically uses a
|
||||
* lower() function to make the expression case insensitive.
|
||||
*/
|
||||
public static Expression istartsWith(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().istartsWith(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends With - property like %value.
|
||||
*/
|
||||
public static Expression endsWith(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().endsWith(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Case insensitive Ends With - property like %value. Typically uses a lower()
|
||||
* function to make the expression case insensitive.
|
||||
*/
|
||||
public static Expression iendsWith(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().iendsWith(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains - property like %value%.
|
||||
*/
|
||||
public static Expression contains(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().contains(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Case insensitive Contains - property like %value%. Typically uses a lower()
|
||||
* function to make the expression case insensitive.
|
||||
*/
|
||||
public static Expression icontains(String propertyName, String value) {
|
||||
return Ebean.getExpressionFactory().icontains(propertyName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* In - property has a value in the array of values.
|
||||
*/
|
||||
public static Expression in(String propertyName, Object[] values) {
|
||||
return Ebean.getExpressionFactory().in(propertyName, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* In - using a subQuery.
|
||||
*/
|
||||
public static Expression in(String propertyName, Query<?> subQuery) {
|
||||
return Ebean.getExpressionFactory().in(propertyName, subQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* In - property has a value in the collection of values.
|
||||
*/
|
||||
public static Expression in(String propertyName, Collection<?> values) {
|
||||
return Ebean.getExpressionFactory().in(propertyName, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Id Equal to - ID property is equal to the value.
|
||||
*/
|
||||
public static Expression idEq(Object value) {
|
||||
return Ebean.getExpressionFactory().idEq(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* All Equal - Map containing property names and their values.
|
||||
* <p>
|
||||
* Expression where all the property names in the map are equal to the
|
||||
* corresponding value.
|
||||
* </p>
|
||||
*
|
||||
* @param propertyMap
|
||||
* a map keyed by property names.
|
||||
*/
|
||||
public static Expression allEq(Map<String, Object> propertyMap) {
|
||||
return Ebean.getExpressionFactory().allEq(propertyMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add raw expression with a single parameter.
|
||||
* <p>
|
||||
* The raw expression should contain a single ? at the location of the
|
||||
* parameter.
|
||||
* </p>
|
||||
*/
|
||||
public static Expression raw(String raw, Object value) {
|
||||
return Ebean.getExpressionFactory().raw(raw, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add raw expression with an array of parameters.
|
||||
* <p>
|
||||
* The raw expression should contain the same number of ? as there are
|
||||
* parameters.
|
||||
* </p>
|
||||
*/
|
||||
public static Expression raw(String raw, Object[] values) {
|
||||
return Ebean.getExpressionFactory().raw(raw, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add raw expression with no parameters.
|
||||
*/
|
||||
public static Expression raw(String raw) {
|
||||
return Ebean.getExpressionFactory().raw(raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* And - join two expressions with a logical and.
|
||||
*/
|
||||
public static Expression and(Expression expOne, Expression expTwo) {
|
||||
|
||||
return Ebean.getExpressionFactory().and(expOne, expTwo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Or - join two expressions with a logical or.
|
||||
*/
|
||||
public static Expression or(Expression expOne, Expression expTwo) {
|
||||
|
||||
return Ebean.getExpressionFactory().or(expOne, expTwo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate the expression (prefix it with NOT).
|
||||
*/
|
||||
public static Expression not(Expression exp) {
|
||||
|
||||
return Ebean.getExpressionFactory().not(exp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by AND's.
|
||||
*/
|
||||
public static <T> Junction<T> conjunction(Query<T> query) {
|
||||
|
||||
return Ebean.getExpressionFactory().conjunction(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by OR's.
|
||||
*/
|
||||
public static <T> Junction<T> disjunction(Query<T> query) {
|
||||
|
||||
return Ebean.getExpressionFactory().disjunction(query);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* An expression that is part of a WHERE or HAVING clause.
|
||||
*/
|
||||
public interface Expression extends Serializable {
|
||||
|
||||
}
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* An expression that is part of a WHERE or HAVING clause.
|
||||
*/
|
||||
public interface Expression extends Serializable {
|
||||
|
||||
}
|
||||
|
||||
@@ -1,252 +1,262 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Expression factory for creating standard expressions.
|
||||
* <p>
|
||||
* Creates standard common expressions for using in a Query Where or Having
|
||||
* clause.
|
||||
* </p>
|
||||
* <p>
|
||||
* You will often not use this class directly but instead just add expressions
|
||||
* via the methods on ExpressionList such as
|
||||
* {@link ExpressionList#gt(String, Object)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* The ExpressionList is returned from {@link Query#where()}.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // Example: fetch orders where status equals new or orderDate > lastWeek.
|
||||
*
|
||||
* Expression newOrLastWeek =
|
||||
* Expr.or(Expr.eq("status", Order.Status.NEW),
|
||||
* Expr.gt("orderDate", lastWeek));
|
||||
*
|
||||
* Query<Order> query = Ebean.createQuery(Order.class);
|
||||
* query.where().add(newOrLastWeek);
|
||||
* List<Order> list = query.findList();
|
||||
* ...
|
||||
* </pre>
|
||||
*
|
||||
* @see Query#where()
|
||||
*/
|
||||
public interface ExpressionFactory {
|
||||
|
||||
/**
|
||||
* Equal To - property equal to the given value.
|
||||
*/
|
||||
public Expression eq(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Not Equal To - property not equal to the given value.
|
||||
*/
|
||||
public Expression ne(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Case Insensitive Equal To - property equal to the given value (typically
|
||||
* using a lower() function to make it case insensitive).
|
||||
*/
|
||||
public Expression ieq(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Between - property between the two given values.
|
||||
*/
|
||||
public Expression between(String propertyName, Object value1, Object value2);
|
||||
|
||||
/**
|
||||
* Between - value between two given properties.
|
||||
*/
|
||||
public Expression betweenProperties(String lowProperty, String highProperty, Object value);
|
||||
|
||||
/**
|
||||
* Greater Than - property greater than the given value.
|
||||
*/
|
||||
public Expression gt(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Greater Than or Equal to - property greater than or equal to the given
|
||||
* value.
|
||||
*/
|
||||
public Expression ge(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Less Than - property less than the given value.
|
||||
*/
|
||||
public Expression lt(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Less Than or Equal to - property less than or equal to the given value.
|
||||
*/
|
||||
public Expression le(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Is Null - property is null.
|
||||
*/
|
||||
public Expression isNull(String propertyName);
|
||||
|
||||
/**
|
||||
* Is Not Null - property is not null.
|
||||
*/
|
||||
public Expression isNotNull(String propertyName);
|
||||
|
||||
/**
|
||||
* Case insensitive {@link #exampleLike(Object)}
|
||||
*/
|
||||
public ExampleExpression iexampleLike(Object example);
|
||||
|
||||
/**
|
||||
* Create the query by Example expression which is case sensitive and using
|
||||
* LikeType.RAW (you need to add you own wildcards % and _).
|
||||
*/
|
||||
public ExampleExpression exampleLike(Object example);
|
||||
|
||||
/**
|
||||
* Create the query by Example expression specifying more options.
|
||||
*/
|
||||
public ExampleExpression exampleLike(Object example, boolean caseInsensitive, LikeType likeType);
|
||||
|
||||
/**
|
||||
* Like - property like value where the value contains the SQL wild card
|
||||
* characters % (percentage) and _ (underscore).
|
||||
*/
|
||||
public Expression like(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Case insensitive Like - property like value where the value contains the
|
||||
* SQL wild card characters % (percentage) and _ (underscore). Typically uses
|
||||
* a lower() function to make the expression case insensitive.
|
||||
*/
|
||||
public Expression ilike(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Starts With - property like value%.
|
||||
*/
|
||||
public Expression startsWith(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Case insensitive Starts With - property like value%. Typically uses a
|
||||
* lower() function to make the expression case insensitive.
|
||||
*/
|
||||
public Expression istartsWith(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Ends With - property like %value.
|
||||
*/
|
||||
public Expression endsWith(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Case insensitive Ends With - property like %value. Typically uses a lower()
|
||||
* function to make the expression case insensitive.
|
||||
*/
|
||||
public Expression iendsWith(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Contains - property like %value%.
|
||||
*/
|
||||
public Expression contains(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Case insensitive Contains - property like %value%. Typically uses a lower()
|
||||
* function to make the expression case insensitive.
|
||||
*/
|
||||
public Expression icontains(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* In - property has a value in the array of values.
|
||||
*/
|
||||
public Expression in(String propertyName, Object[] values);
|
||||
|
||||
/**
|
||||
* In - using a subQuery.
|
||||
*/
|
||||
public Expression in(String propertyName, Query<?> subQuery);
|
||||
|
||||
/**
|
||||
* In - property has a value in the collection of values.
|
||||
*/
|
||||
public Expression in(String propertyName, Collection<?> values);
|
||||
|
||||
/**
|
||||
* Id Equal to - ID property is equal to the value.
|
||||
*/
|
||||
public Expression idEq(Object value);
|
||||
|
||||
/**
|
||||
* Id IN a list of Id values.
|
||||
*/
|
||||
public Expression idIn(List<?> idList);
|
||||
|
||||
/**
|
||||
* All Equal - Map containing property names and their values.
|
||||
* <p>
|
||||
* Expression where all the property names in the map are equal to the
|
||||
* corresponding value.
|
||||
* </p>
|
||||
*
|
||||
* @param propertyMap
|
||||
* a map keyed by property names.
|
||||
*/
|
||||
public Expression allEq(Map<String, Object> propertyMap);
|
||||
|
||||
/**
|
||||
* Add raw expression with a single parameter.
|
||||
* <p>
|
||||
* The raw expression should contain a single ? at the location of the
|
||||
* parameter.
|
||||
* </p>
|
||||
*/
|
||||
public Expression raw(String raw, Object value);
|
||||
|
||||
/**
|
||||
* Add raw expression with an array of parameters.
|
||||
* <p>
|
||||
* The raw expression should contain the same number of ? as there are
|
||||
* parameters.
|
||||
* </p>
|
||||
*/
|
||||
public Expression raw(String raw, Object[] values);
|
||||
|
||||
/**
|
||||
* Add raw expression with no parameters.
|
||||
*/
|
||||
public Expression raw(String raw);
|
||||
|
||||
/**
|
||||
* And - join two expressions with a logical and.
|
||||
*/
|
||||
public Expression and(Expression expOne, Expression expTwo);
|
||||
|
||||
/**
|
||||
* Or - join two expressions with a logical or.
|
||||
*/
|
||||
public Expression or(Expression expOne, Expression expTwo);
|
||||
|
||||
/**
|
||||
* Negate the expression (prefix it with NOT).
|
||||
*/
|
||||
public Expression not(Expression exp);
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by AND's.
|
||||
*/
|
||||
public <T> Junction<T> conjunction(Query<T> query);
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by OR's.
|
||||
*/
|
||||
public <T> Junction<T> disjunction(Query<T> query);
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by AND's.
|
||||
*/
|
||||
public <T> Junction<T> conjunction(Query<T> query, ExpressionList<T> parent);
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by OR's.
|
||||
*/
|
||||
public <T> Junction<T> disjunction(Query<T> query, ExpressionList<T> parent);
|
||||
}
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Expression factory for creating standard expressions.
|
||||
* <p>
|
||||
* Creates standard common expressions for using in a Query Where or Having
|
||||
* clause.
|
||||
* </p>
|
||||
* <p>
|
||||
* You will often not use this class directly but instead just add expressions
|
||||
* via the methods on ExpressionList such as
|
||||
* {@link ExpressionList#gt(String, Object)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* The ExpressionList is returned from {@link Query#where()}.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // Example: fetch orders where status equals new or orderDate > lastWeek.
|
||||
*
|
||||
* Expression newOrLastWeek =
|
||||
* Expr.or(Expr.eq("status", Order.Status.NEW),
|
||||
* Expr.gt("orderDate", lastWeek));
|
||||
*
|
||||
* Query<Order> query = Ebean.createQuery(Order.class);
|
||||
* query.where().add(newOrLastWeek);
|
||||
* List<Order> list = query.findList();
|
||||
* ...
|
||||
* </pre>
|
||||
*
|
||||
* @see Query#where()
|
||||
*/
|
||||
public interface ExpressionFactory {
|
||||
|
||||
/**
|
||||
* Equal To - property equal to the given value.
|
||||
*/
|
||||
Expression eq(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Not Equal To - property not equal to the given value.
|
||||
*/
|
||||
Expression ne(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Case Insensitive Equal To - property equal to the given value (typically
|
||||
* using a lower() function to make it case insensitive).
|
||||
*/
|
||||
Expression ieq(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Between - property between the two given values.
|
||||
*/
|
||||
Expression between(String propertyName, Object value1, Object value2);
|
||||
|
||||
/**
|
||||
* Between - value between two given properties.
|
||||
*/
|
||||
Expression betweenProperties(String lowProperty, String highProperty, Object value);
|
||||
|
||||
/**
|
||||
* Greater Than - property greater than the given value.
|
||||
*/
|
||||
Expression gt(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Greater Than or Equal to - property greater than or equal to the given
|
||||
* value.
|
||||
*/
|
||||
Expression ge(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Less Than - property less than the given value.
|
||||
*/
|
||||
Expression lt(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Less Than or Equal to - property less than or equal to the given value.
|
||||
*/
|
||||
Expression le(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Is Null - property is null.
|
||||
*/
|
||||
Expression isNull(String propertyName);
|
||||
|
||||
/**
|
||||
* Is Not Null - property is not null.
|
||||
*/
|
||||
Expression isNotNull(String propertyName);
|
||||
|
||||
/**
|
||||
* Case insensitive {@link #exampleLike(Object)}
|
||||
*/
|
||||
ExampleExpression iexampleLike(Object example);
|
||||
|
||||
/**
|
||||
* Create the query by Example expression which is case sensitive and using
|
||||
* LikeType.RAW (you need to add you own wildcards % and _).
|
||||
*/
|
||||
ExampleExpression exampleLike(Object example);
|
||||
|
||||
/**
|
||||
* Create the query by Example expression specifying more options.
|
||||
*/
|
||||
ExampleExpression exampleLike(Object example, boolean caseInsensitive, LikeType likeType);
|
||||
|
||||
/**
|
||||
* Like - property like value where the value contains the SQL wild card
|
||||
* characters % (percentage) and _ (underscore).
|
||||
*/
|
||||
Expression like(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Case insensitive Like - property like value where the value contains the
|
||||
* SQL wild card characters % (percentage) and _ (underscore). Typically uses
|
||||
* a lower() function to make the expression case insensitive.
|
||||
*/
|
||||
Expression ilike(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Starts With - property like value%.
|
||||
*/
|
||||
Expression startsWith(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Case insensitive Starts With - property like value%. Typically uses a
|
||||
* lower() function to make the expression case insensitive.
|
||||
*/
|
||||
Expression istartsWith(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Ends With - property like %value.
|
||||
*/
|
||||
Expression endsWith(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Case insensitive Ends With - property like %value. Typically uses a lower()
|
||||
* function to make the expression case insensitive.
|
||||
*/
|
||||
Expression iendsWith(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Contains - property like %value%.
|
||||
*/
|
||||
Expression contains(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Case insensitive Contains - property like %value%. Typically uses a lower()
|
||||
* function to make the expression case insensitive.
|
||||
*/
|
||||
Expression icontains(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* In - property has a value in the array of values.
|
||||
*/
|
||||
Expression in(String propertyName, Object[] values);
|
||||
|
||||
/**
|
||||
* In - using a subQuery.
|
||||
*/
|
||||
Expression in(String propertyName, Query<?> subQuery);
|
||||
|
||||
/**
|
||||
* In - property has a value in the collection of values.
|
||||
*/
|
||||
Expression in(String propertyName, Collection<?> values);
|
||||
|
||||
/**
|
||||
* Exists expression
|
||||
*/
|
||||
Expression exists(Query<?> subQuery);
|
||||
|
||||
/**
|
||||
* Not exists expression
|
||||
*/
|
||||
Expression notExists(Query<?> subQuery);
|
||||
|
||||
/**
|
||||
* Id Equal to - ID property is equal to the value.
|
||||
*/
|
||||
Expression idEq(Object value);
|
||||
|
||||
/**
|
||||
* Id IN a list of Id values.
|
||||
*/
|
||||
Expression idIn(List<?> idList);
|
||||
|
||||
/**
|
||||
* All Equal - Map containing property names and their values.
|
||||
* <p>
|
||||
* Expression where all the property names in the map are equal to the
|
||||
* corresponding value.
|
||||
* </p>
|
||||
*
|
||||
* @param propertyMap
|
||||
* a map keyed by property names.
|
||||
*/
|
||||
Expression allEq(Map<String, Object> propertyMap);
|
||||
|
||||
/**
|
||||
* Add raw expression with a single parameter.
|
||||
* <p>
|
||||
* The raw expression should contain a single ? at the location of the
|
||||
* parameter.
|
||||
* </p>
|
||||
*/
|
||||
Expression raw(String raw, Object value);
|
||||
|
||||
/**
|
||||
* Add raw expression with an array of parameters.
|
||||
* <p>
|
||||
* The raw expression should contain the same number of ? as there are
|
||||
* parameters.
|
||||
* </p>
|
||||
*/
|
||||
Expression raw(String raw, Object[] values);
|
||||
|
||||
/**
|
||||
* Add raw expression with no parameters.
|
||||
*/
|
||||
Expression raw(String raw);
|
||||
|
||||
/**
|
||||
* And - join two expressions with a logical and.
|
||||
*/
|
||||
Expression and(Expression expOne, Expression expTwo);
|
||||
|
||||
/**
|
||||
* Or - join two expressions with a logical or.
|
||||
*/
|
||||
Expression or(Expression expOne, Expression expTwo);
|
||||
|
||||
/**
|
||||
* Negate the expression (prefix it with NOT).
|
||||
*/
|
||||
Expression not(Expression exp);
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by AND's.
|
||||
*/
|
||||
<T> Junction<T> conjunction(Query<T> query);
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by OR's.
|
||||
*/
|
||||
<T> Junction<T> disjunction(Query<T> query);
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by AND's.
|
||||
*/
|
||||
<T> Junction<T> conjunction(Query<T> query, ExpressionList<T> parent);
|
||||
|
||||
/**
|
||||
* Return a list of expressions that will be joined by OR's.
|
||||
*/
|
||||
<T> Junction<T> disjunction(Query<T> query, ExpressionList<T> parent);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,252 +1,252 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Defines the configuration options for a "query fetch" or a
|
||||
* "lazy loading fetch". This gives you the ability to use multiple smaller
|
||||
* queries to populate an object graph as opposed to a single large query.
|
||||
* <p>
|
||||
* The primary goal is to provide efficient ways of loading complex object
|
||||
* graphs avoiding SQL Cartesian product and issues around populating object
|
||||
* graphs that have multiple *ToMany relationships.
|
||||
* </p>
|
||||
* <p>
|
||||
* It also provides the ability to control the lazy loading queries (batch size,
|
||||
* selected properties and fetches) to avoid N+1 queries etc.
|
||||
* <p>
|
||||
* There can also be cases loading across a single OneToMany where 2 SQL queries
|
||||
* using Ebean FetchConfig.query() can be more efficient than one SQL query.
|
||||
* When the "One" side is wide (lots of columns) and the cardinality difference
|
||||
* is high (a lot of "Many" beans per "One" bean) then this can be more
|
||||
* efficient loaded as 2 SQL queries.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // Normal fetch join results in a single SQL query
|
||||
* List<Order> list = Ebean.find(Order.class).fetch("details").findList();
|
||||
*
|
||||
* // Find Orders join details using a single SQL query
|
||||
* </pre>
|
||||
* <p>
|
||||
* Example: Using a "query join" instead of a "fetch join" we instead use 2 SQL
|
||||
* queries
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // This will use 2 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* .fetch("details", new FetchConfig().query())
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order
|
||||
* // query 2) find orderDetails where order.id in (?,?...) // first 100 order id's
|
||||
* </pre>
|
||||
* <p>
|
||||
* Example: Using 2 "query joins"
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // This will use 3 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* .fetch("details", new FetchConfig().query())
|
||||
* .fetch("customer", new FetchConfig().queryFirst(5))
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order
|
||||
* // query 2) find orderDetails where order.id in (?,?...) // first 100 order id's
|
||||
* // query 3) find customer where id in (?,?,?,?,?) // first 5 customers
|
||||
* </pre>
|
||||
* <p>
|
||||
* Example: Using "query joins" and partial objects
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // This will use 3 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* .select("status, shipDate")
|
||||
* .fetch("details", "quantity, price", new FetchConfig().query())
|
||||
* .fetch("details.product", "sku, name")
|
||||
* .fetch("customer", "name", new FetchConfig().queryFirst(5))
|
||||
* .fetch("customer.contacts")
|
||||
* .fetch("customer.shippingAddress")
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order (status, shipDate)
|
||||
* // query 2) find orderDetail (quantity, price) fetch product (sku, name) where
|
||||
* // order.id in (?,? ...)
|
||||
* // query 3) find customer (name) fetch contacts (*) fetch shippingAddress (*)
|
||||
* // where id in (?,?,?,?,?)
|
||||
*
|
||||
* // Note: the fetch of "details.product" is automatically included into the
|
||||
* // fetch of "details"
|
||||
* //
|
||||
* // Note: the fetch of "customer.contacts" and "customer.shippingAddress"
|
||||
* // are automatically included in the fetch of "customer"
|
||||
* </pre>
|
||||
* <p>
|
||||
* You can use query() and lazy together on a single join. The query is executed
|
||||
* immediately and the lazy defines the batch size to use for further lazy
|
||||
* loading (if lazy loading is invoked).
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* .fetch("customer", new FetchConfig().query(10).lazy(5))
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order
|
||||
* // query 2) find customer where id in (?,?,?,?,?,?,?,?,?,?) // first 10 customers
|
||||
* // .. then if lazy loading of customers is invoked
|
||||
* // .. use a batch size of 5 to load the customers
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Example of controlling the lazy loading query:
|
||||
* </p>
|
||||
* <p>
|
||||
* This gives us the ability to optimise the lazy loading query for a given use
|
||||
* case.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* List<Order> list = Ebean.find(Order.class)
|
||||
* .fetch("customer","name", new FetchConfig().lazy(5))
|
||||
* .fetch("customer.contacts","contactName, phone, email")
|
||||
* .fetch("customer.shippingAddress")
|
||||
* .where().eq("status",Order.Status.NEW)
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order where status = Order.Status.NEW
|
||||
* //
|
||||
* // .. if lazy loading of customers is invoked
|
||||
* // .. use a batch size of 5 to load the customers
|
||||
*
|
||||
* find customer (name)
|
||||
* fetch customer.contacts (contactName, phone, email)
|
||||
* fetch customer.shippingAddress (*)
|
||||
* where id in (?,?,?,?,?)
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author mario
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class FetchConfig implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private int lazyBatchSize = -1;
|
||||
|
||||
private int queryBatchSize = -1;
|
||||
|
||||
private boolean queryAll;
|
||||
|
||||
/**
|
||||
* Construct the fetch configuration object.
|
||||
*/
|
||||
public FetchConfig() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that this path should be lazy loaded using the default batch load
|
||||
* size.
|
||||
*/
|
||||
public FetchConfig lazy() {
|
||||
this.lazyBatchSize = 0;
|
||||
this.queryAll = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that this path should be lazy loaded with a specified batch size.
|
||||
*
|
||||
* @param lazyBatchSize
|
||||
* the batch size for lazy loading
|
||||
*/
|
||||
public FetchConfig lazy(int lazyBatchSize) {
|
||||
this.lazyBatchSize = lazyBatchSize;
|
||||
this.queryAll = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly fetch the beans in this path as a separate query (rather than as
|
||||
* part of the main query).
|
||||
* <p>
|
||||
* This will use the default batch size for separate query which is 100.
|
||||
* </p>
|
||||
*/
|
||||
public FetchConfig query() {
|
||||
this.queryBatchSize = 0;
|
||||
this.queryAll = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly fetch the beans in this path as a separate query (rather than as
|
||||
* part of the main query).
|
||||
* <p>
|
||||
* The queryBatchSize is the number of parent id's that this separate query
|
||||
* will load per batch.
|
||||
* </p>
|
||||
* <p>
|
||||
* This will load all beans on this path eagerly unless a {@link #lazy(int)}
|
||||
* is also used.
|
||||
* </p>
|
||||
*
|
||||
* @param queryBatchSize
|
||||
* the batch size used to load beans on this path
|
||||
*/
|
||||
public FetchConfig query(int queryBatchSize) {
|
||||
this.queryBatchSize = queryBatchSize;
|
||||
// queryAll true as long as a lazy batch size has not already been set
|
||||
this.queryAll = (lazyBatchSize == -1);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly fetch the first batch of beans on this path.
|
||||
* This is similar to {@link #query(int)} but only fetches the first batch.
|
||||
* <p>
|
||||
* If there are more parent beans than the batch size then they will not be
|
||||
* loaded eagerly but instead use lazy loading.
|
||||
* </p>
|
||||
*
|
||||
* @param queryBatchSize
|
||||
* the number of parent beans this path is populated for
|
||||
*/
|
||||
public FetchConfig queryFirst(int queryBatchSize) {
|
||||
this.queryBatchSize = queryBatchSize;
|
||||
this.queryAll = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch size for lazy loading.
|
||||
*/
|
||||
public int getLazyBatchSize() {
|
||||
return lazyBatchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch size for separate query load.
|
||||
*/
|
||||
public int getQueryBatchSize() {
|
||||
return queryBatchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the query fetch should fetch 'all' rather than just the
|
||||
* 'first' batch.
|
||||
*/
|
||||
public boolean isQueryAll() {
|
||||
return queryAll;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Defines the configuration options for a "query fetch" or a
|
||||
* "lazy loading fetch". This gives you the ability to use multiple smaller
|
||||
* queries to populate an object graph as opposed to a single large query.
|
||||
* <p>
|
||||
* The primary goal is to provide efficient ways of loading complex object
|
||||
* graphs avoiding SQL Cartesian product and issues around populating object
|
||||
* graphs that have multiple *ToMany relationships.
|
||||
* </p>
|
||||
* <p>
|
||||
* It also provides the ability to control the lazy loading queries (batch size,
|
||||
* selected properties and fetches) to avoid N+1 queries etc.
|
||||
* <p>
|
||||
* There can also be cases loading across a single OneToMany where 2 SQL queries
|
||||
* using Ebean FetchConfig.query() can be more efficient than one SQL query.
|
||||
* When the "One" side is wide (lots of columns) and the cardinality difference
|
||||
* is high (a lot of "Many" beans per "One" bean) then this can be more
|
||||
* efficient loaded as 2 SQL queries.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // Normal fetch join results in a single SQL query
|
||||
* List<Order> list = Ebean.find(Order.class).fetch("details").findList();
|
||||
*
|
||||
* // Find Orders join details using a single SQL query
|
||||
* </pre>
|
||||
* <p>
|
||||
* Example: Using a "query join" instead of a "fetch join" we instead use 2 SQL
|
||||
* queries
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // This will use 2 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* .fetch("details", new FetchConfig().query())
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order
|
||||
* // query 2) find orderDetails where order.id in (?,?...) // first 100 order id's
|
||||
* </pre>
|
||||
* <p>
|
||||
* Example: Using 2 "query joins"
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // This will use 3 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* .fetch("details", new FetchConfig().query())
|
||||
* .fetch("customer", new FetchConfig().queryFirst(5))
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order
|
||||
* // query 2) find orderDetails where order.id in (?,?...) // first 100 order id's
|
||||
* // query 3) find customer where id in (?,?,?,?,?) // first 5 customers
|
||||
* </pre>
|
||||
* <p>
|
||||
* Example: Using "query joins" and partial objects
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // This will use 3 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* .select("status, shipDate")
|
||||
* .fetch("details", "quantity, price", new FetchConfig().query())
|
||||
* .fetch("details.product", "sku, name")
|
||||
* .fetch("customer", "name", new FetchConfig().queryFirst(5))
|
||||
* .fetch("customer.contacts")
|
||||
* .fetch("customer.shippingAddress")
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order (status, shipDate)
|
||||
* // query 2) find orderDetail (quantity, price) fetch product (sku, name) where
|
||||
* // order.id in (?,? ...)
|
||||
* // query 3) find customer (name) fetch contacts (*) fetch shippingAddress (*)
|
||||
* // where id in (?,?,?,?,?)
|
||||
*
|
||||
* // Note: the fetch of "details.product" is automatically included into the
|
||||
* // fetch of "details"
|
||||
* //
|
||||
* // Note: the fetch of "customer.contacts" and "customer.shippingAddress"
|
||||
* // are automatically included in the fetch of "customer"
|
||||
* </pre>
|
||||
* <p>
|
||||
* You can use query() and lazy together on a single join. The query is executed
|
||||
* immediately and the lazy defines the batch size to use for further lazy
|
||||
* loading (if lazy loading is invoked).
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* .fetch("customer", new FetchConfig().query(10).lazy(5))
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order
|
||||
* // query 2) find customer where id in (?,?,?,?,?,?,?,?,?,?) // first 10 customers
|
||||
* // .. then if lazy loading of customers is invoked
|
||||
* // .. use a batch size of 5 to load the customers
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Example of controlling the lazy loading query:
|
||||
* </p>
|
||||
* <p>
|
||||
* This gives us the ability to optimise the lazy loading query for a given use
|
||||
* case.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* List<Order> list = Ebean.find(Order.class)
|
||||
* .fetch("customer","name", new FetchConfig().lazy(5))
|
||||
* .fetch("customer.contacts","contactName, phone, email")
|
||||
* .fetch("customer.shippingAddress")
|
||||
* .where().eq("status",Order.Status.NEW)
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order where status = Order.Status.NEW
|
||||
* //
|
||||
* // .. if lazy loading of customers is invoked
|
||||
* // .. use a batch size of 5 to load the customers
|
||||
*
|
||||
* find customer (name)
|
||||
* fetch customer.contacts (contactName, phone, email)
|
||||
* fetch customer.shippingAddress (*)
|
||||
* where id in (?,?,?,?,?)
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author mario
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class FetchConfig implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private int lazyBatchSize = -1;
|
||||
|
||||
private int queryBatchSize = -1;
|
||||
|
||||
private boolean queryAll;
|
||||
|
||||
/**
|
||||
* Construct the fetch configuration object.
|
||||
*/
|
||||
public FetchConfig() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that this path should be lazy loaded using the default batch load
|
||||
* size.
|
||||
*/
|
||||
public FetchConfig lazy() {
|
||||
this.lazyBatchSize = 0;
|
||||
this.queryAll = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that this path should be lazy loaded with a specified batch size.
|
||||
*
|
||||
* @param lazyBatchSize
|
||||
* the batch size for lazy loading
|
||||
*/
|
||||
public FetchConfig lazy(int lazyBatchSize) {
|
||||
this.lazyBatchSize = lazyBatchSize;
|
||||
this.queryAll = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly fetch the beans in this path as a separate query (rather than as
|
||||
* part of the main query).
|
||||
* <p>
|
||||
* This will use the default batch size for separate query which is 100.
|
||||
* </p>
|
||||
*/
|
||||
public FetchConfig query() {
|
||||
this.queryBatchSize = 0;
|
||||
this.queryAll = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly fetch the beans in this path as a separate query (rather than as
|
||||
* part of the main query).
|
||||
* <p>
|
||||
* The queryBatchSize is the number of parent id's that this separate query
|
||||
* will load per batch.
|
||||
* </p>
|
||||
* <p>
|
||||
* This will load all beans on this path eagerly unless a {@link #lazy(int)}
|
||||
* is also used.
|
||||
* </p>
|
||||
*
|
||||
* @param queryBatchSize
|
||||
* the batch size used to load beans on this path
|
||||
*/
|
||||
public FetchConfig query(int queryBatchSize) {
|
||||
this.queryBatchSize = queryBatchSize;
|
||||
// queryAll true as long as a lazy batch size has not already been set
|
||||
this.queryAll = (lazyBatchSize == -1);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly fetch the first batch of beans on this path.
|
||||
* This is similar to {@link #query(int)} but only fetches the first batch.
|
||||
* <p>
|
||||
* If there are more parent beans than the batch size then they will not be
|
||||
* loaded eagerly but instead use lazy loading.
|
||||
* </p>
|
||||
*
|
||||
* @param queryBatchSize
|
||||
* the number of parent beans this path is populated for
|
||||
*/
|
||||
public FetchConfig queryFirst(int queryBatchSize) {
|
||||
this.queryBatchSize = queryBatchSize;
|
||||
this.queryAll = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch size for lazy loading.
|
||||
*/
|
||||
public int getLazyBatchSize() {
|
||||
return lazyBatchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch size for separate query load.
|
||||
*/
|
||||
public int getQueryBatchSize() {
|
||||
return queryBatchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the query fetch should fetch 'all' rather than just the
|
||||
* 'first' batch.
|
||||
*/
|
||||
public boolean isQueryAll() {
|
||||
return queryAll;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -90,98 +90,98 @@ public interface Filter<T> {
|
||||
* Refer to {@link Ebean#sort(List, String)} for more detail.
|
||||
* </p>
|
||||
*/
|
||||
public Filter<T> sort(String sortByClause);
|
||||
Filter<T> sort(String sortByClause);
|
||||
|
||||
/**
|
||||
* Specify the maximum number of rows/elements to return.
|
||||
*/
|
||||
public Filter<T> maxRows(int maxRows);
|
||||
Filter<T> maxRows(int maxRows);
|
||||
|
||||
/**
|
||||
* Equal To - property equal to the given value.
|
||||
*/
|
||||
public Filter<T> eq(String prop, Object value);
|
||||
Filter<T> eq(String prop, Object value);
|
||||
|
||||
/**
|
||||
* Not Equal To - property not equal to the given value.
|
||||
*/
|
||||
public Filter<T> ne(String propertyName, Object value);
|
||||
Filter<T> ne(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Case Insensitive Equal To.
|
||||
*/
|
||||
public Filter<T> ieq(String propertyName, String value);
|
||||
Filter<T> ieq(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Between - property between the two given values.
|
||||
*/
|
||||
public Filter<T> between(String propertyName, Object value1, Object value2);
|
||||
Filter<T> between(String propertyName, Object value1, Object value2);
|
||||
|
||||
/**
|
||||
* Greater Than - property greater than the given value.
|
||||
*/
|
||||
public Filter<T> gt(String propertyName, Object value);
|
||||
Filter<T> gt(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Greater Than or Equal to - property greater than or equal to the given
|
||||
* value.
|
||||
*/
|
||||
public Filter<T> ge(String propertyName, Object value);
|
||||
Filter<T> ge(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Less Than - property less than the given value.
|
||||
*/
|
||||
public Filter<T> lt(String propertyName, Object value);
|
||||
Filter<T> lt(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Less Than or Equal to - property less than or equal to the given value.
|
||||
*/
|
||||
public Filter<T> le(String propertyName, Object value);
|
||||
Filter<T> le(String propertyName, Object value);
|
||||
|
||||
/**
|
||||
* Is Null - property is null.
|
||||
*/
|
||||
public Filter<T> isNull(String propertyName);
|
||||
Filter<T> isNull(String propertyName);
|
||||
|
||||
/**
|
||||
* Is Not Null - property is not null.
|
||||
*/
|
||||
public Filter<T> isNotNull(String propertyName);
|
||||
Filter<T> isNotNull(String propertyName);
|
||||
|
||||
/**
|
||||
* Starts With.
|
||||
*/
|
||||
public Filter<T> startsWith(String propertyName, String value);
|
||||
Filter<T> startsWith(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Case insensitive Starts With.
|
||||
*/
|
||||
public Filter<T> istartsWith(String propertyName, String value);
|
||||
Filter<T> istartsWith(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Ends With.
|
||||
*/
|
||||
public Filter<T> endsWith(String propertyName, String value);
|
||||
Filter<T> endsWith(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Case insensitive Ends With.
|
||||
*/
|
||||
public Filter<T> iendsWith(String propertyName, String value);
|
||||
Filter<T> iendsWith(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Contains - property contains the string "value".
|
||||
*/
|
||||
public Filter<T> contains(String propertyName, String value);
|
||||
Filter<T> contains(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* Case insensitive Contains.
|
||||
*/
|
||||
public Filter<T> icontains(String propertyName, String value);
|
||||
Filter<T> icontains(String propertyName, String value);
|
||||
|
||||
/**
|
||||
* In - property has a value contained in the set of values.
|
||||
*/
|
||||
public Filter<T> in(String propertyName, Set<?> values);
|
||||
Filter<T> in(String propertyName, Set<?> values);
|
||||
|
||||
/**
|
||||
* Apply the filter to the list returning a new list of the matching elements
|
||||
@@ -192,6 +192,6 @@ public interface Filter<T> {
|
||||
*
|
||||
* @return Returns a new list with the sorting and filters applied.
|
||||
*/
|
||||
public List<T> filter(List<T> sourceList);
|
||||
List<T> filter(List<T> sourceList);
|
||||
|
||||
}
|
||||
@@ -1,34 +1,34 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* FutureIds represents the result of a background query execution for the Id's.
|
||||
* <p>
|
||||
* It extends the java.util.concurrent.Future with the ability to get the Id's
|
||||
* while the query is still executing in the background.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface FutureIds<T> extends Future<List<Object>> {
|
||||
|
||||
/**
|
||||
* Returns the original query used to fetch the Id's.
|
||||
*/
|
||||
public Query<T> getQuery();
|
||||
|
||||
/**
|
||||
* Return the list of Id's which could be partially populated.
|
||||
* <p>
|
||||
* That is the query getting the id's could still be running and adding id's
|
||||
* to this list.
|
||||
* </p>
|
||||
* <p>
|
||||
* To get the list of Id's ensuring the query has finished use the
|
||||
* {@link Future#get()} method instead of this one.
|
||||
* </p>
|
||||
*/
|
||||
public List<Object> getPartialIds();
|
||||
}
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* FutureIds represents the result of a background query execution for the Id's.
|
||||
* <p>
|
||||
* It extends the java.util.concurrent.Future with the ability to get the Id's
|
||||
* while the query is still executing in the background.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface FutureIds<T> extends Future<List<Object>> {
|
||||
|
||||
/**
|
||||
* Returns the original query used to fetch the Id's.
|
||||
*/
|
||||
Query<T> getQuery();
|
||||
|
||||
/**
|
||||
* Return the list of Id's which could be partially populated.
|
||||
* <p>
|
||||
* That is the query getting the id's could still be running and adding id's
|
||||
* to this list.
|
||||
* </p>
|
||||
* <p>
|
||||
* To get the list of Id's ensuring the query has finished use the
|
||||
* {@link Future#get()} method instead of this one.
|
||||
* </p>
|
||||
*/
|
||||
List<Object> getPartialIds();
|
||||
}
|
||||
|
||||
@@ -1,76 +1,76 @@
|
||||
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
|
||||
* return a list of entities.
|
||||
* <p>
|
||||
* It extends the java.util.concurrent.Future with the ability to cancel the
|
||||
* query, check if it is finished and get the resulting list waiting for the
|
||||
* query to finish (ie. the standard features of java.util.concurrent.Future).
|
||||
* </p>
|
||||
* <p>
|
||||
* A simple example:
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* // create a query to find all orders
|
||||
* Query<Order> query = Ebean.find(Order.class);
|
||||
*
|
||||
* // execute the query in a background thread
|
||||
* // immediately returning the futureList
|
||||
* FutureList<Order> futureList = query.findFutureList();
|
||||
*
|
||||
* // do something else ...
|
||||
*
|
||||
* if (!futureList.isDone()){
|
||||
* // we can cancel the query execution. This will cancel
|
||||
* // the underlying query if that is supported by the JDBC
|
||||
* // driver and database
|
||||
* futureList.cancel(true);
|
||||
* }
|
||||
*
|
||||
*
|
||||
* if (!futureList.isCancelled()){
|
||||
* // wait for the query to finish and return the list
|
||||
* List<Order> list = futureList.get();
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public interface FutureList<T> extends Future<List<T>> {
|
||||
|
||||
/**
|
||||
* Return the query that is being executed by a background thread.
|
||||
*/
|
||||
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;
|
||||
|
||||
}
|
||||
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
|
||||
* return a list of entities.
|
||||
* <p>
|
||||
* It extends the java.util.concurrent.Future with the ability to cancel the
|
||||
* query, check if it is finished and get the resulting list waiting for the
|
||||
* query to finish (ie. the standard features of java.util.concurrent.Future).
|
||||
* </p>
|
||||
* <p>
|
||||
* A simple example:
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* // create a query to find all orders
|
||||
* Query<Order> query = Ebean.find(Order.class);
|
||||
*
|
||||
* // execute the query in a background thread
|
||||
* // immediately returning the futureList
|
||||
* FutureList<Order> futureList = query.findFutureList();
|
||||
*
|
||||
* // do something else ...
|
||||
*
|
||||
* if (!futureList.isDone()){
|
||||
* // we can cancel the query execution. This will cancel
|
||||
* // the underlying query if that is supported by the JDBC
|
||||
* // driver and database
|
||||
* futureList.cancel(true);
|
||||
* }
|
||||
*
|
||||
*
|
||||
* if (!futureList.isCancelled()){
|
||||
* // wait for the query to finish and return the list
|
||||
* List<Order> list = futureList.get();
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public interface FutureList<T> extends Future<List<T>> {
|
||||
|
||||
/**
|
||||
* Return the query that is being executed by a background thread.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
List<T> getUnchecked(long timeout, TimeUnit unit) throws TimeoutException;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* Represents the result of a background query execution for the total row count
|
||||
* for a query.
|
||||
* <p>
|
||||
* It extends the java.util.concurrent.Future.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface FutureRowCount<T> extends Future<Integer> {
|
||||
}
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* Represents the result of a background query execution for the total row count
|
||||
* for a query.
|
||||
* <p>
|
||||
* It extends the java.util.concurrent.Future.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface FutureRowCount<T> extends Future<Integer> {
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.text.PathProperties;
|
||||
import com.avaje.ebean.util.ClassUtil;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.GenericArrayType;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.*;
|
||||
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
@@ -34,7 +36,7 @@ import javax.persistence.MappedSuperclass;
|
||||
*
|
||||
* <p>
|
||||
* If you choose to use the Model mapped superclass you will probably also chose to additionally add
|
||||
* a {@link Finder} as a public static field to complete the active record pattern and provide a
|
||||
* a {@link Find} as a public static field to complete the active record pattern and provide a
|
||||
* relatively nice clean way to write queries.
|
||||
*
|
||||
* <h3>Typical common @MappedSuperclass</h3>
|
||||
@@ -64,19 +66,15 @@ import javax.persistence.MappedSuperclass;
|
||||
* // Extend the mappedSuperclass
|
||||
*
|
||||
* @Entity @Table(name="oto_account")
|
||||
* public class Account extends BaseModel {
|
||||
* public class Customer extends BaseModel {
|
||||
*
|
||||
* // add a static Finder
|
||||
* // ... with Long being the type of our ID property ...
|
||||
* // Add a static Find
|
||||
* // ... with Long being the type of our @Id property.
|
||||
* // ... Note the {} at the end as Find is an abstract class.
|
||||
*
|
||||
* public static final Finder<Long,Account> find =
|
||||
* new Finder<Long,Account>(Long.class, Account.class);
|
||||
* public static final Find<Long,Account> find = new Find<Long,Account>(){};
|
||||
*
|
||||
* String name;
|
||||
*
|
||||
* @OneToOne(mappedBy = "account",optional = true)
|
||||
* User user;
|
||||
*
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
@@ -86,28 +84,28 @@ import javax.persistence.MappedSuperclass;
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Active record style ... save(), delete() etc
|
||||
* Account account = new Account();
|
||||
* account.setName("AC234");
|
||||
* Customer customer = new Customer();
|
||||
* customer.setName("AC234");
|
||||
*
|
||||
* // save() method inherited from Model
|
||||
* account.save();
|
||||
* customer.save();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Finder: find byId</h3>
|
||||
* <h3>Find byId</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // find byId
|
||||
* Account account = Account.find.byId(42);
|
||||
* Customer customer = Customer.find.byId(42);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Finder: find where</h3>
|
||||
* <h3>Find where</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // find where ...
|
||||
* List<Account> accounts =
|
||||
* Account.find
|
||||
* List<Customer> customers =
|
||||
* Customer.find
|
||||
* .where().gt("startDate", lastMonth)
|
||||
* .findList();
|
||||
*
|
||||
@@ -124,7 +122,8 @@ public abstract class Model {
|
||||
*
|
||||
* <p>
|
||||
* Example:
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
*
|
||||
* Transaction transaction = Customer.db().beginTransaction();
|
||||
* try {
|
||||
*
|
||||
@@ -141,7 +140,7 @@ public abstract class Model {
|
||||
* customer.save();
|
||||
*
|
||||
* Customer otherCustomer = new Customer();
|
||||
* otherCustomer.setName("Franko");
|
||||
* otherCustomer.setName("Franko");
|
||||
* otherCustomer.save();
|
||||
*
|
||||
* transaction.commit();
|
||||
@@ -150,7 +149,7 @@ public abstract class Model {
|
||||
* transaction.end();
|
||||
* }
|
||||
*
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*/
|
||||
public static EbeanServer db() {
|
||||
return Ebean.getServer(null);
|
||||
@@ -179,7 +178,7 @@ public abstract class Model {
|
||||
* 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 = Customer.find.byId(id);
|
||||
*
|
||||
@@ -188,7 +187,7 @@ public abstract class Model {
|
||||
* customer.markAsDirty();
|
||||
* customer.save();
|
||||
*
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* @see EbeanServer#markAsDirty(Object)
|
||||
*/
|
||||
@@ -266,46 +265,193 @@ public abstract class Model {
|
||||
db().refresh(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* A concrete implementation of Find.
|
||||
* <p>
|
||||
* It should be preferred to use {@link Find} instead of Finder as that can use reflection to determine the class
|
||||
* literal type of the entity bean.
|
||||
* </p>
|
||||
* @param <I> type of the Id property
|
||||
* @param <T> type of the entity bean
|
||||
*/
|
||||
public static class Finder<I, T> extends Find<I, T> {
|
||||
|
||||
/**
|
||||
* Create with the type of the entity bean.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* @Entity
|
||||
* public class Customer extends BaseModel {
|
||||
*
|
||||
* public static final Finder<Long,Customer> find = new Finder<Long,Customer>(Customer.class);
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p/>
|
||||
* The preferred approach is to instead use <code>Find</code> as below. This approach is more DRY in that it does
|
||||
* not require the class literal Customer.class to be passed into the constructor.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* @Entity
|
||||
* public class Customer extends BaseModel {
|
||||
*
|
||||
* public static final Find<Long,Customer> find = new Find<Long,Customer>(){};
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public Finder(Class<T> type) {
|
||||
super(null, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create with the type of the entity bean and specific server name.
|
||||
*/
|
||||
public Finder(String serverName, Class<T> type) {
|
||||
super(serverName, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Please migrate to use {@link Find} or constructor <code>Finder(Class)</code> that
|
||||
* does not have the idType parameter.
|
||||
* <p/>
|
||||
* Create with the type of the ID property and entity bean and specific server name.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public Finder(Class<I> idType, Class<T> type) {
|
||||
super(null, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Please migrate to use the constructor <code>Finder(String, Class)</code> that
|
||||
* does not have the idType parameter.
|
||||
* <p/>
|
||||
* Create with the type of the ID property and entity bean and specific server name.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public Finder(String serverName, Class<I> idType, Class<T> type) {
|
||||
super(serverName, type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper object for performing queries.
|
||||
*
|
||||
* <p>
|
||||
* Typically a Finder is defined as a public static field on an entity bean class to provide a
|
||||
* Typically a Find instance is defined as a public static field on an entity bean class to provide a
|
||||
* nice way to write queries.
|
||||
*
|
||||
*
|
||||
* <h3>Example use:</h3>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* @Entity
|
||||
* public class Customer extends BaseModel {
|
||||
*
|
||||
* public static final Find<Long,Customer> find = new Find<Long,Customer>(){};
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
* <p/>
|
||||
* This enables you to write code like:
|
||||
* <pre>{@code
|
||||
*
|
||||
* Customer customer = Customer.find.byId(42L);
|
||||
*
|
||||
* List<Customer> customers =
|
||||
* Customer.find
|
||||
* .select("name, dateOfBirth")
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Kotlin</h3>
|
||||
* In Kotlin you would typically create Find as a companion object.
|
||||
* <pre>{@code
|
||||
*
|
||||
* // kotlin
|
||||
* companion object : Model.Find<Long, Product>() {}
|
||||
*
|
||||
* }</pre>
|
||||
* @param <I>
|
||||
* The Id type. This is most often a {@link Long} but is also often a {@link UUID} or
|
||||
* {@link String}.
|
||||
*
|
||||
* @param <T>
|
||||
* The bean type
|
||||
* The entity bean type
|
||||
*/
|
||||
public static class Finder<I, T> {
|
||||
public static abstract class Find<I, T> {
|
||||
|
||||
private final Class<I> idType;
|
||||
/**
|
||||
* The entity bean type.
|
||||
*/
|
||||
private final Class<T> type;
|
||||
|
||||
/**
|
||||
* The name of the EbeanServer, null for the default server.
|
||||
*/
|
||||
private final String serverName;
|
||||
|
||||
/**
|
||||
* Creates a finder for entity of type <code>T</code> with ID of type <code>I</code>.
|
||||
*
|
||||
* <p>
|
||||
* Typically you use this constructor to have a static "find" field on each entity bean.
|
||||
* <p/>
|
||||
* Typically you create Find as a public static field on each entity bean as the example below.
|
||||
*
|
||||
* <p/>
|
||||
* Note that Find is an abstract class and hence <code>{}</code> is required. This is done so
|
||||
* that the type (class literal) of the entity bean can be derived from the generics parameter.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* @Entity
|
||||
* public class Customer extends BaseModel {
|
||||
*
|
||||
* // Note the trailing {} as Find is an abstract class.
|
||||
* // We do this so that we can derive the type literal Customer.class
|
||||
* // via reflection
|
||||
* public static final Find<Long,Customer> find = new Find<Long,Customer>(){};
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
* <p/>
|
||||
* This enables you to write code like:
|
||||
* <pre>{@code
|
||||
*
|
||||
* Customer customer = Customer.find.byId(42L);
|
||||
*
|
||||
* List<Customer> customers =
|
||||
* Customer.find
|
||||
* .select("name, email, dateOfBirth")
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Kotlin</h3>
|
||||
* In Kotlin you would typically create it as a companion object.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // kotlin
|
||||
* companion object : Model.Find<Long, Product>() {}
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public Finder(Class<I> idType, Class<T> type) {
|
||||
this(null, idType, type);
|
||||
public Find() {
|
||||
this.serverName = null;
|
||||
this.type = (Class<T>)ClassUtil.getSecondArgumentType(getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a finder for entity of type <code>T</code> with ID of type <code>I</code>, using a
|
||||
* specific EbeanServer.
|
||||
*
|
||||
* <p>
|
||||
* Typically you don't need to use this method.
|
||||
* Construct passing the class literal type of the entity type.
|
||||
*/
|
||||
public Finder(String serverName, Class<I> idType, Class<T> type) {
|
||||
protected Find(String serverName, Class<T> type) {
|
||||
this.type = type;
|
||||
this.idType = idType;
|
||||
this.serverName = serverName;
|
||||
}
|
||||
|
||||
@@ -335,12 +481,12 @@ public abstract class Model {
|
||||
|
||||
/**
|
||||
* Creates a Finder for the named EbeanServer.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* Create and return a new Finder for a different server.
|
||||
*/
|
||||
public Finder<I, T> on(String server) {
|
||||
return new Finder<I, T>(server, idType, type);
|
||||
return new Finder<I, T>(server, type);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,351 +1,351 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents an Order By for a Query.
|
||||
* <p>
|
||||
* Is a ordered list of OrderBy.Property objects each specifying a property and
|
||||
* whether it is ascending or descending order.
|
||||
* </p>
|
||||
* <p>
|
||||
* Typically you will not construct an OrderBy yourself but use one that exists
|
||||
* on the Query object.
|
||||
* </p>
|
||||
*/
|
||||
public final class OrderBy<T> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 9157089257745730539L;
|
||||
|
||||
private transient Query<T> query;
|
||||
|
||||
private final List<Property> list;
|
||||
|
||||
/**
|
||||
* Create an empty OrderBy with no associated query.
|
||||
*/
|
||||
public OrderBy() {
|
||||
this.list = new ArrayList<Property>(2);
|
||||
}
|
||||
|
||||
private OrderBy(List<Property> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an orderBy parsing the order by clause.
|
||||
* <p>
|
||||
* The order by clause follows SQL order by clause with comma's between each
|
||||
* property and optionally "asc" or "desc" to represent ascending or
|
||||
* descending order respectively.
|
||||
* </p>
|
||||
*/
|
||||
public OrderBy(String orderByClause) {
|
||||
this(null, orderByClause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with a given query and order by clause.
|
||||
*/
|
||||
public OrderBy(Query<T> query, String orderByClause) {
|
||||
this.query = query;
|
||||
this.list = new ArrayList<Property>(2);
|
||||
parse(orderByClause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the ascending/descending order on all the properties.
|
||||
*/
|
||||
public void reverse() {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
list.get(i).reverse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a property with ascending order to this OrderBy.
|
||||
*/
|
||||
public Query<T> asc(String propertyName) {
|
||||
|
||||
list.add(new Property(propertyName, true));
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a property with descending order to this OrderBy.
|
||||
*/
|
||||
public Query<T> desc(String propertyName) {
|
||||
|
||||
list.add(new Property(propertyName, false));
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this OrderBy with the path trimmed.
|
||||
*/
|
||||
public OrderBy<T> copyWithTrim(String path) {
|
||||
List<Property> newList = new ArrayList<Property>(list.size());
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
newList.add(list.get(i).copyWithTrim(path));
|
||||
}
|
||||
return new OrderBy<T>(newList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the properties for this OrderBy.
|
||||
*/
|
||||
public List<Property> getProperties() {
|
||||
// not returning an Immutable list at this point
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this OrderBy does not have any properties.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return list.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated query if there is one.
|
||||
*/
|
||||
public Query<T> getQuery() {
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate this OrderBy with a query.
|
||||
*/
|
||||
public void setQuery(Query<T> query) {
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of the OrderBy.
|
||||
*/
|
||||
public OrderBy<T> copy() {
|
||||
|
||||
OrderBy<T> copy = new OrderBy<T>();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
copy.add(list.get(i).copy());
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a property to the order by.
|
||||
*/
|
||||
public void add(Property p) {
|
||||
list.add(p);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return list.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the OrderBy in string format.
|
||||
*/
|
||||
public String toStringFormat() {
|
||||
if (list.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
Property property = list.get(i);
|
||||
if (i > 0) {
|
||||
sb.append(", ");
|
||||
}
|
||||
sb.append(property.toStringFormat());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof OrderBy<?>)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
OrderBy<?> e = (OrderBy<?>) obj;
|
||||
return e.list.equals(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a hash value for this OrderBy. This can be to determine logical
|
||||
* equality for OrderBy clauses.
|
||||
*/
|
||||
public int hashCode() {
|
||||
return list.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* A property and its ascending descending order.
|
||||
*/
|
||||
public static final class Property implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1546009780322478077L;
|
||||
|
||||
private String property;
|
||||
|
||||
private boolean ascending;
|
||||
|
||||
public Property(String property, boolean ascending) {
|
||||
this.property = property;
|
||||
this.ascending = ascending;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this Property with the path trimmed.
|
||||
*/
|
||||
public Property copyWithTrim(String path) {
|
||||
return new Property(property.substring(path.length() + 1), ascending);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int hc = property.hashCode();
|
||||
hc = hc * 31 + (ascending ? 0 : 1);
|
||||
return hc;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof Property)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Property e = (Property) obj;
|
||||
return e.ascending == ascending
|
||||
&& e.property.equals(property);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return toStringFormat();
|
||||
}
|
||||
|
||||
public String toStringFormat() {
|
||||
if (ascending) {
|
||||
return property;
|
||||
} else {
|
||||
return property + " desc";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the ascending/descending order for this property.
|
||||
*/
|
||||
public void reverse() {
|
||||
this.ascending = !ascending;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim off the pathPrefix.
|
||||
*/
|
||||
public void trim(String pathPrefix) {
|
||||
property = property.substring(pathPrefix.length() + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this property.
|
||||
*/
|
||||
public Property copy() {
|
||||
return new Property(property, ascending);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property name.
|
||||
*/
|
||||
public String getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the property name.
|
||||
*/
|
||||
public void setProperty(String property) {
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the order is ascending.
|
||||
*/
|
||||
public boolean isAscending() {
|
||||
return ascending;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if the order is ascending.
|
||||
*/
|
||||
public void setAscending(boolean ascending) {
|
||||
this.ascending = ascending;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void parse(String orderByClause) {
|
||||
|
||||
if (orderByClause == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String[] chunks = orderByClause.split(",");
|
||||
for (int i = 0; i < chunks.length; i++) {
|
||||
|
||||
String[] pairs = chunks[i].split(" ");
|
||||
Property p = parseProperty(pairs);
|
||||
if (p != null) {
|
||||
list.add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Property parseProperty(String[] pairs) {
|
||||
if (pairs.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayList<String> wordList = new ArrayList<String>(pairs.length);
|
||||
for (int i = 0; i < pairs.length; i++) {
|
||||
if (!isEmptyString(pairs[i])) {
|
||||
wordList.add(pairs[i]);
|
||||
}
|
||||
}
|
||||
if (wordList.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (wordList.size() == 1) {
|
||||
return new Property(wordList.get(0), true);
|
||||
}
|
||||
if (wordList.size() == 2) {
|
||||
boolean asc = isAscending(wordList.get(1));
|
||||
return new Property(wordList.get(0), asc);
|
||||
}
|
||||
String m = "Expecting a max of 2 words in [" + Arrays.toString(pairs)
|
||||
+ "] but got " + wordList.size();
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
|
||||
private boolean isAscending(String s) {
|
||||
s = s.toLowerCase();
|
||||
if (s.startsWith("asc")) {
|
||||
return true;
|
||||
}
|
||||
if (s.startsWith("desc")) {
|
||||
return false;
|
||||
}
|
||||
String m = "Expecting [" + s + "] to be asc or desc?";
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
|
||||
private boolean isEmptyString(String s) {
|
||||
return s == null || s.length() == 0;
|
||||
}
|
||||
}
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents an Order By for a Query.
|
||||
* <p>
|
||||
* Is a ordered list of OrderBy.Property objects each specifying a property and
|
||||
* whether it is ascending or descending order.
|
||||
* </p>
|
||||
* <p>
|
||||
* Typically you will not construct an OrderBy yourself but use one that exists
|
||||
* on the Query object.
|
||||
* </p>
|
||||
*/
|
||||
public final class OrderBy<T> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 9157089257745730539L;
|
||||
|
||||
private transient Query<T> query;
|
||||
|
||||
private final List<Property> list;
|
||||
|
||||
/**
|
||||
* Create an empty OrderBy with no associated query.
|
||||
*/
|
||||
public OrderBy() {
|
||||
this.list = new ArrayList<Property>(2);
|
||||
}
|
||||
|
||||
private OrderBy(List<Property> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an orderBy parsing the order by clause.
|
||||
* <p>
|
||||
* The order by clause follows SQL order by clause with comma's between each
|
||||
* property and optionally "asc" or "desc" to represent ascending or
|
||||
* descending order respectively.
|
||||
* </p>
|
||||
*/
|
||||
public OrderBy(String orderByClause) {
|
||||
this(null, orderByClause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with a given query and order by clause.
|
||||
*/
|
||||
public OrderBy(Query<T> query, String orderByClause) {
|
||||
this.query = query;
|
||||
this.list = new ArrayList<Property>(2);
|
||||
parse(orderByClause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the ascending/descending order on all the properties.
|
||||
*/
|
||||
public void reverse() {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
list.get(i).reverse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a property with ascending order to this OrderBy.
|
||||
*/
|
||||
public Query<T> asc(String propertyName) {
|
||||
|
||||
list.add(new Property(propertyName, true));
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a property with descending order to this OrderBy.
|
||||
*/
|
||||
public Query<T> desc(String propertyName) {
|
||||
|
||||
list.add(new Property(propertyName, false));
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this OrderBy with the path trimmed.
|
||||
*/
|
||||
public OrderBy<T> copyWithTrim(String path) {
|
||||
List<Property> newList = new ArrayList<Property>(list.size());
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
newList.add(list.get(i).copyWithTrim(path));
|
||||
}
|
||||
return new OrderBy<T>(newList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the properties for this OrderBy.
|
||||
*/
|
||||
public List<Property> getProperties() {
|
||||
// not returning an Immutable list at this point
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this OrderBy does not have any properties.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return list.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated query if there is one.
|
||||
*/
|
||||
public Query<T> getQuery() {
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate this OrderBy with a query.
|
||||
*/
|
||||
public void setQuery(Query<T> query) {
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of the OrderBy.
|
||||
*/
|
||||
public OrderBy<T> copy() {
|
||||
|
||||
OrderBy<T> copy = new OrderBy<T>();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
copy.add(list.get(i).copy());
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a property to the order by.
|
||||
*/
|
||||
public void add(Property p) {
|
||||
list.add(p);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return list.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the OrderBy in string format.
|
||||
*/
|
||||
public String toStringFormat() {
|
||||
if (list.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
Property property = list.get(i);
|
||||
if (i > 0) {
|
||||
sb.append(", ");
|
||||
}
|
||||
sb.append(property.toStringFormat());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof OrderBy<?>)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
OrderBy<?> e = (OrderBy<?>) obj;
|
||||
return e.list.equals(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a hash value for this OrderBy. This can be to determine logical
|
||||
* equality for OrderBy clauses.
|
||||
*/
|
||||
public int hashCode() {
|
||||
return list.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* A property and its ascending descending order.
|
||||
*/
|
||||
public static final class Property implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1546009780322478077L;
|
||||
|
||||
private String property;
|
||||
|
||||
private boolean ascending;
|
||||
|
||||
public Property(String property, boolean ascending) {
|
||||
this.property = property;
|
||||
this.ascending = ascending;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this Property with the path trimmed.
|
||||
*/
|
||||
public Property copyWithTrim(String path) {
|
||||
return new Property(property.substring(path.length() + 1), ascending);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int hc = property.hashCode();
|
||||
hc = hc * 31 + (ascending ? 0 : 1);
|
||||
return hc;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof Property)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Property e = (Property) obj;
|
||||
return e.ascending == ascending
|
||||
&& e.property.equals(property);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return toStringFormat();
|
||||
}
|
||||
|
||||
public String toStringFormat() {
|
||||
if (ascending) {
|
||||
return property;
|
||||
} else {
|
||||
return property + " desc";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the ascending/descending order for this property.
|
||||
*/
|
||||
public void reverse() {
|
||||
this.ascending = !ascending;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim off the pathPrefix.
|
||||
*/
|
||||
public void trim(String pathPrefix) {
|
||||
property = property.substring(pathPrefix.length() + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this property.
|
||||
*/
|
||||
public Property copy() {
|
||||
return new Property(property, ascending);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property name.
|
||||
*/
|
||||
public String getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the property name.
|
||||
*/
|
||||
public void setProperty(String property) {
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the order is ascending.
|
||||
*/
|
||||
public boolean isAscending() {
|
||||
return ascending;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if the order is ascending.
|
||||
*/
|
||||
public void setAscending(boolean ascending) {
|
||||
this.ascending = ascending;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void parse(String orderByClause) {
|
||||
|
||||
if (orderByClause == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String[] chunks = orderByClause.split(",");
|
||||
for (int i = 0; i < chunks.length; i++) {
|
||||
|
||||
String[] pairs = chunks[i].split(" ");
|
||||
Property p = parseProperty(pairs);
|
||||
if (p != null) {
|
||||
list.add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Property parseProperty(String[] pairs) {
|
||||
if (pairs.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayList<String> wordList = new ArrayList<String>(pairs.length);
|
||||
for (int i = 0; i < pairs.length; i++) {
|
||||
if (!isEmptyString(pairs[i])) {
|
||||
wordList.add(pairs[i]);
|
||||
}
|
||||
}
|
||||
if (wordList.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (wordList.size() == 1) {
|
||||
return new Property(wordList.get(0), true);
|
||||
}
|
||||
if (wordList.size() == 2) {
|
||||
boolean asc = isAscending(wordList.get(1));
|
||||
return new Property(wordList.get(0), asc);
|
||||
}
|
||||
String m = "Expecting a max of 2 words in [" + Arrays.toString(pairs)
|
||||
+ "] but got " + wordList.size();
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
|
||||
private boolean isAscending(String s) {
|
||||
s = s.toLowerCase();
|
||||
if (s.startsWith("asc")) {
|
||||
return true;
|
||||
}
|
||||
if (s.startsWith("desc")) {
|
||||
return false;
|
||||
}
|
||||
String m = "Expecting [" + s + "] to be asc or desc?";
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
|
||||
private boolean isEmptyString(String s) {
|
||||
return s == null || s.length() == 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,192 +1,192 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* Represents a page of results.
|
||||
* <p>
|
||||
* The benefit of using PagedList over just using the normal Query with
|
||||
* {@link Query#setFirstRow(int)} and {@link Query#setMaxRows(int)} is that it additionally wraps
|
||||
* functionality that can call {@link Query#findFutureRowCount()} to determine total row count,
|
||||
* total page count etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* Internally this works using {@link Query#setFirstRow(int)} and {@link Query#setMaxRows(int)} on
|
||||
* the query. This translates into SQL that uses limit offset, rownum or row_number function to
|
||||
* limit the result set.
|
||||
* </p>
|
||||
*
|
||||
* <h4>Example: typical use including total row count</h4>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // We want to find the first 100 new orders
|
||||
* // ... 0 means first page
|
||||
* // ... page size is 100
|
||||
*
|
||||
* PagedList<Order> pagedList
|
||||
* = ebeanServer.find(Order.class)
|
||||
* .where().eq("status", Order.Status.NEW)
|
||||
* .order().asc("id")
|
||||
* .findPagedList(0, 100);
|
||||
*
|
||||
* // Optional: initiate the loading of the total
|
||||
* // row count in a background thread
|
||||
* pagedList.loadRowCount();
|
||||
*
|
||||
* // fetch and return the list in the foreground thread
|
||||
* List<Order> orders = pagedList.getList();
|
||||
*
|
||||
* // get the total row count (from the future)
|
||||
* int totalRowCount = pagedList.getTotalRowCount();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h4>Example: No total row count required</h4>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // If you are not getting the 'first page' often
|
||||
* // you do not bother getting the total row count again
|
||||
* // so instead just get the page list of data
|
||||
*
|
||||
* // fetch and return the list in the foreground thread
|
||||
* List<Order> orders = pagedList.getList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param <T>
|
||||
* the entity bean type
|
||||
*
|
||||
* @see Query#findPagedList(int, int)
|
||||
*/
|
||||
public interface PagedList<T> {
|
||||
|
||||
/**
|
||||
* Initiate the loading of the total row count in the background.
|
||||
* <pre>{@code
|
||||
*
|
||||
* // initiate the loading of the total row count
|
||||
* // in a background thread
|
||||
* pagedList.loadRowCount();
|
||||
*
|
||||
* // fetch and return the list in the foreground thread
|
||||
* List<Order> orders = pagedList.getList();
|
||||
*
|
||||
* // get the total row count (from the future)
|
||||
* int totalRowCount = pagedList.getTotalRowCount();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Also note that using loadRowCount() and getTotalRowCount() rather than getFutureRowCount()
|
||||
* means that exceptions ExecutionException, InterruptedException, TimeoutException are instead
|
||||
* wrapped in the unchecked PersistenceException (which might be preferrable).
|
||||
* </p>
|
||||
*/
|
||||
public void loadRowCount();
|
||||
|
||||
/**
|
||||
* Return the Future row count. You might get this if you wish to cancel the total row count query
|
||||
* or specify a timeout for the row count query.
|
||||
* <p>
|
||||
* The loadRowCount() & getTotalRowCount() methods internally make use of this getFutureRowCount() method.
|
||||
* Generally I expect people to prefer loadRowCount() & getTotalRowCount() over getFutureRowCount().
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // initiate the row count query in the background thread
|
||||
* Future<Integer> rowCount = pagedList.getFutureRowCount();
|
||||
*
|
||||
* // fetch and return the list in the foreground thread
|
||||
* List<Order> orders = pagedList.getList();
|
||||
*
|
||||
* // now get the total count with a timeout
|
||||
* Integer totalRowCount = rowCount.get(30, TimeUnit.SECONDS);
|
||||
*
|
||||
* // or ge the total count without a timeout
|
||||
* Integer totalRowCountViaFuture = rowCount.get();
|
||||
*
|
||||
* // which is actually the same as ...
|
||||
* int totalRowCount = pagedList.getTotalRowCount();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public Future<Integer> getFutureRowCount();
|
||||
|
||||
/**
|
||||
* Return the list of entities for this page.
|
||||
*/
|
||||
public List<T> getList();
|
||||
|
||||
/**
|
||||
* Return the total row count for all pages.
|
||||
* <p>
|
||||
* If loadRowCount() has already been called then the row count query is already executing in a background thread
|
||||
* and this gets the associated Future and gets the value waiting for the future to finish.
|
||||
* </p>
|
||||
* <p>
|
||||
* If loadRowCount() has not been called then this executes the find row count query and returns the result and this
|
||||
* will just occur in the current thread and not use a background thread.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Optional: initiate the loading of the total
|
||||
* // row count in a background thread
|
||||
* pagedList.loadRowCount();
|
||||
*
|
||||
* // fetch and return the list in the foreground thread
|
||||
* List<Order> orders = pagedList.getList();
|
||||
*
|
||||
* // get the total row count (which was being executed
|
||||
* // in a background thread if loadRowCount() was used)
|
||||
* int totalRowCount = pagedList.getTotalRowCount();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public int getTotalRowCount();
|
||||
|
||||
/**
|
||||
* Return the total number of pages based on the page size and total row count.
|
||||
* <p>
|
||||
* This method requires that the total row count has been fetched and will invoke
|
||||
* the total row count query if it has not already been invoked.
|
||||
* </p>
|
||||
*/
|
||||
public int getTotalPageCount();
|
||||
|
||||
/**
|
||||
* Return the index position of this page. Zero based.
|
||||
*/
|
||||
public int getPageIndex();
|
||||
|
||||
/**
|
||||
* Return true if there is a next page.
|
||||
* <p>
|
||||
* This method requires that the total row count has been fetched and will invoke
|
||||
* the total row count query if it has not already been invoked.
|
||||
* </p>
|
||||
*/
|
||||
public boolean hasNext();
|
||||
|
||||
/**
|
||||
* Return true if there is a previous page.
|
||||
*/
|
||||
public boolean hasPrev();
|
||||
|
||||
/**
|
||||
* Helper method to return a "X to Y of Z" string for this page where X is the first row, Y the
|
||||
* last row and Z the total row count.
|
||||
* <p>
|
||||
* This method requires that the total row count has been fetched and will invoke
|
||||
* the total row count query if it has not already been invoked.
|
||||
* </p>
|
||||
*
|
||||
* @param to
|
||||
* String to put between the first and last row
|
||||
* @param of
|
||||
* String to put between the last row and the total row count
|
||||
*
|
||||
* @return String of the format XtoYofZ.
|
||||
*/
|
||||
public String getDisplayXtoYofZ(String to, String of);
|
||||
}
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* Represents a page of results.
|
||||
* <p>
|
||||
* The benefit of using PagedList over just using the normal Query with
|
||||
* {@link Query#setFirstRow(int)} and {@link Query#setMaxRows(int)} is that it additionally wraps
|
||||
* functionality that can call {@link Query#findFutureRowCount()} to determine total row count,
|
||||
* total page count etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* Internally this works using {@link Query#setFirstRow(int)} and {@link Query#setMaxRows(int)} on
|
||||
* the query. This translates into SQL that uses limit offset, rownum or row_number function to
|
||||
* limit the result set.
|
||||
* </p>
|
||||
*
|
||||
* <h4>Example: typical use including total row count</h4>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // We want to find the first 100 new orders
|
||||
* // ... 0 means first page
|
||||
* // ... page size is 100
|
||||
*
|
||||
* PagedList<Order> pagedList
|
||||
* = ebeanServer.find(Order.class)
|
||||
* .where().eq("status", Order.Status.NEW)
|
||||
* .order().asc("id")
|
||||
* .findPagedList(0, 100);
|
||||
*
|
||||
* // Optional: initiate the loading of the total
|
||||
* // row count in a background thread
|
||||
* pagedList.loadRowCount();
|
||||
*
|
||||
* // fetch and return the list in the foreground thread
|
||||
* List<Order> orders = pagedList.getList();
|
||||
*
|
||||
* // get the total row count (from the future)
|
||||
* int totalRowCount = pagedList.getTotalRowCount();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h4>Example: No total row count required</h4>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // If you are not getting the 'first page' often
|
||||
* // you do not bother getting the total row count again
|
||||
* // so instead just get the page list of data
|
||||
*
|
||||
* // fetch and return the list in the foreground thread
|
||||
* List<Order> orders = pagedList.getList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param <T>
|
||||
* the entity bean type
|
||||
*
|
||||
* @see Query#findPagedList(int, int)
|
||||
*/
|
||||
public interface PagedList<T> {
|
||||
|
||||
/**
|
||||
* Initiate the loading of the total row count in the background.
|
||||
* <pre>{@code
|
||||
*
|
||||
* // initiate the loading of the total row count
|
||||
* // in a background thread
|
||||
* pagedList.loadRowCount();
|
||||
*
|
||||
* // fetch and return the list in the foreground thread
|
||||
* List<Order> orders = pagedList.getList();
|
||||
*
|
||||
* // get the total row count (from the future)
|
||||
* int totalRowCount = pagedList.getTotalRowCount();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Also note that using loadRowCount() and getTotalRowCount() rather than getFutureRowCount()
|
||||
* means that exceptions ExecutionException, InterruptedException, TimeoutException are instead
|
||||
* wrapped in the unchecked PersistenceException (which might be preferrable).
|
||||
* </p>
|
||||
*/
|
||||
void loadRowCount();
|
||||
|
||||
/**
|
||||
* Return the Future row count. You might get this if you wish to cancel the total row count query
|
||||
* or specify a timeout for the row count query.
|
||||
* <p>
|
||||
* The loadRowCount() & getTotalRowCount() methods internally make use of this getFutureRowCount() method.
|
||||
* Generally I expect people to prefer loadRowCount() & getTotalRowCount() over getFutureRowCount().
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // initiate the row count query in the background thread
|
||||
* Future<Integer> rowCount = pagedList.getFutureRowCount();
|
||||
*
|
||||
* // fetch and return the list in the foreground thread
|
||||
* List<Order> orders = pagedList.getList();
|
||||
*
|
||||
* // now get the total count with a timeout
|
||||
* Integer totalRowCount = rowCount.get(30, TimeUnit.SECONDS);
|
||||
*
|
||||
* // or ge the total count without a timeout
|
||||
* Integer totalRowCountViaFuture = rowCount.get();
|
||||
*
|
||||
* // which is actually the same as ...
|
||||
* int totalRowCount = pagedList.getTotalRowCount();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
Future<Integer> getFutureRowCount();
|
||||
|
||||
/**
|
||||
* Return the list of entities for this page.
|
||||
*/
|
||||
List<T> getList();
|
||||
|
||||
/**
|
||||
* Return the total row count for all pages.
|
||||
* <p>
|
||||
* If loadRowCount() has already been called then the row count query is already executing in a background thread
|
||||
* and this gets the associated Future and gets the value waiting for the future to finish.
|
||||
* </p>
|
||||
* <p>
|
||||
* If loadRowCount() has not been called then this executes the find row count query and returns the result and this
|
||||
* will just occur in the current thread and not use a background thread.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Optional: initiate the loading of the total
|
||||
* // row count in a background thread
|
||||
* pagedList.loadRowCount();
|
||||
*
|
||||
* // fetch and return the list in the foreground thread
|
||||
* List<Order> orders = pagedList.getList();
|
||||
*
|
||||
* // get the total row count (which was being executed
|
||||
* // in a background thread if loadRowCount() was used)
|
||||
* int totalRowCount = pagedList.getTotalRowCount();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
int getTotalRowCount();
|
||||
|
||||
/**
|
||||
* Return the total number of pages based on the page size and total row count.
|
||||
* <p>
|
||||
* This method requires that the total row count has been fetched and will invoke
|
||||
* the total row count query if it has not already been invoked.
|
||||
* </p>
|
||||
*/
|
||||
int getTotalPageCount();
|
||||
|
||||
/**
|
||||
* Return the index position of this page. Zero based.
|
||||
*/
|
||||
int getPageIndex();
|
||||
|
||||
/**
|
||||
* Return true if there is a next page.
|
||||
* <p>
|
||||
* This method requires that the total row count has been fetched and will invoke
|
||||
* the total row count query if it has not already been invoked.
|
||||
* </p>
|
||||
*/
|
||||
boolean hasNext();
|
||||
|
||||
/**
|
||||
* Return true if there is a previous page.
|
||||
*/
|
||||
boolean hasPrev();
|
||||
|
||||
/**
|
||||
* Helper method to return a "X to Y of Z" string for this page where X is the first row, Y the
|
||||
* last row and Z the total row count.
|
||||
* <p>
|
||||
* This method requires that the total row count has been fetched and will invoke
|
||||
* the total row count query if it has not already been invoked.
|
||||
* </p>
|
||||
*
|
||||
* @param to
|
||||
* String to put between the first and last row
|
||||
* @param of
|
||||
* String to put between the last row and the total row count
|
||||
*
|
||||
* @return String of the format XtoYofZ.
|
||||
*/
|
||||
String getDisplayXtoYofZ(String to, String of);
|
||||
}
|
||||
|
||||
@@ -46,10 +46,35 @@ class PrimaryServer {
|
||||
if (globalProperties == null) {
|
||||
globalProperties = PropertyMap.defaultProperties();
|
||||
}
|
||||
defaultServerName = globalProperties.getProperty("datasource.default");
|
||||
if (defaultServerName == null) {
|
||||
defaultServerName = globalProperties.getProperty("ebean.default.datasource");
|
||||
defaultServerName = determineDefaultServerName();
|
||||
}
|
||||
return globalProperties;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine and return the default server name checking system environment variables and then global properties.
|
||||
*/
|
||||
private static String determineDefaultServerName() {
|
||||
|
||||
String defaultServerName = System.getProperty("datasource.default");
|
||||
if (isEmpty(defaultServerName)) {
|
||||
defaultServerName = System.getProperty("ebean.default.datasource");
|
||||
}
|
||||
if (isEmpty(defaultServerName)) {
|
||||
defaultServerName = globalProperties.getProperty("datasource.default");
|
||||
}
|
||||
if (isEmpty(defaultServerName)) {
|
||||
defaultServerName = globalProperties.getProperty("ebean.default.datasource");
|
||||
}
|
||||
return defaultServerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the string is null or empty.
|
||||
*/
|
||||
private static boolean isEmpty(String value) {
|
||||
return value == null || value.trim().length() == 0;
|
||||
}
|
||||
}
|
||||
|
||||
+1238
-1233
File diff suppressed because it is too large
Load Diff
@@ -1,41 +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>{@code
|
||||
*
|
||||
* Query<Customer> query = server.find(Customer.class)
|
||||
* .where().eq("status", Status.NEW)
|
||||
* .order().asc("id");
|
||||
*
|
||||
* query.findEach((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);
|
||||
}
|
||||
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>{@code
|
||||
*
|
||||
* Query<Customer> query = server.find(Customer.class)
|
||||
* .where().eq("status", Status.NEW)
|
||||
* .order().asc("id");
|
||||
*
|
||||
* query.findEach((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
|
||||
*/
|
||||
void accept(T bean);
|
||||
}
|
||||
|
||||
@@ -1,45 +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);
|
||||
}
|
||||
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.
|
||||
*/
|
||||
boolean accept(T bean);
|
||||
}
|
||||
|
||||
@@ -1,60 +1,60 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Used to provide iteration over query results.
|
||||
* <p>
|
||||
* This can be used when you want to process a very large number of results and
|
||||
* means that you don't have to hold all the results in memory at once (unlike
|
||||
* findList(), findSet() etc where all the beans are held in the List or Set
|
||||
* etc).
|
||||
* </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);
|
||||
*
|
||||
* QueryIterator<Customer> it = query.findIterate();
|
||||
* try {
|
||||
* while (it.hasNext()) {
|
||||
* Customer customer = it.next();
|
||||
* // do something with customer...
|
||||
* }
|
||||
* } finally {
|
||||
* // close the associated resources
|
||||
* it.close();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* @param <T>
|
||||
* the type of entity bean in the iteration
|
||||
*/
|
||||
public interface QueryIterator<T> extends Iterator<T>, java.io.Closeable {
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if the iteration has more elements.
|
||||
*/
|
||||
public boolean hasNext();
|
||||
|
||||
/**
|
||||
* Returns the next element in the iteration.
|
||||
*/
|
||||
public T next();
|
||||
|
||||
/**
|
||||
* Remove is not allowed.
|
||||
*/
|
||||
public void remove();
|
||||
|
||||
/**
|
||||
* Close the underlying resources held by this iterator.
|
||||
*/
|
||||
public void close();
|
||||
}
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Used to provide iteration over query results.
|
||||
* <p>
|
||||
* This can be used when you want to process a very large number of results and
|
||||
* means that you don't have to hold all the results in memory at once (unlike
|
||||
* findList(), findSet() etc where all the beans are held in the List or Set
|
||||
* etc).
|
||||
* </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);
|
||||
*
|
||||
* QueryIterator<Customer> it = query.findIterate();
|
||||
* try {
|
||||
* while (it.hasNext()) {
|
||||
* Customer customer = it.next();
|
||||
* // do something with customer...
|
||||
* }
|
||||
* } finally {
|
||||
* // close the associated resources
|
||||
* it.close();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* @param <T>
|
||||
* the type of entity bean in the iteration
|
||||
*/
|
||||
public interface QueryIterator<T> extends Iterator<T>, java.io.Closeable {
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if the iteration has more elements.
|
||||
*/
|
||||
boolean hasNext();
|
||||
|
||||
/**
|
||||
* Returns the next element in the iteration.
|
||||
*/
|
||||
T next();
|
||||
|
||||
/**
|
||||
* Remove is not allowed.
|
||||
*/
|
||||
void remove();
|
||||
|
||||
/**
|
||||
* Close the underlying resources held by this iterator.
|
||||
*/
|
||||
void close();
|
||||
}
|
||||
|
||||
@@ -1,49 +1,49 @@
|
||||
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)
|
||||
* .fetch("contacts", new FetchConfig().query(2))
|
||||
* .where().gt("id", 0)
|
||||
* .orderBy("id")
|
||||
* .setMaxRows(2);
|
||||
*
|
||||
* query.findVisit(new QueryResultVisitor<Customer>() {
|
||||
*
|
||||
* public boolean accept(Customer customer) {
|
||||
* // do something with customer
|
||||
* System.out.println("-- visit " + customer);
|
||||
* return true;
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* @param <T>
|
||||
* the type of entity bean being queried.
|
||||
*/
|
||||
public interface QueryResultVisitor<T> {
|
||||
|
||||
/**
|
||||
* Process the bean and return true if you want to continue processing more
|
||||
* beans. Return false if you want to stop processing further.
|
||||
*
|
||||
* @param bean
|
||||
* the entity bean to process
|
||||
* @return true to continue processing or false to stop.
|
||||
*/
|
||||
public boolean accept(T bean);
|
||||
}
|
||||
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)
|
||||
* .fetch("contacts", new FetchConfig().query(2))
|
||||
* .where().gt("id", 0)
|
||||
* .orderBy("id")
|
||||
* .setMaxRows(2);
|
||||
*
|
||||
* query.findVisit(new QueryResultVisitor<Customer>() {
|
||||
*
|
||||
* public boolean accept(Customer customer) {
|
||||
* // do something with customer
|
||||
* System.out.println("-- visit " + customer);
|
||||
* return true;
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* @param <T>
|
||||
* the type of entity bean being queried.
|
||||
*/
|
||||
public interface QueryResultVisitor<T> {
|
||||
|
||||
/**
|
||||
* Process the bean and return true if you want to continue processing more
|
||||
* beans. Return false if you want to stop processing further.
|
||||
*
|
||||
* @param bean
|
||||
* the entity bean to process
|
||||
* @return true to continue processing or false to stop.
|
||||
*/
|
||||
boolean accept(T bean);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,132 +1,132 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
|
||||
import com.avaje.ebean.RawSql.ColumnMapping;
|
||||
import com.avaje.ebean.RawSql.Sql;
|
||||
|
||||
/**
|
||||
* Builds RawSql instances from a SQL string and column mappings.
|
||||
* <p>
|
||||
* Note that RawSql can also be defined in ebean-orm.xml files and be used as a
|
||||
* named query.
|
||||
* </p>
|
||||
*
|
||||
* @see RawSql
|
||||
*/
|
||||
public class RawSqlBuilder {
|
||||
|
||||
/**
|
||||
* Special property name assigned to a DB column that should be ignored.
|
||||
*/
|
||||
public static final String IGNORE_COLUMN = "$$_IGNORE_COLUMN_$$";
|
||||
|
||||
private final ResultSet resultSet;
|
||||
|
||||
private final Sql sql;
|
||||
|
||||
private final ColumnMapping columnMapping;
|
||||
|
||||
/**
|
||||
* Create and return a RawSql object based on the resultSet and list of properties the columns in
|
||||
* the resultSet map to.
|
||||
* <p>
|
||||
* The properties listed in the propertyNames must be in the same order as the columns in the
|
||||
* resultSet.
|
||||
*/
|
||||
public static RawSql resultSet(ResultSet resultSet, String... propertyNames) {
|
||||
return new RawSql(resultSet, propertyNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an unparsed RawSqlBuilder. Unlike a parsed one this query can not be
|
||||
* modified - so no additional WHERE or HAVING expressions can be added to
|
||||
* this query.
|
||||
*/
|
||||
public static RawSqlBuilder unparsed(String sql) {
|
||||
|
||||
Sql s = new Sql(sql);
|
||||
return new RawSqlBuilder(s, new ColumnMapping());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a RawSqlBuilder parsing the sql.
|
||||
* <p>
|
||||
* The sql statement will be parsed so that Ebean can determine where it can
|
||||
* insert additional WHERE or HAVING expressions.
|
||||
* </p>
|
||||
* <p>
|
||||
* Additionally the selected columns are parsed to determine the column
|
||||
* ordering. This also means additional checks can be made with the column
|
||||
* mapping - specifically we can check that all columns are mapped and that
|
||||
* correct column names are entered into the mapping.
|
||||
* </p>
|
||||
*/
|
||||
public static RawSqlBuilder parse(String sql) {
|
||||
|
||||
Sql sql2 = DRawSqlParser.parse(sql);
|
||||
String select = sql2.getPreFrom();
|
||||
|
||||
ColumnMapping mapping = DRawSqlColumnsParser.parse(select);
|
||||
return new RawSqlBuilder(sql2, mapping);
|
||||
}
|
||||
|
||||
private RawSqlBuilder(Sql sql, ColumnMapping columnMapping) {
|
||||
this.sql = sql;
|
||||
this.columnMapping = columnMapping;
|
||||
this.resultSet = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mapping of a DB Column to a bean property.
|
||||
* <p>
|
||||
* For Unparsed SQL the columnMapping MUST be defined in the same order that
|
||||
* the columns appear in the SQL statement.
|
||||
* </p>
|
||||
*
|
||||
* @param dbColumn
|
||||
* the DB column that we are mapping to a bean property
|
||||
* @param propertyName
|
||||
* the bean property that we are mapping the DB column to.
|
||||
*/
|
||||
public RawSqlBuilder columnMapping(String dbColumn, String propertyName) {
|
||||
columnMapping.columnMapping(dbColumn, propertyName);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ignore this DB column. It is not mapped to any bean property.
|
||||
*/
|
||||
public RawSqlBuilder columnMappingIgnore(String dbColumn) {
|
||||
return columnMapping(dbColumn, IGNORE_COLUMN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify any column mappings with the given table alias to have the path prefix.
|
||||
* <p>
|
||||
* For example modify all mappings with table alias "c" to have the path prefix "customer".
|
||||
* </p>
|
||||
*/
|
||||
public RawSqlBuilder tableAliasMapping(String tableAlias, String path) {
|
||||
columnMapping.tableAliasMapping(tableAlias, path);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the immutable RawSql object. Do this after all the column mapping
|
||||
* has been defined.
|
||||
*/
|
||||
public RawSql create() {
|
||||
return new RawSql(resultSet, sql, columnMapping.createImmutableCopy());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the internal parsed Sql object (for testing).
|
||||
*/
|
||||
protected Sql getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
|
||||
import com.avaje.ebean.RawSql.ColumnMapping;
|
||||
import com.avaje.ebean.RawSql.Sql;
|
||||
|
||||
/**
|
||||
* Builds RawSql instances from a SQL string and column mappings.
|
||||
* <p>
|
||||
* Note that RawSql can also be defined in ebean-orm.xml files and be used as a
|
||||
* named query.
|
||||
* </p>
|
||||
*
|
||||
* @see RawSql
|
||||
*/
|
||||
public class RawSqlBuilder {
|
||||
|
||||
/**
|
||||
* Special property name assigned to a DB column that should be ignored.
|
||||
*/
|
||||
public static final String IGNORE_COLUMN = "$$_IGNORE_COLUMN_$$";
|
||||
|
||||
private final ResultSet resultSet;
|
||||
|
||||
private final Sql sql;
|
||||
|
||||
private final ColumnMapping columnMapping;
|
||||
|
||||
/**
|
||||
* Create and return a RawSql object based on the resultSet and list of properties the columns in
|
||||
* the resultSet map to.
|
||||
* <p>
|
||||
* The properties listed in the propertyNames must be in the same order as the columns in the
|
||||
* resultSet.
|
||||
*/
|
||||
public static RawSql resultSet(ResultSet resultSet, String... propertyNames) {
|
||||
return new RawSql(resultSet, propertyNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an unparsed RawSqlBuilder. Unlike a parsed one this query can not be
|
||||
* modified - so no additional WHERE or HAVING expressions can be added to
|
||||
* this query.
|
||||
*/
|
||||
public static RawSqlBuilder unparsed(String sql) {
|
||||
|
||||
Sql s = new Sql(sql);
|
||||
return new RawSqlBuilder(s, new ColumnMapping());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a RawSqlBuilder parsing the sql.
|
||||
* <p>
|
||||
* The sql statement will be parsed so that Ebean can determine where it can
|
||||
* insert additional WHERE or HAVING expressions.
|
||||
* </p>
|
||||
* <p>
|
||||
* Additionally the selected columns are parsed to determine the column
|
||||
* ordering. This also means additional checks can be made with the column
|
||||
* mapping - specifically we can check that all columns are mapped and that
|
||||
* correct column names are entered into the mapping.
|
||||
* </p>
|
||||
*/
|
||||
public static RawSqlBuilder parse(String sql) {
|
||||
|
||||
Sql sql2 = DRawSqlParser.parse(sql);
|
||||
String select = sql2.getPreFrom();
|
||||
|
||||
ColumnMapping mapping = DRawSqlColumnsParser.parse(select);
|
||||
return new RawSqlBuilder(sql2, mapping);
|
||||
}
|
||||
|
||||
private RawSqlBuilder(Sql sql, ColumnMapping columnMapping) {
|
||||
this.sql = sql;
|
||||
this.columnMapping = columnMapping;
|
||||
this.resultSet = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mapping of a DB Column to a bean property.
|
||||
* <p>
|
||||
* For Unparsed SQL the columnMapping MUST be defined in the same order that
|
||||
* the columns appear in the SQL statement.
|
||||
* </p>
|
||||
*
|
||||
* @param dbColumn
|
||||
* the DB column that we are mapping to a bean property
|
||||
* @param propertyName
|
||||
* the bean property that we are mapping the DB column to.
|
||||
*/
|
||||
public RawSqlBuilder columnMapping(String dbColumn, String propertyName) {
|
||||
columnMapping.columnMapping(dbColumn, propertyName);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ignore this DB column. It is not mapped to any bean property.
|
||||
*/
|
||||
public RawSqlBuilder columnMappingIgnore(String dbColumn) {
|
||||
return columnMapping(dbColumn, IGNORE_COLUMN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify any column mappings with the given table alias to have the path prefix.
|
||||
* <p>
|
||||
* For example modify all mappings with table alias "c" to have the path prefix "customer".
|
||||
* </p>
|
||||
*/
|
||||
public RawSqlBuilder tableAliasMapping(String tableAlias, String path) {
|
||||
columnMapping.tableAliasMapping(tableAlias, path);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the immutable RawSql object. Do this after all the column mapping
|
||||
* has been defined.
|
||||
*/
|
||||
public RawSql create() {
|
||||
return new RawSql(resultSet, sql, columnMapping.createImmutableCopy());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the internal parsed Sql object (for testing).
|
||||
*/
|
||||
protected Sql getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,47 +1,47 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* The SqlFutureList represents the result of a background SQL query execution.
|
||||
*
|
||||
* <p>
|
||||
* It extends the java.util.concurrent.Future.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // create a query
|
||||
* String sql = ... ;
|
||||
* SqlQuery sqlQuery = Ebean.createSqlQuery(sql);
|
||||
*
|
||||
* // execute the query in a background thread
|
||||
* SqlFutureList sqlFuture = sqlQuery.findFutureList();
|
||||
*
|
||||
* // do something else ... we will sleep
|
||||
* Thread.sleep(3000);
|
||||
* System.out.println("end of sleep");
|
||||
*
|
||||
* if (!futureList.isDone()){
|
||||
* // we can cancel the query execution
|
||||
* futureList.cancel(true);
|
||||
* }
|
||||
*
|
||||
* System.out.println("and... done:"+futureList.isDone());
|
||||
*
|
||||
* if (!futureList.isCancelled()){
|
||||
* // wait for the query to finish and return the list
|
||||
* List<SqlRow> list = futureList.get();
|
||||
* System.out.println("list:"+list);
|
||||
* }
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author rob
|
||||
*
|
||||
*/
|
||||
public interface SqlFutureList extends Future<List<SqlRow>> {
|
||||
|
||||
public SqlQuery getQuery();
|
||||
|
||||
}
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* The SqlFutureList represents the result of a background SQL query execution.
|
||||
*
|
||||
* <p>
|
||||
* It extends the java.util.concurrent.Future.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // create a query
|
||||
* String sql = ... ;
|
||||
* SqlQuery sqlQuery = Ebean.createSqlQuery(sql);
|
||||
*
|
||||
* // execute the query in a background thread
|
||||
* SqlFutureList sqlFuture = sqlQuery.findFutureList();
|
||||
*
|
||||
* // do something else ... we will sleep
|
||||
* Thread.sleep(3000);
|
||||
* System.out.println("end of sleep");
|
||||
*
|
||||
* if (!futureList.isDone()){
|
||||
* // we can cancel the query execution
|
||||
* futureList.cancel(true);
|
||||
* }
|
||||
*
|
||||
* System.out.println("and... done:"+futureList.isDone());
|
||||
*
|
||||
* if (!futureList.isCancelled()){
|
||||
* // wait for the query to finish and return the list
|
||||
* List<SqlRow> list = futureList.get();
|
||||
* System.out.println("list:"+list);
|
||||
* }
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author rob
|
||||
*
|
||||
*/
|
||||
public interface SqlFutureList extends Future<List<SqlRow>> {
|
||||
|
||||
SqlQuery getQuery();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,151 +1,151 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Query object for performing native SQL queries that return SqlRow's.
|
||||
* <p>
|
||||
* Firstly note that you can use your own sql queries with <em>entity beans</em>
|
||||
* by using the SqlSelect annotation. This should be your first approach when
|
||||
* wanting to use your own SQL queries.
|
||||
* </p>
|
||||
* <p>
|
||||
* If ORM Mapping is too tight and constraining for your problem then SqlQuery
|
||||
* could be a good approach.
|
||||
* </p>
|
||||
* <p>
|
||||
* The returned SqlRow objects are similar to a LinkedHashMap with some type
|
||||
* conversion support added.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // its typically a good idea to use a named query
|
||||
* // and put the sql in the orm.xml instead of in your code
|
||||
*
|
||||
* String sql = "select id, name from customer where name like :name and status_code = :status";
|
||||
*
|
||||
* SqlQuery sqlQuery = Ebean.createSqlQuery(sql);
|
||||
* sqlQuery.setParameter("name", "Acme%");
|
||||
* sqlQuery.setParameter("status", "ACTIVE");
|
||||
*
|
||||
* // execute the query returning a List of MapBean objects
|
||||
* List<SqlRow> list = sqlQuery.findList();
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
public interface SqlQuery extends Serializable {
|
||||
|
||||
/**
|
||||
* Cancel the query if support by the underlying database and driver.
|
||||
* <p>
|
||||
* This must be called from a different thread to the one executing the query.
|
||||
* </p>
|
||||
*/
|
||||
public void cancel();
|
||||
|
||||
/**
|
||||
* Execute the query returning a list.
|
||||
*/
|
||||
public List<SqlRow> findList();
|
||||
|
||||
/**
|
||||
* Execute the query returning a set.
|
||||
*/
|
||||
public Set<SqlRow> findSet();
|
||||
|
||||
/**
|
||||
* Execute the query returning a map.
|
||||
*/
|
||||
public Map<?, SqlRow> findMap();
|
||||
|
||||
/**
|
||||
* Execute the query returning a single row or null.
|
||||
* <p>
|
||||
* If this query finds 2 or more rows then it will throw a
|
||||
* PersistenceException.
|
||||
* </p>
|
||||
*/
|
||||
public SqlRow findUnique();
|
||||
|
||||
/**
|
||||
* Execute find list SQL query in a background thread.
|
||||
* <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>
|
||||
*
|
||||
* @return a Future object for the list result of the query
|
||||
* @deprecated
|
||||
*/
|
||||
public SqlFutureList findFutureList();
|
||||
|
||||
/**
|
||||
* The same as bind for named parameters.
|
||||
*/
|
||||
public SqlQuery setParameter(String name, Object value);
|
||||
|
||||
/**
|
||||
* The same as bind for positioned parameters.
|
||||
*/
|
||||
public SqlQuery setParameter(int position, Object value);
|
||||
|
||||
/**
|
||||
* Set a listener to process the query on a row by row basis.
|
||||
* <p>
|
||||
* It this case the rows are not loaded into the persistence context and
|
||||
* instead can be processed by the query listener.
|
||||
* </p>
|
||||
* <p>
|
||||
* Use this when you want to process a large query and do not want to hold the
|
||||
* entire query result in memory.
|
||||
* </p>
|
||||
*/
|
||||
public SqlQuery setListener(SqlQueryListener queryListener);
|
||||
|
||||
/**
|
||||
* Set the index of the first row of the results to return.
|
||||
*/
|
||||
public SqlQuery setFirstRow(int firstRow);
|
||||
|
||||
/**
|
||||
* Set the maximum number of query results to return.
|
||||
*/
|
||||
public SqlQuery setMaxRows(int maxRows);
|
||||
|
||||
/**
|
||||
* Set the index after which fetching continues in a background thread.
|
||||
*/
|
||||
public SqlQuery setBackgroundFetchAfter(int backgroundFetchAfter);
|
||||
|
||||
/**
|
||||
* Set the column to use to determine the keys for a Map.
|
||||
*/
|
||||
public SqlQuery setMapKey(String mapKey);
|
||||
|
||||
/**
|
||||
* Set a timeout on this query.
|
||||
* <p>
|
||||
* This will typically result in a call to setQueryTimeout() on a
|
||||
* preparedStatement. If the timeout occurs an exception will be thrown - this
|
||||
* will be a SQLException wrapped up in a PersistenceException.
|
||||
* </p>
|
||||
*
|
||||
* @param secs
|
||||
* the query timeout limit in seconds. Zero means there is no limit.
|
||||
*/
|
||||
public SqlQuery setTimeout(int secs);
|
||||
|
||||
/**
|
||||
* A hint which for JDBC translates to the Statement.fetchSize().
|
||||
* <p>
|
||||
* Gives the JDBC driver a hint as to the number of rows that should be
|
||||
* fetched from the database when more rows are needed for ResultSet.
|
||||
* </p>
|
||||
*/
|
||||
public SqlQuery setBufferFetchSizeHint(int bufferFetchSizeHint);
|
||||
|
||||
}
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Query object for performing native SQL queries that return SqlRow's.
|
||||
* <p>
|
||||
* Firstly note that you can use your own sql queries with <em>entity beans</em>
|
||||
* by using the SqlSelect annotation. This should be your first approach when
|
||||
* wanting to use your own SQL queries.
|
||||
* </p>
|
||||
* <p>
|
||||
* If ORM Mapping is too tight and constraining for your problem then SqlQuery
|
||||
* could be a good approach.
|
||||
* </p>
|
||||
* <p>
|
||||
* The returned SqlRow objects are similar to a LinkedHashMap with some type
|
||||
* conversion support added.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // its typically a good idea to use a named query
|
||||
* // and put the sql in the orm.xml instead of in your code
|
||||
*
|
||||
* String sql = "select id, name from customer where name like :name and status_code = :status";
|
||||
*
|
||||
* SqlQuery sqlQuery = Ebean.createSqlQuery(sql);
|
||||
* sqlQuery.setParameter("name", "Acme%");
|
||||
* sqlQuery.setParameter("status", "ACTIVE");
|
||||
*
|
||||
* // execute the query returning a List of MapBean objects
|
||||
* List<SqlRow> list = sqlQuery.findList();
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
public interface SqlQuery extends Serializable {
|
||||
|
||||
/**
|
||||
* Cancel the query if support by the underlying database and driver.
|
||||
* <p>
|
||||
* This must be called from a different thread to the one executing the query.
|
||||
* </p>
|
||||
*/
|
||||
void cancel();
|
||||
|
||||
/**
|
||||
* Execute the query returning a list.
|
||||
*/
|
||||
List<SqlRow> findList();
|
||||
|
||||
/**
|
||||
* Execute the query returning a set.
|
||||
*/
|
||||
Set<SqlRow> findSet();
|
||||
|
||||
/**
|
||||
* Execute the query returning a map.
|
||||
*/
|
||||
Map<?, SqlRow> findMap();
|
||||
|
||||
/**
|
||||
* Execute the query returning a single row or null.
|
||||
* <p>
|
||||
* If this query finds 2 or more rows then it will throw a
|
||||
* PersistenceException.
|
||||
* </p>
|
||||
*/
|
||||
SqlRow findUnique();
|
||||
|
||||
/**
|
||||
* Execute find list SQL query in a background thread.
|
||||
* <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>
|
||||
*
|
||||
* @return a Future object for the list result of the query
|
||||
* @deprecated
|
||||
*/
|
||||
SqlFutureList findFutureList();
|
||||
|
||||
/**
|
||||
* The same as bind for named parameters.
|
||||
*/
|
||||
SqlQuery setParameter(String name, Object value);
|
||||
|
||||
/**
|
||||
* The same as bind for positioned parameters.
|
||||
*/
|
||||
SqlQuery setParameter(int position, Object value);
|
||||
|
||||
/**
|
||||
* Set a listener to process the query on a row by row basis.
|
||||
* <p>
|
||||
* It this case the rows are not loaded into the persistence context and
|
||||
* instead can be processed by the query listener.
|
||||
* </p>
|
||||
* <p>
|
||||
* Use this when you want to process a large query and do not want to hold the
|
||||
* entire query result in memory.
|
||||
* </p>
|
||||
*/
|
||||
SqlQuery setListener(SqlQueryListener queryListener);
|
||||
|
||||
/**
|
||||
* Set the index of the first row of the results to return.
|
||||
*/
|
||||
SqlQuery setFirstRow(int firstRow);
|
||||
|
||||
/**
|
||||
* Set the maximum number of query results to return.
|
||||
*/
|
||||
SqlQuery setMaxRows(int maxRows);
|
||||
|
||||
/**
|
||||
* Set the index after which fetching continues in a background thread.
|
||||
*/
|
||||
SqlQuery setBackgroundFetchAfter(int backgroundFetchAfter);
|
||||
|
||||
/**
|
||||
* Set the column to use to determine the keys for a Map.
|
||||
*/
|
||||
SqlQuery setMapKey(String mapKey);
|
||||
|
||||
/**
|
||||
* Set a timeout on this query.
|
||||
* <p>
|
||||
* This will typically result in a call to setQueryTimeout() on a
|
||||
* preparedStatement. If the timeout occurs an exception will be thrown - this
|
||||
* will be a SQLException wrapped up in a PersistenceException.
|
||||
* </p>
|
||||
*
|
||||
* @param secs
|
||||
* the query timeout limit in seconds. Zero means there is no limit.
|
||||
*/
|
||||
SqlQuery setTimeout(int secs);
|
||||
|
||||
/**
|
||||
* A hint which for JDBC translates to the Statement.fetchSize().
|
||||
* <p>
|
||||
* Gives the JDBC driver a hint as to the number of rows that should be
|
||||
* fetched from the database when more rows are needed for ResultSet.
|
||||
* </p>
|
||||
*/
|
||||
SqlQuery setBufferFetchSizeHint(int bufferFetchSizeHint);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Provides a mechanism for processing a SqlQuery one SqlRow at a time.
|
||||
* <p>
|
||||
* This is useful when the query will return a large number of results and you
|
||||
* want to process the beans one at a time rather than have all of the beans in
|
||||
* memory at once.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* SqlQueryListener listener = ...;
|
||||
*
|
||||
* SqlQuery query = Ebean.createSqlQuery("my.large.query");
|
||||
*
|
||||
* // set the listener that will process each row one at a time
|
||||
* query.setListener(listener);
|
||||
*
|
||||
* // execute the query. Note that the returned
|
||||
* // list will be empty ... so don't bother assigning it...
|
||||
* query.findList();
|
||||
* </pre>
|
||||
*/
|
||||
public interface SqlQueryListener {
|
||||
|
||||
/**
|
||||
* Process the bean that has just been read.
|
||||
* <p>
|
||||
* Note this bean will not be added to the List Set or Map.
|
||||
* </p>
|
||||
*/
|
||||
public void process(SqlRow bean);
|
||||
}
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Provides a mechanism for processing a SqlQuery one SqlRow at a time.
|
||||
* <p>
|
||||
* This is useful when the query will return a large number of results and you
|
||||
* want to process the beans one at a time rather than have all of the beans in
|
||||
* memory at once.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* SqlQueryListener listener = ...;
|
||||
*
|
||||
* SqlQuery query = Ebean.createSqlQuery("my.large.query");
|
||||
*
|
||||
* // set the listener that will process each row one at a time
|
||||
* query.setListener(listener);
|
||||
*
|
||||
* // execute the query. Note that the returned
|
||||
* // list will be empty ... so don't bother assigning it...
|
||||
* query.findList();
|
||||
* </pre>
|
||||
*/
|
||||
public interface SqlQueryListener {
|
||||
|
||||
/**
|
||||
* Process the bean that has just been read.
|
||||
* <p>
|
||||
* Note this bean will not be added to the List Set or Map.
|
||||
* </p>
|
||||
*/
|
||||
void process(SqlRow bean);
|
||||
}
|
||||
|
||||
@@ -1,168 +1,168 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.Date;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Used to return raw SQL query results.
|
||||
* <p>
|
||||
* Refer to {@link SqlQuery} for examples.
|
||||
* </p>
|
||||
* <p>
|
||||
* There are convenience methods such as getInteger(), getBigDecimal() etc. The
|
||||
* reason for these methods is that the values put into this map often come
|
||||
* straight from the JDBC resultSet. Depending on the JDBC driver it may put a
|
||||
* different type into a given property. For example an Integer, BigDecimal,
|
||||
* Double could all be put into a property depending on the JDBC driver used.
|
||||
* These convenience methods automatically convert the value as required
|
||||
* returning the type you expect.
|
||||
* </p>
|
||||
*/
|
||||
public interface SqlRow extends Serializable, Map<String, Object> {
|
||||
|
||||
/**
|
||||
* Return the property names (String).
|
||||
* <p>
|
||||
* Internally this uses LinkedHashMap and so the order of the property names
|
||||
* should be predictable and ordered by the use of LinkedHashMap.
|
||||
* </p>
|
||||
*/
|
||||
public Iterator<String> keys();
|
||||
|
||||
/**
|
||||
* Remove a property from the map. Returns the value of the removed property.
|
||||
*/
|
||||
public Object remove(Object name);
|
||||
|
||||
/**
|
||||
* Return a property value by its name.
|
||||
*/
|
||||
public Object get(Object name);
|
||||
|
||||
/**
|
||||
* Set a value to a property.
|
||||
*/
|
||||
public Object put(String name, Object value);
|
||||
|
||||
/**
|
||||
* Exactly the same as the put method.
|
||||
* <p>
|
||||
* I added this method because it seems more bean like to have get and set
|
||||
* methods.
|
||||
* </p>
|
||||
*/
|
||||
public Object set(String name, Object value);
|
||||
|
||||
/**
|
||||
* Return a property as a Boolean.
|
||||
*/
|
||||
public Boolean getBoolean(String name);
|
||||
|
||||
/**
|
||||
* Return a property as a UUID.
|
||||
*/
|
||||
public UUID getUUID(String name);
|
||||
|
||||
/**
|
||||
* Return a property as an Integer.
|
||||
*/
|
||||
public Integer getInteger(String name);
|
||||
|
||||
/**
|
||||
* Return a property value as a BigDecimal.
|
||||
*/
|
||||
public BigDecimal getBigDecimal(String name);
|
||||
|
||||
/**
|
||||
* Return a property value as a Long.
|
||||
*/
|
||||
public Long getLong(String name);
|
||||
|
||||
/**
|
||||
* Return the property value as a Double.
|
||||
*/
|
||||
public Double getDouble(String name);
|
||||
|
||||
/**
|
||||
* Return the property value as a Float.
|
||||
*/
|
||||
public Float getFloat(String name);
|
||||
|
||||
/**
|
||||
* Return a property as a String.
|
||||
*/
|
||||
public String getString(String name);
|
||||
|
||||
/**
|
||||
* Return the property as a java.util.Date.
|
||||
*/
|
||||
public java.util.Date getUtilDate(String name);
|
||||
|
||||
/**
|
||||
* Return the property as a sql date.
|
||||
*/
|
||||
public Date getDate(String name);
|
||||
|
||||
/**
|
||||
* Return the property as a sql timestamp.
|
||||
*/
|
||||
public Timestamp getTimestamp(String name);
|
||||
|
||||
/**
|
||||
* String description of the underlying map.
|
||||
*/
|
||||
public String toString();
|
||||
|
||||
/**
|
||||
* Clear the map.
|
||||
*/
|
||||
public void clear();
|
||||
|
||||
/**
|
||||
* Returns true if the map contains the property.
|
||||
*/
|
||||
public boolean containsKey(Object key);
|
||||
|
||||
/**
|
||||
* Returns true if the map contains the value.
|
||||
*/
|
||||
public boolean containsValue(Object value);
|
||||
|
||||
/**
|
||||
* Returns the entrySet of the map.
|
||||
*/
|
||||
public Set<Map.Entry<String, Object>> entrySet();
|
||||
|
||||
/**
|
||||
* Returns true if the map is empty.
|
||||
*/
|
||||
public boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Returns the key set of the map.
|
||||
*/
|
||||
public Set<String> keySet();
|
||||
|
||||
/**
|
||||
* Put all the values from t into this map.
|
||||
*/
|
||||
public void putAll(Map<? extends String, ? extends Object> t);
|
||||
|
||||
/**
|
||||
* Return the size of the map.
|
||||
*/
|
||||
public int size();
|
||||
|
||||
/**
|
||||
* Return the values from this map.
|
||||
*/
|
||||
public Collection<Object> values();
|
||||
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.Date;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Used to return raw SQL query results.
|
||||
* <p>
|
||||
* Refer to {@link SqlQuery} for examples.
|
||||
* </p>
|
||||
* <p>
|
||||
* There are convenience methods such as getInteger(), getBigDecimal() etc. The
|
||||
* reason for these methods is that the values put into this map often come
|
||||
* straight from the JDBC resultSet. Depending on the JDBC driver it may put a
|
||||
* different type into a given property. For example an Integer, BigDecimal,
|
||||
* Double could all be put into a property depending on the JDBC driver used.
|
||||
* These convenience methods automatically convert the value as required
|
||||
* returning the type you expect.
|
||||
* </p>
|
||||
*/
|
||||
public interface SqlRow extends Serializable, Map<String, Object> {
|
||||
|
||||
/**
|
||||
* Return the property names (String).
|
||||
* <p>
|
||||
* Internally this uses LinkedHashMap and so the order of the property names
|
||||
* should be predictable and ordered by the use of LinkedHashMap.
|
||||
* </p>
|
||||
*/
|
||||
Iterator<String> keys();
|
||||
|
||||
/**
|
||||
* Remove a property from the map. Returns the value of the removed property.
|
||||
*/
|
||||
Object remove(Object name);
|
||||
|
||||
/**
|
||||
* Return a property value by its name.
|
||||
*/
|
||||
Object get(Object name);
|
||||
|
||||
/**
|
||||
* Set a value to a property.
|
||||
*/
|
||||
Object put(String name, Object value);
|
||||
|
||||
/**
|
||||
* Exactly the same as the put method.
|
||||
* <p>
|
||||
* I added this method because it seems more bean like to have get and set
|
||||
* methods.
|
||||
* </p>
|
||||
*/
|
||||
Object set(String name, Object value);
|
||||
|
||||
/**
|
||||
* Return a property as a Boolean.
|
||||
*/
|
||||
Boolean getBoolean(String name);
|
||||
|
||||
/**
|
||||
* Return a property as a UUID.
|
||||
*/
|
||||
UUID getUUID(String name);
|
||||
|
||||
/**
|
||||
* Return a property as an Integer.
|
||||
*/
|
||||
Integer getInteger(String name);
|
||||
|
||||
/**
|
||||
* Return a property value as a BigDecimal.
|
||||
*/
|
||||
BigDecimal getBigDecimal(String name);
|
||||
|
||||
/**
|
||||
* Return a property value as a Long.
|
||||
*/
|
||||
Long getLong(String name);
|
||||
|
||||
/**
|
||||
* Return the property value as a Double.
|
||||
*/
|
||||
Double getDouble(String name);
|
||||
|
||||
/**
|
||||
* Return the property value as a Float.
|
||||
*/
|
||||
Float getFloat(String name);
|
||||
|
||||
/**
|
||||
* Return a property as a String.
|
||||
*/
|
||||
String getString(String name);
|
||||
|
||||
/**
|
||||
* Return the property as a java.util.Date.
|
||||
*/
|
||||
java.util.Date getUtilDate(String name);
|
||||
|
||||
/**
|
||||
* Return the property as a sql date.
|
||||
*/
|
||||
Date getDate(String name);
|
||||
|
||||
/**
|
||||
* Return the property as a sql timestamp.
|
||||
*/
|
||||
Timestamp getTimestamp(String name);
|
||||
|
||||
/**
|
||||
* String description of the underlying map.
|
||||
*/
|
||||
String toString();
|
||||
|
||||
/**
|
||||
* Clear the map.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Returns true if the map contains the property.
|
||||
*/
|
||||
boolean containsKey(Object key);
|
||||
|
||||
/**
|
||||
* Returns true if the map contains the value.
|
||||
*/
|
||||
boolean containsValue(Object value);
|
||||
|
||||
/**
|
||||
* Returns the entrySet of the map.
|
||||
*/
|
||||
Set<Map.Entry<String, Object>> entrySet();
|
||||
|
||||
/**
|
||||
* Returns true if the map is empty.
|
||||
*/
|
||||
boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Returns the key set of the map.
|
||||
*/
|
||||
Set<String> keySet();
|
||||
|
||||
/**
|
||||
* Put all the values from t into this map.
|
||||
*/
|
||||
void putAll(Map<? extends String, ? extends Object> t);
|
||||
|
||||
/**
|
||||
* Return the size of the map.
|
||||
*/
|
||||
int size();
|
||||
|
||||
/**
|
||||
* Return the values from this map.
|
||||
*/
|
||||
Collection<Object> values();
|
||||
|
||||
}
|
||||
@@ -1,146 +1,146 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* A SqlUpdate for executing insert update or delete statements.
|
||||
* <p>
|
||||
* Provides a simple way to execute raw SQL insert update or delete statements
|
||||
* without having to resort to JDBC.
|
||||
* </p>
|
||||
* <p>
|
||||
* Supports the use of positioned or named parameters and can automatically
|
||||
* notify Ebean of the table modified so that Ebean can maintain its cache.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that {@link #setAutoTableMod(boolean)} and
|
||||
* Ebean#externalModification(String, boolean, boolean, boolean)} can be to
|
||||
* notify Ebean of external changes and enable Ebean to maintain it's "L2"
|
||||
* server cache.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // example that uses 'named' parameters
|
||||
* String s = "UPDATE f_topic set post_count = :count where id = :id"
|
||||
* SqlUpdate update = Ebean.createSqlUpdate(s);
|
||||
* update.setParameter("id", 1);
|
||||
* update.setParameter("count", 50);
|
||||
*
|
||||
* int modifiedCount = Ebean.execute(update);
|
||||
*
|
||||
* String msg = "There where " + modifiedCount + "rows updated"
|
||||
* </pre>
|
||||
*
|
||||
* @see Update
|
||||
* @see SqlQuery
|
||||
* @see CallableSql
|
||||
*/
|
||||
public interface SqlUpdate {
|
||||
|
||||
/**
|
||||
* Execute the update returning the number of rows modified.
|
||||
* <p>
|
||||
* After you have executed the SqlUpdate you can bind new variables using
|
||||
* {@link #setParameter(String, Object)} etc and then execute the SqlUpdate
|
||||
* again.
|
||||
* </p>
|
||||
* <p>
|
||||
* For JDBC batch processing refer to
|
||||
* {@link Transaction#setBatchMode(boolean)} and
|
||||
* {@link Transaction#setBatchSize(int)}.
|
||||
* </p>
|
||||
*
|
||||
* @see com.avaje.ebean.Ebean#execute(SqlUpdate)
|
||||
*/
|
||||
public int execute();
|
||||
|
||||
/**
|
||||
* Return true if eBean should automatically deduce the table modification
|
||||
* information and process it.
|
||||
* <p>
|
||||
* If this is true then cache invalidation and text index management are aware
|
||||
* of the modification.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isAutoTableMod();
|
||||
|
||||
/**
|
||||
* Set this to false if you don't want eBean to automatically deduce the table
|
||||
* modification information and process it.
|
||||
* <p>
|
||||
* Set this to false if you don't want any cache invalidation or text index
|
||||
* management to occur. You may do this when say you update only one column
|
||||
* and you know that it is not important for cached objects or text indexes.
|
||||
* </p>
|
||||
*/
|
||||
public SqlUpdate setAutoTableMod(boolean isAutoTableMod);
|
||||
|
||||
/**
|
||||
* Return the label that can be seen in the transaction logs.
|
||||
*/
|
||||
public String getLabel();
|
||||
|
||||
/**
|
||||
* Set a descriptive text that can be put into the transaction log.
|
||||
* <p>
|
||||
* Useful when identifying the statement in the transaction log.
|
||||
* </p>
|
||||
*/
|
||||
public SqlUpdate setLabel(String label);
|
||||
|
||||
/**
|
||||
* Return the sql statement.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public int getTimeout();
|
||||
|
||||
/**
|
||||
* Set the timeout in seconds. Zero implies no limit.
|
||||
* <p>
|
||||
* This will set the query timeout on the underlying PreparedStatement. If the
|
||||
* timeout expires a SQLException will be throw and wrapped in a
|
||||
* PersistenceException.
|
||||
* </p>
|
||||
*/
|
||||
public SqlUpdate setTimeout(int secs);
|
||||
|
||||
/**
|
||||
* Set a parameter via its index position.
|
||||
*/
|
||||
public SqlUpdate setParameter(int position, Object value);
|
||||
|
||||
/**
|
||||
* Set a null parameter via its index position. Exactly the same as
|
||||
* {@link #setNull(int, int)}.
|
||||
*/
|
||||
public SqlUpdate setNull(int position, int jdbcType);
|
||||
|
||||
/**
|
||||
* Set a null valued parameter using its index position.
|
||||
*/
|
||||
public SqlUpdate setNullParameter(int position, int jdbcType);
|
||||
|
||||
/**
|
||||
* Set a named parameter value.
|
||||
*/
|
||||
public SqlUpdate setParameter(String name, Object param);
|
||||
|
||||
/**
|
||||
* Set a named parameter that has a null value. Exactly the same as
|
||||
* {@link #setNullParameter(String, int)}.
|
||||
*/
|
||||
public SqlUpdate setNull(String name, int jdbcType);
|
||||
|
||||
/**
|
||||
* Set a named parameter that has a null value.
|
||||
*/
|
||||
public SqlUpdate setNullParameter(String name, int jdbcType);
|
||||
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* A SqlUpdate for executing insert update or delete statements.
|
||||
* <p>
|
||||
* Provides a simple way to execute raw SQL insert update or delete statements
|
||||
* without having to resort to JDBC.
|
||||
* </p>
|
||||
* <p>
|
||||
* Supports the use of positioned or named parameters and can automatically
|
||||
* notify Ebean of the table modified so that Ebean can maintain its cache.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that {@link #setAutoTableMod(boolean)} and
|
||||
* Ebean#externalModification(String, boolean, boolean, boolean)} can be to
|
||||
* notify Ebean of external changes and enable Ebean to maintain it's "L2"
|
||||
* server cache.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // example that uses 'named' parameters
|
||||
* String s = "UPDATE f_topic set post_count = :count where id = :id"
|
||||
* SqlUpdate update = Ebean.createSqlUpdate(s);
|
||||
* update.setParameter("id", 1);
|
||||
* update.setParameter("count", 50);
|
||||
*
|
||||
* int modifiedCount = Ebean.execute(update);
|
||||
*
|
||||
* String msg = "There where " + modifiedCount + "rows updated"
|
||||
* </pre>
|
||||
*
|
||||
* @see Update
|
||||
* @see SqlQuery
|
||||
* @see CallableSql
|
||||
*/
|
||||
public interface SqlUpdate {
|
||||
|
||||
/**
|
||||
* Execute the update returning the number of rows modified.
|
||||
* <p>
|
||||
* After you have executed the SqlUpdate you can bind new variables using
|
||||
* {@link #setParameter(String, Object)} etc and then execute the SqlUpdate
|
||||
* again.
|
||||
* </p>
|
||||
* <p>
|
||||
* For JDBC batch processing refer to
|
||||
* {@link Transaction#setBatchMode(boolean)} and
|
||||
* {@link Transaction#setBatchSize(int)}.
|
||||
* </p>
|
||||
*
|
||||
* @see com.avaje.ebean.Ebean#execute(SqlUpdate)
|
||||
*/
|
||||
int execute();
|
||||
|
||||
/**
|
||||
* Return true if eBean should automatically deduce the table modification
|
||||
* information and process it.
|
||||
* <p>
|
||||
* If this is true then cache invalidation and text index management are aware
|
||||
* of the modification.
|
||||
* </p>
|
||||
*/
|
||||
boolean isAutoTableMod();
|
||||
|
||||
/**
|
||||
* Set this to false if you don't want eBean to automatically deduce the table
|
||||
* modification information and process it.
|
||||
* <p>
|
||||
* Set this to false if you don't want any cache invalidation or text index
|
||||
* management to occur. You may do this when say you update only one column
|
||||
* and you know that it is not important for cached objects or text indexes.
|
||||
* </p>
|
||||
*/
|
||||
SqlUpdate setAutoTableMod(boolean isAutoTableMod);
|
||||
|
||||
/**
|
||||
* Return the label that can be seen in the transaction logs.
|
||||
*/
|
||||
String getLabel();
|
||||
|
||||
/**
|
||||
* Set a descriptive text that can be put into the transaction log.
|
||||
* <p>
|
||||
* Useful when identifying the statement in the transaction log.
|
||||
* </p>
|
||||
*/
|
||||
SqlUpdate setLabel(String label);
|
||||
|
||||
/**
|
||||
* Return the sql statement.
|
||||
*/
|
||||
String getSql();
|
||||
|
||||
/**
|
||||
* Return the generated sql that has named parameters converted to positioned parameters.
|
||||
*/
|
||||
String getGeneratedSql();
|
||||
|
||||
/**
|
||||
* Return the timeout used to execute this statement.
|
||||
*/
|
||||
int getTimeout();
|
||||
|
||||
/**
|
||||
* Set the timeout in seconds. Zero implies no limit.
|
||||
* <p>
|
||||
* This will set the query timeout on the underlying PreparedStatement. If the
|
||||
* timeout expires a SQLException will be throw and wrapped in a
|
||||
* PersistenceException.
|
||||
* </p>
|
||||
*/
|
||||
SqlUpdate setTimeout(int secs);
|
||||
|
||||
/**
|
||||
* Set a parameter via its index position.
|
||||
*/
|
||||
SqlUpdate setParameter(int position, Object value);
|
||||
|
||||
/**
|
||||
* Set a null parameter via its index position. Exactly the same as
|
||||
* {@link #setNull(int, int)}.
|
||||
*/
|
||||
SqlUpdate setNull(int position, int jdbcType);
|
||||
|
||||
/**
|
||||
* Set a null valued parameter using its index position.
|
||||
*/
|
||||
SqlUpdate setNullParameter(int position, int jdbcType);
|
||||
|
||||
/**
|
||||
* Set a named parameter value.
|
||||
*/
|
||||
SqlUpdate setParameter(String name, Object param);
|
||||
|
||||
/**
|
||||
* Set a named parameter that has a null value. Exactly the same as
|
||||
* {@link #setNullParameter(String, int)}.
|
||||
*/
|
||||
SqlUpdate setNull(String name, int jdbcType);
|
||||
|
||||
/**
|
||||
* Set a named parameter that has a null value.
|
||||
*/
|
||||
SqlUpdate setNullParameter(String name, int jdbcType);
|
||||
|
||||
}
|
||||
@@ -1,329 +1,329 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.persistence.RollbackException;
|
||||
import java.io.Closeable;
|
||||
import java.sql.Connection;
|
||||
|
||||
/**
|
||||
* The Transaction object. Typically representing a JDBC or JTA transaction.
|
||||
*/
|
||||
public interface Transaction extends Closeable {
|
||||
|
||||
/**
|
||||
* Read Committed transaction isolation. Same as
|
||||
* java.sql.Connection.TRANSACTION_READ_COMMITTED.
|
||||
*/
|
||||
public static final int READ_COMMITTED = java.sql.Connection.TRANSACTION_READ_COMMITTED;
|
||||
|
||||
/**
|
||||
* Read Uncommitted transaction isolation. Same as
|
||||
* java.sql.Connection.TRANSACTION_READ_UNCOMMITTED.
|
||||
*/
|
||||
public static final int READ_UNCOMMITTED = java.sql.Connection.TRANSACTION_READ_UNCOMMITTED;
|
||||
|
||||
/**
|
||||
* Repeatable read transaction isolation. Same as
|
||||
* java.sql.Connection.TRANSACTION_REPEATABLE_READ.
|
||||
*/
|
||||
public static final int REPEATABLE_READ = java.sql.Connection.TRANSACTION_REPEATABLE_READ;
|
||||
|
||||
/**
|
||||
* Serializable transaction isolation. Same as
|
||||
* java.sql.Connection.TRANSACTION_SERIALIZABLE.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public boolean isReadOnly();
|
||||
|
||||
/**
|
||||
* Set whether this transaction should be readOnly.
|
||||
*/
|
||||
public void setReadOnly(boolean readOnly);
|
||||
|
||||
/**
|
||||
* Commit the transaction.
|
||||
*/
|
||||
public void commit() throws RollbackException;
|
||||
|
||||
/**
|
||||
* Rollback the transaction.
|
||||
*/
|
||||
public void rollback() throws PersistenceException;
|
||||
|
||||
/**
|
||||
* Rollback the transaction specifying a throwable that caused the rollback to
|
||||
* occur.
|
||||
* <p>
|
||||
* If you are using transaction logging this will log the throwable in the
|
||||
* transaction logs.
|
||||
* </p>
|
||||
*/
|
||||
public void rollback(Throwable e) throws PersistenceException;
|
||||
|
||||
/**
|
||||
* If the transaction is active then perform rollback. Otherwise do nothing.
|
||||
*/
|
||||
public void end() throws PersistenceException;
|
||||
|
||||
/**
|
||||
* Return true if the transaction is active.
|
||||
*/
|
||||
public boolean isActive();
|
||||
|
||||
/**
|
||||
* Explicitly turn off or on the cascading nature of save() and delete(). This
|
||||
* gives the developer exact control over what beans are saved and deleted
|
||||
* rather than Ebean cascading detecting 'dirty/modified' beans etc.
|
||||
* <p>
|
||||
* This is useful if you can getting back entity beans from a layer of code
|
||||
* (potentially remote) and you prefer to have exact control.
|
||||
* </p>
|
||||
* <p>
|
||||
* This may also be useful if you are using jdbc batching with jdbc drivers
|
||||
* that do not support getGeneratedKeys.
|
||||
* </p>
|
||||
*/
|
||||
public void setPersistCascade(boolean persistCascade);
|
||||
|
||||
/**
|
||||
* Turn on or off statement batching. Statement batching can be transparent
|
||||
* for drivers and databases that support getGeneratedKeys. Otherwise you may
|
||||
* wish to specifically control when batching is used via this method.
|
||||
* <p>
|
||||
* Refer to <code>java.sql.PreparedStatement.addBatch();</code>
|
||||
* <p>
|
||||
* Note that you may also wish to use the setPersistCascade method to stop
|
||||
* save and delete cascade behaviour. You may do this to have full control
|
||||
* over the order of execution rather than the normal cascading fashion.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that the <em>execution order</em> in batch mode may be different from
|
||||
* non batch mode execution order. Also note that <em>insert behaviour</em>
|
||||
* may be different depending on the JDBC driver and its support for
|
||||
* getGeneratedKeys. That is, for JDBC drivers that do not support
|
||||
* getGeneratedKeys you may not get back the generated IDs (used for inserting
|
||||
* associated detail beans etc).
|
||||
* </p>
|
||||
* <p>
|
||||
* Calls to save(), delete(), insert() and execute() all support batch
|
||||
* processing. This includes normal beans, MapBean, CallableSql and UpdateSql.
|
||||
* </p>
|
||||
* <p>
|
||||
* The flushing of the batched statements is automatic but you can call
|
||||
* batchFlush when you like. Note that flushing occurs when a query is
|
||||
* executed or when you mix UpdateSql and CallableSql with save and delete of
|
||||
* beans.
|
||||
* </p>
|
||||
* <p>
|
||||
* Example: batch processing executing every 3 rows
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* String data = "This is a simple test of the batch processing"
|
||||
* + " mode and the transaction execute batch method";
|
||||
*
|
||||
* String[] da = data.split(" ");
|
||||
*
|
||||
* String sql = "{call sp_t3(?,?)}";
|
||||
*
|
||||
* CallableSql cs = new CallableSql(sql);
|
||||
* cs.registerOut(2, Types.INTEGER);
|
||||
*
|
||||
* // (optional) inform eBean this stored procedure
|
||||
* // inserts into a table called sp_test
|
||||
* cs.addModification("sp_test", true, false, false);
|
||||
*
|
||||
* Transaction txn = ebeanServer.beginTransaction();
|
||||
* txn.setBatchMode(true);
|
||||
* txn.setBatchSize(3);
|
||||
* try {
|
||||
* for (int i = 0; i < da.length;) {
|
||||
* cs.setParameter(1, da[i]);
|
||||
* ebeanServer.execute(cs);
|
||||
* }
|
||||
*
|
||||
* // NB: commit implicitly flushes
|
||||
* txn.commit();
|
||||
*
|
||||
* } finally {
|
||||
* txn.end();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*/
|
||||
public void setBatchMode(boolean useBatch);
|
||||
|
||||
/**
|
||||
* The JDBC batch mode to use for this transaction.
|
||||
* <p>
|
||||
* If this is NONE then JDBC batch can still be used for each request - save(), insert(), update() or delete()
|
||||
* and this would be useful if the request cascades to detail beans.
|
||||
* </p>
|
||||
*
|
||||
* @param persistBatchMode the batch mode to use for this transaction
|
||||
*
|
||||
* @see com.avaje.ebean.config.ServerConfig#setPersistBatch(com.avaje.ebean.config.PersistBatch)
|
||||
*/
|
||||
public void setBatch(PersistBatch persistBatchMode);
|
||||
|
||||
/**
|
||||
* Return the batch mode at the transaction level.
|
||||
*/
|
||||
public PersistBatch getBatch();
|
||||
|
||||
/**
|
||||
* Set the JDBC batch mode to use for a save() or delete() request.
|
||||
* <p>
|
||||
* This only takes effect when batch mode on the transaction has not already meant that
|
||||
* JDBC batch mode is being used.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is useful when the single save() or delete() cascades. For example, inserting a 'master' cascades
|
||||
* and inserts a collection of 'detail' beans. The detail beans can be inserted using JDBC batch.
|
||||
* </p>
|
||||
*
|
||||
* @param batchOnCascadeMode the batch mode to use per save(), insert(), update() or delete()
|
||||
*
|
||||
* @see com.avaje.ebean.config.ServerConfig#setPersistBatchOnCascade(com.avaje.ebean.config.PersistBatch)
|
||||
*/
|
||||
public void setBatchOnCascade(PersistBatch batchOnCascadeMode);
|
||||
|
||||
/**
|
||||
* Return the batch mode at the request level (for each save(), insert(), update() or delete()).
|
||||
*/
|
||||
public PersistBatch getBatchOnCascade();
|
||||
|
||||
/**
|
||||
* Specify the number of statements before a batch is flushed automatically.
|
||||
*/
|
||||
public void setBatchSize(int batchSize);
|
||||
|
||||
/**
|
||||
* Return the current batch size.
|
||||
*/
|
||||
public int getBatchSize();
|
||||
|
||||
/**
|
||||
* Specify if you want batched inserts to use getGeneratedKeys.
|
||||
* <p>
|
||||
* By default batched inserts will try to use getGeneratedKeys if it is
|
||||
* supported by the underlying jdbc driver and database.
|
||||
* </p>
|
||||
* <p>
|
||||
* You may want to turn getGeneratedKeys off when you are inserting a large
|
||||
* number of objects and you don't care about getting back the ids.
|
||||
* </p>
|
||||
*/
|
||||
public void setBatchGetGeneratedKeys(boolean getGeneratedKeys);
|
||||
|
||||
/**
|
||||
* By default when mixing UpdateSql (or CallableSql) with Beans the batch is
|
||||
* automatically flushed when you change (between persisting beans and
|
||||
* executing UpdateSql or CallableSql).
|
||||
* <p>
|
||||
* If you want to execute both WITHOUT having the batch automatically flush
|
||||
* you need to call this with batchFlushOnMixed = false.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that UpdateSql and CallableSql are ALWAYS executed first (before the
|
||||
* beans are executed). This is because the UpdateSql and CallableSql have
|
||||
* already been bound to their PreparedStatements. The beans on the other hand
|
||||
* have a 2 step process (delayed binding).
|
||||
* </p>
|
||||
*/
|
||||
public void setBatchFlushOnMixed(boolean batchFlushOnMixed);
|
||||
|
||||
/**
|
||||
* By default executing a query will automatically flush any batched
|
||||
* statements (persisted beans, executed UpdateSql etc).
|
||||
* <p>
|
||||
* Calling this method with batchFlushOnQuery = false means that you can
|
||||
* execute a query and the batch will not be automatically flushed.
|
||||
* </p>
|
||||
*/
|
||||
public void setBatchFlushOnQuery(boolean batchFlushOnQuery);
|
||||
|
||||
/**
|
||||
* Return true if the batch (of persisted beans or executed UpdateSql etc)
|
||||
* should be flushed prior to executing a query.
|
||||
* <p>
|
||||
* The default is for this to be true.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isBatchFlushOnQuery();
|
||||
|
||||
/**
|
||||
* The batch will be flushing automatically but you can use this to explicitly
|
||||
* flush the batch if you like.
|
||||
* <p>
|
||||
* Flushing occurs automatically when:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>the batch size is reached</li>
|
||||
* <li>A query is executed on the same transaction</li>
|
||||
* <li>UpdateSql or CallableSql are mixed with bean save and delete</li>
|
||||
* <li>Transaction commit occurs</li>
|
||||
* </ul>
|
||||
*/
|
||||
public void flushBatch() throws PersistenceException, OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Return the underlying Connection object.
|
||||
* <p>
|
||||
* Useful where a Developer wishes to use the JDBC API directly. Note that the
|
||||
* commit() rollback() and end() methods on the Transaction should still be
|
||||
* used. Calling these methods on the Connection would be a big no no unless
|
||||
* you know what you are doing.
|
||||
* </p>
|
||||
* <p>
|
||||
* Examples of when a developer may wish to use the connection directly are:
|
||||
* Savepoints, advanced CLOB BLOB use and advanced stored procedure calls.
|
||||
* </p>
|
||||
*/
|
||||
public Connection getConnection();
|
||||
|
||||
/**
|
||||
* Add table modification information to the TransactionEvent.
|
||||
* <p>
|
||||
* Use this in conjunction with getConnection() and raw JDBC.
|
||||
* </p>
|
||||
* <p>
|
||||
* This effectively informs Ebean of the data that has been changed by the
|
||||
* transaction and this information is normally automatically handled by Ebean
|
||||
* when you save entity beans or use UpdateSql etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* If you use raw JDBC then you can use this method to inform Ebean for the
|
||||
* tables that have been modified. Ebean uses this information to keep its
|
||||
* caches in synch and maintain text indexes.
|
||||
* </p>
|
||||
*/
|
||||
public void addModification(String tableName, boolean inserts, boolean updates, boolean deletes);
|
||||
|
||||
/**
|
||||
* Add an arbitrary user object to the transaction. The objects added have no
|
||||
* impact on any internals of ebena and are solely meant as a convenient
|
||||
* method push user information to e.g. the
|
||||
* {@link com.avaje.ebean.event.TransactionEventListener}.
|
||||
*/
|
||||
public void putUserObject(String name, Object value);
|
||||
|
||||
/**
|
||||
* Get an object added with {@link #putUserObject(String, Object)}.
|
||||
*/
|
||||
public Object getUserObject(String name);
|
||||
}
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.persistence.RollbackException;
|
||||
import java.io.Closeable;
|
||||
import java.sql.Connection;
|
||||
|
||||
/**
|
||||
* The Transaction object. Typically representing a JDBC or JTA transaction.
|
||||
*/
|
||||
public interface Transaction extends Closeable {
|
||||
|
||||
/**
|
||||
* Read Committed transaction isolation. Same as
|
||||
* java.sql.Connection.TRANSACTION_READ_COMMITTED.
|
||||
*/
|
||||
int READ_COMMITTED = java.sql.Connection.TRANSACTION_READ_COMMITTED;
|
||||
|
||||
/**
|
||||
* Read Uncommitted transaction isolation. Same as
|
||||
* java.sql.Connection.TRANSACTION_READ_UNCOMMITTED.
|
||||
*/
|
||||
int READ_UNCOMMITTED = java.sql.Connection.TRANSACTION_READ_UNCOMMITTED;
|
||||
|
||||
/**
|
||||
* Repeatable read transaction isolation. Same as
|
||||
* java.sql.Connection.TRANSACTION_REPEATABLE_READ.
|
||||
*/
|
||||
int REPEATABLE_READ = java.sql.Connection.TRANSACTION_REPEATABLE_READ;
|
||||
|
||||
/**
|
||||
* Serializable transaction isolation. Same as
|
||||
* java.sql.Connection.TRANSACTION_SERIALIZABLE.
|
||||
*/
|
||||
int SERIALIZABLE = java.sql.Connection.TRANSACTION_SERIALIZABLE;
|
||||
|
||||
/**
|
||||
* Register a TransactionCallback with this transaction.
|
||||
*/
|
||||
void register(TransactionCallback callback);
|
||||
|
||||
/**
|
||||
* Return true if this transaction is read only.
|
||||
*/
|
||||
boolean isReadOnly();
|
||||
|
||||
/**
|
||||
* Set whether this transaction should be readOnly.
|
||||
*/
|
||||
void setReadOnly(boolean readOnly);
|
||||
|
||||
/**
|
||||
* Commit the transaction.
|
||||
*/
|
||||
void commit() throws RollbackException;
|
||||
|
||||
/**
|
||||
* Rollback the transaction.
|
||||
*/
|
||||
void rollback() throws PersistenceException;
|
||||
|
||||
/**
|
||||
* Rollback the transaction specifying a throwable that caused the rollback to
|
||||
* occur.
|
||||
* <p>
|
||||
* If you are using transaction logging this will log the throwable in the
|
||||
* transaction logs.
|
||||
* </p>
|
||||
*/
|
||||
void rollback(Throwable e) throws PersistenceException;
|
||||
|
||||
/**
|
||||
* If the transaction is active then perform rollback. Otherwise do nothing.
|
||||
*/
|
||||
void end() throws PersistenceException;
|
||||
|
||||
/**
|
||||
* Return true if the transaction is active.
|
||||
*/
|
||||
boolean isActive();
|
||||
|
||||
/**
|
||||
* Explicitly turn off or on the cascading nature of save() and delete(). This
|
||||
* gives the developer exact control over what beans are saved and deleted
|
||||
* rather than Ebean cascading detecting 'dirty/modified' beans etc.
|
||||
* <p>
|
||||
* This is useful if you can getting back entity beans from a layer of code
|
||||
* (potentially remote) and you prefer to have exact control.
|
||||
* </p>
|
||||
* <p>
|
||||
* This may also be useful if you are using jdbc batching with jdbc drivers
|
||||
* that do not support getGeneratedKeys.
|
||||
* </p>
|
||||
*/
|
||||
void setPersistCascade(boolean persistCascade);
|
||||
|
||||
/**
|
||||
* Turn on or off statement batching. Statement batching can be transparent
|
||||
* for drivers and databases that support getGeneratedKeys. Otherwise you may
|
||||
* wish to specifically control when batching is used via this method.
|
||||
* <p>
|
||||
* Refer to <code>java.sql.PreparedStatement.addBatch();</code>
|
||||
* <p>
|
||||
* Note that you may also wish to use the setPersistCascade method to stop
|
||||
* save and delete cascade behaviour. You may do this to have full control
|
||||
* over the order of execution rather than the normal cascading fashion.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that the <em>execution order</em> in batch mode may be different from
|
||||
* non batch mode execution order. Also note that <em>insert behaviour</em>
|
||||
* may be different depending on the JDBC driver and its support for
|
||||
* getGeneratedKeys. That is, for JDBC drivers that do not support
|
||||
* getGeneratedKeys you may not get back the generated IDs (used for inserting
|
||||
* associated detail beans etc).
|
||||
* </p>
|
||||
* <p>
|
||||
* Calls to save(), delete(), insert() and execute() all support batch
|
||||
* processing. This includes normal beans, MapBean, CallableSql and UpdateSql.
|
||||
* </p>
|
||||
* <p>
|
||||
* The flushing of the batched statements is automatic but you can call
|
||||
* batchFlush when you like. Note that flushing occurs when a query is
|
||||
* executed or when you mix UpdateSql and CallableSql with save and delete of
|
||||
* beans.
|
||||
* </p>
|
||||
* <p>
|
||||
* Example: batch processing executing every 3 rows
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* String data = "This is a simple test of the batch processing"
|
||||
* + " mode and the transaction execute batch method";
|
||||
*
|
||||
* String[] da = data.split(" ");
|
||||
*
|
||||
* String sql = "{call sp_t3(?,?)}";
|
||||
*
|
||||
* CallableSql cs = new CallableSql(sql);
|
||||
* cs.registerOut(2, Types.INTEGER);
|
||||
*
|
||||
* // (optional) inform eBean this stored procedure
|
||||
* // inserts into a table called sp_test
|
||||
* cs.addModification("sp_test", true, false, false);
|
||||
*
|
||||
* Transaction txn = ebeanServer.beginTransaction();
|
||||
* txn.setBatchMode(true);
|
||||
* txn.setBatchSize(3);
|
||||
* try {
|
||||
* for (int i = 0; i < da.length;) {
|
||||
* cs.setParameter(1, da[i]);
|
||||
* ebeanServer.execute(cs);
|
||||
* }
|
||||
*
|
||||
* // NB: commit implicitly flushes
|
||||
* txn.commit();
|
||||
*
|
||||
* } finally {
|
||||
* txn.end();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*/
|
||||
void setBatchMode(boolean useBatch);
|
||||
|
||||
/**
|
||||
* The JDBC batch mode to use for this transaction.
|
||||
* <p>
|
||||
* If this is NONE then JDBC batch can still be used for each request - save(), insert(), update() or delete()
|
||||
* and this would be useful if the request cascades to detail beans.
|
||||
* </p>
|
||||
*
|
||||
* @param persistBatchMode the batch mode to use for this transaction
|
||||
*
|
||||
* @see com.avaje.ebean.config.ServerConfig#setPersistBatch(com.avaje.ebean.config.PersistBatch)
|
||||
*/
|
||||
void setBatch(PersistBatch persistBatchMode);
|
||||
|
||||
/**
|
||||
* Return the batch mode at the transaction level.
|
||||
*/
|
||||
PersistBatch getBatch();
|
||||
|
||||
/**
|
||||
* Set the JDBC batch mode to use for a save() or delete() request.
|
||||
* <p>
|
||||
* This only takes effect when batch mode on the transaction has not already meant that
|
||||
* JDBC batch mode is being used.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is useful when the single save() or delete() cascades. For example, inserting a 'master' cascades
|
||||
* and inserts a collection of 'detail' beans. The detail beans can be inserted using JDBC batch.
|
||||
* </p>
|
||||
*
|
||||
* @param batchOnCascadeMode the batch mode to use per save(), insert(), update() or delete()
|
||||
*
|
||||
* @see com.avaje.ebean.config.ServerConfig#setPersistBatchOnCascade(com.avaje.ebean.config.PersistBatch)
|
||||
*/
|
||||
void setBatchOnCascade(PersistBatch batchOnCascadeMode);
|
||||
|
||||
/**
|
||||
* Return the batch mode at the request level (for each save(), insert(), update() or delete()).
|
||||
*/
|
||||
PersistBatch getBatchOnCascade();
|
||||
|
||||
/**
|
||||
* Specify the number of statements before a batch is flushed automatically.
|
||||
*/
|
||||
void setBatchSize(int batchSize);
|
||||
|
||||
/**
|
||||
* Return the current batch size.
|
||||
*/
|
||||
int getBatchSize();
|
||||
|
||||
/**
|
||||
* Specify if you want batched inserts to use getGeneratedKeys.
|
||||
* <p>
|
||||
* By default batched inserts will try to use getGeneratedKeys if it is
|
||||
* supported by the underlying jdbc driver and database.
|
||||
* </p>
|
||||
* <p>
|
||||
* You may want to turn getGeneratedKeys off when you are inserting a large
|
||||
* number of objects and you don't care about getting back the ids.
|
||||
* </p>
|
||||
*/
|
||||
void setBatchGetGeneratedKeys(boolean getGeneratedKeys);
|
||||
|
||||
/**
|
||||
* By default when mixing UpdateSql (or CallableSql) with Beans the batch is
|
||||
* automatically flushed when you change (between persisting beans and
|
||||
* executing UpdateSql or CallableSql).
|
||||
* <p>
|
||||
* If you want to execute both WITHOUT having the batch automatically flush
|
||||
* you need to call this with batchFlushOnMixed = false.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that UpdateSql and CallableSql are ALWAYS executed first (before the
|
||||
* beans are executed). This is because the UpdateSql and CallableSql have
|
||||
* already been bound to their PreparedStatements. The beans on the other hand
|
||||
* have a 2 step process (delayed binding).
|
||||
* </p>
|
||||
*/
|
||||
void setBatchFlushOnMixed(boolean batchFlushOnMixed);
|
||||
|
||||
/**
|
||||
* By default executing a query will automatically flush any batched
|
||||
* statements (persisted beans, executed UpdateSql etc).
|
||||
* <p>
|
||||
* Calling this method with batchFlushOnQuery = false means that you can
|
||||
* execute a query and the batch will not be automatically flushed.
|
||||
* </p>
|
||||
*/
|
||||
void setBatchFlushOnQuery(boolean batchFlushOnQuery);
|
||||
|
||||
/**
|
||||
* Return true if the batch (of persisted beans or executed UpdateSql etc)
|
||||
* should be flushed prior to executing a query.
|
||||
* <p>
|
||||
* The default is for this to be true.
|
||||
* </p>
|
||||
*/
|
||||
boolean isBatchFlushOnQuery();
|
||||
|
||||
/**
|
||||
* The batch will be flushing automatically but you can use this to explicitly
|
||||
* flush the batch if you like.
|
||||
* <p>
|
||||
* Flushing occurs automatically when:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>the batch size is reached</li>
|
||||
* <li>A query is executed on the same transaction</li>
|
||||
* <li>UpdateSql or CallableSql are mixed with bean save and delete</li>
|
||||
* <li>Transaction commit occurs</li>
|
||||
* </ul>
|
||||
*/
|
||||
void flushBatch() throws PersistenceException, OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Return the underlying Connection object.
|
||||
* <p>
|
||||
* Useful where a Developer wishes to use the JDBC API directly. Note that the
|
||||
* commit() rollback() and end() methods on the Transaction should still be
|
||||
* used. Calling these methods on the Connection would be a big no no unless
|
||||
* you know what you are doing.
|
||||
* </p>
|
||||
* <p>
|
||||
* Examples of when a developer may wish to use the connection directly are:
|
||||
* Savepoints, advanced CLOB BLOB use and advanced stored procedure calls.
|
||||
* </p>
|
||||
*/
|
||||
Connection getConnection();
|
||||
|
||||
/**
|
||||
* Add table modification information to the TransactionEvent.
|
||||
* <p>
|
||||
* Use this in conjunction with getConnection() and raw JDBC.
|
||||
* </p>
|
||||
* <p>
|
||||
* This effectively informs Ebean of the data that has been changed by the
|
||||
* transaction and this information is normally automatically handled by Ebean
|
||||
* when you save entity beans or use UpdateSql etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* If you use raw JDBC then you can use this method to inform Ebean for the
|
||||
* tables that have been modified. Ebean uses this information to keep its
|
||||
* caches in synch and maintain text indexes.
|
||||
* </p>
|
||||
*/
|
||||
void addModification(String tableName, boolean inserts, boolean updates, boolean deletes);
|
||||
|
||||
/**
|
||||
* Add an arbitrary user object to the transaction. The objects added have no
|
||||
* impact on any internals of ebena and are solely meant as a convenient
|
||||
* method push user information to e.g. the
|
||||
* {@link com.avaje.ebean.event.TransactionEventListener}.
|
||||
*/
|
||||
void putUserObject(String name, Object value);
|
||||
|
||||
/**
|
||||
* Get an object added with {@link #putUserObject(String, Object)}.
|
||||
*/
|
||||
Object getUserObject(String name);
|
||||
}
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Execute a TxCallable in a Transaction scope.
|
||||
* <p>
|
||||
* Use this with the {@link Ebean#execute(TxCallable)} method.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that this is basically the same as TxRunnable except that it returns an
|
||||
* Object (and you specify the return type via generics).
|
||||
* </p>
|
||||
* <p>
|
||||
* See also {@link TxRunnable}.
|
||||
* </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);
|
||||
*
|
||||
* u1.setName("u1 mod");
|
||||
* u2.setName("u2 mod");
|
||||
*
|
||||
* Ebean.save(u1);
|
||||
* Ebean.save(u2);
|
||||
*
|
||||
* return u1.getEmail();
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @see TxRunnable
|
||||
*/
|
||||
public interface TxCallable<T> {
|
||||
|
||||
/**
|
||||
* Execute the method within a transaction scope returning the result.
|
||||
* <p>
|
||||
* If you do not want to return a result you should look to use TxRunnable
|
||||
* instead.
|
||||
* </p>
|
||||
*/
|
||||
public T call();
|
||||
}
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Execute a TxCallable in a Transaction scope.
|
||||
* <p>
|
||||
* Use this with the {@link Ebean#execute(TxCallable)} method.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that this is basically the same as TxRunnable except that it returns an
|
||||
* Object (and you specify the return type via generics).
|
||||
* </p>
|
||||
* <p>
|
||||
* See also {@link TxRunnable}.
|
||||
* </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);
|
||||
*
|
||||
* u1.setName("u1 mod");
|
||||
* u2.setName("u2 mod");
|
||||
*
|
||||
* Ebean.save(u1);
|
||||
* Ebean.save(u2);
|
||||
*
|
||||
* return u1.getEmail();
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @see TxRunnable
|
||||
*/
|
||||
public interface TxCallable<T> {
|
||||
|
||||
/**
|
||||
* Execute the method within a transaction scope returning the result.
|
||||
* <p>
|
||||
* If you do not want to return a result you should look to use TxRunnable
|
||||
* instead.
|
||||
* </p>
|
||||
*/
|
||||
T call();
|
||||
}
|
||||
|
||||
@@ -1,100 +1,100 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
/**
|
||||
* The Transaction Isolation levels.
|
||||
* <p>
|
||||
* These match those of java.sql.Connection with the addition of DEFAULT which
|
||||
* implies the configured default of the DataSource.
|
||||
* </p>
|
||||
* <p>
|
||||
* This can be used with TxScope to define transactional scopes to execute
|
||||
* method within.
|
||||
* </p>
|
||||
*
|
||||
* @see TxScope
|
||||
*/
|
||||
public enum TxIsolation {
|
||||
|
||||
/**
|
||||
* Read Committed Isolation level. This is typically the default for most
|
||||
* configurations.
|
||||
*/
|
||||
READ_COMMITED(Connection.TRANSACTION_READ_COMMITTED),
|
||||
|
||||
/**
|
||||
* Read uncommitted Isolation level.
|
||||
*/
|
||||
READ_UNCOMMITTED(Connection.TRANSACTION_READ_UNCOMMITTED),
|
||||
|
||||
/**
|
||||
* Repeatable Read Isolation level.
|
||||
*/
|
||||
REPEATABLE_READ(Connection.TRANSACTION_REPEATABLE_READ),
|
||||
|
||||
/**
|
||||
* Serializable Isolation level.
|
||||
*/
|
||||
SERIALIZABLE(Connection.TRANSACTION_SERIALIZABLE),
|
||||
|
||||
/**
|
||||
* No Isolation level.
|
||||
*/
|
||||
NONE(Connection.TRANSACTION_NONE),
|
||||
|
||||
/**
|
||||
* The default isolation level. This typically means the default that the
|
||||
* DataSource is using or configured to use.
|
||||
*/
|
||||
DEFAULT(-1);
|
||||
|
||||
final int level;
|
||||
|
||||
private TxIsolation(int level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the level as per java.sql.Connection.
|
||||
* <p>
|
||||
* Note that -1 denotes the default isolation level.
|
||||
* </p>
|
||||
*/
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the TxIsolation given the java.sql.Connection isolation level.
|
||||
* <p>
|
||||
* Note that -1 denotes the default isolation level.
|
||||
* </p>
|
||||
*/
|
||||
public static TxIsolation fromLevel(int connectionIsolationLevel) {
|
||||
|
||||
switch (connectionIsolationLevel) {
|
||||
case Connection.TRANSACTION_READ_UNCOMMITTED:
|
||||
return TxIsolation.READ_UNCOMMITTED;
|
||||
|
||||
case Connection.TRANSACTION_READ_COMMITTED:
|
||||
return TxIsolation.READ_COMMITED;
|
||||
|
||||
case Connection.TRANSACTION_REPEATABLE_READ:
|
||||
return TxIsolation.REPEATABLE_READ;
|
||||
|
||||
case Connection.TRANSACTION_SERIALIZABLE:
|
||||
return TxIsolation.SERIALIZABLE;
|
||||
|
||||
case Connection.TRANSACTION_NONE:
|
||||
return TxIsolation.NONE;
|
||||
|
||||
case -1:
|
||||
return TxIsolation.DEFAULT;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Unknown isolation level " + connectionIsolationLevel);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
/**
|
||||
* The Transaction Isolation levels.
|
||||
* <p>
|
||||
* These match those of java.sql.Connection with the addition of DEFAULT which
|
||||
* implies the configured default of the DataSource.
|
||||
* </p>
|
||||
* <p>
|
||||
* This can be used with TxScope to define transactional scopes to execute
|
||||
* method within.
|
||||
* </p>
|
||||
*
|
||||
* @see TxScope
|
||||
*/
|
||||
public enum TxIsolation {
|
||||
|
||||
/**
|
||||
* Read Committed Isolation level. This is typically the default for most
|
||||
* configurations.
|
||||
*/
|
||||
READ_COMMITED(Connection.TRANSACTION_READ_COMMITTED),
|
||||
|
||||
/**
|
||||
* Read uncommitted Isolation level.
|
||||
*/
|
||||
READ_UNCOMMITTED(Connection.TRANSACTION_READ_UNCOMMITTED),
|
||||
|
||||
/**
|
||||
* Repeatable Read Isolation level.
|
||||
*/
|
||||
REPEATABLE_READ(Connection.TRANSACTION_REPEATABLE_READ),
|
||||
|
||||
/**
|
||||
* Serializable Isolation level.
|
||||
*/
|
||||
SERIALIZABLE(Connection.TRANSACTION_SERIALIZABLE),
|
||||
|
||||
/**
|
||||
* No Isolation level.
|
||||
*/
|
||||
NONE(Connection.TRANSACTION_NONE),
|
||||
|
||||
/**
|
||||
* The default isolation level. This typically means the default that the
|
||||
* DataSource is using or configured to use.
|
||||
*/
|
||||
DEFAULT(-1);
|
||||
|
||||
final int level;
|
||||
|
||||
TxIsolation(int level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the level as per java.sql.Connection.
|
||||
* <p>
|
||||
* Note that -1 denotes the default isolation level.
|
||||
* </p>
|
||||
*/
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the TxIsolation given the java.sql.Connection isolation level.
|
||||
* <p>
|
||||
* Note that -1 denotes the default isolation level.
|
||||
* </p>
|
||||
*/
|
||||
public static TxIsolation fromLevel(int connectionIsolationLevel) {
|
||||
|
||||
switch (connectionIsolationLevel) {
|
||||
case Connection.TRANSACTION_READ_UNCOMMITTED:
|
||||
return TxIsolation.READ_UNCOMMITTED;
|
||||
|
||||
case Connection.TRANSACTION_READ_COMMITTED:
|
||||
return TxIsolation.READ_COMMITED;
|
||||
|
||||
case Connection.TRANSACTION_REPEATABLE_READ:
|
||||
return TxIsolation.REPEATABLE_READ;
|
||||
|
||||
case Connection.TRANSACTION_SERIALIZABLE:
|
||||
return TxIsolation.SERIALIZABLE;
|
||||
|
||||
case Connection.TRANSACTION_NONE:
|
||||
return TxIsolation.NONE;
|
||||
|
||||
case -1:
|
||||
return TxIsolation.DEFAULT;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Unknown isolation level " + connectionIsolationLevel);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Execute a TxRunnable in a Transaction scope.
|
||||
* <p>
|
||||
* Use this with the {@link Ebean#execute(TxRunnable)} method.
|
||||
* </p>
|
||||
* <p>
|
||||
* See also {@link TxCallable}.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* // this run method runs in a transaction scope
|
||||
* // which by default is TxScope.REQUIRED
|
||||
*
|
||||
* 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");
|
||||
*
|
||||
* Ebean.save(u1);
|
||||
* Ebean.save(u2);
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @see TxCallable
|
||||
*/
|
||||
public interface TxRunnable {
|
||||
|
||||
/**
|
||||
* Run the method in a transaction sope.
|
||||
*/
|
||||
public void run();
|
||||
}
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Execute a TxRunnable in a Transaction scope.
|
||||
* <p>
|
||||
* Use this with the {@link Ebean#execute(TxRunnable)} method.
|
||||
* </p>
|
||||
* <p>
|
||||
* See also {@link TxCallable}.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* // this run method runs in a transaction scope
|
||||
* // which by default is TxScope.REQUIRED
|
||||
*
|
||||
* 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");
|
||||
*
|
||||
* Ebean.save(u1);
|
||||
* Ebean.save(u2);
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @see TxCallable
|
||||
*/
|
||||
public interface TxRunnable {
|
||||
|
||||
/**
|
||||
* Run the method in a transaction sope.
|
||||
*/
|
||||
void run();
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ public interface Update<T> {
|
||||
/**
|
||||
* Return the name if it is a named update.
|
||||
*/
|
||||
public String getName();
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Set this to false if you do not want the cache to invalidate related
|
||||
@@ -64,7 +64,7 @@ public interface Update<T> {
|
||||
* parts of the "L2" server cache.
|
||||
* </p>
|
||||
*/
|
||||
public Update<T> setNotifyCache(boolean notifyCache);
|
||||
Update<T> setNotifyCache(boolean notifyCache);
|
||||
|
||||
/**
|
||||
* Set a timeout for statement execution.
|
||||
@@ -77,12 +77,12 @@ public interface Update<T> {
|
||||
* @param secs
|
||||
* the timeout in seconds. Zero implies unlimited.
|
||||
*/
|
||||
public Update<T> setTimeout(int secs);
|
||||
Update<T> setTimeout(int secs);
|
||||
|
||||
/**
|
||||
* Execute the statement returning the number of rows modified.
|
||||
*/
|
||||
public int execute();
|
||||
int execute();
|
||||
|
||||
/**
|
||||
* Set an ordered bind parameter.
|
||||
@@ -98,7 +98,7 @@ public interface Update<T> {
|
||||
* @param value
|
||||
* the parameter value to bind.
|
||||
*/
|
||||
public Update<T> set(int position, Object value);
|
||||
Update<T> set(int position, Object value);
|
||||
|
||||
/**
|
||||
* Set and ordered bind parameter (same as bind).
|
||||
@@ -108,7 +108,7 @@ public interface Update<T> {
|
||||
* @param value
|
||||
* the parameter value to bind.
|
||||
*/
|
||||
public Update<T> setParameter(int position, Object value);
|
||||
Update<T> setParameter(int position, Object value);
|
||||
|
||||
/**
|
||||
* Set an ordered parameter that is null. The JDBC type of the null must be
|
||||
@@ -117,12 +117,12 @@ public interface Update<T> {
|
||||
* position starts at value 1 (not 0) to be consistent with PreparedStatement.
|
||||
* </p>
|
||||
*/
|
||||
public Update<T> setNull(int position, int jdbcType);
|
||||
Update<T> setNull(int position, int jdbcType);
|
||||
|
||||
/**
|
||||
* Set an ordered parameter that is null (same as bind).
|
||||
*/
|
||||
public Update<T> setNullParameter(int position, int jdbcType);
|
||||
Update<T> setNullParameter(int position, int jdbcType);
|
||||
|
||||
/**
|
||||
* Set a named parameter. Named parameters have a colon to prefix the name.
|
||||
@@ -135,12 +135,12 @@ public interface Update<T> {
|
||||
* @param value
|
||||
* the parameter value.
|
||||
*/
|
||||
public Update<T> set(String name, Object value);
|
||||
Update<T> set(String name, Object value);
|
||||
|
||||
/**
|
||||
* Bind a named parameter (same as bind).
|
||||
*/
|
||||
public Update<T> setParameter(String name, Object param);
|
||||
Update<T> setParameter(String name, Object param);
|
||||
|
||||
/**
|
||||
* Set a named parameter that is null. The JDBC type of the null must be
|
||||
@@ -154,16 +154,16 @@ public interface Update<T> {
|
||||
* @param jdbcType
|
||||
* the type of the property being bound.
|
||||
*/
|
||||
public Update<T> setNull(String name, int jdbcType);
|
||||
Update<T> setNull(String name, int jdbcType);
|
||||
|
||||
/**
|
||||
* Bind a named parameter that is null (same as bind).
|
||||
*/
|
||||
public Update<T> setNullParameter(String name, int jdbcType);
|
||||
Update<T> setNullParameter(String name, int jdbcType);
|
||||
|
||||
/**
|
||||
* Return the sql that is actually executed.
|
||||
*/
|
||||
public String getGeneratedSql();
|
||||
String getGeneratedSql();
|
||||
|
||||
}
|
||||
@@ -1,50 +1,50 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Holds two values as the result of a difference comparison.
|
||||
*/
|
||||
public class ValuePair {
|
||||
|
||||
private final Object newValue;
|
||||
|
||||
private final Object oldValue;
|
||||
|
||||
public ValuePair(Object newValue, Object oldValue) {
|
||||
this.newValue = newValue;
|
||||
this.oldValue = oldValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the new value.
|
||||
*/
|
||||
public Object getNewValue() {
|
||||
return newValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the old value.
|
||||
*/
|
||||
public Object getOldValue() {
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the new value.
|
||||
*/
|
||||
@Deprecated
|
||||
public Object getValue1() {
|
||||
return newValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the old value.
|
||||
*/
|
||||
@Deprecated
|
||||
public Object getValue2() {
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return newValue + "," + oldValue;
|
||||
}
|
||||
}
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Holds two values as the result of a difference comparison.
|
||||
*/
|
||||
public class ValuePair {
|
||||
|
||||
private final Object newValue;
|
||||
|
||||
private final Object oldValue;
|
||||
|
||||
public ValuePair(Object newValue, Object oldValue) {
|
||||
this.newValue = newValue;
|
||||
this.oldValue = oldValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the new value.
|
||||
*/
|
||||
public Object getNewValue() {
|
||||
return newValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the old value.
|
||||
*/
|
||||
public Object getOldValue() {
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the new value.
|
||||
*/
|
||||
@Deprecated
|
||||
public Object getValue1() {
|
||||
return newValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the old value.
|
||||
*/
|
||||
@Deprecated
|
||||
public Object getValue2() {
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return newValue + "," + oldValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,58 +1,58 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.avaje.ebean.Query;
|
||||
|
||||
/**
|
||||
* Specify the default cache use specific entity type.
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface CacheStrategy {
|
||||
|
||||
/**
|
||||
* When set to true the bean cache will be used unless explicitly stated not
|
||||
* to in a query via {@link Query#setUseCache(boolean)}.
|
||||
*/
|
||||
boolean useBeanCache() default true;
|
||||
|
||||
/**
|
||||
* A single property that is a natural unique identifier for the bean.
|
||||
* <p>
|
||||
* When a findUnique query is used with this property as the sole expression
|
||||
* then there will be a lookup into the L2 natural key cache.
|
||||
* </p>
|
||||
*/
|
||||
String naturalKey() default "";
|
||||
|
||||
/**
|
||||
* When set to true the beans returned from a query will default to be
|
||||
* readOnly.
|
||||
* <p>
|
||||
* If the bean is readOnly and has no relationships then it may be sharable.
|
||||
* </p>
|
||||
* <p>
|
||||
* If you try to modify a readOnly bean it will throw an
|
||||
* IllegalStateException.
|
||||
* </p>
|
||||
*/
|
||||
boolean readOnly() default false;
|
||||
|
||||
/**
|
||||
* Specify a query that can be used to warm the cache.
|
||||
* <p>
|
||||
* All the beans fetched by this query will be loaded into the bean cache and
|
||||
* the query itself will be loaded into the query cache.
|
||||
* </p>
|
||||
* <p>
|
||||
* The warming query will typically be executed at startup time after a short
|
||||
* delay (defaults to a 30 seconds delay).
|
||||
* </p>
|
||||
*/
|
||||
String warmingQuery() default "";
|
||||
|
||||
};
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.avaje.ebean.Query;
|
||||
|
||||
/**
|
||||
* Specify the default cache use specific entity type.
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface CacheStrategy {
|
||||
|
||||
/**
|
||||
* When set to true the bean cache will be used unless explicitly stated not
|
||||
* to in a query via {@link Query#setUseCache(boolean)}.
|
||||
*/
|
||||
boolean useBeanCache() default true;
|
||||
|
||||
/**
|
||||
* A single property that is a natural unique identifier for the bean.
|
||||
* <p>
|
||||
* When a findUnique query is used with this property as the sole expression
|
||||
* then there will be a lookup into the L2 natural key cache.
|
||||
* </p>
|
||||
*/
|
||||
String naturalKey() default "";
|
||||
|
||||
/**
|
||||
* When set to true the beans returned from a query will default to be
|
||||
* readOnly.
|
||||
* <p>
|
||||
* If the bean is readOnly and has no relationships then it may be sharable.
|
||||
* </p>
|
||||
* <p>
|
||||
* If you try to modify a readOnly bean it will throw an
|
||||
* IllegalStateException.
|
||||
* </p>
|
||||
*/
|
||||
boolean readOnly() default false;
|
||||
|
||||
/**
|
||||
* Specify a query that can be used to warm the cache.
|
||||
* <p>
|
||||
* All the beans fetched by this query will be loaded into the bean cache and
|
||||
* the query itself will be loaded into the query cache.
|
||||
* </p>
|
||||
* <p>
|
||||
* The warming query will typically be executed at startup time after a short
|
||||
* delay (defaults to a 30 seconds delay).
|
||||
* </p>
|
||||
*/
|
||||
String warmingQuery() default "";
|
||||
|
||||
}
|
||||
|
||||
@@ -1,47 +1,47 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify cache tuning for a specific entity type.
|
||||
* <p>
|
||||
* If this is not specified then the system default settings are used.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface CacheTuning {
|
||||
|
||||
/**
|
||||
* The maximum size for the cache.
|
||||
* <p>
|
||||
* This defaults to 0 which means unlimited.
|
||||
* </p>
|
||||
*/
|
||||
int maxSize() default 0;
|
||||
|
||||
/**
|
||||
* The maximum time (in seconds) that a cache entry is allowed to stay in the
|
||||
* cache when it has not been accessed.
|
||||
* <p>
|
||||
* This defaults to 0 which means unlimited.
|
||||
* </p>
|
||||
*/
|
||||
int maxIdleSecs() default 0;
|
||||
|
||||
/**
|
||||
* The maximum time (in seconds) a cache entry is allowed to stay in the
|
||||
* cache.
|
||||
* <p>
|
||||
* This is not generally required as the cache entries are automatically
|
||||
* evicted when related data changes are committed.
|
||||
* </p>
|
||||
* <p>
|
||||
* This defaults to 0 which means unlimited.
|
||||
* </p>
|
||||
*/
|
||||
int maxSecsToLive() default 0;
|
||||
};
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify cache tuning for a specific entity type.
|
||||
* <p>
|
||||
* If this is not specified then the system default settings are used.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface CacheTuning {
|
||||
|
||||
/**
|
||||
* The maximum size for the cache.
|
||||
* <p>
|
||||
* This defaults to 0 which means unlimited.
|
||||
* </p>
|
||||
*/
|
||||
int maxSize() default 0;
|
||||
|
||||
/**
|
||||
* The maximum time (in seconds) that a cache entry is allowed to stay in the
|
||||
* cache when it has not been accessed.
|
||||
* <p>
|
||||
* This defaults to 0 which means unlimited.
|
||||
* </p>
|
||||
*/
|
||||
int maxIdleSecs() default 0;
|
||||
|
||||
/**
|
||||
* The maximum time (in seconds) a cache entry is allowed to stay in the
|
||||
* cache.
|
||||
* <p>
|
||||
* This is not generally required as the cache entries are automatically
|
||||
* evicted when related data changes are committed.
|
||||
* </p>
|
||||
* <p>
|
||||
* This defaults to 0 which means unlimited.
|
||||
* </p>
|
||||
*/
|
||||
int maxSecsToLive() default 0;
|
||||
}
|
||||
|
||||
@@ -6,8 +6,10 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
*
|
||||
* Deprecated - please use @DbHstore instead.
|
||||
* @see DbHstore
|
||||
*/
|
||||
@Deprecated
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface ColumnHstore {
|
||||
|
||||
@@ -1,31 +1,34 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* For a timestamp property that is set to the datetime when the entity is
|
||||
* created/inserted.
|
||||
* <p>
|
||||
* An alternative to using this annotation would be to use insertable=false,
|
||||
* updateable=false with @Column and have the DB insert the current time
|
||||
* (default value on the DB column is SYSTIME etc).
|
||||
* </p>
|
||||
* <p>
|
||||
* The downside to this approach is that the inserted entity does not have the
|
||||
* timestamp value after the insert has occurred. You need to fetch the entity
|
||||
* back to get the inserted timestamp if you want to used it.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* @Column(insertable = false, updateable = false)
|
||||
* Timestamp cretimestamp;
|
||||
* </pre>
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface CreatedTimestamp {
|
||||
|
||||
};
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* For a timestamp property that is set to the datetime when the entity is
|
||||
* created/inserted.
|
||||
* <p>
|
||||
* An alternative to using this annotation would be to use insertable=false,
|
||||
* updateable=false with @Column and have the DB insert the current time
|
||||
* (default value on the DB column is SYSTIME etc).
|
||||
* </p>
|
||||
* <p>
|
||||
* The downside to this approach is that the inserted entity does not have the
|
||||
* timestamp value after the insert has occurred. You need to fetch the entity
|
||||
* back to get the inserted timestamp if you want to used it.
|
||||
* </p>
|
||||
*
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* @CreatedTimestamp
|
||||
* Timestamp whenCreated;
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface CreatedTimestamp {
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Used for mapping a Map<String,String> type property to Postgres HSTORE data type.
|
||||
* <p>
|
||||
* The Map property should have keys and values of type String.
|
||||
* </p>
|
||||
*
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* @DbHstore
|
||||
* Map<String, String> tags;
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface DbHstore {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify a property holding JSON content.
|
||||
* <p>
|
||||
* By default the content will be stored in a DB Clob except on Postgres where DB JSON type is used.
|
||||
* </p>
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Store as JSON on Postgres or Clob on other databases
|
||||
* @DbJson
|
||||
* Map<String,Object> content;
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Example with JSONB storage</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Store as JSONB on Postgres or Clob on other databases
|
||||
* @DbJson(storage = DbJsonType.JSONB)
|
||||
* Map<String,Object> content;
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface DbJson {
|
||||
|
||||
/**
|
||||
* Specify the database type used to store the JSON content.
|
||||
*/
|
||||
DbJsonType storage() default DbJsonType.JSON;
|
||||
|
||||
/**
|
||||
* For VARCHAR storage specify the column length (defaults to 3000).
|
||||
*/
|
||||
int length() default 0;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify a property holding JSON content.
|
||||
* <p>
|
||||
* The content will be stored on Postgres using it's JSONB type and as Clob for other databases.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is equivalent to using <code>@DbJson(storage = DbJsonType.JSONB)</code>
|
||||
* </p>
|
||||
*
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Store as JSONB on Postgres or Clob on other databases
|
||||
* @DbJsonB
|
||||
* Map<String,Object> content;
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Equivalent to:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Store as JSONB on Postgres or Clob on other databases
|
||||
* @DbJson(storage = DbJsonType.JSONB)
|
||||
* Map<String,Object> content;
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface DbJsonB {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
/**
|
||||
* Specify the DB storage type used to store JSON content.
|
||||
*/
|
||||
public enum DbJsonType {
|
||||
|
||||
/**
|
||||
* Store as JSON on Postgres and for other databases store as CLOB.
|
||||
*/
|
||||
JSON,
|
||||
|
||||
/**
|
||||
* Store as JSONB on Postgres and for other databases store as CLOB.
|
||||
*/
|
||||
JSONB,
|
||||
|
||||
/**
|
||||
* Store as database VARCHAR.
|
||||
*/
|
||||
VARCHAR,
|
||||
|
||||
/**
|
||||
* Store as database CLOB.
|
||||
*/
|
||||
CLOB,
|
||||
|
||||
/**
|
||||
* Store as database BLOB.
|
||||
*/
|
||||
BLOB
|
||||
}
|
||||
@@ -1,31 +1,31 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify property name to db column mapping for Embedded beans.
|
||||
* <p>
|
||||
* This is designed to be easier to use than the AttributeOverride annotation in
|
||||
* standard JPA.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface EmbeddedColumns {
|
||||
|
||||
/**
|
||||
* A list of property names mapped to DB columns.
|
||||
* <p>
|
||||
* For example <code>currency=IN_CURR, amount=IN_AMOUNT</code>
|
||||
* </p>
|
||||
* <p>
|
||||
* Where currency and amount are properties and IN_CURR and IN_AMOUNT are the
|
||||
* respective DB columns these properties will be mapped to.
|
||||
* </p>
|
||||
*/
|
||||
String columns() default "";
|
||||
|
||||
};
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify property name to db column mapping for Embedded beans.
|
||||
* <p>
|
||||
* This is designed to be easier to use than the AttributeOverride annotation in
|
||||
* standard JPA.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface EmbeddedColumns {
|
||||
|
||||
/**
|
||||
* A list of property names mapped to DB columns.
|
||||
* <p>
|
||||
* For example <code>currency=IN_CURR, amount=IN_AMOUNT</code>
|
||||
* </p>
|
||||
* <p>
|
||||
* Where currency and amount are properties and IN_CURR and IN_AMOUNT are the
|
||||
* respective DB columns these properties will be mapped to.
|
||||
* </p>
|
||||
*/
|
||||
String columns() default "";
|
||||
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify that the property is stored in encrypted form.
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Encrypted {
|
||||
|
||||
/**
|
||||
* When true try to use DB encryption rather than local java encryption.
|
||||
*/
|
||||
boolean dbEncryption() default true;
|
||||
|
||||
/**
|
||||
* Used to specify the DB column length.
|
||||
*/
|
||||
int dbLength() default 0;
|
||||
};
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify that the property is stored in encrypted form.
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Encrypted {
|
||||
|
||||
/**
|
||||
* When true try to use DB encryption rather than local java encryption.
|
||||
*/
|
||||
boolean dbEncryption() default true;
|
||||
|
||||
/**
|
||||
* Used to specify the DB column length.
|
||||
*/
|
||||
int dbLength() default 0;
|
||||
}
|
||||
|
||||
@@ -1,90 +1,90 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* For mapping the values of an Enum to and from Database values.
|
||||
* <p>
|
||||
* Also refer to the {@link EnumValue} approach which probably the preferred now
|
||||
* (preferred over using this EnumMapping annotation).
|
||||
* </p>
|
||||
* <p>
|
||||
* Both of the approaches defined in the JPA have significant problems!!!
|
||||
* </p>
|
||||
* <p>
|
||||
* Using the ordinal value is VERY RISKY because that depends on the compile
|
||||
* order of the enum values. Aka if you change the order of the enum values you
|
||||
* have changed their ordinal values and now your DB values are WRONG - a HUGE
|
||||
* disaster!!!.
|
||||
* </p>
|
||||
* <p>
|
||||
* Using the String values of enums is fairly restrictive because in a Database
|
||||
* these values are usually truncated into short codes (e.g. "A" short for
|
||||
* "ACTIVE") so space used in the database is minimised. Making your enum names
|
||||
* match the database values would give them very short less meaningful names -
|
||||
* not a great solution.
|
||||
* </p>
|
||||
* <p>
|
||||
* You can use this annotation to control the mapping of your enums to database
|
||||
* values.
|
||||
* </p>
|
||||
* <p>
|
||||
* The design of this using nameValuePairs is not optimal for safety or
|
||||
* refactoring so if you have a better solution I'm all ears. The other
|
||||
* solutions would probably involve modifying each enumeration with a method
|
||||
* which may be ok.
|
||||
* </p>
|
||||
* <p>
|
||||
* An example mapping the UserState enum.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* ...
|
||||
* @EnumMapping(nameValuePairs="NEW=N, ACTIVE=A, INACTIVE=I")
|
||||
* public enum UserState {
|
||||
* NEW,
|
||||
* ACTIVE,
|
||||
* INACTIVE;
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @see EnumValue
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface EnumMapping {
|
||||
|
||||
/**
|
||||
* A comma delimited list of name=value pairs.
|
||||
* <p>
|
||||
* e.g. "ACTIVE=A, INACTIVE=I, NEW=N".
|
||||
* </p>
|
||||
* <p>
|
||||
* Where ACTIVE, INACTIVE and NEW are the enumeration values and "A", "I" and
|
||||
* "N" are the database values.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is not really an optimal approach so if you have a better one I'm all
|
||||
* ears - thanks.
|
||||
* </p>
|
||||
*/
|
||||
String nameValuePairs();
|
||||
|
||||
/**
|
||||
* Defaults to mapping values to database VARCHAR type. If this is set to true
|
||||
* then the values will be converted to INTEGER and mapped to the database
|
||||
* integer type.
|
||||
* <p>
|
||||
* e.g. "ACTIVE=1, INACTIVE=0, NEW=2".
|
||||
* </p>
|
||||
*/
|
||||
boolean integerType() default false;
|
||||
|
||||
/**
|
||||
* The length of DB column if mapping to string values.
|
||||
*/
|
||||
int length() default 0;
|
||||
};
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* For mapping the values of an Enum to and from Database values.
|
||||
* <p>
|
||||
* Also refer to the {@link EnumValue} approach which probably the preferred now
|
||||
* (preferred over using this EnumMapping annotation).
|
||||
* </p>
|
||||
* <p>
|
||||
* Both of the approaches defined in the JPA have significant problems!!!
|
||||
* </p>
|
||||
* <p>
|
||||
* Using the ordinal value is VERY RISKY because that depends on the compile
|
||||
* order of the enum values. Aka if you change the order of the enum values you
|
||||
* have changed their ordinal values and now your DB values are WRONG - a HUGE
|
||||
* disaster!!!.
|
||||
* </p>
|
||||
* <p>
|
||||
* Using the String values of enums is fairly restrictive because in a Database
|
||||
* these values are usually truncated into short codes (e.g. "A" short for
|
||||
* "ACTIVE") so space used in the database is minimised. Making your enum names
|
||||
* match the database values would give them very short less meaningful names -
|
||||
* not a great solution.
|
||||
* </p>
|
||||
* <p>
|
||||
* You can use this annotation to control the mapping of your enums to database
|
||||
* values.
|
||||
* </p>
|
||||
* <p>
|
||||
* The design of this using nameValuePairs is not optimal for safety or
|
||||
* refactoring so if you have a better solution I'm all ears. The other
|
||||
* solutions would probably involve modifying each enumeration with a method
|
||||
* which may be ok.
|
||||
* </p>
|
||||
* <p>
|
||||
* An example mapping the UserState enum.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* ...
|
||||
* @EnumMapping(nameValuePairs="NEW=N, ACTIVE=A, INACTIVE=I")
|
||||
* public enum UserState {
|
||||
* NEW,
|
||||
* ACTIVE,
|
||||
* INACTIVE;
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @see EnumValue
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface EnumMapping {
|
||||
|
||||
/**
|
||||
* A comma delimited list of name=value pairs.
|
||||
* <p>
|
||||
* e.g. "ACTIVE=A, INACTIVE=I, NEW=N".
|
||||
* </p>
|
||||
* <p>
|
||||
* Where ACTIVE, INACTIVE and NEW are the enumeration values and "A", "I" and
|
||||
* "N" are the database values.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is not really an optimal approach so if you have a better one I'm all
|
||||
* ears - thanks.
|
||||
* </p>
|
||||
*/
|
||||
String nameValuePairs();
|
||||
|
||||
/**
|
||||
* Defaults to mapping values to database VARCHAR type. If this is set to true
|
||||
* then the values will be converted to INTEGER and mapped to the database
|
||||
* integer type.
|
||||
* <p>
|
||||
* e.g. "ACTIVE=1, INACTIVE=0, NEW=2".
|
||||
* </p>
|
||||
*/
|
||||
boolean integerType() default false;
|
||||
|
||||
/**
|
||||
* The length of DB column if mapping to string values.
|
||||
*/
|
||||
int length() default 0;
|
||||
}
|
||||
|
||||
@@ -1,46 +1,48 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Enables you to specify a value to use to persist for an enum value.
|
||||
*
|
||||
* <pre class="code">
|
||||
* public enum Status {
|
||||
* @EnumValue("N")
|
||||
* NEW,
|
||||
*
|
||||
* @EnumValue("A")
|
||||
* ACTIVE,
|
||||
*
|
||||
* @EnumValue("I")
|
||||
* INACTIVE,
|
||||
* }
|
||||
*
|
||||
* </pre>
|
||||
* <p>
|
||||
* This is an alternative to using the JPA standard approach or Ebean's
|
||||
* {@link EnumMapping} annotation.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that if all the EnumValue values are parsable as Integers then Ebean
|
||||
* will persist and fetch them as integers - otherwise they will be persisted
|
||||
* and fetched as strings.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface EnumValue {
|
||||
|
||||
/**
|
||||
* Specify the value to persist for a specific enum value.
|
||||
* <p>
|
||||
* If all the values are parsable as Integers then Ebean will persist and
|
||||
* fetch them as integers rather than strings.
|
||||
* </p>
|
||||
*/
|
||||
String value();
|
||||
};
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Enables you to specify a value to use to persist for an enum value.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* public enum Status {
|
||||
*
|
||||
* @EnumValue("N")
|
||||
* NEW,
|
||||
*
|
||||
* @EnumValue("A")
|
||||
* ACTIVE,
|
||||
*
|
||||
* @EnumValue("I")
|
||||
* INACTIVE,
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* This is an alternative to using the JPA standard approach or Ebean's
|
||||
* {@link EnumMapping} annotation.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that if all the EnumValue values are parsable as Integers then Ebean
|
||||
* will persist and fetch them as integers - otherwise they will be persisted
|
||||
* and fetched as strings.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface EnumValue {
|
||||
|
||||
/**
|
||||
* Specify the value to persist for a specific enum value.
|
||||
* <p>
|
||||
* If all the values are parsable as Integers then Ebean will persist and
|
||||
* fetch them as integers rather than strings.
|
||||
* </p>
|
||||
*/
|
||||
String value();
|
||||
}
|
||||
|
||||
@@ -12,17 +12,17 @@ import java.lang.annotation.Target;
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Expose {
|
||||
|
||||
/**
|
||||
* If {@code true}, the field marked with this annotation is written out in the JSON while
|
||||
* serializing. If {@code false}, the field marked with this annotation is skipped from the
|
||||
* serialized output. Defaults to {@code true}.
|
||||
*/
|
||||
public boolean serialize() default true;
|
||||
/**
|
||||
* If {@code true}, the field marked with this annotation is written out in the JSON while
|
||||
* serializing. If {@code false}, the field marked with this annotation is skipped from the
|
||||
* serialized output. Defaults to {@code true}.
|
||||
*/
|
||||
boolean serialize() default true;
|
||||
|
||||
/**
|
||||
* If {@code true}, the field marked with this annotation is deserialized from the JSON.
|
||||
* If {@code false}, the field marked with this annotation is skipped during deserialization.
|
||||
* Defaults to {@code true}.
|
||||
*/
|
||||
public boolean deserialize() default true;
|
||||
/**
|
||||
* If {@code true}, the field marked with this annotation is deserialized from the JSON.
|
||||
* If {@code false}, the field marked with this annotation is skipped during deserialization.
|
||||
* Defaults to {@code true}.
|
||||
*/
|
||||
boolean deserialize() default true;
|
||||
}
|
||||
@@ -1,103 +1,106 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.avaje.ebean.Query;
|
||||
|
||||
/**
|
||||
* Assign to a property to be based on a SQL formula.
|
||||
* <p>
|
||||
* This is typically a SQL Literal value, SQL case statement, SQL function or
|
||||
* similar.
|
||||
* </p>
|
||||
* <p>
|
||||
* Any property based on a formula becomes a read only property.
|
||||
* </p>
|
||||
* <p>
|
||||
* You may also put use the Transient annotation with the Formula annotation.
|
||||
* The effect of the Transient annotation in this case is that the formula will
|
||||
* <b>NOT</b> be included in queries by default - you have to explicitly include
|
||||
* it via {@link Query#select(String)} or {@link Query#fetch(String, String, com.avaje.ebean.FetchConfig)}.
|
||||
* You may want to do this if the Formula is relatively expensive and only want
|
||||
* it included in the query when you explicitly state it.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // On the Order "master" bean
|
||||
* // ... a formula using the Order details
|
||||
* // ... sum(order_qty*unit_price)
|
||||
* @Transient
|
||||
* @Formula(select = "_b${ta}.total_amount", join = "join (select order_id, sum(order_qty*unit_price) as total_amount from o_order_detail group by order_id) as _b${ta} on _b${ta}.order_id = ${ta}.id")
|
||||
* Double totalAmount;
|
||||
*
|
||||
* </pre>
|
||||
* <p>
|
||||
* As the totalAmount formula is also Transient it is not included by default in
|
||||
* queries - it needs to be explicitly included.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // find by Id
|
||||
* Order o1 = Ebean.find(Order.class)
|
||||
* .select("id, totalAmount")
|
||||
* .setId(1).findUnique();
|
||||
*
|
||||
* // find list ... using totalAmount in the where clause
|
||||
* List<Order> list = Ebean.find(Order.class)
|
||||
* .select("id, totalAmount")
|
||||
* .where()
|
||||
* .eq("status", Order.Status.NEW)
|
||||
* .gt("totalAmount", 10)
|
||||
* .findList();
|
||||
*
|
||||
* // as a join from customer
|
||||
* List<Customer> l0 = Ebean.find(Customer.class)
|
||||
* .select("id, name")
|
||||
* .join("orders", "status, totalAmount")
|
||||
* .where()
|
||||
* .gt("id", 0)
|
||||
* .gt("orders.totalAmount", 10)
|
||||
* .findList();
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Formula {
|
||||
|
||||
/**
|
||||
* The SQL to be used in the SELECT part of the SQL to populate a property.
|
||||
*/
|
||||
String select();
|
||||
|
||||
/**
|
||||
* OPTIONAL - the SQL to be used in the JOIN part of the SQL to support the
|
||||
* formula.
|
||||
* <p>
|
||||
* This is commonly used to join a 'dynamic view' to support aggregation such
|
||||
* as count, sum etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* The join string should start with either "left outer join" or "join".
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* You will almost certainly use the "${ta}" as a place holder for the table
|
||||
* alias of the table you are joining back to (the "base table" of the entity
|
||||
* bean).
|
||||
* </p>
|
||||
* <p>
|
||||
* The example below is used to support a total count of topics created by a
|
||||
* user.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* join (select user_id, count(*) as topic_count from f_topic group by user_id) as _tc on _tc.user_id = ${ta}.id
|
||||
* </pre>
|
||||
*/
|
||||
String join() default "";
|
||||
|
||||
};
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.avaje.ebean.Query;
|
||||
|
||||
/**
|
||||
* Assign to a property to be based on a SQL formula.
|
||||
* <p>
|
||||
* This is typically a SQL Literal value, SQL case statement, SQL function or
|
||||
* similar.
|
||||
* </p>
|
||||
* <p>
|
||||
* Any property based on a formula becomes a read only property.
|
||||
* </p>
|
||||
* <p>
|
||||
* You may also put use the Transient annotation with the Formula annotation.
|
||||
* The effect of the Transient annotation in this case is that the formula will
|
||||
* <b>NOT</b> be included in queries by default - you have to explicitly include
|
||||
* it via {@link Query#select(String)} or {@link Query#fetch(String, String, com.avaje.ebean.FetchConfig)}.
|
||||
* You may want to do this if the Formula is relatively expensive and only want
|
||||
* it included in the query when you explicitly state it.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // On the Order "master" bean
|
||||
* // ... a formula using the Order details
|
||||
* // ... sum(order_qty*unit_price)
|
||||
* @Transient
|
||||
* @Formula(select = "_b${ta}.total_amount", join = "join (select order_id, sum(order_qty*unit_price) as total_amount from o_order_detail group by order_id) as _b${ta} on _b${ta}.order_id = ${ta}.id")
|
||||
* Double totalAmount;
|
||||
*
|
||||
* </pre>
|
||||
* <p>
|
||||
* As the totalAmount formula is also Transient it is not included by default in
|
||||
* queries - it needs to be explicitly included.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // find by Id
|
||||
* Order o1 = Ebean.find(Order.class)
|
||||
* .select("id, totalAmount")
|
||||
* .setId(1).findUnique();
|
||||
*
|
||||
* // find list ... using totalAmount in the where clause
|
||||
* List<Order> list = Ebean.find(Order.class)
|
||||
* .select("id, totalAmount")
|
||||
* .where()
|
||||
* .eq("status", Order.Status.NEW)
|
||||
* .gt("totalAmount", 10)
|
||||
* .findList();
|
||||
*
|
||||
* // as a join from customer
|
||||
* List<Customer> l0 = Ebean.find(Customer.class)
|
||||
* .select("id, name")
|
||||
* .fetch("orders", "status, totalAmount")
|
||||
* .where()
|
||||
* .gt("id", 0)
|
||||
* .gt("orders.totalAmount", 10)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Formula {
|
||||
|
||||
/**
|
||||
* The SQL to be used in the SELECT part of the SQL to populate a property.
|
||||
*/
|
||||
String select();
|
||||
|
||||
/**
|
||||
* OPTIONAL - the SQL to be used in the JOIN part of the SQL to support the
|
||||
* formula.
|
||||
* <p>
|
||||
* This is commonly used to join a 'dynamic view' to support aggregation such
|
||||
* as count, sum etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* The join string should start with either "left outer join" or "join".
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* You will almost certainly use the "${ta}" as a place holder for the table
|
||||
* alias of the table you are joining back to (the "base table" of the entity
|
||||
* bean).
|
||||
* </p>
|
||||
* <p>
|
||||
* The example below is used to support a total count of topics created by a
|
||||
* user.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* join (select user_id, count(*) as topic_count from f_topic group by user_id) as _tc on _tc.user_id = ${ta}.id
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
String join() default "";
|
||||
|
||||
}
|
||||
|
||||
@@ -14,11 +14,11 @@ import java.lang.annotation.Target;
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Index {
|
||||
|
||||
/**
|
||||
* Name of the index
|
||||
*
|
||||
* @return index name
|
||||
*/
|
||||
String value() default "";
|
||||
/**
|
||||
* Name of the index
|
||||
*
|
||||
* @return index name
|
||||
*/
|
||||
String value() default "";
|
||||
|
||||
}
|
||||
|
||||
@@ -1,37 +1,37 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* An Update statement for a particular entity bean type.
|
||||
* <p>
|
||||
* The update can either be a sql insert,update or delete statement with tables
|
||||
* and columns etc or the equivalent statement but with table names and columns
|
||||
* expressed as bean types and bean properties.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface NamedUpdate {
|
||||
|
||||
/**
|
||||
* The name of the update.
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* The insert, update or delete statement.
|
||||
*/
|
||||
String update();
|
||||
|
||||
/**
|
||||
* Set this to false if you do not want the cache to be notified. If true the
|
||||
* cache will invalidate appropriate objects from the cache (after a
|
||||
* successful transaction commit).
|
||||
*/
|
||||
boolean notifyCache() default true;
|
||||
|
||||
};
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* An Update statement for a particular entity bean type.
|
||||
* <p>
|
||||
* The update can either be a sql insert,update or delete statement with tables
|
||||
* and columns etc or the equivalent statement but with table names and columns
|
||||
* expressed as bean types and bean properties.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface NamedUpdate {
|
||||
|
||||
/**
|
||||
* The name of the update.
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* The insert, update or delete statement.
|
||||
*/
|
||||
String update();
|
||||
|
||||
/**
|
||||
* Set this to false if you do not want the cache to be notified. If true the
|
||||
* cache will invalidate appropriate objects from the cache (after a
|
||||
* successful transaction commit).
|
||||
*/
|
||||
boolean notifyCache() default true;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Holds an array of named Update statements for a particular entity bean type.
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface NamedUpdates {
|
||||
|
||||
/**
|
||||
* An array of named updates.
|
||||
*/
|
||||
NamedUpdate[] value();
|
||||
|
||||
};
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Holds an array of named Update statements for a particular entity bean type.
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface NamedUpdates {
|
||||
|
||||
/**
|
||||
* An array of named updates.
|
||||
*/
|
||||
NamedUpdate[] value();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify that the elements of a OneToMany are private owned.
|
||||
* <p>
|
||||
* This means that if they are removed from the List/Set/Map they will be
|
||||
* deleted when their parent object is saved.
|
||||
* </p>
|
||||
* <p>
|
||||
* This could also be described as deleting orphans - in that beans removed from
|
||||
* the List/Set/Map will be deleted automatically when the parent bean is saved.
|
||||
* They are considered 'orphans' when they have been removed from the collection
|
||||
* in that they are no longer associated/linked to their parent bean.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface PrivateOwned {
|
||||
|
||||
/**
|
||||
* Set this to false if you don't want cascade REMOVE on this relationship.
|
||||
* <p>
|
||||
* That is, by default PrivateOwned implicitly adds a cascade REMOVE to the
|
||||
* relationship and if you don't want that you need to set this to false.
|
||||
* </p>
|
||||
*/
|
||||
boolean cascadeRemove() default true;
|
||||
|
||||
};
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify that the elements of a OneToMany are private owned.
|
||||
* <p>
|
||||
* This means that if they are removed from the List/Set/Map they will be
|
||||
* deleted when their parent object is saved.
|
||||
* </p>
|
||||
* <p>
|
||||
* This could also be described as deleting orphans - in that beans removed from
|
||||
* the List/Set/Map will be deleted automatically when the parent bean is saved.
|
||||
* They are considered 'orphans' when they have been removed from the collection
|
||||
* in that they are no longer associated/linked to their parent bean.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface PrivateOwned {
|
||||
|
||||
/**
|
||||
* Set this to false if you don't want cascade REMOVE on this relationship.
|
||||
* <p>
|
||||
* That is, by default PrivateOwned implicitly adds a cascade REMOVE to the
|
||||
* relationship and if you don't want that you need to set this to false.
|
||||
* </p>
|
||||
*/
|
||||
boolean cascadeRemove() default true;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify explicit sql for multiple select statements. Need to use this if you
|
||||
* have more than one SqlSelect for a given bean.
|
||||
* <p>
|
||||
* FUTURE: Support explicit sql for SqlInsert, SqlUpdate and SqlDelete.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Sql {
|
||||
|
||||
/**
|
||||
* The sql select statements.
|
||||
*/
|
||||
SqlSelect[] select() default { @SqlSelect };
|
||||
|
||||
};
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify explicit sql for multiple select statements. Need to use this if you
|
||||
* have more than one SqlSelect for a given bean.
|
||||
* <p>
|
||||
* FUTURE: Support explicit sql for SqlInsert, SqlUpdate and SqlDelete.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Sql {
|
||||
|
||||
/**
|
||||
* The sql select statements.
|
||||
*/
|
||||
SqlSelect[] select() default { @SqlSelect };
|
||||
|
||||
}
|
||||
|
||||
@@ -1,298 +1,298 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.avaje.ebean.Query;
|
||||
|
||||
/**
|
||||
* Specify an explicit sql select statement to use for querying an entity bean.
|
||||
* <p>
|
||||
* The reason for using explicit sql is that you want better control over the
|
||||
* exact sql or sql that Ebean does not generate for you (such as group by,
|
||||
* union, intersection, window functions, recursive queries).
|
||||
* </p>
|
||||
* <p>
|
||||
* An example of two sql select queries deployed on the ReportTopic entity bean.
|
||||
* The first one has no name specified so it becomes the default query. The
|
||||
* second query extends the first adding a where clause with a named parameter.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* ...
|
||||
* @Entity
|
||||
* @Sql(select = {
|
||||
* @SqlSelect(query =
|
||||
* "select t.id, t.title, count(p.id) as score "+
|
||||
* "from f_topic t "+
|
||||
* "join f_topic_post p on p.topic_id = t.id "+
|
||||
* "group by t.id, t.title"),
|
||||
* @SqlSelect(
|
||||
* name = "with.title",
|
||||
* extend = "default",
|
||||
* debug = true,
|
||||
* where = "title like :likeTitle")
|
||||
* })
|
||||
* public class ReportTopic
|
||||
* @Id Integer id;
|
||||
* String title;
|
||||
* Double score;
|
||||
* ...
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* An example using the first "default" query.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* List<ReportTopic> list =
|
||||
* Ebean.find(ReportTopic.class)
|
||||
* .having().gt("score", 0)
|
||||
* .findList();
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* The resulting sql, note the having clause has been added.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* select t.id, t.title, count(p.id) as score
|
||||
* from f_topic t join f_topic_post p on p.topic_id = t.id
|
||||
* group by t.id, t.title
|
||||
* having count(p.id) > ?
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* An example using the second query. Note the named parameter "likeTitle" must
|
||||
* be set.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* List<ReportTopic> list =
|
||||
* Ebean.find(ReportTopic.class, "with.title")
|
||||
* .set("likeTitle", "a%")
|
||||
* .findList();
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Ebean tries to parse the sql in the query to determine 4 things
|
||||
* <li>Location for inserting WHERE expressions (if required)</li>
|
||||
* <li>Location for inserting HAVING expressions (if required)</li>
|
||||
* <li>Mapping of columns to bean properties</li>
|
||||
* <li>The order by clause</li>
|
||||
* </p>
|
||||
* <p>
|
||||
* If Ebean is unable to parse out this information (perhaps because the sql
|
||||
* contains multiple select from keywords etc) then you need to manually specify
|
||||
* it.
|
||||
* </p>
|
||||
* <p>
|
||||
* Insert ${where} or ${andWhere} into the location where Ebean can insert any
|
||||
* expressions added to the where clause. Use ${andWhere} if the sql already has
|
||||
* the WHERE keyword and Ebean will instead start with a AND keyword.
|
||||
* </p>
|
||||
* <p>
|
||||
* Insert ${having} or ${andHaving} into the location where Ebean can insert any
|
||||
* expressions added to the having clause. Use ${andHaving} if the sql already
|
||||
* has a HAVING keyword and Ebean will instead start with a AND keyword.
|
||||
* </p>
|
||||
* <p>
|
||||
* Use the columnMapping property if Ebean is unable to determine the columns
|
||||
* and map them to bean properties.
|
||||
* </p>
|
||||
* <p>
|
||||
* Example with ${andWhere} & ${having}.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* @SqlSelect(
|
||||
* name = "explicit.where",
|
||||
* query =
|
||||
* "select t.id, t.title, count(p.id) as score "+
|
||||
* "from f_topic t, f_topic_post p "+
|
||||
* "where p.topic_id = t.id ${andWhere} "+
|
||||
* "group by t.id, t.title ${having}"),
|
||||
* </pre>
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Deprecated
|
||||
public @interface SqlSelect {
|
||||
|
||||
/**
|
||||
* The name of the query. If left blank this is assumed to be the default
|
||||
* query for this bean type.
|
||||
* <p>
|
||||
* This will default to "default" and in that case becomes the default query
|
||||
* used for the bean.
|
||||
* </p>
|
||||
*/
|
||||
String name() default "default";
|
||||
|
||||
/**
|
||||
* The tableAlias used when adding where expressions to the query.
|
||||
*/
|
||||
String tableAlias() default "";
|
||||
|
||||
/**
|
||||
* The sql select statement.
|
||||
* <p>
|
||||
* If this query <em>extends</em> another then this string is appended to the
|
||||
* parent query string. Often when using <em>extend</em> you will leave the
|
||||
* query part blank and just specify a where and/or having clauses.
|
||||
* </p>
|
||||
* <p>
|
||||
* This sql <em>CAN NOT</em> contain named parameters. You have to put these
|
||||
* in the separate where and/or having sections.
|
||||
* </p>
|
||||
* <p>
|
||||
* Ebean automatically tries to determine the location in the sql string for
|
||||
* putting in additional where or having clauses. If Ebean is unable to
|
||||
* successfully determine this then you have to explicitly specify these
|
||||
* locations by including
|
||||
* <em>${where} or ${andWhere} and ${having} or ${andHaving}</em> in the sql.
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>${where}</b> location of where clause (and will add WHERE ... ) <br/>
|
||||
* Use this when there is no where clause in the sql. If expressions are added
|
||||
* to the where clause Ebean will put them in at this location starting with
|
||||
* the WHERE keyword.
|
||||
* <p>
|
||||
* <p>
|
||||
* <b>${andWhere}</b> <br/>
|
||||
* Use this instead of ${where} if there IS an existing where clause in the
|
||||
* sql. Ebean will add the expressions starting with the AND keyword.
|
||||
* <p>
|
||||
* <b>${having}</b> location of having clause (and will add HAVING... ) <br/>
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>${andHaving}</b> <br/>
|
||||
* Use this instead of ${having} when there IS an existing HAVING clause.
|
||||
* Ebean will add the expressions starting with the AND keyword.
|
||||
* </p>
|
||||
* <p>
|
||||
* You can include one of ${where} OR ${andWhere} but not both.
|
||||
* </p>
|
||||
* <p>
|
||||
* You can include one of ${having} OR ${andHaving} but not both.
|
||||
* </p>
|
||||
*/
|
||||
String query() default "";
|
||||
|
||||
/**
|
||||
* Specify the name of a sql-select query that this one 'extends'.
|
||||
* <p>
|
||||
* When a query is extended the sql query contents are appended together. The
|
||||
* where and having clauses are NOT appended but overridden.
|
||||
* </p>
|
||||
*/
|
||||
String extend() default "";
|
||||
|
||||
/**
|
||||
* Specify a where clause typically containing named parameters.
|
||||
* <p>
|
||||
* If a where clause is specified with named parameters then they will need to
|
||||
* be set on the query via {@link Query#setParameter(String, Object)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* In the example below the query specifies a where clause that includes a
|
||||
* named parameter "likeTitle".
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* ...
|
||||
* @Entity
|
||||
* @Sql(select = {
|
||||
* ...
|
||||
* @SqlSelect(
|
||||
* name = "with.title",
|
||||
* extend = "default",
|
||||
* debug = true,
|
||||
* where = "title like :likeTitle")
|
||||
* })
|
||||
* public class ReportTopic
|
||||
* ...
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Example use of the above named query.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* Query<ReportTopic> query0 = Ebean.createQuery(ReportTopic.class, "with.title");
|
||||
*
|
||||
* query0.set("likeTitle", "Bana%");
|
||||
*
|
||||
* List<ReportTopic> list0 = query0.findList();
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
String where() default "";
|
||||
|
||||
/**
|
||||
* Specify a having clause typically containing named parameters.
|
||||
* <p>
|
||||
* If a having clause is specified with named parameters then they will need
|
||||
* to be set on the query via {@link Query#setParameter(String, Object)}.
|
||||
* </p>
|
||||
*/
|
||||
String having() default "";
|
||||
|
||||
/**
|
||||
* (Optional) Explicitly specify column to property mapping.
|
||||
* <p>
|
||||
* This is required when Ebean is unable to parse the sql. This could occur if
|
||||
* the sql contains multiple select keywords etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* Specify the columns and property names they map to in the format.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* column1 propertyName1, column2 propertyName2, ...
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Optionally put a AS keyword between the column and property.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // the AS keyword is optional
|
||||
* column1 AS propertyName1, column2 propertyName2, ...
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* <b>column</b> should contain the table alias if there is one
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>propertyName</b> should match the property name.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Example mapping 5 columns to properties.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* columnMapping="t.id, t.bug_body description, t.bug_title as title, count(p.id) as scoreValue",
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Without this set Ebean will parse the sql looking for the select clause and
|
||||
* try to map the columns to property names. It is expected that Ebean will
|
||||
* not be able to successfully parse some sql and for those cases you should
|
||||
* specify the column to property mapping explicitly.
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
String columnMapping() default "";
|
||||
|
||||
/**
|
||||
* Set this to true to have debug output when Ebean parses the sql-select.
|
||||
*/
|
||||
boolean debug() default false;
|
||||
};
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.avaje.ebean.Query;
|
||||
|
||||
/**
|
||||
* Specify an explicit sql select statement to use for querying an entity bean.
|
||||
* <p>
|
||||
* The reason for using explicit sql is that you want better control over the
|
||||
* exact sql or sql that Ebean does not generate for you (such as group by,
|
||||
* union, intersection, window functions, recursive queries).
|
||||
* </p>
|
||||
* <p>
|
||||
* An example of two sql select queries deployed on the ReportTopic entity bean.
|
||||
* The first one has no name specified so it becomes the default query. The
|
||||
* second query extends the first adding a where clause with a named parameter.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* ...
|
||||
* @Entity
|
||||
* @Sql(select = {
|
||||
* @SqlSelect(query =
|
||||
* "select t.id, t.title, count(p.id) as score "+
|
||||
* "from f_topic t "+
|
||||
* "join f_topic_post p on p.topic_id = t.id "+
|
||||
* "group by t.id, t.title"),
|
||||
* @SqlSelect(
|
||||
* name = "with.title",
|
||||
* extend = "default",
|
||||
* debug = true,
|
||||
* where = "title like :likeTitle")
|
||||
* })
|
||||
* public class ReportTopic
|
||||
* @Id Integer id;
|
||||
* String title;
|
||||
* Double score;
|
||||
* ...
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* An example using the first "default" query.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* List<ReportTopic> list =
|
||||
* Ebean.find(ReportTopic.class)
|
||||
* .having().gt("score", 0)
|
||||
* .findList();
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* The resulting sql, note the having clause has been added.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* select t.id, t.title, count(p.id) as score
|
||||
* from f_topic t join f_topic_post p on p.topic_id = t.id
|
||||
* group by t.id, t.title
|
||||
* having count(p.id) > ?
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* An example using the second query. Note the named parameter "likeTitle" must
|
||||
* be set.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* List<ReportTopic> list =
|
||||
* Ebean.find(ReportTopic.class, "with.title")
|
||||
* .set("likeTitle", "a%")
|
||||
* .findList();
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Ebean tries to parse the sql in the query to determine 4 things
|
||||
* <li>Location for inserting WHERE expressions (if required)</li>
|
||||
* <li>Location for inserting HAVING expressions (if required)</li>
|
||||
* <li>Mapping of columns to bean properties</li>
|
||||
* <li>The order by clause</li>
|
||||
* </p>
|
||||
* <p>
|
||||
* If Ebean is unable to parse out this information (perhaps because the sql
|
||||
* contains multiple select from keywords etc) then you need to manually specify
|
||||
* it.
|
||||
* </p>
|
||||
* <p>
|
||||
* Insert ${where} or ${andWhere} into the location where Ebean can insert any
|
||||
* expressions added to the where clause. Use ${andWhere} if the sql already has
|
||||
* the WHERE keyword and Ebean will instead start with a AND keyword.
|
||||
* </p>
|
||||
* <p>
|
||||
* Insert ${having} or ${andHaving} into the location where Ebean can insert any
|
||||
* expressions added to the having clause. Use ${andHaving} if the sql already
|
||||
* has a HAVING keyword and Ebean will instead start with a AND keyword.
|
||||
* </p>
|
||||
* <p>
|
||||
* Use the columnMapping property if Ebean is unable to determine the columns
|
||||
* and map them to bean properties.
|
||||
* </p>
|
||||
* <p>
|
||||
* Example with ${andWhere} & ${having}.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* @SqlSelect(
|
||||
* name = "explicit.where",
|
||||
* query =
|
||||
* "select t.id, t.title, count(p.id) as score "+
|
||||
* "from f_topic t, f_topic_post p "+
|
||||
* "where p.topic_id = t.id ${andWhere} "+
|
||||
* "group by t.id, t.title ${having}"),
|
||||
* </pre>
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Deprecated
|
||||
public @interface SqlSelect {
|
||||
|
||||
/**
|
||||
* The name of the query. If left blank this is assumed to be the default
|
||||
* query for this bean type.
|
||||
* <p>
|
||||
* This will default to "default" and in that case becomes the default query
|
||||
* used for the bean.
|
||||
* </p>
|
||||
*/
|
||||
String name() default "default";
|
||||
|
||||
/**
|
||||
* The tableAlias used when adding where expressions to the query.
|
||||
*/
|
||||
String tableAlias() default "";
|
||||
|
||||
/**
|
||||
* The sql select statement.
|
||||
* <p>
|
||||
* If this query <em>extends</em> another then this string is appended to the
|
||||
* parent query string. Often when using <em>extend</em> you will leave the
|
||||
* query part blank and just specify a where and/or having clauses.
|
||||
* </p>
|
||||
* <p>
|
||||
* This sql <em>CAN NOT</em> contain named parameters. You have to put these
|
||||
* in the separate where and/or having sections.
|
||||
* </p>
|
||||
* <p>
|
||||
* Ebean automatically tries to determine the location in the sql string for
|
||||
* putting in additional where or having clauses. If Ebean is unable to
|
||||
* successfully determine this then you have to explicitly specify these
|
||||
* locations by including
|
||||
* <em>${where} or ${andWhere} and ${having} or ${andHaving}</em> in the sql.
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>${where}</b> location of where clause (and will add WHERE ... ) <br/>
|
||||
* Use this when there is no where clause in the sql. If expressions are added
|
||||
* to the where clause Ebean will put them in at this location starting with
|
||||
* the WHERE keyword.
|
||||
* <p>
|
||||
* <p>
|
||||
* <b>${andWhere}</b> <br/>
|
||||
* Use this instead of ${where} if there IS an existing where clause in the
|
||||
* sql. Ebean will add the expressions starting with the AND keyword.
|
||||
* <p>
|
||||
* <b>${having}</b> location of having clause (and will add HAVING... ) <br/>
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>${andHaving}</b> <br/>
|
||||
* Use this instead of ${having} when there IS an existing HAVING clause.
|
||||
* Ebean will add the expressions starting with the AND keyword.
|
||||
* </p>
|
||||
* <p>
|
||||
* You can include one of ${where} OR ${andWhere} but not both.
|
||||
* </p>
|
||||
* <p>
|
||||
* You can include one of ${having} OR ${andHaving} but not both.
|
||||
* </p>
|
||||
*/
|
||||
String query() default "";
|
||||
|
||||
/**
|
||||
* Specify the name of a sql-select query that this one 'extends'.
|
||||
* <p>
|
||||
* When a query is extended the sql query contents are appended together. The
|
||||
* where and having clauses are NOT appended but overridden.
|
||||
* </p>
|
||||
*/
|
||||
String extend() default "";
|
||||
|
||||
/**
|
||||
* Specify a where clause typically containing named parameters.
|
||||
* <p>
|
||||
* If a where clause is specified with named parameters then they will need to
|
||||
* be set on the query via {@link Query#setParameter(String, Object)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* In the example below the query specifies a where clause that includes a
|
||||
* named parameter "likeTitle".
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* ...
|
||||
* @Entity
|
||||
* @Sql(select = {
|
||||
* ...
|
||||
* @SqlSelect(
|
||||
* name = "with.title",
|
||||
* extend = "default",
|
||||
* debug = true,
|
||||
* where = "title like :likeTitle")
|
||||
* })
|
||||
* public class ReportTopic
|
||||
* ...
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Example use of the above named query.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* Query<ReportTopic> query0 = Ebean.createQuery(ReportTopic.class, "with.title");
|
||||
*
|
||||
* query0.set("likeTitle", "Bana%");
|
||||
*
|
||||
* List<ReportTopic> list0 = query0.findList();
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
String where() default "";
|
||||
|
||||
/**
|
||||
* Specify a having clause typically containing named parameters.
|
||||
* <p>
|
||||
* If a having clause is specified with named parameters then they will need
|
||||
* to be set on the query via {@link Query#setParameter(String, Object)}.
|
||||
* </p>
|
||||
*/
|
||||
String having() default "";
|
||||
|
||||
/**
|
||||
* (Optional) Explicitly specify column to property mapping.
|
||||
* <p>
|
||||
* This is required when Ebean is unable to parse the sql. This could occur if
|
||||
* the sql contains multiple select keywords etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* Specify the columns and property names they map to in the format.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* column1 propertyName1, column2 propertyName2, ...
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Optionally put a AS keyword between the column and property.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // the AS keyword is optional
|
||||
* column1 AS propertyName1, column2 propertyName2, ...
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* <b>column</b> should contain the table alias if there is one
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>propertyName</b> should match the property name.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Example mapping 5 columns to properties.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* columnMapping="t.id, t.bug_body description, t.bug_title as title, count(p.id) as scoreValue",
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Without this set Ebean will parse the sql looking for the select clause and
|
||||
* try to map the columns to property names. It is expected that Ebean will
|
||||
* not be able to successfully parse some sql and for those cases you should
|
||||
* specify the column to property mapping explicitly.
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
String columnMapping() default "";
|
||||
|
||||
/**
|
||||
* Set this to true to have debug output when Ebean parses the sql-select.
|
||||
*/
|
||||
boolean debug() default false;
|
||||
}
|
||||
|
||||
@@ -125,4 +125,4 @@ public @interface Transactional {
|
||||
*/
|
||||
Class<? extends Throwable>[] noRollbackFor() default {};
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify the update mode for the specific entity type.
|
||||
* <p>
|
||||
* Control whether all 'loaded' properties are included in an Update or whether
|
||||
* just properties that have changed will be included in the update.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that the default can be set via ebean.properties.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* ## Set to update all loaded properties
|
||||
* ebean.updateChangesOnly=false
|
||||
* </pre>
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface UpdateMode {
|
||||
|
||||
/**
|
||||
* Set to false if you want to include all the 'loaded' properties in the
|
||||
* update. Otherwise, just the properties that have changed will be included
|
||||
* in the update.
|
||||
*/
|
||||
boolean updateChangesOnly() default true;
|
||||
|
||||
};
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify the update mode for the specific entity type.
|
||||
* <p>
|
||||
* Control whether all 'loaded' properties are included in an Update or whether
|
||||
* just properties that have changed will be included in the update.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that the default can be set via ebean.properties.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* ## Set to update all loaded properties
|
||||
* ebean.updateChangesOnly=false
|
||||
* </pre>
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface UpdateMode {
|
||||
|
||||
/**
|
||||
* Set to false if you want to include all the 'loaded' properties in the
|
||||
* update. Otherwise, just the properties that have changed will be included
|
||||
* in the update.
|
||||
*/
|
||||
boolean updateChangesOnly() default true;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* For a timestamp property that is set to the datetime when the entity was last
|
||||
* updated.
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface UpdatedTimestamp {
|
||||
|
||||
};
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* For a timestamp property that is set to the datetime when the entity was last
|
||||
* updated.
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface UpdatedTimestamp {
|
||||
|
||||
}
|
||||
|
||||
@@ -1,51 +1,54 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Add an Literal to add to the where clause when a many property (List, Set or
|
||||
* Map) is loaded or refreshed.
|
||||
*
|
||||
* <pre class="code">
|
||||
* // on a OneToMany property...
|
||||
*
|
||||
* @OneToMany
|
||||
* @Where(clause = "deleted='y'")
|
||||
* List<Topic> topics;
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Note that you can include "${ta}" as a place holder for the table alias if
|
||||
* you need to include the table alias in the clause.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // ... including the ${ta} table alias placeholder...
|
||||
*
|
||||
* @OneToMany
|
||||
* @Where(clause = "${ta}.deleted='y'")
|
||||
* List<Topic> topics;
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* This will be added to the where clause when lazy loading the OneToMany
|
||||
* property or when there is a join to that OneToMany property.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Where {
|
||||
|
||||
/**
|
||||
* The clause added to the lazy load query.
|
||||
* <p>
|
||||
* Note that you can include "${ta}" as a place holder for the table alias if
|
||||
* you need to include the table alias in the clause.
|
||||
* </p>
|
||||
*/
|
||||
String clause();
|
||||
|
||||
};
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Add an Literal to add to the where clause when a many property (List, Set or
|
||||
* Map) is loaded or refreshed.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // on a OneToMany property...
|
||||
*
|
||||
* @OneToMany
|
||||
* @Where(clause = "deleted='y'")
|
||||
* List<Topic> topics;
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Note that you can include "${ta}" as a place holder for the table alias if
|
||||
* you need to include the table alias in the clause.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* // ... including the ${ta} table alias placeholder...
|
||||
*
|
||||
* @OneToMany
|
||||
* @Where(clause = "${ta}.deleted='y'")
|
||||
* List<Topic> topics;
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* This will be added to the where clause when lazy loading the OneToMany
|
||||
* property or when there is a join to that OneToMany property.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Where {
|
||||
|
||||
/**
|
||||
* The clause added to the lazy load query.
|
||||
* <p>
|
||||
* Note that you can include "${ta}" as a place holder for the table alias if
|
||||
* you need to include the table alias in the clause.
|
||||
* </p>
|
||||
*/
|
||||
String clause();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,201 +1,201 @@
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.ExpressionList;
|
||||
|
||||
/**
|
||||
* Lazy loading capable Maps, Lists and Sets.
|
||||
* <p>
|
||||
* This also includes the ability to listen for additions and removals to or
|
||||
* from the Map Set or List. The purpose of gathering the additions and removals
|
||||
* is to support persisting ManyToMany objects. The additions and removals
|
||||
* become inserts and deletes from the intersection table.
|
||||
* </p>
|
||||
* <p>
|
||||
* Technically this is <em>NOT</em> an extension of
|
||||
* <em>java.util.Collection</em>. The reason being that java.util.Map is not a
|
||||
* Collection. I realise this makes this name confusing so I apologise for that.
|
||||
* </p>
|
||||
*/
|
||||
public interface BeanCollection<E> extends Serializable {
|
||||
|
||||
public enum ModifyListenMode {
|
||||
/** The common mode */
|
||||
NONE,
|
||||
/** Mode used for PrivateOwned */
|
||||
REMOVALS,
|
||||
/** Mode used for ManyToMany relationships */
|
||||
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.
|
||||
*/
|
||||
public boolean isEmptyAndUntouched();
|
||||
|
||||
/**
|
||||
* Return the bean that owns this collection.
|
||||
*/
|
||||
public EntityBean getOwnerBean();
|
||||
|
||||
/**
|
||||
* Return the bean property name this collection represents.
|
||||
*/
|
||||
public String getPropertyName();
|
||||
|
||||
/**
|
||||
* Check after the lazy load that the underlying collection is not null
|
||||
* (handle case where join to many not outer).
|
||||
* <p>
|
||||
* That is, if the collection was not loaded due to filterMany predicates etc
|
||||
* then make sure the collection is set to empty.
|
||||
* </p>
|
||||
*/
|
||||
public boolean checkEmptyLazyLoad();
|
||||
|
||||
/**
|
||||
* Return the filter (if any) that was used in building this collection.
|
||||
* <p>
|
||||
* This is so that the filter can be applied on refresh.
|
||||
* </p>
|
||||
*/
|
||||
public ExpressionList<?> getFilterMany();
|
||||
|
||||
/**
|
||||
* Set the filter that was used in building this collection.
|
||||
*/
|
||||
public void setFilterMany(ExpressionList<?> filterMany);
|
||||
|
||||
/**
|
||||
* Set a listener to be notified when the BeanCollection is first touched.
|
||||
*/
|
||||
public void setBeanCollectionTouched(BeanCollectionTouched notify);
|
||||
|
||||
/**
|
||||
* Return true if the collection has been registered with the batch loading context.
|
||||
*/
|
||||
public boolean isRegisteredWithLoadContext();
|
||||
|
||||
/**
|
||||
* Set the loader that will be used to lazy/query load this collection.
|
||||
* <p>
|
||||
* This is effectively the batch loading context this collection is registered with.
|
||||
* </p>
|
||||
*/
|
||||
public void setLoader(BeanCollectionLoader beanLoader);
|
||||
|
||||
/**
|
||||
* Set to true if you want the BeanCollection to be treated as read only. This
|
||||
* means no elements can be added or removed etc.
|
||||
*/
|
||||
public void setReadOnly(boolean readOnly);
|
||||
|
||||
/**
|
||||
* Return true if the collection should be treated as readOnly and no elements
|
||||
* can be added or removed etc.
|
||||
*/
|
||||
public boolean isReadOnly();
|
||||
|
||||
/**
|
||||
* Add the bean to the collection.
|
||||
* <p>
|
||||
* This is disallowed for BeanMap.
|
||||
* </p>
|
||||
*/
|
||||
public void internalAdd(Object bean);
|
||||
|
||||
/**
|
||||
* Return the number of elements in the List Set or Map.
|
||||
*/
|
||||
public int size();
|
||||
|
||||
/**
|
||||
* Return true if the List Set or Map is empty.
|
||||
*/
|
||||
public boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Returns the underlying collection of beans from the Set, Map or List.
|
||||
*/
|
||||
public Collection<E> getActualDetails();
|
||||
|
||||
/**
|
||||
* Returns the underlying entries so for Maps this is a collection of
|
||||
* Map.Entry.
|
||||
* <p>
|
||||
* For maps this returns the entrySet as we need the keys of the map.
|
||||
* </p>
|
||||
*/
|
||||
public Collection<?> getActualEntries();
|
||||
|
||||
/**
|
||||
* return true if there are real rows held. Return false is this is using
|
||||
* Deferred fetch to lazy load the rows and the rows have not yet been
|
||||
* fetched.
|
||||
*/
|
||||
public boolean isPopulated();
|
||||
|
||||
/**
|
||||
* Return true if this is a reference (lazy loading) bean collection. This is
|
||||
* the same as !isPopulated();
|
||||
*/
|
||||
public boolean isReference();
|
||||
|
||||
/**
|
||||
* Set modify listening on or off. This is used to keep track of objects that
|
||||
* have been added to or removed from the list set or map.
|
||||
* <p>
|
||||
* This is required only for ManyToMany collections. The additions and
|
||||
* deletions are used to insert or delete entries from the intersection table.
|
||||
* Otherwise modifyListening is false.
|
||||
* </p>
|
||||
*/
|
||||
public void setModifyListening(ModifyListenMode modifyListenMode);
|
||||
|
||||
/**
|
||||
* Add an object to the additions list.
|
||||
* <p>
|
||||
* This will potentially end up as an insert into a intersection table for a
|
||||
* ManyToMany.
|
||||
* </p>
|
||||
*/
|
||||
public void modifyAddition(E bean);
|
||||
|
||||
/**
|
||||
* Add an object to the deletions list.
|
||||
* <p>
|
||||
* This will potentially end up as an delete from an intersection table for a
|
||||
* ManyToMany.
|
||||
* </p>
|
||||
*/
|
||||
public void modifyRemoval(Object bean);
|
||||
|
||||
/**
|
||||
* Return the list of objects added to the list set or map. These will used to
|
||||
* insert rows into the intersection table of a ManyToMany.
|
||||
*/
|
||||
public Set<E> getModifyAdditions();
|
||||
|
||||
/**
|
||||
* Return the list of objects removed from the list set or map. These will
|
||||
* used to delete rows from the intersection table of a ManyToMany.
|
||||
*/
|
||||
public Set<E> getModifyRemovals();
|
||||
|
||||
/**
|
||||
* Reset the set of additions and deletions. This is called after the
|
||||
* additions and removals have been processed.
|
||||
*/
|
||||
public void modifyReset();
|
||||
}
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.ExpressionList;
|
||||
|
||||
/**
|
||||
* Lazy loading capable Maps, Lists and Sets.
|
||||
* <p>
|
||||
* This also includes the ability to listen for additions and removals to or
|
||||
* from the Map Set or List. The purpose of gathering the additions and removals
|
||||
* is to support persisting ManyToMany objects. The additions and removals
|
||||
* become inserts and deletes from the intersection table.
|
||||
* </p>
|
||||
* <p>
|
||||
* Technically this is <em>NOT</em> an extension of
|
||||
* <em>java.util.Collection</em>. The reason being that java.util.Map is not a
|
||||
* Collection. I realise this makes this name confusing so I apologise for that.
|
||||
* </p>
|
||||
*/
|
||||
public interface BeanCollection<E> extends Serializable {
|
||||
|
||||
enum ModifyListenMode {
|
||||
/** The common mode */
|
||||
NONE,
|
||||
/** Mode used for PrivateOwned */
|
||||
REMOVALS,
|
||||
/** Mode used for ManyToMany relationships */
|
||||
ALL
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the collection back to an empty state ready for reloading.
|
||||
* <p>
|
||||
* This is done as part of bean refresh.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
boolean isEmptyAndUntouched();
|
||||
|
||||
/**
|
||||
* Return the bean that owns this collection.
|
||||
*/
|
||||
EntityBean getOwnerBean();
|
||||
|
||||
/**
|
||||
* Return the bean property name this collection represents.
|
||||
*/
|
||||
String getPropertyName();
|
||||
|
||||
/**
|
||||
* Check after the lazy load that the underlying collection is not null
|
||||
* (handle case where join to many not outer).
|
||||
* <p>
|
||||
* That is, if the collection was not loaded due to filterMany predicates etc
|
||||
* then make sure the collection is set to empty.
|
||||
* </p>
|
||||
*/
|
||||
boolean checkEmptyLazyLoad();
|
||||
|
||||
/**
|
||||
* Return the filter (if any) that was used in building this collection.
|
||||
* <p>
|
||||
* This is so that the filter can be applied on refresh.
|
||||
* </p>
|
||||
*/
|
||||
ExpressionList<?> getFilterMany();
|
||||
|
||||
/**
|
||||
* Set the filter that was used in building this collection.
|
||||
*/
|
||||
void setFilterMany(ExpressionList<?> filterMany);
|
||||
|
||||
/**
|
||||
* Set a listener to be notified when the BeanCollection is first touched.
|
||||
*/
|
||||
void setBeanCollectionTouched(BeanCollectionTouched notify);
|
||||
|
||||
/**
|
||||
* Return true if the collection has been registered with the batch loading context.
|
||||
*/
|
||||
boolean isRegisteredWithLoadContext();
|
||||
|
||||
/**
|
||||
* Set the loader that will be used to lazy/query load this collection.
|
||||
* <p>
|
||||
* This is effectively the batch loading context this collection is registered with.
|
||||
* </p>
|
||||
*/
|
||||
void setLoader(BeanCollectionLoader beanLoader);
|
||||
|
||||
/**
|
||||
* Set to true if you want the BeanCollection to be treated as read only. This
|
||||
* means no elements can be added or removed etc.
|
||||
*/
|
||||
void setReadOnly(boolean readOnly);
|
||||
|
||||
/**
|
||||
* Return true if the collection should be treated as readOnly and no elements
|
||||
* can be added or removed etc.
|
||||
*/
|
||||
boolean isReadOnly();
|
||||
|
||||
/**
|
||||
* Add the bean to the collection.
|
||||
* <p>
|
||||
* This is disallowed for BeanMap.
|
||||
* </p>
|
||||
*/
|
||||
void internalAdd(Object bean);
|
||||
|
||||
/**
|
||||
* Return the number of elements in the List Set or Map.
|
||||
*/
|
||||
int size();
|
||||
|
||||
/**
|
||||
* Return true if the List Set or Map is empty.
|
||||
*/
|
||||
boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Returns the underlying collection of beans from the Set, Map or List.
|
||||
*/
|
||||
Collection<E> getActualDetails();
|
||||
|
||||
/**
|
||||
* Returns the underlying entries so for Maps this is a collection of
|
||||
* Map.Entry.
|
||||
* <p>
|
||||
* For maps this returns the entrySet as we need the keys of the map.
|
||||
* </p>
|
||||
*/
|
||||
Collection<?> getActualEntries();
|
||||
|
||||
/**
|
||||
* return true if there are real rows held. Return false is this is using
|
||||
* Deferred fetch to lazy load the rows and the rows have not yet been
|
||||
* fetched.
|
||||
*/
|
||||
boolean isPopulated();
|
||||
|
||||
/**
|
||||
* Return true if this is a reference (lazy loading) bean collection. This is
|
||||
* the same as !isPopulated();
|
||||
*/
|
||||
boolean isReference();
|
||||
|
||||
/**
|
||||
* Set modify listening on or off. This is used to keep track of objects that
|
||||
* have been added to or removed from the list set or map.
|
||||
* <p>
|
||||
* This is required only for ManyToMany collections. The additions and
|
||||
* deletions are used to insert or delete entries from the intersection table.
|
||||
* Otherwise modifyListening is false.
|
||||
* </p>
|
||||
*/
|
||||
void setModifyListening(ModifyListenMode modifyListenMode);
|
||||
|
||||
/**
|
||||
* Add an object to the additions list.
|
||||
* <p>
|
||||
* This will potentially end up as an insert into a intersection table for a
|
||||
* ManyToMany.
|
||||
* </p>
|
||||
*/
|
||||
void modifyAddition(E bean);
|
||||
|
||||
/**
|
||||
* Add an object to the deletions list.
|
||||
* <p>
|
||||
* This will potentially end up as an delete from an intersection table for a
|
||||
* ManyToMany.
|
||||
* </p>
|
||||
*/
|
||||
void modifyRemoval(Object bean);
|
||||
|
||||
/**
|
||||
* Return the list of objects added to the list set or map. These will used to
|
||||
* insert rows into the intersection table of a ManyToMany.
|
||||
*/
|
||||
Set<E> getModifyAdditions();
|
||||
|
||||
/**
|
||||
* Return the list of objects removed from the list set or map. These will
|
||||
* used to delete rows from the intersection table of a ManyToMany.
|
||||
*/
|
||||
Set<E> getModifyRemovals();
|
||||
|
||||
/**
|
||||
* Reset the set of additions and deletions. This is called after the
|
||||
* additions and removals have been processed.
|
||||
*/
|
||||
void modifyReset();
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
/**
|
||||
* Interface to define the addition of a bean to the underlying collection.
|
||||
* <p>
|
||||
* For maps this takes into account the map key. For List and Set this simply
|
||||
* adds the bean to the underlying list or set.
|
||||
* </p>
|
||||
*/
|
||||
public interface BeanCollectionAdd {
|
||||
|
||||
/**
|
||||
* Add a loaded bean to the collection.
|
||||
*/
|
||||
public void addBean(EntityBean bean);
|
||||
}
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
/**
|
||||
* Interface to define the addition of a bean to the underlying collection.
|
||||
* <p>
|
||||
* For maps this takes into account the map key. For List and Set this simply
|
||||
* adds the bean to the underlying list or set.
|
||||
* </p>
|
||||
*/
|
||||
public interface BeanCollectionAdd {
|
||||
|
||||
/**
|
||||
* Add a loaded bean to the collection.
|
||||
*/
|
||||
void addBean(EntityBean bean);
|
||||
}
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
/**
|
||||
* Loads a entity bean collection.
|
||||
* <p>
|
||||
* Typically invokes lazy loading for a single or batch of collections.
|
||||
* </p>
|
||||
*/
|
||||
public interface BeanCollectionLoader {
|
||||
|
||||
/**
|
||||
* Return the name of the associated EbeanServer.
|
||||
*/
|
||||
public String getName();
|
||||
|
||||
/**
|
||||
* Invoke the lazy loading for this bean collection.
|
||||
*/
|
||||
public void loadMany(BeanCollection<?> collection, boolean onlyIds);
|
||||
|
||||
}
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
/**
|
||||
* Loads a entity bean collection.
|
||||
* <p>
|
||||
* Typically invokes lazy loading for a single or batch of collections.
|
||||
* </p>
|
||||
*/
|
||||
public interface BeanCollectionLoader {
|
||||
|
||||
/**
|
||||
* Return the name of the associated EbeanServer.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Invoke the lazy loading for this bean collection.
|
||||
*/
|
||||
void loadMany(BeanCollection<?> collection, boolean onlyIds);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
/**
|
||||
* Used to specify a listener to be notified when a BeanCollection is first
|
||||
* used.
|
||||
* <p>
|
||||
* To use this you can set a BeanCollectionTouched onto a BeanCollection before
|
||||
* it has been used. When the BeanCollection is first used by the client code
|
||||
* then the BeanCollectionTouched is notified. It can only be notified once.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface BeanCollectionTouched {
|
||||
|
||||
/**
|
||||
* Notify the listener that the bean collection has been used.
|
||||
*/
|
||||
public void notifyTouched(BeanCollection<?> c);
|
||||
}
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
/**
|
||||
* Used to specify a listener to be notified when a BeanCollection is first
|
||||
* used.
|
||||
* <p>
|
||||
* To use this you can set a BeanCollectionTouched onto a BeanCollection before
|
||||
* it has been used. When the BeanCollection is first used by the client code
|
||||
* then the BeanCollectionTouched is notified. It can only be notified once.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface BeanCollectionTouched {
|
||||
|
||||
/**
|
||||
* Notify the listener that the bean collection has been used.
|
||||
*/
|
||||
void notifyTouched(BeanCollection<?> c);
|
||||
}
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
/**
|
||||
* Loads a entity bean.
|
||||
* <p>
|
||||
* Typically invokes lazy loading for a single or batch of entity beans.
|
||||
* </p>
|
||||
*/
|
||||
public interface BeanLoader {
|
||||
|
||||
/**
|
||||
* Return the name of the associated EbeanServer.
|
||||
*/
|
||||
public String getName();
|
||||
|
||||
/**
|
||||
* Invoke the lazy loading for this bean.
|
||||
*/
|
||||
public void loadBean(EntityBeanIntercept ebi);
|
||||
|
||||
}
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
/**
|
||||
* Loads a entity bean.
|
||||
* <p>
|
||||
* Typically invokes lazy loading for a single or batch of entity beans.
|
||||
* </p>
|
||||
*/
|
||||
public interface BeanLoader {
|
||||
|
||||
/**
|
||||
* Return the name of the associated EbeanServer.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Invoke the lazy loading for this bean.
|
||||
*/
|
||||
void loadBean(EntityBeanIntercept ebi);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,118 +1,118 @@
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Represent the call stack (stack trace elements).
|
||||
* <p>
|
||||
* Used with a query to identify a CallStackQuery for AutoFetch automatic query
|
||||
* tuning.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is used so that a single query called from different methods can be
|
||||
* tuned for each different call stack.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note the call stack is trimmed to remove the common ebean internal elements.
|
||||
* </p>
|
||||
*/
|
||||
public final class CallStack implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -8590644046907438579L;
|
||||
|
||||
private final String zeroHash;
|
||||
private final String pathHash;
|
||||
|
||||
private final StackTraceElement[] callStack;
|
||||
|
||||
public CallStack(StackTraceElement[] callStack) {
|
||||
this.callStack = callStack;
|
||||
this.zeroHash = enc(callStack[0].hashCode());
|
||||
int hc = 0;
|
||||
for (int i = 1; i < callStack.length; i++) {
|
||||
hc = 31 * hc + callStack[i].hashCode();
|
||||
}
|
||||
this.pathHash = enc(hc);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int hc = 0;
|
||||
for (int i = 0; i < callStack.length; i++) {
|
||||
hc = 31 * hc + callStack[i].hashCode();
|
||||
}
|
||||
return hc;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof CallStack)) {
|
||||
return false;
|
||||
}
|
||||
CallStack e = (CallStack) obj;
|
||||
return Arrays.equals(callStack, e.callStack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the first element of the call stack.
|
||||
*/
|
||||
public StackTraceElement getFirstStackTraceElement() {
|
||||
return callStack[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the call stack.
|
||||
*/
|
||||
public StackTraceElement[] getCallStack() {
|
||||
return callStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hash for the first stack element.
|
||||
*/
|
||||
public String getZeroHash() {
|
||||
return zeroHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hash for the stack elements (excluding first stack element).
|
||||
*/
|
||||
public String getPathHash() {
|
||||
return pathHash;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return zeroHash + ":" + pathHash + ":" + callStack[0];
|
||||
}
|
||||
|
||||
public String getOriginKey(int queryHash) {
|
||||
return zeroHash + "." + enc(queryHash) + "." + pathHash;
|
||||
}
|
||||
|
||||
private static final int radix = 1 << 6;
|
||||
private static final int mask = radix - 1;
|
||||
|
||||
/**
|
||||
* Convert the integer to unsigned base 64.
|
||||
*/
|
||||
public static String enc(int i) {
|
||||
char[] buf = new char[32];
|
||||
int charPos = 32;
|
||||
do {
|
||||
buf[--charPos] = intToBase64[i & mask];
|
||||
i >>>= 6;
|
||||
} while (i != 0);
|
||||
|
||||
return new String(buf, charPos, (32 - charPos));
|
||||
}
|
||||
|
||||
private static final char intToBase64[] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
|
||||
};
|
||||
}
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Represent the call stack (stack trace elements).
|
||||
* <p>
|
||||
* Used with a query to identify a CallStackQuery for AutoFetch automatic query
|
||||
* tuning.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is used so that a single query called from different methods can be
|
||||
* tuned for each different call stack.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note the call stack is trimmed to remove the common ebean internal elements.
|
||||
* </p>
|
||||
*/
|
||||
public final class CallStack implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -8590644046907438579L;
|
||||
|
||||
private final String zeroHash;
|
||||
private final String pathHash;
|
||||
|
||||
private final StackTraceElement[] callStack;
|
||||
|
||||
public CallStack(StackTraceElement[] callStack) {
|
||||
this.callStack = callStack;
|
||||
this.zeroHash = enc(callStack[0].hashCode());
|
||||
int hc = 0;
|
||||
for (int i = 1; i < callStack.length; i++) {
|
||||
hc = 31 * hc + callStack[i].hashCode();
|
||||
}
|
||||
this.pathHash = enc(hc);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int hc = 0;
|
||||
for (int i = 0; i < callStack.length; i++) {
|
||||
hc = 31 * hc + callStack[i].hashCode();
|
||||
}
|
||||
return hc;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof CallStack)) {
|
||||
return false;
|
||||
}
|
||||
CallStack e = (CallStack) obj;
|
||||
return Arrays.equals(callStack, e.callStack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the first element of the call stack.
|
||||
*/
|
||||
public StackTraceElement getFirstStackTraceElement() {
|
||||
return callStack[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the call stack.
|
||||
*/
|
||||
public StackTraceElement[] getCallStack() {
|
||||
return callStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hash for the first stack element.
|
||||
*/
|
||||
public String getZeroHash() {
|
||||
return zeroHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hash for the stack elements (excluding first stack element).
|
||||
*/
|
||||
public String getPathHash() {
|
||||
return pathHash;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return zeroHash + ":" + pathHash + ":" + callStack[0];
|
||||
}
|
||||
|
||||
public String getOriginKey(int queryHash) {
|
||||
return zeroHash + "." + enc(queryHash) + "." + pathHash;
|
||||
}
|
||||
|
||||
private static final int radix = 1 << 6;
|
||||
private static final int mask = radix - 1;
|
||||
|
||||
/**
|
||||
* Convert the integer to unsigned base 64.
|
||||
*/
|
||||
public static String enc(int i) {
|
||||
char[] buf = new char[32];
|
||||
int charPos = 32;
|
||||
do {
|
||||
buf[--charPos] = intToBase64[i & mask];
|
||||
i >>>= 6;
|
||||
} while (i != 0);
|
||||
|
||||
return new String(buf, charPos, (32 - charPos));
|
||||
}
|
||||
|
||||
private static final char intToBase64[] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,114 +1,114 @@
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Bean that is aware of EntityBeanIntercept.
|
||||
* <p>
|
||||
* This interface and implementation of these methods is added to Entity Beans
|
||||
* via instrumentation. These methods have a funny _ebean_ prefix to avoid any
|
||||
* clash with normal methods these beans would have. These methods are not for
|
||||
* general application consumption.
|
||||
* </p>
|
||||
*/
|
||||
public interface EntityBean extends Serializable {
|
||||
|
||||
public String[] _ebean_getPropertyNames();
|
||||
|
||||
public String _ebean_getPropertyName(int pos);
|
||||
|
||||
/**
|
||||
* Return the enhancement marker value.
|
||||
* <p>
|
||||
* This is the class name of the enhanced class and used to check that all
|
||||
* entity classes are enhanced (specifically not just a super class).
|
||||
* </p>
|
||||
*/
|
||||
public String _ebean_getMarker();
|
||||
|
||||
/**
|
||||
* Create and return a new entity bean instance.
|
||||
*/
|
||||
public Object _ebean_newInstance();
|
||||
|
||||
/**
|
||||
* Add a PropertyChangeListener to this bean.
|
||||
*/
|
||||
public void addPropertyChangeListener(PropertyChangeListener listener);
|
||||
|
||||
/**
|
||||
* Remove a PropertyChangeListener from this bean.
|
||||
*/
|
||||
public void removePropertyChangeListener(PropertyChangeListener listener);
|
||||
|
||||
/**
|
||||
* Generated method that sets the loaded state on all the embedded beans on
|
||||
* this entity bean by using EntityBeanIntercept.setEmbeddedLoaded(Object o);
|
||||
*/
|
||||
public void _ebean_setEmbeddedLoaded();
|
||||
|
||||
/**
|
||||
* Return true if any embedded beans are new or dirty.
|
||||
*/
|
||||
public boolean _ebean_isEmbeddedNewOrDirty();
|
||||
|
||||
/**
|
||||
* Return the intercept for this object.
|
||||
*/
|
||||
public EntityBeanIntercept _ebean_getIntercept();
|
||||
|
||||
/**
|
||||
* Similar to _ebean_getIntercept() except it checks to see if the intercept
|
||||
* field is null and will create it if required.
|
||||
* <p>
|
||||
* This is really only required when transientInternalFields=true as an
|
||||
* enhancement option. In this case the intercept field is transient and will
|
||||
* be null after a bean has been deserialised.
|
||||
* </p>
|
||||
* <p>
|
||||
* This transientInternalFields=true option was to support some serialization
|
||||
* frameworks that can't take into account our ebean fields.
|
||||
* </p>
|
||||
*/
|
||||
public EntityBeanIntercept _ebean_intercept();
|
||||
|
||||
/**
|
||||
* Create a copy of this entity bean.
|
||||
* <p>
|
||||
* This occurs when a bean is changed. The copy represents the bean as it was
|
||||
* initially (oldValues) before any changes where made. This is used for
|
||||
* optimistic concurrency control.
|
||||
* </p>
|
||||
*/
|
||||
public Object _ebean_createCopy();
|
||||
|
||||
/**
|
||||
* Set the value of a field of an entity bean of this type.
|
||||
* <p>
|
||||
* Note that using this method bypasses any interception that otherwise occurs
|
||||
* on entity beans. That means lazy loading and oldValues creation.
|
||||
* </p>
|
||||
*/
|
||||
public void _ebean_setField(int fieldIndex, Object value);
|
||||
|
||||
/**
|
||||
* Set the field value with interception.
|
||||
*/
|
||||
public void _ebean_setFieldIntercept(int fieldIndex, Object value);
|
||||
|
||||
/**
|
||||
* Return the value of a field from an entity bean of this type.
|
||||
* <p>
|
||||
* Note that using this method bypasses any interception that otherwise occurs
|
||||
* on entity beans. That means lazy loading.
|
||||
* </p>
|
||||
*/
|
||||
public Object _ebean_getField(int fieldIndex);
|
||||
|
||||
/**
|
||||
* Return the field value with interception.
|
||||
*/
|
||||
public Object _ebean_getFieldIntercept(int fieldIndex);
|
||||
|
||||
}
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Bean that is aware of EntityBeanIntercept.
|
||||
* <p>
|
||||
* This interface and implementation of these methods is added to Entity Beans
|
||||
* via instrumentation. These methods have a funny _ebean_ prefix to avoid any
|
||||
* clash with normal methods these beans would have. These methods are not for
|
||||
* general application consumption.
|
||||
* </p>
|
||||
*/
|
||||
public interface EntityBean extends Serializable {
|
||||
|
||||
String[] _ebean_getPropertyNames();
|
||||
|
||||
String _ebean_getPropertyName(int pos);
|
||||
|
||||
/**
|
||||
* Return the enhancement marker value.
|
||||
* <p>
|
||||
* This is the class name of the enhanced class and used to check that all
|
||||
* entity classes are enhanced (specifically not just a super class).
|
||||
* </p>
|
||||
*/
|
||||
String _ebean_getMarker();
|
||||
|
||||
/**
|
||||
* Create and return a new entity bean instance.
|
||||
*/
|
||||
Object _ebean_newInstance();
|
||||
|
||||
/**
|
||||
* Add a PropertyChangeListener to this bean.
|
||||
*/
|
||||
void addPropertyChangeListener(PropertyChangeListener listener);
|
||||
|
||||
/**
|
||||
* Remove a PropertyChangeListener from this bean.
|
||||
*/
|
||||
void removePropertyChangeListener(PropertyChangeListener listener);
|
||||
|
||||
/**
|
||||
* Generated method that sets the loaded state on all the embedded beans on
|
||||
* this entity bean by using EntityBeanIntercept.setEmbeddedLoaded(Object o);
|
||||
*/
|
||||
void _ebean_setEmbeddedLoaded();
|
||||
|
||||
/**
|
||||
* Return true if any embedded beans are new or dirty.
|
||||
*/
|
||||
boolean _ebean_isEmbeddedNewOrDirty();
|
||||
|
||||
/**
|
||||
* Return the intercept for this object.
|
||||
*/
|
||||
EntityBeanIntercept _ebean_getIntercept();
|
||||
|
||||
/**
|
||||
* Similar to _ebean_getIntercept() except it checks to see if the intercept
|
||||
* field is null and will create it if required.
|
||||
* <p>
|
||||
* This is really only required when transientInternalFields=true as an
|
||||
* enhancement option. In this case the intercept field is transient and will
|
||||
* be null after a bean has been deserialised.
|
||||
* </p>
|
||||
* <p>
|
||||
* This transientInternalFields=true option was to support some serialization
|
||||
* frameworks that can't take into account our ebean fields.
|
||||
* </p>
|
||||
*/
|
||||
EntityBeanIntercept _ebean_intercept();
|
||||
|
||||
/**
|
||||
* Create a copy of this entity bean.
|
||||
* <p>
|
||||
* This occurs when a bean is changed. The copy represents the bean as it was
|
||||
* initially (oldValues) before any changes where made. This is used for
|
||||
* optimistic concurrency control.
|
||||
* </p>
|
||||
*/
|
||||
Object _ebean_createCopy();
|
||||
|
||||
/**
|
||||
* Set the value of a field of an entity bean of this type.
|
||||
* <p>
|
||||
* Note that using this method bypasses any interception that otherwise occurs
|
||||
* on entity beans. That means lazy loading and oldValues creation.
|
||||
* </p>
|
||||
*/
|
||||
void _ebean_setField(int fieldIndex, Object value);
|
||||
|
||||
/**
|
||||
* Set the field value with interception.
|
||||
*/
|
||||
void _ebean_setFieldIntercept(int fieldIndex, Object value);
|
||||
|
||||
/**
|
||||
* Return the value of a field from an entity bean of this type.
|
||||
* <p>
|
||||
* Note that using this method bypasses any interception that otherwise occurs
|
||||
* on entity beans. That means lazy loading.
|
||||
* </p>
|
||||
*/
|
||||
Object _ebean_getField(int fieldIndex);
|
||||
|
||||
/**
|
||||
* Return the field value with interception.
|
||||
*/
|
||||
Object _ebean_getFieldIntercept(int fieldIndex);
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,126 +1,126 @@
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* Collects profile information for a bean (or reference/proxy bean) at a given
|
||||
* AutoFetchNode.
|
||||
* <p>
|
||||
* The AutoFetchNode identifies the location of the bean in the object graph.
|
||||
* </p>
|
||||
* <p>
|
||||
* It has to use a weak reference so as to ensure that it does not stop the
|
||||
* associated bean from being garbage collected.
|
||||
* </p>
|
||||
*/
|
||||
public final class NodeUsageCollector {
|
||||
|
||||
/**
|
||||
* The point in the object graph for a specific query and call stack point.
|
||||
*/
|
||||
private final ObjectGraphNode node;
|
||||
|
||||
/**
|
||||
* Weak to allow garbage collection.
|
||||
*/
|
||||
private final WeakReference<NodeUsageListener> managerRef;
|
||||
|
||||
/**
|
||||
* The properties used at this profile point.
|
||||
*/
|
||||
private final HashSet<String> used = new HashSet<String>();
|
||||
|
||||
/**
|
||||
* set to true if the bean is modified (setter called)
|
||||
*/
|
||||
private boolean modified;
|
||||
|
||||
/**
|
||||
* The property that cause a reference to lazy load.
|
||||
*/
|
||||
private String loadProperty;
|
||||
|
||||
public NodeUsageCollector(ObjectGraphNode node, WeakReference<NodeUsageListener> managerRef) {
|
||||
this.node = node;
|
||||
// weak to allow garbage collection.
|
||||
this.managerRef = managerRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* The bean has been modified by a setter method.
|
||||
*/
|
||||
public void setModified() {
|
||||
modified = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the name of a property that has been used.
|
||||
*/
|
||||
public void addUsed(String property) {
|
||||
used.add(property);
|
||||
}
|
||||
|
||||
/**
|
||||
* The property that invoked a lazy load.
|
||||
*/
|
||||
public void setLoadProperty(String loadProperty) {
|
||||
this.loadProperty = loadProperty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish the usage info to the manager.
|
||||
*/
|
||||
private void publishUsageInfo() {
|
||||
NodeUsageListener manager = managerRef.get();
|
||||
if (manager != null) {
|
||||
manager.collectNodeUsage(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* publish the collected usage information when garbage collection occurs.
|
||||
*/
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
publishUsageInfo();
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated node which identifies the location in the object
|
||||
* graph of the bean/reference.
|
||||
*/
|
||||
public ObjectGraphNode getNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if no properties where used.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return used.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the set of used properties.
|
||||
*/
|
||||
public HashSet<String> getUsed() {
|
||||
return used;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the bean was modified by a setter.
|
||||
*/
|
||||
public boolean isModified() {
|
||||
return modified;
|
||||
}
|
||||
|
||||
public String getLoadProperty() {
|
||||
return loadProperty;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return node + " read:" + used + " modified:" + modified;
|
||||
}
|
||||
}
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* Collects profile information for a bean (or reference/proxy bean) at a given
|
||||
* AutoFetchNode.
|
||||
* <p>
|
||||
* The AutoFetchNode identifies the location of the bean in the object graph.
|
||||
* </p>
|
||||
* <p>
|
||||
* It has to use a weak reference so as to ensure that it does not stop the
|
||||
* associated bean from being garbage collected.
|
||||
* </p>
|
||||
*/
|
||||
public final class NodeUsageCollector {
|
||||
|
||||
/**
|
||||
* The point in the object graph for a specific query and call stack point.
|
||||
*/
|
||||
private final ObjectGraphNode node;
|
||||
|
||||
/**
|
||||
* Weak to allow garbage collection.
|
||||
*/
|
||||
private final WeakReference<NodeUsageListener> managerRef;
|
||||
|
||||
/**
|
||||
* The properties used at this profile point.
|
||||
*/
|
||||
private final HashSet<String> used = new HashSet<String>();
|
||||
|
||||
/**
|
||||
* set to true if the bean is modified (setter called)
|
||||
*/
|
||||
private boolean modified;
|
||||
|
||||
/**
|
||||
* The property that cause a reference to lazy load.
|
||||
*/
|
||||
private String loadProperty;
|
||||
|
||||
public NodeUsageCollector(ObjectGraphNode node, WeakReference<NodeUsageListener> managerRef) {
|
||||
this.node = node;
|
||||
// weak to allow garbage collection.
|
||||
this.managerRef = managerRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* The bean has been modified by a setter method.
|
||||
*/
|
||||
public void setModified() {
|
||||
modified = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the name of a property that has been used.
|
||||
*/
|
||||
public void addUsed(String property) {
|
||||
used.add(property);
|
||||
}
|
||||
|
||||
/**
|
||||
* The property that invoked a lazy load.
|
||||
*/
|
||||
public void setLoadProperty(String loadProperty) {
|
||||
this.loadProperty = loadProperty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish the usage info to the manager.
|
||||
*/
|
||||
private void publishUsageInfo() {
|
||||
NodeUsageListener manager = managerRef.get();
|
||||
if (manager != null) {
|
||||
manager.collectNodeUsage(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* publish the collected usage information when garbage collection occurs.
|
||||
*/
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
publishUsageInfo();
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated node which identifies the location in the object
|
||||
* graph of the bean/reference.
|
||||
*/
|
||||
public ObjectGraphNode getNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if no properties where used.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return used.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the set of used properties.
|
||||
*/
|
||||
public HashSet<String> getUsed() {
|
||||
return used;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the bean was modified by a setter.
|
||||
*/
|
||||
public boolean isModified() {
|
||||
return modified;
|
||||
}
|
||||
|
||||
public String getLoadProperty() {
|
||||
return loadProperty;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return node + " read:" + used + " modified:" + modified;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
/**
|
||||
* Collects the profile information.
|
||||
*/
|
||||
public interface NodeUsageListener {
|
||||
|
||||
/**
|
||||
* Collect node usage "profiling" information.
|
||||
* <p>
|
||||
* This is the properties that are used for a given bean in the object graph.
|
||||
* This information is used by autoFetch to tune queries.
|
||||
* </p>
|
||||
*/
|
||||
public void collectNodeUsage(NodeUsageCollector collector);
|
||||
}
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
/**
|
||||
* Collects the profile information.
|
||||
*/
|
||||
public interface NodeUsageListener {
|
||||
|
||||
/**
|
||||
* Collect node usage "profiling" information.
|
||||
* <p>
|
||||
* This is the properties that are used for a given bean in the object graph.
|
||||
* This information is used by autoFetch to tune queries.
|
||||
* </p>
|
||||
*/
|
||||
void collectNodeUsage(NodeUsageCollector collector);
|
||||
}
|
||||
|
||||
@@ -1,88 +1,88 @@
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Identifies a unique node of an object graph.
|
||||
* <p>
|
||||
* It represents a location relative to the root of an object graph and specific
|
||||
* to a query and call stack hash.
|
||||
* </p>
|
||||
*/
|
||||
public final class ObjectGraphNode implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 2087081778650228996L;
|
||||
|
||||
/**
|
||||
* Identifies the origin.
|
||||
*/
|
||||
private final ObjectGraphOrigin originQueryPoint;
|
||||
|
||||
/**
|
||||
* The path relative to the root.
|
||||
*/
|
||||
private final String path;
|
||||
|
||||
/**
|
||||
* Create at a sub level.
|
||||
*/
|
||||
public ObjectGraphNode(ObjectGraphNode parent, String path) {
|
||||
this.originQueryPoint = parent.getOriginQueryPoint();
|
||||
this.path = parent.getChildPath(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an the root level.
|
||||
*/
|
||||
public ObjectGraphNode(ObjectGraphOrigin originQueryPoint, String path) {
|
||||
this.originQueryPoint = originQueryPoint;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the origin query point.
|
||||
*/
|
||||
public ObjectGraphOrigin getOriginQueryPoint() {
|
||||
return originQueryPoint;
|
||||
}
|
||||
|
||||
private String getChildPath(String childPath) {
|
||||
if (path == null) {
|
||||
return childPath;
|
||||
} else if (childPath == null) {
|
||||
return path;
|
||||
} else {
|
||||
return path + "." + childPath;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path relative to the root.
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "origin:" + originQueryPoint + " path[" + path+"]";
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int hc = 31 * originQueryPoint.hashCode();
|
||||
hc = 31 * hc + (path == null ? 0 : path.hashCode());
|
||||
return hc;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof ObjectGraphNode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ObjectGraphNode e = (ObjectGraphNode) obj;
|
||||
return ((e.path == path) || (e.path != null && e.path.equals(path)))
|
||||
&& e.originQueryPoint.equals(originQueryPoint);
|
||||
}
|
||||
}
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Identifies a unique node of an object graph.
|
||||
* <p>
|
||||
* It represents a location relative to the root of an object graph and specific
|
||||
* to a query and call stack hash.
|
||||
* </p>
|
||||
*/
|
||||
public final class ObjectGraphNode implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 2087081778650228996L;
|
||||
|
||||
/**
|
||||
* Identifies the origin.
|
||||
*/
|
||||
private final ObjectGraphOrigin originQueryPoint;
|
||||
|
||||
/**
|
||||
* The path relative to the root.
|
||||
*/
|
||||
private final String path;
|
||||
|
||||
/**
|
||||
* Create at a sub level.
|
||||
*/
|
||||
public ObjectGraphNode(ObjectGraphNode parent, String path) {
|
||||
this.originQueryPoint = parent.getOriginQueryPoint();
|
||||
this.path = parent.getChildPath(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an the root level.
|
||||
*/
|
||||
public ObjectGraphNode(ObjectGraphOrigin originQueryPoint, String path) {
|
||||
this.originQueryPoint = originQueryPoint;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the origin query point.
|
||||
*/
|
||||
public ObjectGraphOrigin getOriginQueryPoint() {
|
||||
return originQueryPoint;
|
||||
}
|
||||
|
||||
private String getChildPath(String childPath) {
|
||||
if (path == null) {
|
||||
return childPath;
|
||||
} else if (childPath == null) {
|
||||
return path;
|
||||
} else {
|
||||
return path + "." + childPath;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path relative to the root.
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "origin:" + originQueryPoint + " path[" + path+"]";
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int hc = 31 * originQueryPoint.hashCode();
|
||||
hc = 31 * hc + (path == null ? 0 : path.hashCode());
|
||||
return hc;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof ObjectGraphNode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ObjectGraphNode e = (ObjectGraphNode) obj;
|
||||
return ((e.path == path) || (e.path != null && e.path.equals(path)))
|
||||
&& e.originQueryPoint.equals(originQueryPoint);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,84 +1,84 @@
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Represents a "origin" of an ORM object graph. This combines the call stack
|
||||
* and query plan hash.
|
||||
* <p>
|
||||
* The call stack is included so that the query can have different tuned fetches
|
||||
* for each unique call stack. For example, a query to fetch a customer could be
|
||||
* called by three different methods and each can be treated as a separate
|
||||
* origin point (and autoFetch can tune each one separately).
|
||||
* </p>
|
||||
*/
|
||||
public final class ObjectGraphOrigin implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 410937765287968708L;
|
||||
|
||||
private final CallStack callStack;
|
||||
|
||||
private final String beanType;
|
||||
|
||||
private final int queryHash;
|
||||
|
||||
private final String key;
|
||||
|
||||
public ObjectGraphOrigin(int queryHash, CallStack callStack, String beanType) {
|
||||
this.callStack = callStack;
|
||||
this.beanType = beanType;
|
||||
this.queryHash = queryHash;
|
||||
this.key = callStack.getOriginKey(queryHash);
|
||||
}
|
||||
|
||||
/**
|
||||
* The key includes the queryPlan hash and the callStack hash. This becomes
|
||||
* the unique identifier for a query point.
|
||||
*/
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of bean the query is fetching.
|
||||
*/
|
||||
public String getBeanType() {
|
||||
return beanType;
|
||||
}
|
||||
|
||||
/**
|
||||
* The call stack involved.
|
||||
*/
|
||||
public CallStack getCallStack() {
|
||||
return callStack;
|
||||
}
|
||||
|
||||
public String getFirstStackElement() {
|
||||
return callStack.getFirstStackTraceElement().toString();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "key["+ key + "] type[" + beanType + "] " + callStack.getFirstStackTraceElement()+" ";
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int hc = 31 * callStack.hashCode();
|
||||
hc = 31 * hc + beanType.hashCode();
|
||||
hc = 31 * hc + queryHash;
|
||||
return hc;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof ObjectGraphOrigin)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ObjectGraphOrigin e = (ObjectGraphOrigin) obj;
|
||||
return e.queryHash == queryHash
|
||||
&& e.beanType.equals(beanType)
|
||||
&& e.callStack.equals(callStack);
|
||||
}
|
||||
}
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Represents a "origin" of an ORM object graph. This combines the call stack
|
||||
* and query plan hash.
|
||||
* <p>
|
||||
* The call stack is included so that the query can have different tuned fetches
|
||||
* for each unique call stack. For example, a query to fetch a customer could be
|
||||
* called by three different methods and each can be treated as a separate
|
||||
* origin point (and autoFetch can tune each one separately).
|
||||
* </p>
|
||||
*/
|
||||
public final class ObjectGraphOrigin implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 410937765287968708L;
|
||||
|
||||
private final CallStack callStack;
|
||||
|
||||
private final String beanType;
|
||||
|
||||
private final int queryHash;
|
||||
|
||||
private final String key;
|
||||
|
||||
public ObjectGraphOrigin(int queryHash, CallStack callStack, String beanType) {
|
||||
this.callStack = callStack;
|
||||
this.beanType = beanType;
|
||||
this.queryHash = queryHash;
|
||||
this.key = callStack.getOriginKey(queryHash);
|
||||
}
|
||||
|
||||
/**
|
||||
* The key includes the queryPlan hash and the callStack hash. This becomes
|
||||
* the unique identifier for a query point.
|
||||
*/
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of bean the query is fetching.
|
||||
*/
|
||||
public String getBeanType() {
|
||||
return beanType;
|
||||
}
|
||||
|
||||
/**
|
||||
* The call stack involved.
|
||||
*/
|
||||
public CallStack getCallStack() {
|
||||
return callStack;
|
||||
}
|
||||
|
||||
public String getFirstStackElement() {
|
||||
return callStack.getFirstStackTraceElement().toString();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "key["+ key + "] type[" + beanType + "] " + callStack.getFirstStackTraceElement()+" ";
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int hc = 31 * callStack.hashCode();
|
||||
hc = 31 * hc + beanType.hashCode();
|
||||
hc = 31 * hc + queryHash;
|
||||
return hc;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof ObjectGraphOrigin)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ObjectGraphOrigin e = (ObjectGraphOrigin) obj;
|
||||
return e.queryHash == queryHash
|
||||
&& e.beanType.equals(beanType)
|
||||
&& e.callStack.equals(callStack);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,110 +1,110 @@
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
/**
|
||||
* Holds entity beans by there type and id.
|
||||
* <p>
|
||||
* This is used to ensure only one instance for a given entity type and id is
|
||||
* used to build object graphs from queries and lazy loading.
|
||||
* </p>
|
||||
*/
|
||||
public interface PersistenceContext {
|
||||
|
||||
/**
|
||||
* Put the entity bean into the PersistanceContext.
|
||||
*/
|
||||
public void put(Object id, Object bean);
|
||||
|
||||
/**
|
||||
* Put the entity bean into the PersistanceContext if one is not already
|
||||
* present (for this id).
|
||||
* <p>
|
||||
* Returns an existing entity bean (if one is already there) and otherwise
|
||||
* returns null.
|
||||
* </p>
|
||||
*/
|
||||
public Object putIfAbsent(Object id, Object bean);
|
||||
|
||||
/**
|
||||
* Return an object given its type and unique id.
|
||||
*/
|
||||
public Object get(Class<?> beanType, Object uid);
|
||||
|
||||
/**
|
||||
* Get the bean from the persistence context also checked to see if it had
|
||||
* been previously deleted (if so then you also can't hit the L2 cache to
|
||||
* fetch the bean for this particular persistence context).
|
||||
*/
|
||||
public WithOption getWithOption(Class<?> beanType, Object uid);
|
||||
|
||||
/**
|
||||
* Clear all the references.
|
||||
*/
|
||||
public void clear();
|
||||
|
||||
/**
|
||||
* Clear all the references for a given type of entity bean.
|
||||
*/
|
||||
public void clear(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* Clear the reference to a specific entity bean.
|
||||
*/
|
||||
public void clear(Class<?> beanType, Object uid);
|
||||
|
||||
/**
|
||||
* Clear the reference as a result of an entity being deleted.
|
||||
*/
|
||||
public void deleted(Class<?> beanType, Object id);
|
||||
|
||||
/**
|
||||
* Return the number of beans of the given type in the persistence context.
|
||||
*/
|
||||
public int size(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* Wrapper on a bean to also indicate if a bean has been deleted.
|
||||
* <p>
|
||||
* If a bean has been deleted then for the same persistence context is should
|
||||
* not be able to be fetched from persistence context or L2 cache.
|
||||
* </p>
|
||||
*/
|
||||
public static class WithOption {
|
||||
|
||||
/**
|
||||
* The bean was previously deleted from this persistence context (can't hit
|
||||
* L2 cache).
|
||||
*/
|
||||
public static WithOption DELETED = new WithOption(true);
|
||||
|
||||
private final boolean deleted;
|
||||
private final Object bean;
|
||||
|
||||
private WithOption(boolean deleted) {
|
||||
this.deleted = true;
|
||||
this.bean = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The bean exists in the persistence context (and not been previously deleted).
|
||||
*/
|
||||
public WithOption(Object bean) {
|
||||
this.deleted = false;
|
||||
this.bean = bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the bean was deleted. This means you can't hit the L2
|
||||
* cache.
|
||||
*/
|
||||
public boolean isDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean (from the persistence context).
|
||||
*/
|
||||
public Object getBean() {
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
/**
|
||||
* Holds entity beans by there type and id.
|
||||
* <p>
|
||||
* This is used to ensure only one instance for a given entity type and id is
|
||||
* used to build object graphs from queries and lazy loading.
|
||||
* </p>
|
||||
*/
|
||||
public interface PersistenceContext {
|
||||
|
||||
/**
|
||||
* Put the entity bean into the PersistanceContext.
|
||||
*/
|
||||
void put(Object id, Object bean);
|
||||
|
||||
/**
|
||||
* Put the entity bean into the PersistanceContext if one is not already
|
||||
* present (for this id).
|
||||
* <p>
|
||||
* Returns an existing entity bean (if one is already there) and otherwise
|
||||
* returns null.
|
||||
* </p>
|
||||
*/
|
||||
Object putIfAbsent(Object id, Object bean);
|
||||
|
||||
/**
|
||||
* Return an object given its type and unique id.
|
||||
*/
|
||||
Object get(Class<?> beanType, Object uid);
|
||||
|
||||
/**
|
||||
* Get the bean from the persistence context also checked to see if it had
|
||||
* been previously deleted (if so then you also can't hit the L2 cache to
|
||||
* fetch the bean for this particular persistence context).
|
||||
*/
|
||||
WithOption getWithOption(Class<?> beanType, Object uid);
|
||||
|
||||
/**
|
||||
* Clear all the references.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Clear all the references for a given type of entity bean.
|
||||
*/
|
||||
void clear(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* Clear the reference to a specific entity bean.
|
||||
*/
|
||||
void clear(Class<?> beanType, Object uid);
|
||||
|
||||
/**
|
||||
* Clear the reference as a result of an entity being deleted.
|
||||
*/
|
||||
void deleted(Class<?> beanType, Object id);
|
||||
|
||||
/**
|
||||
* Return the number of beans of the given type in the persistence context.
|
||||
*/
|
||||
int size(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* Wrapper on a bean to also indicate if a bean has been deleted.
|
||||
* <p>
|
||||
* If a bean has been deleted then for the same persistence context is should
|
||||
* not be able to be fetched from persistence context or L2 cache.
|
||||
* </p>
|
||||
*/
|
||||
class WithOption {
|
||||
|
||||
/**
|
||||
* The bean was previously deleted from this persistence context (can't hit
|
||||
* L2 cache).
|
||||
*/
|
||||
public static WithOption DELETED = new WithOption(true);
|
||||
|
||||
private final boolean deleted;
|
||||
private final Object bean;
|
||||
|
||||
private WithOption(boolean deleted) {
|
||||
this.deleted = true;
|
||||
this.bean = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The bean exists in the persistence context (and not been previously deleted).
|
||||
*/
|
||||
public WithOption(Object bean) {
|
||||
this.deleted = false;
|
||||
this.bean = bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the bean was deleted. This means you can't hit the L2
|
||||
* cache.
|
||||
*/
|
||||
public boolean isDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean (from the persistence context).
|
||||
*/
|
||||
public Object getBean() {
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+89
-89
@@ -1,89 +1,89 @@
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
|
||||
/**
|
||||
* Represents part of the "L2" server side cache.
|
||||
* <p>
|
||||
* This is used to cache beans or query results (bean collections).
|
||||
* </p>
|
||||
* <p>
|
||||
* There are 2 ServerCache's for each bean type. One is used as the 'bean cache'
|
||||
* which holds beans of a given type. The other is the 'query cache' holding
|
||||
* query results for a given type.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface ServerCache {
|
||||
|
||||
/**
|
||||
* Just after a cache is created this init method is called. This is so that a
|
||||
* cache implementation can make use of the BackgroundExecutor service to
|
||||
* trim/cleanup itself or use the EbeanServer to populate itself.
|
||||
* <p>
|
||||
* This method is called after the cache is constructed but before the cache
|
||||
* is made available for use.
|
||||
* </p>
|
||||
*/
|
||||
public void init(EbeanServer ebeanServer);
|
||||
|
||||
/**
|
||||
* Return the configuration options for this cache.
|
||||
*/
|
||||
public ServerCacheOptions getOptions();
|
||||
|
||||
/**
|
||||
* Update the configuration options for this cache.
|
||||
*/
|
||||
public void setOptions(ServerCacheOptions options);
|
||||
|
||||
/**
|
||||
* Return the value given the key.
|
||||
*/
|
||||
public Object get(Object id);
|
||||
|
||||
/**
|
||||
* Put the value in the cache with a given id.
|
||||
*/
|
||||
public Object put(Object id, Object value);
|
||||
|
||||
/**
|
||||
* Put the value in the cache but only if a matching value is not already in
|
||||
* the cache.
|
||||
*/
|
||||
public Object putIfAbsent(Object id, Object value);
|
||||
|
||||
/**
|
||||
* Remove a entry from the cache given its id.
|
||||
*/
|
||||
public Object remove(Object id);
|
||||
|
||||
/**
|
||||
* Clear all entries from the cache.
|
||||
* <p>
|
||||
* NOTE: Be careful using this method in that most of the time application
|
||||
* code should clear BOTH the bean and query caches at the same time. This can
|
||||
* be done via {@link ServerCacheManager#clear(Class)}.
|
||||
* </p>
|
||||
*/
|
||||
public void clear();
|
||||
|
||||
/**
|
||||
* Return the number of entries in the cache.
|
||||
*/
|
||||
public int size();
|
||||
|
||||
/**
|
||||
* Return the hit ratio the cache is currently getting.
|
||||
*/
|
||||
public int getHitRatio();
|
||||
|
||||
/**
|
||||
* Return statistics for the cache.
|
||||
*
|
||||
* @param reset
|
||||
* if true the statistics are reset.
|
||||
*/
|
||||
public ServerCacheStatistics getStatistics(boolean reset);
|
||||
}
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
|
||||
/**
|
||||
* Represents part of the "L2" server side cache.
|
||||
* <p>
|
||||
* This is used to cache beans or query results (bean collections).
|
||||
* </p>
|
||||
* <p>
|
||||
* There are 2 ServerCache's for each bean type. One is used as the 'bean cache'
|
||||
* which holds beans of a given type. The other is the 'query cache' holding
|
||||
* query results for a given type.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface ServerCache {
|
||||
|
||||
/**
|
||||
* Just after a cache is created this init method is called. This is so that a
|
||||
* cache implementation can make use of the BackgroundExecutor service to
|
||||
* trim/cleanup itself or use the EbeanServer to populate itself.
|
||||
* <p>
|
||||
* This method is called after the cache is constructed but before the cache
|
||||
* is made available for use.
|
||||
* </p>
|
||||
*/
|
||||
void init(EbeanServer ebeanServer);
|
||||
|
||||
/**
|
||||
* Return the configuration options for this cache.
|
||||
*/
|
||||
ServerCacheOptions getOptions();
|
||||
|
||||
/**
|
||||
* Update the configuration options for this cache.
|
||||
*/
|
||||
void setOptions(ServerCacheOptions options);
|
||||
|
||||
/**
|
||||
* Return the value given the key.
|
||||
*/
|
||||
Object get(Object id);
|
||||
|
||||
/**
|
||||
* Put the value in the cache with a given id.
|
||||
*/
|
||||
Object put(Object id, Object value);
|
||||
|
||||
/**
|
||||
* Put the value in the cache but only if a matching value is not already in
|
||||
* the cache.
|
||||
*/
|
||||
Object putIfAbsent(Object id, Object value);
|
||||
|
||||
/**
|
||||
* Remove a entry from the cache given its id.
|
||||
*/
|
||||
Object remove(Object id);
|
||||
|
||||
/**
|
||||
* Clear all entries from the cache.
|
||||
* <p>
|
||||
* NOTE: Be careful using this method in that most of the time application
|
||||
* code should clear BOTH the bean and query caches at the same time. This can
|
||||
* be done via {@link ServerCacheManager#clear(Class)}.
|
||||
* </p>
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Return the number of entries in the cache.
|
||||
*/
|
||||
int size();
|
||||
|
||||
/**
|
||||
* Return the hit ratio the cache is currently getting.
|
||||
*/
|
||||
int getHitRatio();
|
||||
|
||||
/**
|
||||
* Return statistics for the cache.
|
||||
*
|
||||
* @param reset
|
||||
* if true the statistics are reset.
|
||||
*/
|
||||
ServerCacheStatistics getStatistics(boolean reset);
|
||||
}
|
||||
|
||||
+26
-26
@@ -1,26 +1,26 @@
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
|
||||
/**
|
||||
* Defines method for constructing caches for beans and queries.
|
||||
*/
|
||||
public interface ServerCacheFactory {
|
||||
|
||||
/**
|
||||
* Just after the ServerCacheFactory is constructed this method is called
|
||||
* passing the EbeanServer.
|
||||
* <p>
|
||||
* This is so that a cache implementation can utilise the EbeanServer to
|
||||
* populate itself or use the BackgroundExecutor service to schedule periodic
|
||||
* cache trimming/cleanup.
|
||||
* </p>
|
||||
*/
|
||||
public void init(EbeanServer ebeanServer);
|
||||
|
||||
/**
|
||||
* Create the cache for the given type with options.
|
||||
*/
|
||||
public ServerCache createCache(String cacheKey, ServerCacheOptions cacheOptions);
|
||||
|
||||
}
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
|
||||
/**
|
||||
* Defines method for constructing caches for beans and queries.
|
||||
*/
|
||||
public interface ServerCacheFactory {
|
||||
|
||||
/**
|
||||
* Just after the ServerCacheFactory is constructed this method is called
|
||||
* passing the EbeanServer.
|
||||
* <p>
|
||||
* This is so that a cache implementation can utilise the EbeanServer to
|
||||
* populate itself or use the BackgroundExecutor service to schedule periodic
|
||||
* cache trimming/cleanup.
|
||||
* </p>
|
||||
*/
|
||||
void init(EbeanServer ebeanServer);
|
||||
|
||||
/**
|
||||
* Create the cache for the given type with options.
|
||||
*/
|
||||
ServerCache createCache(String cacheKey, ServerCacheOptions cacheOptions);
|
||||
|
||||
}
|
||||
|
||||
+55
-55
@@ -1,55 +1,55 @@
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
|
||||
/**
|
||||
* The cache service for server side caching of beans and query results.
|
||||
*/
|
||||
public interface ServerCacheManager {
|
||||
|
||||
/**
|
||||
* This method is called just after the construction of the
|
||||
* ServerCacheManager.
|
||||
* <p>
|
||||
* The EbeanServer is provided so that cache implementations can make use of
|
||||
* EbeanServer and BackgroundExecutor for automatically populating and
|
||||
* background trimming of the cache.
|
||||
* </p>
|
||||
*/
|
||||
public void init(EbeanServer server);
|
||||
|
||||
public void setCaching(Class<?> beanType, boolean useCache);
|
||||
|
||||
/**
|
||||
* Return true if there is an active bean cache for this type of bean.
|
||||
*/
|
||||
public boolean isBeanCaching(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* Return the cache for mapping natural keys to id values.
|
||||
*/
|
||||
public ServerCache getNaturalKeyCache(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* Return the cache for beans of a particular type.
|
||||
*/
|
||||
public ServerCache getBeanCache(Class<?> beanType);
|
||||
|
||||
public ServerCache getCollectionIdsCache(Class<?> beanType, String propertyName);
|
||||
|
||||
/**
|
||||
* Return the cache for query results of a particular type of bean.
|
||||
*/
|
||||
public ServerCache getQueryCache(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* This clears both the bean and query cache for a given type.
|
||||
*/
|
||||
public void clear(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* Clear all the caches.
|
||||
*/
|
||||
public void clearAll();
|
||||
|
||||
}
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
|
||||
/**
|
||||
* The cache service for server side caching of beans and query results.
|
||||
*/
|
||||
public interface ServerCacheManager {
|
||||
|
||||
/**
|
||||
* This method is called just after the construction of the
|
||||
* ServerCacheManager.
|
||||
* <p>
|
||||
* The EbeanServer is provided so that cache implementations can make use of
|
||||
* EbeanServer and BackgroundExecutor for automatically populating and
|
||||
* background trimming of the cache.
|
||||
* </p>
|
||||
*/
|
||||
void init(EbeanServer server);
|
||||
|
||||
void setCaching(Class<?> beanType, boolean useCache);
|
||||
|
||||
/**
|
||||
* Return true if there is an active bean cache for this type of bean.
|
||||
*/
|
||||
boolean isBeanCaching(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* Return the cache for mapping natural keys to id values.
|
||||
*/
|
||||
ServerCache getNaturalKeyCache(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* Return the cache for beans of a particular type.
|
||||
*/
|
||||
ServerCache getBeanCache(Class<?> beanType);
|
||||
|
||||
ServerCache getCollectionIdsCache(Class<?> beanType, String propertyName);
|
||||
|
||||
/**
|
||||
* Return the cache for query results of a particular type of bean.
|
||||
*/
|
||||
ServerCache getQueryCache(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* This clears both the bean and query cache for a given type.
|
||||
*/
|
||||
void clear(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* Clear all the caches.
|
||||
*/
|
||||
void clearAll();
|
||||
|
||||
}
|
||||
|
||||
+110
-110
@@ -1,110 +1,110 @@
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
import com.avaje.ebean.annotation.CacheTuning;
|
||||
|
||||
/**
|
||||
* Options for controlling a cache.
|
||||
*/
|
||||
public class ServerCacheOptions {
|
||||
|
||||
private int maxSize;
|
||||
private int maxIdleSecs;
|
||||
private int maxSecsToLive;
|
||||
|
||||
/**
|
||||
* Construct with no set options.
|
||||
*/
|
||||
public ServerCacheOptions() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create from the cacheTuning deployment annotation.
|
||||
*/
|
||||
public ServerCacheOptions(CacheTuning cacheTuning) {
|
||||
this.maxSize = cacheTuning.maxSize();
|
||||
this.maxIdleSecs = cacheTuning.maxIdleSecs();
|
||||
this.maxSecsToLive = cacheTuning.maxSecsToLive();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create merging default options with the deployment specified ones.
|
||||
*/
|
||||
public ServerCacheOptions(ServerCacheOptions d) {
|
||||
this.maxSize = d.getMaxSize();
|
||||
this.maxIdleSecs = d.getMaxIdleSecs();
|
||||
this.maxSecsToLive = d.getMaxIdleSecs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply any settings from the default settings that have not already been
|
||||
* specifically set.
|
||||
*/
|
||||
public void applyDefaults(ServerCacheOptions defaults) {
|
||||
if (maxSize == 0) {
|
||||
maxSize = defaults.getMaxSize();
|
||||
}
|
||||
if (maxIdleSecs == 0) {
|
||||
maxIdleSecs = defaults.getMaxIdleSecs();
|
||||
}
|
||||
if (maxSecsToLive == 0) {
|
||||
maxSecsToLive = defaults.getMaxSecsToLive();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this object.
|
||||
*/
|
||||
public ServerCacheOptions copy() {
|
||||
|
||||
ServerCacheOptions copy = new ServerCacheOptions();
|
||||
copy.maxSize = maxSize;
|
||||
copy.maxIdleSecs = maxIdleSecs;
|
||||
copy.maxSecsToLive = maxSecsToLive;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum cache size.
|
||||
*/
|
||||
public int getMaxSize() {
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum cache size.
|
||||
*/
|
||||
public void setMaxSize(int maxSize) {
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum idle time.
|
||||
*/
|
||||
public int getMaxIdleSecs() {
|
||||
return maxIdleSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum idle time.
|
||||
*/
|
||||
public void setMaxIdleSecs(int maxIdleSecs) {
|
||||
this.maxIdleSecs = maxIdleSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum time to live.
|
||||
*/
|
||||
public int getMaxSecsToLive() {
|
||||
return maxSecsToLive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum time to live.
|
||||
*/
|
||||
public void setMaxSecsToLive(int maxSecsToLive) {
|
||||
this.maxSecsToLive = maxSecsToLive;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
import com.avaje.ebean.annotation.CacheTuning;
|
||||
|
||||
/**
|
||||
* Options for controlling a cache.
|
||||
*/
|
||||
public class ServerCacheOptions {
|
||||
|
||||
private int maxSize;
|
||||
private int maxIdleSecs;
|
||||
private int maxSecsToLive;
|
||||
|
||||
/**
|
||||
* Construct with no set options.
|
||||
*/
|
||||
public ServerCacheOptions() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create from the cacheTuning deployment annotation.
|
||||
*/
|
||||
public ServerCacheOptions(CacheTuning cacheTuning) {
|
||||
this.maxSize = cacheTuning.maxSize();
|
||||
this.maxIdleSecs = cacheTuning.maxIdleSecs();
|
||||
this.maxSecsToLive = cacheTuning.maxSecsToLive();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create merging default options with the deployment specified ones.
|
||||
*/
|
||||
public ServerCacheOptions(ServerCacheOptions d) {
|
||||
this.maxSize = d.getMaxSize();
|
||||
this.maxIdleSecs = d.getMaxIdleSecs();
|
||||
this.maxSecsToLive = d.getMaxIdleSecs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply any settings from the default settings that have not already been
|
||||
* specifically set.
|
||||
*/
|
||||
public void applyDefaults(ServerCacheOptions defaults) {
|
||||
if (maxSize == 0) {
|
||||
maxSize = defaults.getMaxSize();
|
||||
}
|
||||
if (maxIdleSecs == 0) {
|
||||
maxIdleSecs = defaults.getMaxIdleSecs();
|
||||
}
|
||||
if (maxSecsToLive == 0) {
|
||||
maxSecsToLive = defaults.getMaxSecsToLive();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this object.
|
||||
*/
|
||||
public ServerCacheOptions copy() {
|
||||
|
||||
ServerCacheOptions copy = new ServerCacheOptions();
|
||||
copy.maxSize = maxSize;
|
||||
copy.maxIdleSecs = maxIdleSecs;
|
||||
copy.maxSecsToLive = maxSecsToLive;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum cache size.
|
||||
*/
|
||||
public int getMaxSize() {
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum cache size.
|
||||
*/
|
||||
public void setMaxSize(int maxSize) {
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum idle time.
|
||||
*/
|
||||
public int getMaxIdleSecs() {
|
||||
return maxIdleSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum idle time.
|
||||
*/
|
||||
public void setMaxIdleSecs(int maxIdleSecs) {
|
||||
this.maxIdleSecs = maxIdleSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum time to live.
|
||||
*/
|
||||
public int getMaxSecsToLive() {
|
||||
return maxSecsToLive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum time to live.
|
||||
*/
|
||||
public void setMaxSecsToLive(int maxSecsToLive) {
|
||||
this.maxSecsToLive = maxSecsToLive;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+124
-124
@@ -1,124 +1,124 @@
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
/**
|
||||
* The statistics collected per cache.
|
||||
* <p>
|
||||
* These can be monitored to review the effectiveness of a particular cache.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
*/
|
||||
public class ServerCacheStatistics {
|
||||
|
||||
protected String cacheName;
|
||||
|
||||
protected int maxSize;
|
||||
|
||||
protected int size;
|
||||
|
||||
protected int hitCount;
|
||||
|
||||
protected int missCount;
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(cacheName);
|
||||
sb.append(" size:").append(size);
|
||||
sb.append(" hitRatio:").append(getHitRatio());
|
||||
sb.append(" hitCount:").append(hitCount);
|
||||
sb.append(" missCount:").append(missCount);
|
||||
sb.append(" maxSize:").append(maxSize);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the cache.
|
||||
*/
|
||||
public String getCacheName() {
|
||||
return cacheName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the cache.
|
||||
*/
|
||||
public void setCacheName(String cacheName) {
|
||||
this.cacheName = cacheName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hit count. The number of successful gets.
|
||||
*/
|
||||
public int getHitCount() {
|
||||
return hitCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the hit count.
|
||||
*/
|
||||
public void setHitCount(int hitCount) {
|
||||
this.hitCount = hitCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the miss count. The number of gets that returned null.
|
||||
*/
|
||||
public int getMissCount() {
|
||||
return missCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the miss count.
|
||||
*/
|
||||
public void setMissCount(int missCount) {
|
||||
this.missCount = missCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of the cache.
|
||||
*/
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the size of the cache.
|
||||
*/
|
||||
public void setSize(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum size of the cache.
|
||||
* <p>
|
||||
* Can be used in conjunction with the size to determine if the cache use is
|
||||
* being potentially limited by its maximum size.
|
||||
* </p>
|
||||
*/
|
||||
public int getMaxSize() {
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum size of the cache.
|
||||
*/
|
||||
public void setMaxSize(int maxSize) {
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an int from 0 to 100 (percentage) for the hit ratio.
|
||||
* <p>
|
||||
* A hit ratio of 100 means every get request against the cache hits an entry.
|
||||
* </p>
|
||||
*/
|
||||
public int getHitRatio() {
|
||||
int totalCount = hitCount + missCount;
|
||||
if (totalCount == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return hitCount * 100 / totalCount;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
/**
|
||||
* The statistics collected per cache.
|
||||
* <p>
|
||||
* These can be monitored to review the effectiveness of a particular cache.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
*/
|
||||
public class ServerCacheStatistics {
|
||||
|
||||
protected String cacheName;
|
||||
|
||||
protected int maxSize;
|
||||
|
||||
protected int size;
|
||||
|
||||
protected int hitCount;
|
||||
|
||||
protected int missCount;
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(cacheName);
|
||||
sb.append(" size:").append(size);
|
||||
sb.append(" hitRatio:").append(getHitRatio());
|
||||
sb.append(" hitCount:").append(hitCount);
|
||||
sb.append(" missCount:").append(missCount);
|
||||
sb.append(" maxSize:").append(maxSize);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the cache.
|
||||
*/
|
||||
public String getCacheName() {
|
||||
return cacheName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the cache.
|
||||
*/
|
||||
public void setCacheName(String cacheName) {
|
||||
this.cacheName = cacheName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hit count. The number of successful gets.
|
||||
*/
|
||||
public int getHitCount() {
|
||||
return hitCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the hit count.
|
||||
*/
|
||||
public void setHitCount(int hitCount) {
|
||||
this.hitCount = hitCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the miss count. The number of gets that returned null.
|
||||
*/
|
||||
public int getMissCount() {
|
||||
return missCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the miss count.
|
||||
*/
|
||||
public void setMissCount(int missCount) {
|
||||
this.missCount = missCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of the cache.
|
||||
*/
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the size of the cache.
|
||||
*/
|
||||
public void setSize(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum size of the cache.
|
||||
* <p>
|
||||
* Can be used in conjunction with the size to determine if the cache use is
|
||||
* being potentially limited by its maximum size.
|
||||
* </p>
|
||||
*/
|
||||
public int getMaxSize() {
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum size of the cache.
|
||||
*/
|
||||
public void setMaxSize(int maxSize) {
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an int from 0 to 100 (percentage) for the hit ratio.
|
||||
* <p>
|
||||
* A hit ratio of 100 means every get request against the cache hits an entry.
|
||||
* </p>
|
||||
*/
|
||||
public int getHitRatio() {
|
||||
int totalCount = hitCount + missCount;
|
||||
if (totalCount == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return hitCount * 100 / totalCount;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,222 +1,222 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.ExpressionList;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.BeanCollectionTouched;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
/**
|
||||
* Base class for List Set and Map implementations of BeanCollection.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
|
||||
private static final long serialVersionUID = 3365725236140187588L;
|
||||
|
||||
protected boolean readOnly;
|
||||
|
||||
/**
|
||||
* The EbeanServer this is associated with. (used for lazy fetch).
|
||||
*/
|
||||
protected transient BeanCollectionLoader loader;
|
||||
|
||||
protected transient ExpressionList<?> filterMany;
|
||||
|
||||
/**
|
||||
* Flag set when registered with the batch loading context.
|
||||
*/
|
||||
protected boolean registeredWithLoadContext;
|
||||
|
||||
protected String ebeanServerName;
|
||||
|
||||
protected transient BeanCollectionTouched beanCollectionTouched;
|
||||
|
||||
/**
|
||||
* The owning bean (used for lazy fetch).
|
||||
*/
|
||||
protected EntityBean ownerBean;
|
||||
|
||||
/**
|
||||
* The name of this property in the owning bean (used for lazy fetch).
|
||||
*/
|
||||
protected String propertyName;
|
||||
|
||||
protected ModifyHolder<E> modifyHolder;
|
||||
|
||||
protected ModifyListenMode modifyListenMode;
|
||||
protected boolean modifyAddListening;
|
||||
protected boolean modifyRemoveListening;
|
||||
protected boolean modifyListening;
|
||||
|
||||
/**
|
||||
* Flag used to tell if empty collections have been cleared etc or just
|
||||
* uninitialised.
|
||||
*/
|
||||
protected boolean touched;
|
||||
|
||||
/**
|
||||
* Constructor not non-lazy loading collection.
|
||||
*/
|
||||
public AbstractBeanCollection() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to create deferred fetch proxy.
|
||||
*/
|
||||
public AbstractBeanCollection(BeanCollectionLoader loader, EntityBean ownerBean, String propertyName) {
|
||||
this.loader = loader;
|
||||
this.ebeanServerName = loader.getName();
|
||||
this.ownerBean = ownerBean;
|
||||
this.propertyName = propertyName;
|
||||
this.readOnly = ownerBean._ebean_getIntercept().isReadOnly();
|
||||
}
|
||||
|
||||
public EntityBean getOwnerBean() {
|
||||
return ownerBean;
|
||||
}
|
||||
|
||||
public String getPropertyName() {
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
public ExpressionList<?> getFilterMany() {
|
||||
return filterMany;
|
||||
}
|
||||
|
||||
public void setFilterMany(ExpressionList<?> filterMany) {
|
||||
this.filterMany = filterMany;
|
||||
}
|
||||
|
||||
protected void lazyLoadCollection(boolean onlyIds) {
|
||||
if (loader == null) {
|
||||
loader = (BeanCollectionLoader) Ebean.getServer(ebeanServerName);
|
||||
}
|
||||
if (loader == null) {
|
||||
String msg = "Lazy loading but LazyLoadEbeanServer is null?"
|
||||
+ " The LazyLoadEbeanServer needs to be set after deserialization"
|
||||
+ " to support lazy loading.";
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
|
||||
loader.loadMany(this, onlyIds);
|
||||
checkEmptyLazyLoad();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set touched. If setFlag is false then typically an isEmpty() call and still
|
||||
* considering that to be untouched.
|
||||
*/
|
||||
protected void touched(boolean setFlag) {
|
||||
if (setFlag) {
|
||||
touched = true;
|
||||
}
|
||||
if (beanCollectionTouched != null) {
|
||||
// only call this once
|
||||
beanCollectionTouched.notifyTouched(this);
|
||||
beanCollectionTouched = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setBeanCollectionTouched(BeanCollectionTouched notify) {
|
||||
this.beanCollectionTouched = notify;
|
||||
}
|
||||
|
||||
public boolean isRegisteredWithLoadContext() {
|
||||
return registeredWithLoadContext;
|
||||
}
|
||||
|
||||
public void setLoader(BeanCollectionLoader loader) {
|
||||
this.registeredWithLoadContext = true;
|
||||
this.loader = loader;
|
||||
this.ebeanServerName = loader.getName();
|
||||
}
|
||||
|
||||
public boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
public void setReadOnly(boolean readOnly) {
|
||||
this.readOnly = readOnly;
|
||||
}
|
||||
|
||||
protected void checkReadOnly() {
|
||||
if (readOnly) {
|
||||
String msg = "This collection is in ReadOnly mode";
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Support for modify additions deletions etc - ManyToMany
|
||||
// ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* set modifyListening to be on or off.
|
||||
*/
|
||||
public void setModifyListening(ModifyListenMode mode) {
|
||||
|
||||
this.modifyListenMode = mode;
|
||||
this.modifyAddListening = ModifyListenMode.ALL.equals(mode);
|
||||
this.modifyRemoveListening = modifyAddListening || ModifyListenMode.REMOVALS.equals(mode);
|
||||
this.modifyListening = modifyRemoveListening || modifyAddListening;
|
||||
if (modifyListening) {
|
||||
// lose any existing modifications
|
||||
modifyHolder = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the modify listening mode this collection is using.
|
||||
*/
|
||||
public ModifyListenMode getModifyListenMode() {
|
||||
return modifyListenMode;
|
||||
}
|
||||
|
||||
protected ModifyHolder<E> getModifyHolder() {
|
||||
if (modifyHolder == null) {
|
||||
modifyHolder = new ModifyHolder<E>();
|
||||
}
|
||||
return modifyHolder;
|
||||
}
|
||||
|
||||
public void modifyAddition(E bean) {
|
||||
if (modifyAddListening) {
|
||||
getModifyHolder().modifyAddition(bean);
|
||||
}
|
||||
}
|
||||
|
||||
public void modifyRemoval(Object bean) {
|
||||
if (modifyRemoveListening) {
|
||||
getModifyHolder().modifyRemoval(bean);
|
||||
}
|
||||
}
|
||||
|
||||
public void modifyReset() {
|
||||
if (modifyHolder != null) {
|
||||
modifyHolder.reset();
|
||||
}
|
||||
}
|
||||
|
||||
public Set<E> getModifyAdditions() {
|
||||
if (modifyHolder == null) {
|
||||
return null;
|
||||
} else {
|
||||
return modifyHolder.getModifyAdditions();
|
||||
}
|
||||
}
|
||||
|
||||
public Set<E> getModifyRemovals() {
|
||||
if (modifyHolder == null) {
|
||||
return null;
|
||||
} else {
|
||||
return modifyHolder.getModifyRemovals();
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.ExpressionList;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.BeanCollectionTouched;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
/**
|
||||
* Base class for List Set and Map implementations of BeanCollection.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
|
||||
private static final long serialVersionUID = 3365725236140187588L;
|
||||
|
||||
protected boolean readOnly;
|
||||
|
||||
/**
|
||||
* The EbeanServer this is associated with. (used for lazy fetch).
|
||||
*/
|
||||
protected transient BeanCollectionLoader loader;
|
||||
|
||||
protected transient ExpressionList<?> filterMany;
|
||||
|
||||
/**
|
||||
* Flag set when registered with the batch loading context.
|
||||
*/
|
||||
protected boolean registeredWithLoadContext;
|
||||
|
||||
protected String ebeanServerName;
|
||||
|
||||
protected transient BeanCollectionTouched beanCollectionTouched;
|
||||
|
||||
/**
|
||||
* The owning bean (used for lazy fetch).
|
||||
*/
|
||||
protected EntityBean ownerBean;
|
||||
|
||||
/**
|
||||
* The name of this property in the owning bean (used for lazy fetch).
|
||||
*/
|
||||
protected String propertyName;
|
||||
|
||||
protected ModifyHolder<E> modifyHolder;
|
||||
|
||||
protected ModifyListenMode modifyListenMode;
|
||||
protected boolean modifyAddListening;
|
||||
protected boolean modifyRemoveListening;
|
||||
protected boolean modifyListening;
|
||||
|
||||
/**
|
||||
* Flag used to tell if empty collections have been cleared etc or just
|
||||
* uninitialised.
|
||||
*/
|
||||
protected boolean touched;
|
||||
|
||||
/**
|
||||
* Constructor not non-lazy loading collection.
|
||||
*/
|
||||
public AbstractBeanCollection() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to create deferred fetch proxy.
|
||||
*/
|
||||
public AbstractBeanCollection(BeanCollectionLoader loader, EntityBean ownerBean, String propertyName) {
|
||||
this.loader = loader;
|
||||
this.ebeanServerName = loader.getName();
|
||||
this.ownerBean = ownerBean;
|
||||
this.propertyName = propertyName;
|
||||
this.readOnly = ownerBean._ebean_getIntercept().isReadOnly();
|
||||
}
|
||||
|
||||
public EntityBean getOwnerBean() {
|
||||
return ownerBean;
|
||||
}
|
||||
|
||||
public String getPropertyName() {
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
public ExpressionList<?> getFilterMany() {
|
||||
return filterMany;
|
||||
}
|
||||
|
||||
public void setFilterMany(ExpressionList<?> filterMany) {
|
||||
this.filterMany = filterMany;
|
||||
}
|
||||
|
||||
protected void lazyLoadCollection(boolean onlyIds) {
|
||||
if (loader == null) {
|
||||
loader = (BeanCollectionLoader) Ebean.getServer(ebeanServerName);
|
||||
}
|
||||
if (loader == null) {
|
||||
String msg = "Lazy loading but LazyLoadEbeanServer is null?"
|
||||
+ " The LazyLoadEbeanServer needs to be set after deserialization"
|
||||
+ " to support lazy loading.";
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
|
||||
loader.loadMany(this, onlyIds);
|
||||
checkEmptyLazyLoad();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set touched. If setFlag is false then typically an isEmpty() call and still
|
||||
* considering that to be untouched.
|
||||
*/
|
||||
protected void touched(boolean setFlag) {
|
||||
if (setFlag) {
|
||||
touched = true;
|
||||
}
|
||||
if (beanCollectionTouched != null) {
|
||||
// only call this once
|
||||
beanCollectionTouched.notifyTouched(this);
|
||||
beanCollectionTouched = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setBeanCollectionTouched(BeanCollectionTouched notify) {
|
||||
this.beanCollectionTouched = notify;
|
||||
}
|
||||
|
||||
public boolean isRegisteredWithLoadContext() {
|
||||
return registeredWithLoadContext;
|
||||
}
|
||||
|
||||
public void setLoader(BeanCollectionLoader loader) {
|
||||
this.registeredWithLoadContext = true;
|
||||
this.loader = loader;
|
||||
this.ebeanServerName = loader.getName();
|
||||
}
|
||||
|
||||
public boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
public void setReadOnly(boolean readOnly) {
|
||||
this.readOnly = readOnly;
|
||||
}
|
||||
|
||||
protected void checkReadOnly() {
|
||||
if (readOnly) {
|
||||
String msg = "This collection is in ReadOnly mode";
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Support for modify additions deletions etc - ManyToMany
|
||||
// ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* set modifyListening to be on or off.
|
||||
*/
|
||||
public void setModifyListening(ModifyListenMode mode) {
|
||||
|
||||
this.modifyListenMode = mode;
|
||||
this.modifyAddListening = ModifyListenMode.ALL.equals(mode);
|
||||
this.modifyRemoveListening = modifyAddListening || ModifyListenMode.REMOVALS.equals(mode);
|
||||
this.modifyListening = modifyRemoveListening || modifyAddListening;
|
||||
if (modifyListening) {
|
||||
// lose any existing modifications
|
||||
modifyHolder = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the modify listening mode this collection is using.
|
||||
*/
|
||||
public ModifyListenMode getModifyListenMode() {
|
||||
return modifyListenMode;
|
||||
}
|
||||
|
||||
protected ModifyHolder<E> getModifyHolder() {
|
||||
if (modifyHolder == null) {
|
||||
modifyHolder = new ModifyHolder<E>();
|
||||
}
|
||||
return modifyHolder;
|
||||
}
|
||||
|
||||
public void modifyAddition(E bean) {
|
||||
if (modifyAddListening) {
|
||||
getModifyHolder().modifyAddition(bean);
|
||||
}
|
||||
}
|
||||
|
||||
public void modifyRemoval(Object bean) {
|
||||
if (modifyRemoveListening) {
|
||||
getModifyHolder().modifyRemoval(bean);
|
||||
}
|
||||
}
|
||||
|
||||
public void modifyReset() {
|
||||
if (modifyHolder != null) {
|
||||
modifyHolder.reset();
|
||||
}
|
||||
}
|
||||
|
||||
public Set<E> getModifyAdditions() {
|
||||
if (modifyHolder == null) {
|
||||
return null;
|
||||
} else {
|
||||
return modifyHolder.getModifyAdditions();
|
||||
}
|
||||
}
|
||||
|
||||
public Set<E> getModifyRemovals() {
|
||||
if (modifyHolder == null) {
|
||||
return null;
|
||||
} else {
|
||||
return modifyHolder.getModifyRemovals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,466 +1,468 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollectionAdd;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
/**
|
||||
* List capable of lazy loading.
|
||||
*/
|
||||
public final class BeanList<E> extends AbstractBeanCollection<E> implements List<E>, BeanCollectionAdd {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* The underlying List implementation.
|
||||
*/
|
||||
private List<E> list;
|
||||
|
||||
/**
|
||||
* Specify the underlying List implementation.
|
||||
*/
|
||||
public BeanList(List<E> list) {
|
||||
super();
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses an ArrayList as the underlying List implementation.
|
||||
*/
|
||||
public BeanList() {
|
||||
this(new ArrayList<E>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to create deferred fetch proxy.
|
||||
*/
|
||||
public BeanList(BeanCollectionLoader loader, EntityBean ownerBean, String propertyName) {
|
||||
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());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void addBean(EntityBean bean) {
|
||||
list.add((E) bean);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void internalAdd(Object bean) {
|
||||
if (list == null) {
|
||||
list = new ArrayList<E>();
|
||||
}
|
||||
list.add((E) bean);
|
||||
}
|
||||
|
||||
public boolean checkEmptyLazyLoad() {
|
||||
if (list == null) {
|
||||
list = new ArrayList<E>();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void initClear() {
|
||||
synchronized (this) {
|
||||
if (list == null) {
|
||||
if (modifyListening) {
|
||||
lazyLoadCollection(true);
|
||||
} else {
|
||||
list = new ArrayList<E>();
|
||||
}
|
||||
}
|
||||
touched(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void initAsUntouched() {
|
||||
init(false);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
init(true);
|
||||
}
|
||||
|
||||
private void init(boolean setTouched) {
|
||||
synchronized (this) {
|
||||
if (list == null) {
|
||||
lazyLoadCollection(false);
|
||||
}
|
||||
touched(setTouched);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the actual underlying list.
|
||||
* <p>
|
||||
* This is primarily for the deferred fetching function.
|
||||
* </p>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setActualList(List<?> list) {
|
||||
this.list = (List<E>) list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the actual underlying list.
|
||||
*/
|
||||
public List<E> getActualList() {
|
||||
return list;
|
||||
}
|
||||
|
||||
public Collection<E> getActualDetails() {
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<?> getActualEntries() {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the underlying list is populated.
|
||||
*/
|
||||
public boolean isPopulated() {
|
||||
return list != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a reference (lazy loading) bean collection. This is
|
||||
* the same as !isPopulated();
|
||||
*/
|
||||
public boolean isReference() {
|
||||
return list == null;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer(50);
|
||||
sb.append("BeanList ");
|
||||
if (isReadOnly()) {
|
||||
sb.append("readOnly ");
|
||||
}
|
||||
if (list == null) {
|
||||
sb.append("deferred ");
|
||||
|
||||
} else {
|
||||
sb.append("size[").append(list.size()).append("] ");
|
||||
sb.append("list").append(list).append("");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Equal if obj is a List and equal in a list sense.
|
||||
* <p>
|
||||
* Specifically obj does not need to be a BeanList but any list. This does not
|
||||
* use the FindMany, fetchedMaxRows or finishedFetch properties in the equals
|
||||
* test.
|
||||
* </p>
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
init();
|
||||
return list.equals(obj);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
init();
|
||||
return list.hashCode();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------//
|
||||
// The additional methods are here
|
||||
// -----------------------------------------------------//
|
||||
|
||||
// -----------------------------------------------------//
|
||||
// proxy method for List
|
||||
// -----------------------------------------------------//
|
||||
|
||||
public void add(int index, E element) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyAddListening) {
|
||||
modifyAddition(element);
|
||||
}
|
||||
list.add(index, element);
|
||||
}
|
||||
|
||||
public boolean add(E o) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyAddListening) {
|
||||
if (list.add(o)) {
|
||||
modifyAddition(o);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return list.add(o);
|
||||
}
|
||||
|
||||
public boolean addAll(Collection<? extends E> c) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyAddListening) {
|
||||
// all elements in c are added (no contains checking)
|
||||
getModifyHolder().modifyAdditionAll(c);
|
||||
}
|
||||
return list.addAll(c);
|
||||
}
|
||||
|
||||
public boolean addAll(int index, Collection<? extends E> c) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyAddListening) {
|
||||
// all elements in c are added (no contains checking)
|
||||
getModifyHolder().modifyAdditionAll(c);
|
||||
}
|
||||
return list.addAll(index, c);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
checkReadOnly();
|
||||
// TODO: when clear() and not initialised could be more clever
|
||||
// and fetch just the Id's
|
||||
initClear();
|
||||
if (modifyRemoveListening) {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
getModifyHolder().modifyRemoval(list.get(i));
|
||||
}
|
||||
}
|
||||
list.clear();
|
||||
}
|
||||
|
||||
public boolean contains(Object o) {
|
||||
init();
|
||||
return list.contains(o);
|
||||
}
|
||||
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
init();
|
||||
return list.containsAll(c);
|
||||
}
|
||||
|
||||
public E get(int index) {
|
||||
init();
|
||||
return list.get(index);
|
||||
}
|
||||
|
||||
public int indexOf(Object o) {
|
||||
init();
|
||||
return list.indexOf(o);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
initAsUntouched();
|
||||
return list.isEmpty();
|
||||
}
|
||||
|
||||
public Iterator<E> iterator() {
|
||||
init();
|
||||
if (isReadOnly()) {
|
||||
return new ReadOnlyListIterator<E>(list.listIterator());
|
||||
}
|
||||
if (modifyListening) {
|
||||
Iterator<E> it = list.iterator();
|
||||
return new ModifyIterator<E>(this, it);
|
||||
}
|
||||
return list.iterator();
|
||||
}
|
||||
|
||||
public int lastIndexOf(Object o) {
|
||||
init();
|
||||
return list.lastIndexOf(o);
|
||||
}
|
||||
|
||||
public ListIterator<E> listIterator() {
|
||||
init();
|
||||
if (isReadOnly()) {
|
||||
return new ReadOnlyListIterator<E>(list.listIterator());
|
||||
}
|
||||
if (modifyListening) {
|
||||
ListIterator<E> it = list.listIterator();
|
||||
return new ModifyListIterator<E>(this, it);
|
||||
}
|
||||
return list.listIterator();
|
||||
}
|
||||
|
||||
public ListIterator<E> listIterator(int index) {
|
||||
init();
|
||||
if (isReadOnly()) {
|
||||
return new ReadOnlyListIterator<E>(list.listIterator(index));
|
||||
}
|
||||
if (modifyListening) {
|
||||
ListIterator<E> it = list.listIterator(index);
|
||||
return new ModifyListIterator<E>(this, it);
|
||||
}
|
||||
return list.listIterator(index);
|
||||
}
|
||||
|
||||
public E remove(int index) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyRemoveListening) {
|
||||
E o = list.remove(index);
|
||||
modifyRemoval(o);
|
||||
return o;
|
||||
}
|
||||
return list.remove(index);
|
||||
}
|
||||
|
||||
public boolean remove(Object o) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyRemoveListening) {
|
||||
boolean isRemove = list.remove(o);
|
||||
if (isRemove) {
|
||||
modifyRemoval(o);
|
||||
}
|
||||
return isRemove;
|
||||
}
|
||||
return list.remove(o);
|
||||
}
|
||||
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyRemoveListening) {
|
||||
boolean changed = false;
|
||||
Iterator<?> it = c.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object o = (Object) it.next();
|
||||
if (list.remove(o)) {
|
||||
modifyRemoval(o);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
return list.removeAll(c);
|
||||
}
|
||||
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyRemoveListening) {
|
||||
boolean changed = false;
|
||||
Iterator<E> it = list.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object o = (Object) it.next();
|
||||
if (!c.contains(o)) {
|
||||
it.remove();
|
||||
modifyRemoval(o);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
return list.retainAll(c);
|
||||
}
|
||||
|
||||
public E set(int index, E element) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyListening) {
|
||||
E o = list.set(index, element);
|
||||
modifyAddition(element);
|
||||
modifyRemoval(o);
|
||||
return o;
|
||||
}
|
||||
return list.set(index, element);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
init();
|
||||
return list.size();
|
||||
}
|
||||
|
||||
public List<E> subList(int fromIndex, int toIndex) {
|
||||
init();
|
||||
if (isReadOnly()) {
|
||||
return Collections.unmodifiableList(list.subList(fromIndex, toIndex));
|
||||
}
|
||||
if (modifyListening) {
|
||||
return new ModifyList<E>(this, list.subList(fromIndex, toIndex));
|
||||
}
|
||||
return list.subList(fromIndex, toIndex);
|
||||
}
|
||||
|
||||
public Object[] toArray() {
|
||||
init();
|
||||
return list.toArray();
|
||||
}
|
||||
|
||||
public <T> T[] toArray(T[] a) {
|
||||
init();
|
||||
return list.toArray(a);
|
||||
}
|
||||
|
||||
private static class ReadOnlyListIterator<E> implements ListIterator<E>, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 3097271091406323699L;
|
||||
|
||||
private final ListIterator<E> i;
|
||||
|
||||
ReadOnlyListIterator(ListIterator<E> i) {
|
||||
this.i = i;
|
||||
}
|
||||
|
||||
public void add(E o) {
|
||||
throw new IllegalStateException("This collection is in ReadOnly mode");
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new IllegalStateException("This collection is in ReadOnly mode");
|
||||
}
|
||||
|
||||
public void set(E o) {
|
||||
throw new IllegalStateException("This collection is in ReadOnly mode");
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return i.hasNext();
|
||||
}
|
||||
|
||||
public boolean hasPrevious() {
|
||||
return i.hasPrevious();
|
||||
}
|
||||
|
||||
public E next() {
|
||||
return i.next();
|
||||
}
|
||||
|
||||
public int nextIndex() {
|
||||
return i.nextIndex();
|
||||
}
|
||||
|
||||
public E previous() {
|
||||
return i.previous();
|
||||
}
|
||||
|
||||
public int previousIndex() {
|
||||
return i.previousIndex();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollectionAdd;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
/**
|
||||
* List capable of lazy loading.
|
||||
*/
|
||||
public final class BeanList<E> extends AbstractBeanCollection<E> implements List<E>, BeanCollectionAdd {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* The underlying List implementation.
|
||||
*/
|
||||
private List<E> list;
|
||||
|
||||
/**
|
||||
* Specify the underlying List implementation.
|
||||
*/
|
||||
public BeanList(List<E> list) {
|
||||
super();
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses an ArrayList as the underlying List implementation.
|
||||
*/
|
||||
public BeanList() {
|
||||
this(new ArrayList<E>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to create deferred fetch proxy.
|
||||
*/
|
||||
public BeanList(BeanCollectionLoader loader, EntityBean ownerBean, String propertyName) {
|
||||
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());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void addBean(EntityBean bean) {
|
||||
list.add((E) bean);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void internalAdd(Object bean) {
|
||||
if (list == null) {
|
||||
list = new ArrayList<E>();
|
||||
}
|
||||
if (bean != null) {
|
||||
list.add((E) bean);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean checkEmptyLazyLoad() {
|
||||
if (list == null) {
|
||||
list = new ArrayList<E>();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void initClear() {
|
||||
synchronized (this) {
|
||||
if (list == null) {
|
||||
if (modifyListening) {
|
||||
lazyLoadCollection(true);
|
||||
} else {
|
||||
list = new ArrayList<E>();
|
||||
}
|
||||
}
|
||||
touched(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void initAsUntouched() {
|
||||
init(false);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
init(true);
|
||||
}
|
||||
|
||||
private void init(boolean setTouched) {
|
||||
synchronized (this) {
|
||||
if (list == null) {
|
||||
lazyLoadCollection(false);
|
||||
}
|
||||
touched(setTouched);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the actual underlying list.
|
||||
* <p>
|
||||
* This is primarily for the deferred fetching function.
|
||||
* </p>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setActualList(List<?> list) {
|
||||
this.list = (List<E>) list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the actual underlying list.
|
||||
*/
|
||||
public List<E> getActualList() {
|
||||
return list;
|
||||
}
|
||||
|
||||
public Collection<E> getActualDetails() {
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<?> getActualEntries() {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the underlying list is populated.
|
||||
*/
|
||||
public boolean isPopulated() {
|
||||
return list != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a reference (lazy loading) bean collection. This is
|
||||
* the same as !isPopulated();
|
||||
*/
|
||||
public boolean isReference() {
|
||||
return list == null;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(50);
|
||||
sb.append("BeanList ");
|
||||
if (isReadOnly()) {
|
||||
sb.append("readOnly ");
|
||||
}
|
||||
if (list == null) {
|
||||
sb.append("deferred ");
|
||||
|
||||
} else {
|
||||
sb.append("size[").append(list.size()).append("] ");
|
||||
sb.append("list").append(list).append("");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Equal if obj is a List and equal in a list sense.
|
||||
* <p>
|
||||
* Specifically obj does not need to be a BeanList but any list. This does not
|
||||
* use the FindMany, fetchedMaxRows or finishedFetch properties in the equals
|
||||
* test.
|
||||
* </p>
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
init();
|
||||
return list.equals(obj);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
init();
|
||||
return list.hashCode();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------//
|
||||
// The additional methods are here
|
||||
// -----------------------------------------------------//
|
||||
|
||||
// -----------------------------------------------------//
|
||||
// proxy method for List
|
||||
// -----------------------------------------------------//
|
||||
|
||||
public void add(int index, E element) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyAddListening) {
|
||||
modifyAddition(element);
|
||||
}
|
||||
list.add(index, element);
|
||||
}
|
||||
|
||||
public boolean add(E o) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyAddListening) {
|
||||
if (list.add(o)) {
|
||||
modifyAddition(o);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return list.add(o);
|
||||
}
|
||||
|
||||
public boolean addAll(Collection<? extends E> c) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyAddListening) {
|
||||
// all elements in c are added (no contains checking)
|
||||
getModifyHolder().modifyAdditionAll(c);
|
||||
}
|
||||
return list.addAll(c);
|
||||
}
|
||||
|
||||
public boolean addAll(int index, Collection<? extends E> c) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyAddListening) {
|
||||
// all elements in c are added (no contains checking)
|
||||
getModifyHolder().modifyAdditionAll(c);
|
||||
}
|
||||
return list.addAll(index, c);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
checkReadOnly();
|
||||
// TODO: when clear() and not initialised could be more clever
|
||||
// and fetch just the Id's
|
||||
initClear();
|
||||
if (modifyRemoveListening) {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
getModifyHolder().modifyRemoval(list.get(i));
|
||||
}
|
||||
}
|
||||
list.clear();
|
||||
}
|
||||
|
||||
public boolean contains(Object o) {
|
||||
init();
|
||||
return list.contains(o);
|
||||
}
|
||||
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
init();
|
||||
return list.containsAll(c);
|
||||
}
|
||||
|
||||
public E get(int index) {
|
||||
init();
|
||||
return list.get(index);
|
||||
}
|
||||
|
||||
public int indexOf(Object o) {
|
||||
init();
|
||||
return list.indexOf(o);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
initAsUntouched();
|
||||
return list.isEmpty();
|
||||
}
|
||||
|
||||
public Iterator<E> iterator() {
|
||||
init();
|
||||
if (isReadOnly()) {
|
||||
return new ReadOnlyListIterator<E>(list.listIterator());
|
||||
}
|
||||
if (modifyListening) {
|
||||
Iterator<E> it = list.iterator();
|
||||
return new ModifyIterator<E>(this, it);
|
||||
}
|
||||
return list.iterator();
|
||||
}
|
||||
|
||||
public int lastIndexOf(Object o) {
|
||||
init();
|
||||
return list.lastIndexOf(o);
|
||||
}
|
||||
|
||||
public ListIterator<E> listIterator() {
|
||||
init();
|
||||
if (isReadOnly()) {
|
||||
return new ReadOnlyListIterator<E>(list.listIterator());
|
||||
}
|
||||
if (modifyListening) {
|
||||
ListIterator<E> it = list.listIterator();
|
||||
return new ModifyListIterator<E>(this, it);
|
||||
}
|
||||
return list.listIterator();
|
||||
}
|
||||
|
||||
public ListIterator<E> listIterator(int index) {
|
||||
init();
|
||||
if (isReadOnly()) {
|
||||
return new ReadOnlyListIterator<E>(list.listIterator(index));
|
||||
}
|
||||
if (modifyListening) {
|
||||
ListIterator<E> it = list.listIterator(index);
|
||||
return new ModifyListIterator<E>(this, it);
|
||||
}
|
||||
return list.listIterator(index);
|
||||
}
|
||||
|
||||
public E remove(int index) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyRemoveListening) {
|
||||
E o = list.remove(index);
|
||||
modifyRemoval(o);
|
||||
return o;
|
||||
}
|
||||
return list.remove(index);
|
||||
}
|
||||
|
||||
public boolean remove(Object o) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyRemoveListening) {
|
||||
boolean isRemove = list.remove(o);
|
||||
if (isRemove) {
|
||||
modifyRemoval(o);
|
||||
}
|
||||
return isRemove;
|
||||
}
|
||||
return list.remove(o);
|
||||
}
|
||||
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyRemoveListening) {
|
||||
boolean changed = false;
|
||||
Iterator<?> it = c.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object o = it.next();
|
||||
if (list.remove(o)) {
|
||||
modifyRemoval(o);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
return list.removeAll(c);
|
||||
}
|
||||
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyRemoveListening) {
|
||||
boolean changed = false;
|
||||
Iterator<E> it = list.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object o = it.next();
|
||||
if (!c.contains(o)) {
|
||||
it.remove();
|
||||
modifyRemoval(o);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
return list.retainAll(c);
|
||||
}
|
||||
|
||||
public E set(int index, E element) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyListening) {
|
||||
E o = list.set(index, element);
|
||||
modifyAddition(element);
|
||||
modifyRemoval(o);
|
||||
return o;
|
||||
}
|
||||
return list.set(index, element);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
init();
|
||||
return list.size();
|
||||
}
|
||||
|
||||
public List<E> subList(int fromIndex, int toIndex) {
|
||||
init();
|
||||
if (isReadOnly()) {
|
||||
return Collections.unmodifiableList(list.subList(fromIndex, toIndex));
|
||||
}
|
||||
if (modifyListening) {
|
||||
return new ModifyList<E>(this, list.subList(fromIndex, toIndex));
|
||||
}
|
||||
return list.subList(fromIndex, toIndex);
|
||||
}
|
||||
|
||||
public Object[] toArray() {
|
||||
init();
|
||||
return list.toArray();
|
||||
}
|
||||
|
||||
public <T> T[] toArray(T[] a) {
|
||||
init();
|
||||
return list.toArray(a);
|
||||
}
|
||||
|
||||
private static class ReadOnlyListIterator<E> implements ListIterator<E>, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 3097271091406323699L;
|
||||
|
||||
private final ListIterator<E> i;
|
||||
|
||||
ReadOnlyListIterator(ListIterator<E> i) {
|
||||
this.i = i;
|
||||
}
|
||||
|
||||
public void add(E o) {
|
||||
throw new IllegalStateException("This collection is in ReadOnly mode");
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new IllegalStateException("This collection is in ReadOnly mode");
|
||||
}
|
||||
|
||||
public void set(E o) {
|
||||
throw new IllegalStateException("This collection is in ReadOnly mode");
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return i.hasNext();
|
||||
}
|
||||
|
||||
public boolean hasPrevious() {
|
||||
return i.hasPrevious();
|
||||
}
|
||||
|
||||
public E next() {
|
||||
return i.next();
|
||||
}
|
||||
|
||||
public int nextIndex() {
|
||||
return i.nextIndex();
|
||||
}
|
||||
|
||||
public E previous() {
|
||||
return i.previous();
|
||||
}
|
||||
|
||||
public int previousIndex() {
|
||||
return i.previousIndex();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,295 +1,303 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
/**
|
||||
* Map capable of lazy loading.
|
||||
*/
|
||||
public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Map<K, E> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* The underlying map implementation.
|
||||
*/
|
||||
private Map<K, E> map;
|
||||
|
||||
/**
|
||||
* Create with a given Map.
|
||||
*/
|
||||
public BeanMap(Map<K, E> map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using a underlying LinkedHashMap.
|
||||
*/
|
||||
public BeanMap() {
|
||||
this(new LinkedHashMap<K, E>());
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void internalPut(Object key, Object bean) {
|
||||
if (map == null) {
|
||||
map = new LinkedHashMap<K, E>();
|
||||
}
|
||||
map.put((K)key, (E)bean);
|
||||
}
|
||||
|
||||
public void internalAdd(Object bean) {
|
||||
throw new RuntimeException("Not allowed for map");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the underlying map has been populated. Returns false if it
|
||||
* has a deferred fetch pending.
|
||||
*/
|
||||
public boolean isPopulated() {
|
||||
return map != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a reference (lazy loading) bean collection. This is
|
||||
* the same as !isPopulated();
|
||||
*/
|
||||
public boolean isReference() {
|
||||
return map == null;
|
||||
}
|
||||
|
||||
public boolean checkEmptyLazyLoad() {
|
||||
if (map == null) {
|
||||
map = new LinkedHashMap<K, E>();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void initClear() {
|
||||
synchronized (this) {
|
||||
if (map == null) {
|
||||
if (modifyListening) {
|
||||
lazyLoadCollection(true);
|
||||
} else {
|
||||
map = new LinkedHashMap<K, E>();
|
||||
}
|
||||
}
|
||||
touched(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void initAsUntouched() {
|
||||
init(false);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
init(true);
|
||||
}
|
||||
|
||||
private void init(boolean setTouched) {
|
||||
synchronized (this) {
|
||||
if (map == null) {
|
||||
lazyLoadCollection(false);
|
||||
}
|
||||
touched(setTouched);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the actual underlying map. Used for performing lazy fetch.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setActualMap(Map<?, ?> map) {
|
||||
this.map = (Map<K, E>) map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the actual underlying map.
|
||||
*/
|
||||
public Map<K, E> getActualMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the collection of beans (map values).
|
||||
*/
|
||||
public Collection<E> getActualDetails() {
|
||||
return map.values();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the map entrySet.
|
||||
* <p>
|
||||
* This is because the key values may need to be set against the details (so
|
||||
* they don't need to be set twice).
|
||||
* </p>
|
||||
*/
|
||||
public Collection<?> getActualEntries() {
|
||||
return map.entrySet();
|
||||
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(50);
|
||||
sb.append("BeanMap ");
|
||||
if (isReadOnly()) {
|
||||
sb.append("readOnly ");
|
||||
}
|
||||
if (map == null) {
|
||||
sb.append("deferred ");
|
||||
|
||||
} else {
|
||||
sb.append("size[").append(map.size()).append("]");
|
||||
sb.append(" map").append(map);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Equal if obj is a Map and equal in a Map sense.
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
init();
|
||||
return map.equals(obj);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
init();
|
||||
return map.hashCode();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
checkReadOnly();
|
||||
initClear();
|
||||
if (modifyRemoveListening) {
|
||||
for (K key : map.keySet()) {
|
||||
E o = map.remove(key);
|
||||
modifyRemoval(o);
|
||||
}
|
||||
}
|
||||
map.clear();
|
||||
}
|
||||
|
||||
public boolean containsKey(Object key) {
|
||||
init();
|
||||
return map.containsKey(key);
|
||||
}
|
||||
|
||||
public boolean containsValue(Object value) {
|
||||
init();
|
||||
return map.containsValue(value);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public Set<Entry<K, E>> entrySet() {
|
||||
init();
|
||||
if (isReadOnly()) {
|
||||
return Collections.unmodifiableSet(map.entrySet());
|
||||
}
|
||||
if (modifyListening) {
|
||||
Set<Entry<K, E>> s = map.entrySet();
|
||||
return new ModifySet(this, s);
|
||||
}
|
||||
return map.entrySet();
|
||||
}
|
||||
|
||||
public E get(Object key) {
|
||||
init();
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
initAsUntouched();
|
||||
return map.isEmpty();
|
||||
}
|
||||
|
||||
public Set<K> keySet() {
|
||||
init();
|
||||
if (isReadOnly()) {
|
||||
return Collections.unmodifiableSet(map.keySet());
|
||||
}
|
||||
// we don't really care about modifications to the ketSet?
|
||||
return map.keySet();
|
||||
}
|
||||
|
||||
public E put(K key, E value) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyListening) {
|
||||
Object o = map.put(key, value);
|
||||
modifyAddition(value);
|
||||
modifyRemoval(o);
|
||||
}
|
||||
return map.put(key, value);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void putAll(Map<? extends K, ? extends E> t) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyListening) {
|
||||
Iterator it = t.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) it.next();
|
||||
Object o = map.put((K) entry.getKey(), (E) entry.getValue());
|
||||
modifyAddition((E) entry.getValue());
|
||||
modifyRemoval(o);
|
||||
}
|
||||
}
|
||||
map.putAll(t);
|
||||
}
|
||||
|
||||
public E remove(Object key) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyRemoveListening) {
|
||||
E o = map.remove(key);
|
||||
modifyRemoval(o);
|
||||
return o;
|
||||
}
|
||||
return map.remove(key);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
init();
|
||||
return map.size();
|
||||
}
|
||||
|
||||
public Collection<E> values() {
|
||||
init();
|
||||
if (isReadOnly()) {
|
||||
return Collections.unmodifiableCollection(map.values());
|
||||
}
|
||||
if (modifyListening) {
|
||||
Collection<E> c = map.values();
|
||||
return new ModifyCollection<E>(this, c);
|
||||
}
|
||||
return map.values();
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
/**
|
||||
* Map capable of lazy loading.
|
||||
*/
|
||||
public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Map<K, E> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* The underlying map implementation.
|
||||
*/
|
||||
private Map<K, E> map;
|
||||
|
||||
/**
|
||||
* Create with a given Map.
|
||||
*/
|
||||
public BeanMap(Map<K, E> map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using a underlying LinkedHashMap.
|
||||
*/
|
||||
public BeanMap() {
|
||||
this(new LinkedHashMap<K, E>());
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
public void internalPutNull() {
|
||||
if (map == null) {
|
||||
map = new LinkedHashMap<K, E>();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void internalPut(Object key, Object bean) {
|
||||
if (map == null) {
|
||||
map = new LinkedHashMap<K, E>();
|
||||
}
|
||||
if (key != null) {
|
||||
map.put((K) key, (E) bean);
|
||||
}
|
||||
}
|
||||
|
||||
public void internalAdd(Object bean) {
|
||||
throw new RuntimeException("Not allowed for map");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the underlying map has been populated. Returns false if it
|
||||
* has a deferred fetch pending.
|
||||
*/
|
||||
public boolean isPopulated() {
|
||||
return map != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a reference (lazy loading) bean collection. This is
|
||||
* the same as !isPopulated();
|
||||
*/
|
||||
public boolean isReference() {
|
||||
return map == null;
|
||||
}
|
||||
|
||||
public boolean checkEmptyLazyLoad() {
|
||||
if (map == null) {
|
||||
map = new LinkedHashMap<K, E>();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void initClear() {
|
||||
synchronized (this) {
|
||||
if (map == null) {
|
||||
if (modifyListening) {
|
||||
lazyLoadCollection(true);
|
||||
} else {
|
||||
map = new LinkedHashMap<K, E>();
|
||||
}
|
||||
}
|
||||
touched(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void initAsUntouched() {
|
||||
init(false);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
init(true);
|
||||
}
|
||||
|
||||
private void init(boolean setTouched) {
|
||||
synchronized (this) {
|
||||
if (map == null) {
|
||||
lazyLoadCollection(false);
|
||||
}
|
||||
touched(setTouched);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the actual underlying map. Used for performing lazy fetch.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setActualMap(Map<?, ?> map) {
|
||||
this.map = (Map<K, E>) map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the actual underlying map.
|
||||
*/
|
||||
public Map<K, E> getActualMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the collection of beans (map values).
|
||||
*/
|
||||
public Collection<E> getActualDetails() {
|
||||
return map.values();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the map entrySet.
|
||||
* <p>
|
||||
* This is because the key values may need to be set against the details (so
|
||||
* they don't need to be set twice).
|
||||
* </p>
|
||||
*/
|
||||
public Collection<?> getActualEntries() {
|
||||
return map.entrySet();
|
||||
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(50);
|
||||
sb.append("BeanMap ");
|
||||
if (isReadOnly()) {
|
||||
sb.append("readOnly ");
|
||||
}
|
||||
if (map == null) {
|
||||
sb.append("deferred ");
|
||||
|
||||
} else {
|
||||
sb.append("size[").append(map.size()).append("]");
|
||||
sb.append(" map").append(map);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Equal if obj is a Map and equal in a Map sense.
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
init();
|
||||
return map.equals(obj);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
init();
|
||||
return map.hashCode();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
checkReadOnly();
|
||||
initClear();
|
||||
if (modifyRemoveListening) {
|
||||
for (K key : map.keySet()) {
|
||||
E o = map.remove(key);
|
||||
modifyRemoval(o);
|
||||
}
|
||||
}
|
||||
map.clear();
|
||||
}
|
||||
|
||||
public boolean containsKey(Object key) {
|
||||
init();
|
||||
return map.containsKey(key);
|
||||
}
|
||||
|
||||
public boolean containsValue(Object value) {
|
||||
init();
|
||||
return map.containsValue(value);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public Set<Entry<K, E>> entrySet() {
|
||||
init();
|
||||
if (isReadOnly()) {
|
||||
return Collections.unmodifiableSet(map.entrySet());
|
||||
}
|
||||
if (modifyListening) {
|
||||
Set<Entry<K, E>> s = map.entrySet();
|
||||
return new ModifySet(this, s);
|
||||
}
|
||||
return map.entrySet();
|
||||
}
|
||||
|
||||
public E get(Object key) {
|
||||
init();
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
initAsUntouched();
|
||||
return map.isEmpty();
|
||||
}
|
||||
|
||||
public Set<K> keySet() {
|
||||
init();
|
||||
if (isReadOnly()) {
|
||||
return Collections.unmodifiableSet(map.keySet());
|
||||
}
|
||||
// we don't really care about modifications to the ketSet?
|
||||
return map.keySet();
|
||||
}
|
||||
|
||||
public E put(K key, E value) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyListening) {
|
||||
Object o = map.put(key, value);
|
||||
modifyAddition(value);
|
||||
modifyRemoval(o);
|
||||
}
|
||||
return map.put(key, value);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void putAll(Map<? extends K, ? extends E> t) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyListening) {
|
||||
Iterator it = t.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) it.next();
|
||||
Object o = map.put((K) entry.getKey(), (E) entry.getValue());
|
||||
modifyAddition((E) entry.getValue());
|
||||
modifyRemoval(o);
|
||||
}
|
||||
}
|
||||
map.putAll(t);
|
||||
}
|
||||
|
||||
public E remove(Object key) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyRemoveListening) {
|
||||
E o = map.remove(key);
|
||||
modifyRemoval(o);
|
||||
return o;
|
||||
}
|
||||
return map.remove(key);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
init();
|
||||
return map.size();
|
||||
}
|
||||
|
||||
public Collection<E> values() {
|
||||
init();
|
||||
if (isReadOnly()) {
|
||||
return Collections.unmodifiableCollection(map.values());
|
||||
}
|
||||
if (modifyListening) {
|
||||
Collection<E> c = map.values();
|
||||
return new ModifyCollection<E>(this, c);
|
||||
}
|
||||
return map.values();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,345 +1,340 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollectionAdd;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
/**
|
||||
* Set capable of lazy loading.
|
||||
*/
|
||||
public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E>, BeanCollectionAdd {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* The underlying Set implementation.
|
||||
*/
|
||||
private Set<E> set;
|
||||
|
||||
/**
|
||||
* Create with a specific Set implementation.
|
||||
*/
|
||||
public BeanSet(Set<E> set) {
|
||||
this.set = set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using an underlying LinkedHashSet.
|
||||
*/
|
||||
public BeanSet() {
|
||||
this(new LinkedHashSet<E>());
|
||||
}
|
||||
|
||||
public BeanSet(BeanCollectionLoader loader, EntityBean ownerBean, String propertyName) {
|
||||
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());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void addBean(EntityBean bean) {
|
||||
set.add((E) bean);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void internalAdd(Object bean) {
|
||||
if (set == null) {
|
||||
set = new LinkedHashSet<E>();
|
||||
}
|
||||
set.add((E) bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the underlying set has its data.
|
||||
*/
|
||||
public boolean isPopulated() {
|
||||
return set != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a reference (lazy loading) bean collection. This is
|
||||
* the same as !isPopulated();
|
||||
*/
|
||||
public boolean isReference() {
|
||||
return set == null;
|
||||
}
|
||||
|
||||
public boolean checkEmptyLazyLoad() {
|
||||
if (set == null) {
|
||||
set = new LinkedHashSet<E>();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void initClear() {
|
||||
synchronized (this) {
|
||||
if (set == null) {
|
||||
if (modifyListening) {
|
||||
lazyLoadCollection(true);
|
||||
} else {
|
||||
set = new LinkedHashSet<E>();
|
||||
}
|
||||
}
|
||||
touched(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void initAsUntouched() {
|
||||
init(false);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
init(true);
|
||||
}
|
||||
|
||||
private void init(boolean setTouched) {
|
||||
synchronized (this) {
|
||||
if (set == null) {
|
||||
lazyLoadCollection(true);
|
||||
}
|
||||
touched(setTouched);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the underlying set (used for lazy fetch).
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setActualSet(Set<?> set) {
|
||||
this.set = (Set<E>) set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the actual underlying set.
|
||||
*/
|
||||
public Set<E> getActualSet() {
|
||||
return set;
|
||||
}
|
||||
|
||||
public Collection<E> getActualDetails() {
|
||||
return set;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<?> getActualEntries() {
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying set.
|
||||
*/
|
||||
public Object getActualCollection() {
|
||||
return set;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer(50);
|
||||
sb.append("BeanSet ");
|
||||
if (isReadOnly()) {
|
||||
sb.append("readOnly ");
|
||||
}
|
||||
if (set == null) {
|
||||
sb.append("deferred ");
|
||||
|
||||
} else {
|
||||
sb.append("size[").append(set.size()).append("]");
|
||||
sb.append(" set").append(set);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Equal if obj is a Set and equal in a Set sense.
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
init();
|
||||
return set.equals(obj);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
init();
|
||||
return set.hashCode();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------//
|
||||
// proxy method for map
|
||||
// -----------------------------------------------------//
|
||||
|
||||
public boolean add(E o) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyAddListening) {
|
||||
if (set.add(o)) {
|
||||
modifyAddition(o);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return set.add(o);
|
||||
}
|
||||
|
||||
public boolean addAll(Collection<? extends E> c) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyAddListening) {
|
||||
boolean changed = false;
|
||||
Iterator<? extends E> it = c.iterator();
|
||||
while (it.hasNext()) {
|
||||
E o = it.next();
|
||||
if (set.add(o)) {
|
||||
modifyAddition(o);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
return set.addAll(c);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
checkReadOnly();
|
||||
initClear();
|
||||
if (modifyRemoveListening) {
|
||||
Iterator<E> it = set.iterator();
|
||||
while (it.hasNext()) {
|
||||
E e = it.next();
|
||||
modifyRemoval(e);
|
||||
}
|
||||
}
|
||||
set.clear();
|
||||
}
|
||||
|
||||
public boolean contains(Object o) {
|
||||
init();
|
||||
return set.contains(o);
|
||||
}
|
||||
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
init();
|
||||
return set.containsAll(c);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
initAsUntouched();
|
||||
return set.isEmpty();
|
||||
}
|
||||
|
||||
public Iterator<E> iterator() {
|
||||
init();
|
||||
if (isReadOnly()) {
|
||||
return new ReadOnlyIterator<E>(set.iterator());
|
||||
}
|
||||
if (modifyListening) {
|
||||
return new ModifyIterator<E>(this, set.iterator());
|
||||
}
|
||||
return set.iterator();
|
||||
}
|
||||
|
||||
public boolean remove(Object o) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyRemoveListening) {
|
||||
if (set.remove(o)) {
|
||||
modifyRemoval(o);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return set.remove(o);
|
||||
}
|
||||
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyRemoveListening) {
|
||||
boolean changed = false;
|
||||
Iterator<?> it = c.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object o = (Object) it.next();
|
||||
if (set.remove(o)) {
|
||||
modifyRemoval(o);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
return set.removeAll(c);
|
||||
}
|
||||
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyRemoveListening) {
|
||||
boolean changed = false;
|
||||
Iterator<?> it = set.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object o = it.next();
|
||||
if (!c.contains(o)) {
|
||||
it.remove();
|
||||
modifyRemoval(o);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
return set.retainAll(c);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
init();
|
||||
return set.size();
|
||||
}
|
||||
|
||||
public Object[] toArray() {
|
||||
init();
|
||||
return set.toArray();
|
||||
}
|
||||
|
||||
public <T> T[] toArray(T[] a) {
|
||||
init();
|
||||
return set.toArray(a);
|
||||
}
|
||||
|
||||
private static class ReadOnlyIterator<E> implements Iterator<E>, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 2577697326745352605L;
|
||||
|
||||
private final Iterator<E> it;
|
||||
|
||||
ReadOnlyIterator(Iterator<E> it) {
|
||||
this.it = it;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return it.hasNext();
|
||||
}
|
||||
|
||||
public E next() {
|
||||
return it.next();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new IllegalStateException("This collection is in ReadOnly mode");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollectionAdd;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
/**
|
||||
* Set capable of lazy loading.
|
||||
*/
|
||||
public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E>, BeanCollectionAdd {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* The underlying Set implementation.
|
||||
*/
|
||||
private Set<E> set;
|
||||
|
||||
/**
|
||||
* Create with a specific Set implementation.
|
||||
*/
|
||||
public BeanSet(Set<E> set) {
|
||||
this.set = set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using an underlying LinkedHashSet.
|
||||
*/
|
||||
public BeanSet() {
|
||||
this(new LinkedHashSet<E>());
|
||||
}
|
||||
|
||||
public BeanSet(BeanCollectionLoader loader, EntityBean ownerBean, String propertyName) {
|
||||
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());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void addBean(EntityBean bean) {
|
||||
set.add((E) bean);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void internalAdd(Object bean) {
|
||||
if (set == null) {
|
||||
set = new LinkedHashSet<E>();
|
||||
}
|
||||
if (bean != null) {
|
||||
set.add((E) bean);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the underlying set has its data.
|
||||
*/
|
||||
public boolean isPopulated() {
|
||||
return set != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a reference (lazy loading) bean collection. This is
|
||||
* the same as !isPopulated();
|
||||
*/
|
||||
public boolean isReference() {
|
||||
return set == null;
|
||||
}
|
||||
|
||||
public boolean checkEmptyLazyLoad() {
|
||||
if (set == null) {
|
||||
set = new LinkedHashSet<E>();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void initClear() {
|
||||
synchronized (this) {
|
||||
if (set == null) {
|
||||
if (modifyListening) {
|
||||
lazyLoadCollection(true);
|
||||
} else {
|
||||
set = new LinkedHashSet<E>();
|
||||
}
|
||||
}
|
||||
touched(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void initAsUntouched() {
|
||||
init(false);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
init(true);
|
||||
}
|
||||
|
||||
private void init(boolean setTouched) {
|
||||
synchronized (this) {
|
||||
if (set == null) {
|
||||
lazyLoadCollection(true);
|
||||
}
|
||||
touched(setTouched);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the underlying set (used for lazy fetch).
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setActualSet(Set<?> set) {
|
||||
this.set = (Set<E>) set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the actual underlying set.
|
||||
*/
|
||||
public Set<E> getActualSet() {
|
||||
return set;
|
||||
}
|
||||
|
||||
public Collection<E> getActualDetails() {
|
||||
return set;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<?> getActualEntries() {
|
||||
return set;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(50);
|
||||
sb.append("BeanSet ");
|
||||
if (isReadOnly()) {
|
||||
sb.append("readOnly ");
|
||||
}
|
||||
if (set == null) {
|
||||
sb.append("deferred ");
|
||||
|
||||
} else {
|
||||
sb.append("size[").append(set.size()).append("]");
|
||||
sb.append(" set").append(set);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Equal if obj is a Set and equal in a Set sense.
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
init();
|
||||
return set.equals(obj);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
init();
|
||||
return set.hashCode();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------//
|
||||
// proxy method for map
|
||||
// -----------------------------------------------------//
|
||||
|
||||
public boolean add(E o) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyAddListening) {
|
||||
if (set.add(o)) {
|
||||
modifyAddition(o);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return set.add(o);
|
||||
}
|
||||
|
||||
public boolean addAll(Collection<? extends E> c) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyAddListening) {
|
||||
boolean changed = false;
|
||||
Iterator<? extends E> it = c.iterator();
|
||||
while (it.hasNext()) {
|
||||
E o = it.next();
|
||||
if (set.add(o)) {
|
||||
modifyAddition(o);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
return set.addAll(c);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
checkReadOnly();
|
||||
initClear();
|
||||
if (modifyRemoveListening) {
|
||||
Iterator<E> it = set.iterator();
|
||||
while (it.hasNext()) {
|
||||
E e = it.next();
|
||||
modifyRemoval(e);
|
||||
}
|
||||
}
|
||||
set.clear();
|
||||
}
|
||||
|
||||
public boolean contains(Object o) {
|
||||
init();
|
||||
return set.contains(o);
|
||||
}
|
||||
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
init();
|
||||
return set.containsAll(c);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
initAsUntouched();
|
||||
return set.isEmpty();
|
||||
}
|
||||
|
||||
public Iterator<E> iterator() {
|
||||
init();
|
||||
if (isReadOnly()) {
|
||||
return new ReadOnlyIterator<E>(set.iterator());
|
||||
}
|
||||
if (modifyListening) {
|
||||
return new ModifyIterator<E>(this, set.iterator());
|
||||
}
|
||||
return set.iterator();
|
||||
}
|
||||
|
||||
public boolean remove(Object o) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyRemoveListening) {
|
||||
if (set.remove(o)) {
|
||||
modifyRemoval(o);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return set.remove(o);
|
||||
}
|
||||
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyRemoveListening) {
|
||||
boolean changed = false;
|
||||
Iterator<?> it = c.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object o = it.next();
|
||||
if (set.remove(o)) {
|
||||
modifyRemoval(o);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
return set.removeAll(c);
|
||||
}
|
||||
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyRemoveListening) {
|
||||
boolean changed = false;
|
||||
Iterator<?> it = set.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object o = it.next();
|
||||
if (!c.contains(o)) {
|
||||
it.remove();
|
||||
modifyRemoval(o);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
return set.retainAll(c);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
init();
|
||||
return set.size();
|
||||
}
|
||||
|
||||
public Object[] toArray() {
|
||||
init();
|
||||
return set.toArray();
|
||||
}
|
||||
|
||||
public <T> T[] toArray(T[] a) {
|
||||
init();
|
||||
return set.toArray(a);
|
||||
}
|
||||
|
||||
private static class ReadOnlyIterator<E> implements Iterator<E>, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 2577697326745352605L;
|
||||
|
||||
private final Iterator<E> it;
|
||||
|
||||
ReadOnlyIterator(Iterator<E> it) {
|
||||
this.it = it;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return it.hasNext();
|
||||
}
|
||||
|
||||
public E next() {
|
||||
return it.next();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new IllegalStateException("This collection is in ReadOnly mode");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
|
||||
/**
|
||||
* Creates the EbeanServer implementations. This is used by the Ebean singleton
|
||||
* to determine the implementation for each server name.
|
||||
* <p>
|
||||
* Note that on a remote client it is expected that this factory will return
|
||||
* EbeanServers that behave as a proxy using http or tcp sockets etc to talk to
|
||||
* the EbeanServer on the application server.
|
||||
* </p>
|
||||
*/
|
||||
public interface BootupEbeanManager {
|
||||
|
||||
/**
|
||||
* Create the EbeanServer for a given configuration.
|
||||
*
|
||||
* @param configuration
|
||||
* The configuration information for this server.
|
||||
*/
|
||||
public EbeanServer createServer(ServerConfig configuration);
|
||||
|
||||
/**
|
||||
* Create an EbeanServer just using the name.
|
||||
* <p>
|
||||
* In this case the dataSource parameters etc will be defined on the global
|
||||
* avaje.properties file.
|
||||
* </p>
|
||||
*/
|
||||
public EbeanServer createServer(String name);
|
||||
|
||||
/**
|
||||
* Shutdown any Ebean wide resources such as clustering.
|
||||
*/
|
||||
public void shutdown();
|
||||
}
|
||||
@@ -1,122 +1,122 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
|
||||
/**
|
||||
* Wraps a collection for the purposes of notifying removals and additions to
|
||||
* the BeanCollection owner.
|
||||
* <p>
|
||||
* This is required for persisting ManyToMany objects. Additions and removals
|
||||
* become inserts and deletes to the intersection table.
|
||||
* </p>
|
||||
*/
|
||||
class ModifyCollection<E> implements Collection<E> {
|
||||
|
||||
protected final BeanCollection<E> owner;
|
||||
|
||||
protected final Collection<E> c;
|
||||
|
||||
/**
|
||||
* Create with an Owner and the underlying collection this wraps.
|
||||
* <p>
|
||||
* The owner is notified of the additions and removals.
|
||||
* </p>
|
||||
*/
|
||||
public ModifyCollection(BeanCollection<E> owner, Collection<E> c) {
|
||||
this.owner = owner;
|
||||
this.c = c;
|
||||
}
|
||||
|
||||
public boolean add(E o) {
|
||||
if (c.add(o)) {
|
||||
owner.modifyAddition(o);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean addAll(Collection<? extends E> collection) {
|
||||
boolean changed = false;
|
||||
Iterator<? extends E> it = collection.iterator();
|
||||
while (it.hasNext()) {
|
||||
E o = it.next();
|
||||
if (c.add(o)) {
|
||||
owner.modifyAddition(o);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
c.clear();
|
||||
}
|
||||
|
||||
public boolean contains(Object o) {
|
||||
return c.contains(o);
|
||||
}
|
||||
|
||||
public boolean containsAll(Collection<?> collection) {
|
||||
return c.containsAll(collection);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return c.isEmpty();
|
||||
}
|
||||
|
||||
public Iterator<E> iterator() {
|
||||
Iterator<E> it = c.iterator();
|
||||
return new ModifyIterator<E>(owner, it);
|
||||
}
|
||||
|
||||
public boolean remove(Object o) {
|
||||
if (c.remove(o)) {
|
||||
owner.modifyRemoval(o);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean removeAll(Collection<?> collection) {
|
||||
boolean changed = false;
|
||||
Iterator<?> it = collection.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object o = (Object) it.next();
|
||||
if (c.remove(o)) {
|
||||
owner.modifyRemoval(o);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
public boolean retainAll(Collection<?> collection) {
|
||||
boolean changed = false;
|
||||
Iterator<?> it = c.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object o = (Object) it.next();
|
||||
if (!collection.contains(o)) {
|
||||
it.remove();
|
||||
owner.modifyRemoval(o);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return c.size();
|
||||
}
|
||||
|
||||
public Object[] toArray() {
|
||||
return c.toArray();
|
||||
}
|
||||
|
||||
public <T> T[] toArray(T[] a) {
|
||||
return c.toArray(a);
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
|
||||
/**
|
||||
* Wraps a collection for the purposes of notifying removals and additions to
|
||||
* the BeanCollection owner.
|
||||
* <p>
|
||||
* This is required for persisting ManyToMany objects. Additions and removals
|
||||
* become inserts and deletes to the intersection table.
|
||||
* </p>
|
||||
*/
|
||||
class ModifyCollection<E> implements Collection<E> {
|
||||
|
||||
protected final BeanCollection<E> owner;
|
||||
|
||||
protected final Collection<E> c;
|
||||
|
||||
/**
|
||||
* Create with an Owner and the underlying collection this wraps.
|
||||
* <p>
|
||||
* The owner is notified of the additions and removals.
|
||||
* </p>
|
||||
*/
|
||||
public ModifyCollection(BeanCollection<E> owner, Collection<E> c) {
|
||||
this.owner = owner;
|
||||
this.c = c;
|
||||
}
|
||||
|
||||
public boolean add(E o) {
|
||||
if (c.add(o)) {
|
||||
owner.modifyAddition(o);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean addAll(Collection<? extends E> collection) {
|
||||
boolean changed = false;
|
||||
Iterator<? extends E> it = collection.iterator();
|
||||
while (it.hasNext()) {
|
||||
E o = it.next();
|
||||
if (c.add(o)) {
|
||||
owner.modifyAddition(o);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
c.clear();
|
||||
}
|
||||
|
||||
public boolean contains(Object o) {
|
||||
return c.contains(o);
|
||||
}
|
||||
|
||||
public boolean containsAll(Collection<?> collection) {
|
||||
return c.containsAll(collection);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return c.isEmpty();
|
||||
}
|
||||
|
||||
public Iterator<E> iterator() {
|
||||
Iterator<E> it = c.iterator();
|
||||
return new ModifyIterator<E>(owner, it);
|
||||
}
|
||||
|
||||
public boolean remove(Object o) {
|
||||
if (c.remove(o)) {
|
||||
owner.modifyRemoval(o);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean removeAll(Collection<?> collection) {
|
||||
boolean changed = false;
|
||||
Iterator<?> it = collection.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object o = (Object) it.next();
|
||||
if (c.remove(o)) {
|
||||
owner.modifyRemoval(o);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
public boolean retainAll(Collection<?> collection) {
|
||||
boolean changed = false;
|
||||
Iterator<?> it = c.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object o = (Object) it.next();
|
||||
if (!collection.contains(o)) {
|
||||
it.remove();
|
||||
owner.modifyRemoval(o);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return c.size();
|
||||
}
|
||||
|
||||
public Object[] toArray() {
|
||||
return c.toArray();
|
||||
}
|
||||
|
||||
public <T> T[] toArray(T[] a) {
|
||||
return c.toArray(a);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,74 +1,74 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Holds sets of additions and deletions from a 'owner' List Set or Map.
|
||||
* <p>
|
||||
* These sets of additions and deletions are used to support persisting
|
||||
* ManyToMany relationships. The additions becoming inserts into the
|
||||
* intersection table and the removals becoming deletes from the intersection
|
||||
* table.
|
||||
* </p>
|
||||
*/
|
||||
class ModifyHolder<E> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 2572572897923801083L;
|
||||
|
||||
/**
|
||||
* Deletions list for manyToMany persistence.
|
||||
*/
|
||||
private Set<E> modifyDeletions = new LinkedHashSet<E>();
|
||||
|
||||
/**
|
||||
* Additions list for manyToMany persistence.
|
||||
*/
|
||||
private Set<E> modifyAdditions = new LinkedHashSet<E>();
|
||||
|
||||
void reset() {
|
||||
modifyDeletions = new LinkedHashSet<E>();
|
||||
modifyAdditions = new LinkedHashSet<E>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by BeanList.addAll() methods.
|
||||
*/
|
||||
void modifyAdditionAll(Collection<? extends E> c) {
|
||||
if (c != null) {
|
||||
for (E e : c) {
|
||||
modifyAddition(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void modifyAddition(E bean) {
|
||||
if (bean != null) {
|
||||
// If it is to delete then just remove the deletion
|
||||
if (!modifyDeletions.remove(bean)) {
|
||||
// Insert
|
||||
modifyAdditions.add(bean);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
void modifyRemoval(Object bean) {
|
||||
if (bean != null) {
|
||||
// If it is to be added then just remove the addition
|
||||
if (!modifyAdditions.remove((E) bean)) {
|
||||
modifyDeletions.add((E) bean);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Set<E> getModifyAdditions() {
|
||||
return modifyAdditions;
|
||||
}
|
||||
|
||||
Set<E> getModifyRemovals() {
|
||||
return modifyDeletions;
|
||||
}
|
||||
}
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Holds sets of additions and deletions from a 'owner' List Set or Map.
|
||||
* <p>
|
||||
* These sets of additions and deletions are used to support persisting
|
||||
* ManyToMany relationships. The additions becoming inserts into the
|
||||
* intersection table and the removals becoming deletes from the intersection
|
||||
* table.
|
||||
* </p>
|
||||
*/
|
||||
class ModifyHolder<E> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 2572572897923801083L;
|
||||
|
||||
/**
|
||||
* Deletions list for manyToMany persistence.
|
||||
*/
|
||||
private Set<E> modifyDeletions = new LinkedHashSet<E>();
|
||||
|
||||
/**
|
||||
* Additions list for manyToMany persistence.
|
||||
*/
|
||||
private Set<E> modifyAdditions = new LinkedHashSet<E>();
|
||||
|
||||
void reset() {
|
||||
modifyDeletions = new LinkedHashSet<E>();
|
||||
modifyAdditions = new LinkedHashSet<E>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by BeanList.addAll() methods.
|
||||
*/
|
||||
void modifyAdditionAll(Collection<? extends E> c) {
|
||||
if (c != null) {
|
||||
for (E e : c) {
|
||||
modifyAddition(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void modifyAddition(E bean) {
|
||||
if (bean != null) {
|
||||
// If it is to delete then just remove the deletion
|
||||
if (!modifyDeletions.remove(bean)) {
|
||||
// Insert
|
||||
modifyAdditions.add(bean);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
void modifyRemoval(Object bean) {
|
||||
if (bean != null) {
|
||||
// If it is to be added then just remove the addition
|
||||
if (!modifyAdditions.remove((E) bean)) {
|
||||
modifyDeletions.add((E) bean);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Set<E> getModifyAdditions() {
|
||||
return modifyAdditions;
|
||||
}
|
||||
|
||||
Set<E> getModifyRemovals() {
|
||||
return modifyDeletions;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,48 +1,48 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
|
||||
/**
|
||||
* Wraps an iterator for the purposes of notifying removals and additions to the
|
||||
* BeanCollection owner.
|
||||
* <p>
|
||||
* This is required for persisting ManyToMany objects. Additions and removals
|
||||
* become inserts and deletes to the intersection table.
|
||||
* </p>
|
||||
*/
|
||||
class ModifyIterator<E> implements Iterator<E> {
|
||||
|
||||
private final BeanCollection<E> owner;
|
||||
|
||||
private final Iterator<E> it;
|
||||
|
||||
private E last;
|
||||
|
||||
/**
|
||||
* Create with an Owner and the underlying Iterator this wraps.
|
||||
* <p>
|
||||
* The owner is notified of the removals.
|
||||
* </p>
|
||||
*/
|
||||
ModifyIterator(BeanCollection<E> owner, Iterator<E> it) {
|
||||
this.owner = owner;
|
||||
this.it = it;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return it.hasNext();
|
||||
}
|
||||
|
||||
public E next() {
|
||||
last = it.next();
|
||||
return last;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
owner.modifyRemoval(last);
|
||||
it.remove();
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
|
||||
/**
|
||||
* Wraps an iterator for the purposes of notifying removals and additions to the
|
||||
* BeanCollection owner.
|
||||
* <p>
|
||||
* This is required for persisting ManyToMany objects. Additions and removals
|
||||
* become inserts and deletes to the intersection table.
|
||||
* </p>
|
||||
*/
|
||||
class ModifyIterator<E> implements Iterator<E> {
|
||||
|
||||
private final BeanCollection<E> owner;
|
||||
|
||||
private final Iterator<E> it;
|
||||
|
||||
private E last;
|
||||
|
||||
/**
|
||||
* Create with an Owner and the underlying Iterator this wraps.
|
||||
* <p>
|
||||
* The owner is notified of the removals.
|
||||
* </p>
|
||||
*/
|
||||
ModifyIterator(BeanCollection<E> owner, Iterator<E> it) {
|
||||
this.owner = owner;
|
||||
this.it = it;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return it.hasNext();
|
||||
}
|
||||
|
||||
public E next() {
|
||||
last = it.next();
|
||||
return last;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
owner.modifyRemoval(last);
|
||||
it.remove();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,91 +1,91 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
|
||||
/**
|
||||
* Wraps a List for the purposes of notifying removals and additions to the
|
||||
* BeanCollection owner.
|
||||
* <p>
|
||||
* This is required for persisting ManyToMany objects. Additions and removals
|
||||
* become inserts and deletes to the intersection table.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that this is created by a call to subList() on a BeanList. Thats its
|
||||
* only purpose really. BeanList holds the actual List.
|
||||
* </p>
|
||||
*/
|
||||
class ModifyList<E> extends ModifyCollection<E> implements List<E> {
|
||||
|
||||
/**
|
||||
* The underlying list.
|
||||
*/
|
||||
private final List<E> list;
|
||||
|
||||
/**
|
||||
* Create with an Owner that is notified of any additions or deletions.
|
||||
*/
|
||||
ModifyList(BeanCollection<E> owner, List<E> list) {
|
||||
super(owner, list);
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
public void add(int index, E element) {
|
||||
list.add(index, element);
|
||||
owner.modifyAddition(element);
|
||||
}
|
||||
|
||||
public boolean addAll(int index, Collection<? extends E> co) {
|
||||
if (list.addAll(index, co)) {
|
||||
Iterator<? extends E> it = co.iterator();
|
||||
while (it.hasNext()) {
|
||||
E o = it.next();
|
||||
owner.modifyAddition(o);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public E get(int index) {
|
||||
return list.get(index);
|
||||
}
|
||||
|
||||
public int indexOf(Object o) {
|
||||
return list.indexOf(o);
|
||||
}
|
||||
|
||||
public int lastIndexOf(Object o) {
|
||||
return list.lastIndexOf(o);
|
||||
}
|
||||
|
||||
public ListIterator<E> listIterator() {
|
||||
return new ModifyListIterator<E>(owner, list.listIterator());
|
||||
}
|
||||
|
||||
public ListIterator<E> listIterator(int index) {
|
||||
return new ModifyListIterator<E>(owner, list.listIterator(index));
|
||||
}
|
||||
|
||||
public E remove(int index) {
|
||||
E o = list.remove(index);
|
||||
owner.modifyRemoval(o);
|
||||
return o;
|
||||
}
|
||||
|
||||
public E set(int index, E element) {
|
||||
E o = list.set(index, element);
|
||||
owner.modifyAddition(element);
|
||||
owner.modifyRemoval(o);
|
||||
return o;
|
||||
}
|
||||
|
||||
public List<E> subList(int fromIndex, int toIndex) {
|
||||
return new ModifyList<E>(owner, list.subList(fromIndex, toIndex));
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
|
||||
/**
|
||||
* Wraps a List for the purposes of notifying removals and additions to the
|
||||
* BeanCollection owner.
|
||||
* <p>
|
||||
* This is required for persisting ManyToMany objects. Additions and removals
|
||||
* become inserts and deletes to the intersection table.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that this is created by a call to subList() on a BeanList. Thats its
|
||||
* only purpose really. BeanList holds the actual List.
|
||||
* </p>
|
||||
*/
|
||||
class ModifyList<E> extends ModifyCollection<E> implements List<E> {
|
||||
|
||||
/**
|
||||
* The underlying list.
|
||||
*/
|
||||
private final List<E> list;
|
||||
|
||||
/**
|
||||
* Create with an Owner that is notified of any additions or deletions.
|
||||
*/
|
||||
ModifyList(BeanCollection<E> owner, List<E> list) {
|
||||
super(owner, list);
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
public void add(int index, E element) {
|
||||
list.add(index, element);
|
||||
owner.modifyAddition(element);
|
||||
}
|
||||
|
||||
public boolean addAll(int index, Collection<? extends E> co) {
|
||||
if (list.addAll(index, co)) {
|
||||
Iterator<? extends E> it = co.iterator();
|
||||
while (it.hasNext()) {
|
||||
E o = it.next();
|
||||
owner.modifyAddition(o);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public E get(int index) {
|
||||
return list.get(index);
|
||||
}
|
||||
|
||||
public int indexOf(Object o) {
|
||||
return list.indexOf(o);
|
||||
}
|
||||
|
||||
public int lastIndexOf(Object o) {
|
||||
return list.lastIndexOf(o);
|
||||
}
|
||||
|
||||
public ListIterator<E> listIterator() {
|
||||
return new ModifyListIterator<E>(owner, list.listIterator());
|
||||
}
|
||||
|
||||
public ListIterator<E> listIterator(int index) {
|
||||
return new ModifyListIterator<E>(owner, list.listIterator(index));
|
||||
}
|
||||
|
||||
public E remove(int index) {
|
||||
E o = list.remove(index);
|
||||
owner.modifyRemoval(o);
|
||||
return o;
|
||||
}
|
||||
|
||||
public E set(int index, E element) {
|
||||
E o = list.set(index, element);
|
||||
owner.modifyAddition(element);
|
||||
owner.modifyRemoval(o);
|
||||
return o;
|
||||
}
|
||||
|
||||
public List<E> subList(int fromIndex, int toIndex) {
|
||||
return new ModifyList<E>(owner, list.subList(fromIndex, toIndex));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,79 +1,79 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.util.ListIterator;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
|
||||
/**
|
||||
* Wraps a ListIterator for the purposes of notifying removals and additions to
|
||||
* the BeanCollection owner.
|
||||
* <p>
|
||||
* This is required for persisting ManyToMany objects. Additions and removals
|
||||
* become inserts and deletes to the intersection table.
|
||||
* </p>
|
||||
*/
|
||||
class ModifyListIterator<E> implements ListIterator<E> {
|
||||
|
||||
private final BeanCollection<E> owner;
|
||||
|
||||
private final ListIterator<E> it;
|
||||
|
||||
private E last;
|
||||
|
||||
/**
|
||||
* Create with an Owner that is notified of any additions or deletions.
|
||||
*/
|
||||
ModifyListIterator(BeanCollection<E> owner, ListIterator<E> it) {
|
||||
this.owner = owner;
|
||||
this.it = it;
|
||||
}
|
||||
|
||||
public void add(E bean) {
|
||||
owner.modifyAddition(bean);
|
||||
last = null;
|
||||
it.add(bean);
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return it.hasNext();
|
||||
}
|
||||
|
||||
public boolean hasPrevious() {
|
||||
return it.hasPrevious();
|
||||
}
|
||||
|
||||
public E next() {
|
||||
last = it.next();
|
||||
return last;
|
||||
}
|
||||
|
||||
public int nextIndex() {
|
||||
return it.nextIndex();
|
||||
}
|
||||
|
||||
public E previous() {
|
||||
last = it.previous();
|
||||
return last;
|
||||
}
|
||||
|
||||
public int previousIndex() {
|
||||
return it.previousIndex();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
owner.modifyRemoval(last);
|
||||
last = null;
|
||||
it.remove();
|
||||
}
|
||||
|
||||
public void set(E o) {
|
||||
if (last == null) {
|
||||
// in theory this is not allowed
|
||||
} else {
|
||||
owner.modifyRemoval(last);
|
||||
owner.modifyAddition(o);
|
||||
}
|
||||
it.set(o);
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.util.ListIterator;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
|
||||
/**
|
||||
* Wraps a ListIterator for the purposes of notifying removals and additions to
|
||||
* the BeanCollection owner.
|
||||
* <p>
|
||||
* This is required for persisting ManyToMany objects. Additions and removals
|
||||
* become inserts and deletes to the intersection table.
|
||||
* </p>
|
||||
*/
|
||||
class ModifyListIterator<E> implements ListIterator<E> {
|
||||
|
||||
private final BeanCollection<E> owner;
|
||||
|
||||
private final ListIterator<E> it;
|
||||
|
||||
private E last;
|
||||
|
||||
/**
|
||||
* Create with an Owner that is notified of any additions or deletions.
|
||||
*/
|
||||
ModifyListIterator(BeanCollection<E> owner, ListIterator<E> it) {
|
||||
this.owner = owner;
|
||||
this.it = it;
|
||||
}
|
||||
|
||||
public void add(E bean) {
|
||||
owner.modifyAddition(bean);
|
||||
last = null;
|
||||
it.add(bean);
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return it.hasNext();
|
||||
}
|
||||
|
||||
public boolean hasPrevious() {
|
||||
return it.hasPrevious();
|
||||
}
|
||||
|
||||
public E next() {
|
||||
last = it.next();
|
||||
return last;
|
||||
}
|
||||
|
||||
public int nextIndex() {
|
||||
return it.nextIndex();
|
||||
}
|
||||
|
||||
public E previous() {
|
||||
last = it.previous();
|
||||
return last;
|
||||
}
|
||||
|
||||
public int previousIndex() {
|
||||
return it.previousIndex();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
owner.modifyRemoval(last);
|
||||
last = null;
|
||||
it.remove();
|
||||
}
|
||||
|
||||
public void set(E o) {
|
||||
if (last == null) {
|
||||
// in theory this is not allowed
|
||||
} else {
|
||||
owner.modifyRemoval(last);
|
||||
owner.modifyAddition(o);
|
||||
}
|
||||
it.set(o);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
|
||||
/**
|
||||
* Wraps a Set for the purposes of notifying removals and additions to the
|
||||
* BeanCollection owner.
|
||||
* <p>
|
||||
* This is required for persisting ManyToMany objects. Additions and removals
|
||||
* become inserts and deletes to the intersection table.
|
||||
* </p>
|
||||
*/
|
||||
class ModifySet<E> extends ModifyCollection<E> implements Set<E> {
|
||||
|
||||
/**
|
||||
* Create with an Owner that is notified of any additions or deletions.
|
||||
*/
|
||||
public ModifySet(BeanCollection<E> owner, Set<E> s) {
|
||||
super(owner, s);
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
|
||||
/**
|
||||
* Wraps a Set for the purposes of notifying removals and additions to the
|
||||
* BeanCollection owner.
|
||||
* <p>
|
||||
* This is required for persisting ManyToMany objects. Additions and removals
|
||||
* become inserts and deletes to the intersection table.
|
||||
* </p>
|
||||
*/
|
||||
class ModifySet<E> extends ModifyCollection<E> implements Set<E> {
|
||||
|
||||
/**
|
||||
* Create with an Owner that is notified of any additions or deletions.
|
||||
*/
|
||||
public ModifySet(BeanCollection<E> owner, Set<E> s) {
|
||||
super(owner, s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
|
||||
/**
|
||||
* Creates the EbeanServer implementations. This is used internally by the EbeanServerFactory and is not currently
|
||||
* exposed as public API.
|
||||
*/
|
||||
public interface SpiContainer {
|
||||
|
||||
/**
|
||||
* Create the EbeanServer for a given configuration.
|
||||
*
|
||||
* @param configuration
|
||||
* The configuration information for this server.
|
||||
*/
|
||||
EbeanServer createServer(ServerConfig configuration);
|
||||
|
||||
/**
|
||||
* Create an EbeanServer just using the name.
|
||||
* <p>
|
||||
* In this case the dataSource parameters etc will be defined on the global
|
||||
* avaje.properties file.
|
||||
* </p>
|
||||
*/
|
||||
EbeanServer createServer(String name);
|
||||
|
||||
/**
|
||||
* Shutdown any Ebean wide resources such as clustering.
|
||||
*/
|
||||
void shutdown();
|
||||
}
|
||||
@@ -1,46 +1,46 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* API from creating and getting property values from an Immutable Compound
|
||||
* Value Object.
|
||||
*
|
||||
* <p>
|
||||
* A Compound Value object should contain multiple properties that are stored
|
||||
* separately. If you only have a single scalar value you should instead look to
|
||||
* use {@link ScalarTypeConverter}.
|
||||
* </p>
|
||||
* <p>
|
||||
* For each property in the compound type you need to implement the
|
||||
* {@link CompoundTypeProperty} interface. These must be returned from
|
||||
* {@link #getProperties()} in the same order that the properties appear in the
|
||||
* constructor.
|
||||
* </p>
|
||||
* <p>
|
||||
* If your compound type is mutable then you should look to use the JPA Embedded
|
||||
* annotation instead of implementing this interface.
|
||||
* </p>
|
||||
* <p>
|
||||
* When using classpath search Ebean will detect and automatically register any
|
||||
* implementations of this interface (along with detecting the entity classes
|
||||
* etc).
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* @param <V>
|
||||
* The type of the Value Object
|
||||
*
|
||||
* @see ScalarTypeConverter
|
||||
*/
|
||||
public interface CompoundType<V> {
|
||||
|
||||
/**
|
||||
* Create an instance of the compound type given its property values.
|
||||
*/
|
||||
public V create(Object[] propertyValues);
|
||||
|
||||
/**
|
||||
* Return the properties in the order they appear in the constructor.
|
||||
*/
|
||||
public CompoundTypeProperty<V, ?>[] getProperties();
|
||||
}
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* API from creating and getting property values from an Immutable Compound
|
||||
* Value Object.
|
||||
*
|
||||
* <p>
|
||||
* A Compound Value object should contain multiple properties that are stored
|
||||
* separately. If you only have a single scalar value you should instead look to
|
||||
* use {@link ScalarTypeConverter}.
|
||||
* </p>
|
||||
* <p>
|
||||
* For each property in the compound type you need to implement the
|
||||
* {@link CompoundTypeProperty} interface. These must be returned from
|
||||
* {@link #getProperties()} in the same order that the properties appear in the
|
||||
* constructor.
|
||||
* </p>
|
||||
* <p>
|
||||
* If your compound type is mutable then you should look to use the JPA Embedded
|
||||
* annotation instead of implementing this interface.
|
||||
* </p>
|
||||
* <p>
|
||||
* When using classpath search Ebean will detect and automatically register any
|
||||
* implementations of this interface (along with detecting the entity classes
|
||||
* etc).
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* @param <V>
|
||||
* The type of the Value Object
|
||||
*
|
||||
* @see ScalarTypeConverter
|
||||
*/
|
||||
public interface CompoundType<V> {
|
||||
|
||||
/**
|
||||
* Create an instance of the compound type given its property values.
|
||||
*/
|
||||
V create(Object[] propertyValues);
|
||||
|
||||
/**
|
||||
* Return the properties in the order they appear in the constructor.
|
||||
*/
|
||||
CompoundTypeProperty<V, ?>[] getProperties();
|
||||
}
|
||||
|
||||
@@ -1,51 +1,51 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Represents a Property of a Compound Value Object.
|
||||
* <p>
|
||||
* For each property in a {@link CompoundType} you need an implementation of
|
||||
* this CompoundTypeProperty interface.
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* @param <V>
|
||||
* The type of the Compound value object
|
||||
* @param <P>
|
||||
* The type of the property
|
||||
*
|
||||
* @see CompoundType
|
||||
* @see ScalarTypeConverter
|
||||
*/
|
||||
public interface CompoundTypeProperty<V, P> {
|
||||
|
||||
/**
|
||||
* The name of this property.
|
||||
*/
|
||||
public String getName();
|
||||
|
||||
/**
|
||||
* Return the property value from the containing compound value object.
|
||||
*
|
||||
* @param valueObject
|
||||
* the compound value object
|
||||
* @return the property value.
|
||||
*/
|
||||
public P getValue(V valueObject);
|
||||
|
||||
/**
|
||||
* This should <b>ONLY</b> be used when the persistence type is different from
|
||||
* the logical type returned. It most cases just return 0 and Ebean will
|
||||
* persist the logical type.
|
||||
* <p>
|
||||
* Typically this should be used when the logical type is long but the
|
||||
* persistence type is java.sql.Timestamp. In this case return
|
||||
* java.sql.Types.TIMESTAMP (rather than 0).
|
||||
* </p>
|
||||
*
|
||||
* @return Return the java.sql.Type that you want to use to persist this
|
||||
* property or 0 and Ebean will use the logical type.
|
||||
*/
|
||||
public int getDbType();
|
||||
}
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Represents a Property of a Compound Value Object.
|
||||
* <p>
|
||||
* For each property in a {@link CompoundType} you need an implementation of
|
||||
* this CompoundTypeProperty interface.
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* @param <V>
|
||||
* The type of the Compound value object
|
||||
* @param <P>
|
||||
* The type of the property
|
||||
*
|
||||
* @see CompoundType
|
||||
* @see ScalarTypeConverter
|
||||
*/
|
||||
public interface CompoundTypeProperty<V, P> {
|
||||
|
||||
/**
|
||||
* The name of this property.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Return the property value from the containing compound value object.
|
||||
*
|
||||
* @param valueObject
|
||||
* the compound value object
|
||||
* @return the property value.
|
||||
*/
|
||||
P getValue(V valueObject);
|
||||
|
||||
/**
|
||||
* This should <b>ONLY</b> be used when the persistence type is different from
|
||||
* the logical type returned. It most cases just return 0 and Ebean will
|
||||
* persist the logical type.
|
||||
* <p>
|
||||
* Typically this should be used when the logical type is long but the
|
||||
* persistence type is java.sql.Timestamp. In this case return
|
||||
* java.sql.Types.TIMESTAMP (rather than 0).
|
||||
* </p>
|
||||
*
|
||||
* @return Return the java.sql.Type that you want to use to persist this
|
||||
* property or 0 and Ebean will use the logical type.
|
||||
*/
|
||||
int getDbType();
|
||||
}
|
||||
|
||||
@@ -1,111 +1,111 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Define the encryption options for a bean property.
|
||||
* <p>
|
||||
* You can define the encryption options for a Bean property via the Encrypt
|
||||
* annotation and programmatically via {@link EncryptDeployManager}.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* @see EncryptDeployManager#getEncryptDeploy(TableName, String)
|
||||
*/
|
||||
public class EncryptDeploy {
|
||||
|
||||
/**
|
||||
* Use to define that no encryption should be used.
|
||||
*/
|
||||
public static final EncryptDeploy NO_ENCRYPT = new EncryptDeploy(Mode.MODE_NO_ENCRYPT, true, 0);
|
||||
|
||||
/**
|
||||
* Use to define that the Encrypt annotation should be used to control
|
||||
* encryption.
|
||||
*/
|
||||
public static final EncryptDeploy ANNOTATION = new EncryptDeploy(Mode.MODE_ANNOTATION, true, 0);
|
||||
|
||||
/**
|
||||
* Use to define that Encryption should be used and String types should use DB
|
||||
* encryption.
|
||||
*/
|
||||
public static final EncryptDeploy ENCRYPT_DB = new EncryptDeploy(Mode.MODE_ENCRYPT, true, 0);
|
||||
|
||||
/**
|
||||
* Use to define that Java client Encryption should be used (rather than DB
|
||||
* encryption).
|
||||
*/
|
||||
public static final EncryptDeploy ENCRYPT_CLIENT = new EncryptDeploy(Mode.MODE_ENCRYPT, false, 0);
|
||||
|
||||
/**
|
||||
* The Encryption mode.
|
||||
*/
|
||||
public enum Mode {
|
||||
/**
|
||||
* Encrypt the property using DB encryption or Java client encryption
|
||||
* depending on the type and dbEncryption flag.
|
||||
*/
|
||||
MODE_ENCRYPT,
|
||||
|
||||
/**
|
||||
* No encryption is used, even if there is an Encryption annotation on the
|
||||
* property.
|
||||
*/
|
||||
MODE_NO_ENCRYPT,
|
||||
|
||||
/**
|
||||
* Use encryption options defined by the Encryption annotation on the
|
||||
* property. If no annotation is on the property it is not encrypted.
|
||||
*/
|
||||
MODE_ANNOTATION
|
||||
}
|
||||
|
||||
private final Mode mode;
|
||||
|
||||
private final boolean dbEncrypt;
|
||||
|
||||
private final int dbLength;
|
||||
|
||||
/**
|
||||
* Construct with all options for Encryption including the dbLength.
|
||||
*
|
||||
* @param mode
|
||||
* the Encryption mode
|
||||
* @param dbEncrypt
|
||||
* set to false if you want to use Java client side encryption rather
|
||||
* than DB encryption.
|
||||
* @param dbLength
|
||||
* set the DB length to use.
|
||||
*/
|
||||
public EncryptDeploy(Mode mode, boolean dbEncrypt, int dbLength) {
|
||||
this.mode = mode;
|
||||
this.dbEncrypt = dbEncrypt;
|
||||
this.dbLength = dbLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the encryption mode.
|
||||
*/
|
||||
public Mode getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if String type should use DB encryption.
|
||||
* <p>
|
||||
* Return false if String type should use java client encryption instead.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isDbEncrypt() {
|
||||
return dbEncrypt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a hint to specify the DB length.
|
||||
* <p>
|
||||
* Returning 0 means just use the normal DB length determination.
|
||||
* </p>
|
||||
*/
|
||||
public int getDbLength() {
|
||||
return dbLength;
|
||||
}
|
||||
}
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Define the encryption options for a bean property.
|
||||
* <p>
|
||||
* You can define the encryption options for a Bean property via the Encrypt
|
||||
* annotation and programmatically via {@link EncryptDeployManager}.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* @see EncryptDeployManager#getEncryptDeploy(TableName, String)
|
||||
*/
|
||||
public class EncryptDeploy {
|
||||
|
||||
/**
|
||||
* Use to define that no encryption should be used.
|
||||
*/
|
||||
public static final EncryptDeploy NO_ENCRYPT = new EncryptDeploy(Mode.MODE_NO_ENCRYPT, true, 0);
|
||||
|
||||
/**
|
||||
* Use to define that the Encrypt annotation should be used to control
|
||||
* encryption.
|
||||
*/
|
||||
public static final EncryptDeploy ANNOTATION = new EncryptDeploy(Mode.MODE_ANNOTATION, true, 0);
|
||||
|
||||
/**
|
||||
* Use to define that Encryption should be used and String types should use DB
|
||||
* encryption.
|
||||
*/
|
||||
public static final EncryptDeploy ENCRYPT_DB = new EncryptDeploy(Mode.MODE_ENCRYPT, true, 0);
|
||||
|
||||
/**
|
||||
* Use to define that Java client Encryption should be used (rather than DB
|
||||
* encryption).
|
||||
*/
|
||||
public static final EncryptDeploy ENCRYPT_CLIENT = new EncryptDeploy(Mode.MODE_ENCRYPT, false, 0);
|
||||
|
||||
/**
|
||||
* The Encryption mode.
|
||||
*/
|
||||
public enum Mode {
|
||||
/**
|
||||
* Encrypt the property using DB encryption or Java client encryption
|
||||
* depending on the type and dbEncryption flag.
|
||||
*/
|
||||
MODE_ENCRYPT,
|
||||
|
||||
/**
|
||||
* No encryption is used, even if there is an Encryption annotation on the
|
||||
* property.
|
||||
*/
|
||||
MODE_NO_ENCRYPT,
|
||||
|
||||
/**
|
||||
* Use encryption options defined by the Encryption annotation on the
|
||||
* property. If no annotation is on the property it is not encrypted.
|
||||
*/
|
||||
MODE_ANNOTATION
|
||||
}
|
||||
|
||||
private final Mode mode;
|
||||
|
||||
private final boolean dbEncrypt;
|
||||
|
||||
private final int dbLength;
|
||||
|
||||
/**
|
||||
* Construct with all options for Encryption including the dbLength.
|
||||
*
|
||||
* @param mode
|
||||
* the Encryption mode
|
||||
* @param dbEncrypt
|
||||
* set to false if you want to use Java client side encryption rather
|
||||
* than DB encryption.
|
||||
* @param dbLength
|
||||
* set the DB length to use.
|
||||
*/
|
||||
public EncryptDeploy(Mode mode, boolean dbEncrypt, int dbLength) {
|
||||
this.mode = mode;
|
||||
this.dbEncrypt = dbEncrypt;
|
||||
this.dbLength = dbLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the encryption mode.
|
||||
*/
|
||||
public Mode getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if String type should use DB encryption.
|
||||
* <p>
|
||||
* Return false if String type should use java client encryption instead.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isDbEncrypt() {
|
||||
return dbEncrypt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a hint to specify the DB length.
|
||||
* <p>
|
||||
* Returning 0 means just use the normal DB length determination.
|
||||
* </p>
|
||||
*/
|
||||
public int getDbLength() {
|
||||
return dbLength;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Programmatically define which database columns are encrypted.
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
*/
|
||||
public interface EncryptDeployManager {
|
||||
|
||||
/**
|
||||
* Return true if the table column is encrypted.
|
||||
*/
|
||||
public EncryptDeploy getEncryptDeploy(TableName table, String column);
|
||||
}
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Programmatically define which database columns are encrypted.
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
*/
|
||||
public interface EncryptDeployManager {
|
||||
|
||||
/**
|
||||
* Return true if the table column is encrypted.
|
||||
*/
|
||||
EncryptDeploy getEncryptDeploy(TableName table, String column);
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Represents the key used for encryption.
|
||||
* <p>
|
||||
* For simple cases this often represent a simple String key but depending on
|
||||
* the encryption method this could contain other details.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface EncryptKey {
|
||||
|
||||
/**
|
||||
* Return the string key value.
|
||||
*/
|
||||
public String getStringValue();
|
||||
}
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Represents the key used for encryption.
|
||||
* <p>
|
||||
* For simple cases this often represent a simple String key but depending on
|
||||
* the encryption method this could contain other details.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface EncryptKey {
|
||||
|
||||
/**
|
||||
* Return the string key value.
|
||||
*/
|
||||
String getStringValue();
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user